diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 50c0236c1..ab866a494 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,8 +2,14 @@ name: continuous-integration on: [push, pull_request] jobs: - linux-os: - runs-on: ubuntu-20.04 + Linux: + runs-on: ubuntu-22.04 + permissions: + checks: write + pull-requests: write + env: + ALSOFT_CONF: love2d-${{ github.sha }}/testing/resources/alsoft.conf + DISPLAY: :99 steps: - name: Update APT run: sudo apt-get update @@ -15,14 +21,16 @@ jobs: libxfixes-dev libxi-dev libxinerama-dev libxxf86vm-dev libxss-dev \ libgl1-mesa-dev libdbus-1-dev libudev-dev libgles2-mesa-dev \ libegl1-mesa-dev libibus-1.0-dev fcitx-libs-dev libsamplerate0-dev \ - libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev + libsndio-dev libwayland-dev libxkbcommon-dev libdrm-dev libgbm-dev \ + libcurl4-openssl-dev libfuse2 wmctrl openbox mesa-vulkan-drivers \ + libvulkan1 vulkan-tools vulkan-validationlayers - name: Checkout love-appimage-source - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: repository: love2d/love-appimage-source ref: 12.x - name: Checkout LÖVE - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: love2d-${{ github.sha }} - name: Get Dependencies for AppImage @@ -39,25 +47,115 @@ jobs: run: make LOVE_BRANCH=${{ github.sha }} - name: Print LuaJIT branch run: git -C LuaJIT-v2.1 branch -v + # start xvfb for test running + - name: Start xvfb and openbox + run: | + echo "Starting XVFB on $DISPLAY" + Xvfb $DISPLAY -screen 0, 360x240x24 & + echo "XVFBPID=$!" >> $GITHUB_ENV + # wait for xvfb to startup (3s is the same amount xvfb-run waits by default) + sleep 3 + openbox & + echo "OPENBOXPID=$!" >> $GITHUB_ENV + # linux opengl tests + - name: Run Test Suite (opengl) + run: | + chmod a+x love-${{ github.sha }}.AppImage + ./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --all --isRunner --renderers opengl + - name: Love Test Report (opengl) + id: report1 + uses: ellraiser/love-test-report@main + with: + name: Love Testsuite Linux + title: test-report-linux-opengl + path: love2d-${{ github.sha }}/testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (opengl) + run: | + 7z a -tzip test-output-linux-opengl.zip love2d-${{ github.sha }}/testing/output/ + - name: Artifact Test Output (opengl) + uses: actions/upload-artifact@v4 + with: + name: test-output-linux-opengl-${{ steps.report1.outputs.conclusion }} + path: test-output-linux-opengl.zip + # linux opengles tests + - name: Run Test Suite (opengles) + env: + LOVE_GRAPHICS_DEBUG: 1 + run: | + export LOVE_GRAPHICS_USE_OPENGLES=1 + ./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --all --isRunner --renderers opengl + - name: Love Test Report (opengles) + uses: ellraiser/love-test-report@main + id: report2 + with: + name: Love Testsuite Linux + title: test-report-linux-opengles + path: love2d-${{ github.sha }}/testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (opengles) + run: | + 7z a -tzip test-output-linux-opengles.zip love2d-${{ github.sha }}/testing/output/ + - name: Artifact Test Output (opengles) + uses: actions/upload-artifact@v4 + with: + name: test-output-linux-opengles-${{ steps.report2.outputs.conclusion }} + path: test-output-linux-opengles.zip +# # linux vulkan tests +# - name: Run Test Suite (vulkan) +# env: +# LOVE_GRAPHICS_DEBUG: 1 +# run: | +# ./love-${{ github.sha }}.AppImage love2d-${{ github.sha }}/testing/main.lua --all --isRunner --renderers vulkan +# - name: Love Test Report (vulkan) +# uses: ellraiser/love-test-report@main +# with: +# name: Love Testsuite Linux +# title: test-report-linux-vulkan +# path: love2d-${{ github.sha }}/testing/output/lovetest_all.md +# - name: Zip Test Output (vulkan) +# run: | +# 7z a -tzip test-output-linux-vulkan.zip love2d-${{ github.sha }}/testing/output/ +# - name: Artifact Test Output (vulkan) +# uses: actions/upload-artifact@v4 +# with: +# name: test-output-linux-vulkan +# path: test-output-linux-vulkan.zip + - name: Stop xvfb and openbox + # should always stop xvfb and openbox even if other steps failed + if: always() + run: | + kill $XVFBPID + kill $OPENBOXPID - name: Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: love-linux-x86_64.AppImage path: love-${{ github.sha }}.AppImage - name: Artifact Debug Symbols - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: love-x86_64-AppImage-debug path: love-${{ github.sha }}.AppImage-debug.tar.gz - windows-os: + - name: Check Tests Passing + if: steps.report1.outputs.conclusion == 'failure' || steps.report2.outputs.conclusion == 'failure' + run: | + echo "${{ steps.report1.outputs.failed }} opengl tests failed" + echo "${{ steps.report2.outputs.failed }} opengles tests failed" + exit 1 + + Windows: runs-on: windows-latest + permissions: + checks: write + pull-requests: write + env: + ALSOFT_CONF: megasource/libs/love/testing/resources/alsoft.conf + VK_ICD_FILENAMES: ${{ github.workspace }}\mesa\x64\lvp_icd.x86_64.json + VULKAN_SDK: C:/VulkanSDK/1.3.231.1 strategy: matrix: - platform: [Win32, x64, ARM64] - install: [compat, modern] - exclude: - - platform: ARM64 - install: compat + platform: [x64, ARM64] defaults: run: shell: cmd @@ -66,17 +164,8 @@ jobs: - name: Define Variables id: vars run: | - rem Compat/Modern switch - if "${{ matrix.install }}" == "compat" ( - echo moredef=-DLOVE_INSTALL_UCRT=ON>> "%GITHUB_OUTPUT%" - echo compatname=-compat>> "%GITHUB_OUTPUT%" - ) else ( - echo moredef=>> "%GITHUB_OUTPUT%" - echo compatname=>> "%GITHUB_OUTPUT%" - ) - rem JIT Modules - if "${{ matrix.platform }}-${{ matrix.install }}" == "x64-modern" ( + if "${{ matrix.platform }}" == "x64" ( (echo jitmodules=1)>> "%GITHUB_OUTPUT%" ) else ( (echo jitmodules=0)>> "%GITHUB_OUTPUT%" @@ -104,31 +193,32 @@ jobs: echo nofiles=ignore>> "%GITHUB_OUTPUT%" echo moredef=-DLOVE_EXTRA_DLLS=%CD%\angle\libEGL.dll;%CD%\angle\libGLESv2.dll>> "%GITHUB_OUTPUT%" exit /b 0 - - name: Download Windows SDK Setup 10.0.20348 - run: curl -Lo winsdksetup.exe https://go.microsoft.com/fwlink/?linkid=2164145 - - name: Install Debugging Tools for Windows - id: windbg + - name: Download pdbstr + run: curl -Lfo pdbstr.nupkg https://www.nuget.org/api/v2/package/Microsoft.Debugging.Tools.PdbStr/20230731.1609.0 + - name: Download srctool + run: curl -Lfo srctool.nupkg https://www.nuget.org/api/v2/package/Microsoft.Debugging.Tools.SrcTool/20230731.1609.0 + - name: Extract Tools and Add to PATH run: | - setlocal enabledelayedexpansion - start /WAIT %CD%\winsdksetup.exe /features OptionId.WindowsDesktopDebuggers /q /log %CD%\log.txt - echo ERRORLEVEL=!ERRORLEVEL! >> %GITHUB_OUTPUT% - - name: Print Debugging Tools Install Log - if: always() - run: | - type log.txt - exit /b ${{ steps.windbg.outputs.ERRORLEVEL }} + mkdir debugtools + cd debugtools + if errorlevel 1 exit /b 1 + 7z e ..\srctool.nupkg content/amd64/srctool.exe + if errorlevel 1 exit /b 1 + 7z e ..\pdbstr.nupkg content/amd64/pdbstr.exe + if errorlevel 1 exit /b 1 + echo %CD%>>%GITHUB_PATH% - name: Setup Python 3.10 - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.10" - name: Download source_index.py - run: curl -Lo source_index.py https://gist.github.com/MikuAuahDark/d9c099f5714e09a765496471c2827a55/raw/df34956052035f3473c5f01861dfb53930d06843/source_index.py + run: curl -Lfo source_index.py https://gist.github.com/MikuAuahDark/d9c099f5714e09a765496471c2827a55/raw/df34956052035f3473c5f01861dfb53930d06843/source_index.py - name: Clone Megasource - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: megasource repository: love2d/megasource - ref: 12.x + ref: main - id: megasource name: Get Megasource Commit SHA shell: python @@ -140,11 +230,11 @@ jobs: commit = result.stdout.split()[0] with open(os.environ["GITHUB_OUTPUT"], "w", encoding="UTF-8") as f: f.write(f"commit={commit}") - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: megasource/libs/love - name: Download ANGLE - uses: robinraju/release-downloader@v1.7 + uses: robinraju/release-downloader@v1.9 if: steps.vars.outputs.angle == '1' with: repository: MikuAuahDark/angle-winbuild @@ -157,19 +247,19 @@ jobs: if: steps.vars.outputs.angle == '1' working-directory: angle run: 7z x angle-win-${{ steps.vars.outputs.arch }}.zip - - name: Delete Strawbery Perl + - name: Remove Strawbery Perl From Path # https://github.com/actions/runner-images/issues/6627 # In particular, this is not pretty, but even CMAKE_IGNORE_PREFIX_PATH - # cannot help in this case. Delete the whole folder! + # cannot help in this case. run: | - rmdir /s /q C:\Strawberry + move /y C:\Strawberry C:\Strawberry_not_in_PATH exit /b 0 - name: Configure env: CFLAGS: /Zi CXXFLAGS: /Zi LDFLAGS: /DEBUG:FULL /OPT:REF /OPT:ICF - run: cmake -Bbuild -Smegasource -T v142 -A ${{ matrix.platform }} --install-prefix %CD%\install -DCMAKE_PDB_OUTPUT_DIRECTORY=%CD%\pdb ${{ steps.vars.outputs.moredef }} + run: cmake -Bbuild -Smegasource -T v143 -A ${{ matrix.platform }} --install-prefix %CD%\install -DCMAKE_PDB_OUTPUT_DIRECTORY=%CD%\pdb ${{ steps.vars.outputs.moredef }} - name: Install run: cmake --build build --target PACKAGE --config Release -j2 - name: Copy LuaJIT lua51.pdb @@ -187,35 +277,150 @@ jobs: --source %CD%\build\libs\LuaJIT https://raw.githubusercontent.com/love2d/megasource/${{ steps.megasource.outputs.commit }}/libs/LuaJIT ^ pdb\Release\*.pdb - name: Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: love-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }} + name: love-windows-${{ steps.vars.outputs.arch }} path: | build/*.zip build/*.exe if-no-files-found: ${{ steps.vars.outputs.nofiles }} - name: Artifact JIT Modules if: steps.vars.outputs.jitmodules == '1' - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: love-windows-jitmodules path: build/libs/LuaJIT/src/jit/*.lua - name: Artifact PDB - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: - name: love-windows-${{ steps.vars.outputs.arch }}${{ steps.vars.outputs.compatname }}-dbg + name: love-windows-${{ steps.vars.outputs.arch }}-dbg path: pdb/Release/*.pdb + # install mesa for graphic tests + - name: Install Mesa + if: steps.vars.outputs.arch != 'ARM64' + run: | + curl -L --output mesa.7z --url https://github.com/pal1000/mesa-dist-win/releases/download/23.2.1/mesa3d-23.2.1-release-msvc.7z + 7z x mesa.7z -o* + powershell.exe mesa\systemwidedeploy.cmd 1 + # build love to use for the tests + - name: Build Test Exe + if: steps.vars.outputs.arch != 'ARM64' + run: cmake --build build --config Release --target install + # windows opengl tests + - name: Run Tests (opengl) + if: steps.vars.outputs.arch != 'ARM64' + env: + LOVE_GRAPHICS_DEBUG: 1 + run: | + echo 'check dir' + ls + powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --all --isRunner --renderers opengl + - name: Love Test Report (opengl) + id: report1 + if: steps.vars.outputs.arch != 'ARM64' + uses: ellraiser/love-test-report@main + with: + name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} (opengl) + title: test-report-windows-${{ steps.vars.outputs.arch }}-opengl + path: megasource/libs/love/testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (opengl) + if: steps.vars.outputs.arch != 'ARM64' + run: | + 7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}-opengl.zip megasource/libs/love/testing/output/ + - name: Artifact Test Output (opengl) + if: steps.vars.outputs.arch != 'ARM64' + uses: actions/upload-artifact@v4 + with: + name: test-output-windows-${{ steps.vars.outputs.arch }}-opengl-${{ steps.report1.outputs.conclusion }} + path: test-output-windows-${{ steps.vars.outputs.arch }}-opengl.zip + # windows opengles tests + - name: Run Tests (opengles) + if: steps.vars.outputs.arch != 'ARM64' + env: + LOVE_GRAPHICS_DEBUG: 1 + LOVE_GRAPHICS_USE_OPENGLES: 1 + run: | + powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --all --isRunner --renderers opengl + - name: Love Test Report (opengles) + id: report2 + if: steps.vars.outputs.arch != 'ARM64' + uses: ellraiser/love-test-report@main + with: + name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} (opengles) + title: test-report-windows-${{ steps.vars.outputs.arch }}-opengles + path: megasource/libs/love/testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (opengles) + if: steps.vars.outputs.arch != 'ARM64' + run: | + 7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}-opengles.zip megasource/libs/love/testing/output/ + - name: Artifact Test Output (opengles) + if: steps.vars.outputs.arch != 'ARM64' + uses: actions/upload-artifact@v4 + with: + name: test-output-windows-${{ steps.vars.outputs.arch }}-opengles-${{ steps.report2.outputs.conclusion }} + path: test-output-windows-${{ steps.vars.outputs.arch }}-opengles.zip + - name: Check Tests Passing + if: steps.report1.outputs.conclusion == 'failure' || steps.report2.outputs.conclusion == 'failure' + run: | + echo "${{ steps.report1.outputs.failed }} opengl tests failed" + echo "${{ steps.report2.outputs.failed }} opengles tests failed" + exit 1 +# # install vulkan +# - name: Install Vulkan +# if: steps.vars.outputs.arch != 'ARM64' +# run: | +# curl -L --show-error --output VulkanSDK.exe https://sdk.lunarg.com/sdk/download/1.3.231.1/windows/VulkanSDK-1.3.231.1-Installer.exe +# ./VulkanSDK.exe --root C:/VulkanSDK/1.3.231.1 --accept-licenses --default-answer --confirm-command install com.lunarg.vulkan.core com.lunarg.vulkan.vma +# curl -L --show-error --output vulkan-runtime.zip https://sdk.lunarg.com/sdk/download/1.3.231.1/windows/vulkan-runtime-components.zip +# 7z e vulkan-runtime.zip -o"C:/VulkanSDK/1.3.231.1/runtime/x64" */x64 +# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "mesa/x64" +# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "C:/Windows/System32" +# copy "C:/VulkanSDK/1.3.231.1/runtime/x64/vulkan-1.dll" "love-12.0-win64/love-12.0-win64" +# reg add HKEY_LOCAL_MACHINE\SOFTWARE\Khronos\Vulkan\Drivers /v "${{ github.workspace }}\mesa\x64\lvp_icd.x86_64.json" /t REG_DWORD /d 0 +# powershell.exe C:/VulkanSDK/1.3.231.1/runtime/x64/vulkaninfo.exe --summary +# # windows vulkan tests +# - name: Run Tests (vulkan) +# if: steps.vars.outputs.arch != 'ARM64' +# env: +# LOVE_GRAPHICS_DEBUG: 1 +# run: | +# powershell.exe ./install/lovec.exe ./megasource/libs/love/testing/main.lua --all --isRunner --renderers vulkan +# - name: Love Test Report (vulkan) +# if: steps.vars.outputs.arch != 'ARM64' +# uses: ellraiser/love-test-report@main +# with: +# name: Love Testsuite Windows ${{ steps.vars.outputs.arch }} (vulkan) +# title: test-report-windows-${{ steps.vars.outputs.arch }}-vulkan +# path: megasource/libs/love/testing/output/lovetest_all.md +# - name: Zip Test Output (vulkan) +# if: steps.vars.outputs.arch != 'ARM64' +# run: | +# 7z a -tzip test-output-windows-${{ steps.vars.outputs.arch }}-vulkan.zip megasource/libs/love/testing/output/ +# - name: Artifact Test Output (vulkan) +# if: steps.vars.outputs.arch != 'ARM64' +# uses: actions/upload-artifact@v4 +# with: +# name: test-output-windows-${{ steps.vars.outputs.arch }}-vulkan +# path: test-output-windows-${{ steps.vars.outputs.arch }}-vulkan.zip + macOS: runs-on: macos-latest + permissions: + checks: write + pull-requests: write + env: + ALSOFT_CONF: testing/resources/alsoft.conf steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Clone Dependencies - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: apple-dependencies repository: love2d/love-apple-dependencies - ref: 12.x + ref: main - name: Move Dependencies run: mv apple-dependencies/macOS/Frameworks platform/xcode/macosx @@ -229,24 +434,155 @@ jobs: run: ditto -c -k --sequesterRsrc --keepParent love-macos/love.app love-macos.zip - name: Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: love-macos path: love-macos.zip + # macos opengl tests + - name: Run Test Suite (OpenGL) + env: + LOVE_GRAPHICS_DEBUG: 1 + run: | + ls + love-macos/love.app/Contents/MacOS/love ./testing/main.lua --all --isRunner --renderers opengl + - name: Love Test Report (OpenGL) + id: report1 + uses: ellraiser/love-test-report@main + with: + name: Love Testsuite MacOS + title: test-report-macos-opengl + path: testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (OpenGL) + run: | + 7z a -tzip test-output-macos-opengl.zip ./testing/output/ + - name: Artifact Test Output (OpenGL) + uses: actions/upload-artifact@v4 + with: + name: test-output-macos-opengl-${{ steps.report1.outputs.conclusion }} + path: test-output-macos-opengl.zip + - name: Check Tests Passing (OpenGL) + if: steps.report1.outputs.conclusion == 'failure' + run: | + echo "${{ steps.report1.outputs.failed }} opengl tests failed" + exit 1 + # macos metal tests + - name: Run Test Suite (Metal) + env: + LOVE_GRAPHICS_DEBUG: 1 + run: | + ls + love-macos/love.app/Contents/MacOS/love ./testing/main.lua --all --isRunner --renderers metal + - name: Love Test Report (Metal) + id: report2 + uses: ellraiser/love-test-report@main + with: + name: Love Testsuite MacOS (Metal) + title: test-report-macos-metal + path: testing/output/lovetest_all.md + token: ${{ secrets.GITHUB_TOKEN }} + - name: Zip Test Output (Metal) + run: | + 7z a -tzip test-output-macos-metal.zip ./testing/output/ + - name: Artifact Test Output (Metal) + uses: actions/upload-artifact@v4 + with: + name: test-output-macos-metal-${{ steps.report2.outputs.conclusion }} + path: test-output-macos-metal.zip + - name: Check Tests Passing (Metal) + if: steps.report2.outputs.conclusion == 'failure' + run: | + echo "${{ steps.report2.outputs.failed }} metal tests failed" + exit 1 + iOS-Simulator: - runs-on: macos-latest + runs-on: macos-14 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Clone Dependencies - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: apple-dependencies repository: love2d/love-apple-dependencies - ref: 12.x + ref: main - name: Move Dependencies run: | mv apple-dependencies/iOS/libraries platform/xcode/ios - name: Build run: - xcodebuild -project platform/xcode/love.xcodeproj -scheme love-ios -configuration Release -destination 'platform=iOS Simulator,name=iPhone 11' + xcodebuild -project platform/xcode/love.xcodeproj -scheme love-ios -configuration Release -destination 'platform=iOS Simulator,name=iPhone 15' + + Android: + runs-on: ubuntu-latest + strategy: + matrix: + build_type: [Debug, Release] + env: + GRADLE_OPTS: "-Dorg.gradle.jvmargs='-Xmx4G'" + steps: + - name: Prepare Environment + run: sudo apt-get update && curl -Lfo kitware-archive.sh https://apt.kitware.com/kitware-archive.sh && sudo bash ./kitware-archive.sh + - name: Install Dependencies + run: sudo apt-get install ninja-build cmake + - name: Checkout love-android + uses: actions/checkout@v4 + with: + repository: love2d/love-android + submodules: false + - name: Setup Java 17 + uses: actions/setup-java@v4 + with: + distribution: adopt-hotspot + java-version: 17 + cache: gradle + - name: Clone Megasource + uses: actions/checkout@v4 + with: + path: app/src/main/cpp/megasource + repository: love2d/megasource + ref: main + - name: Checkout + uses: actions/checkout@v4 + with: + path: app/src/main/cpp/love + - name: Build Normal Flavor + run: bash ./gradlew assembleNormalRecord${{ matrix.build_type }} + - name: Build Release-specific Binaries + if: ${{ matrix.build_type == 'Release' }} + run: bash ./gradlew bundleNormalNoRecordRelease bundleEmbedRecordRelease bundleEmbedNoRecordRelease + - name: Artifact (Normal debug APK) + if: ${{ matrix.build_type == 'Debug' }} + uses: actions/upload-artifact@v4 + with: + name: love-android-debug.apk + path: app/build/outputs/apk/normalRecord/debug/app-normal-record-debug.apk + - name: Artifact (Normal unsigned APK) + if: ${{ matrix.build_type == 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: love-android.apk + path: app/build/outputs/apk/normalRecord/release/app-normal-record-release-unsigned.apk + - name: Artifact (Normal AAB w/o recording) + if: ${{ matrix.build_type == 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: love-android-ps.aab + path: app/build/outputs/bundle/normalNoRecordRelease/app-normal-noRecord-release.aab + - name: Artifact (Embed AAB) + if: ${{ matrix.build_type == 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: love-android-embed-record.aab + path: app/build/outputs/bundle/embedRecordRelease/app-embed-record-release.aab + - name: Artifact (Embed AAB w/o recording) + if: ${{ matrix.build_type == 'Release' }} + uses: actions/upload-artifact@v4 + with: + name: love-android-embed.aab + path: app/build/outputs/bundle/embedNoRecordRelease/app-embed-noRecord-release.aab + - name: Artifact (Debug symbols) + uses: actions/upload-artifact@v4 + with: + name: love-android-unstripped-debugsyms-${{ matrix.build_type }} + path: app/build/intermediates/cxx diff --git a/.gitignore b/.gitignore index a8b316a2d..2721f6963 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,9 @@ stamp-h1 /src/love /src/tags .vs/ -.vscode/ \ No newline at end of file +.vscode/ +/testing/output/*.xml +/testing/output/*.html +/testing/output/*.md +/testing/output/actual/*.png +/testing/output/difference/*.png diff --git a/CMakeLists.txt b/CMakeLists.txt index 7e5bc4fcd..3ca84721c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2006-2023 LOVE Development Team +# Copyright (c) 2006-2024 LOVE Development Team # # This software is provided 'as-is', without any express or implied # warranty. In no event will the authors be held liable for any damages @@ -23,28 +23,56 @@ if(${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_CURRENT_BINARY_DIR}) message(FATAL_ERROR "Prevented in-tree build.") endif() -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.16) project(love) -set(LOVE_EXE_NAME love) -set(LOVE_LIB_NAME liblove) - set(CMAKE_MODULE_PATH "${love_SOURCE_DIR}/extra/cmake" ${CMAKE_MODULE_PATH}) -# Needed for shared libs on Linux. (-fPIC). -set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) - -set (CMAKE_CXX_STANDARD 17) +set(CMAKE_POSITION_INDEPENDENT_CODE TRUE) # Needed for shared libs on Linux. (-fPIC). +set(CMAKE_CXX_STANDARD 17) +set_property(GLOBAL PROPERTY USE_FOLDERS ON) # Allow grouping projects in Visual Studio if(APPLE) message(WARNING "CMake is not an officially supported build system for love on Apple platforms.") message(WARNING "Use the prebuilt .app or the xcode project in platform/xcode/ instead.") endif() -if(MSVC) - set(LOVE_CONSOLE_EXE_NAME lovec) +if(MINGW) + message(WARNING "MinGW is not an officially supported build system for love.") + message(WARNING "Use megasource with Visual Studio instead.") + message(WARNING "Please see https://github.com/love2d/megasource") endif() +include(LoveMacros) + +# Extract version.h contents. +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/common/version.h LOVE_VERSION_FILE_CONTENTS) + +# Extract one of LOVE_VERSION_MAJOR/MINOR/REV. +function(match_version ARG_STRING OUT_VAR) + string(REGEX MATCH "VERSION_${ARG_STRING} = ([0-9]+);" TMP_VER "${LOVE_VERSION_FILE_CONTENTS}") + string(REGEX MATCH "[0-9]+" TMP_VER "${TMP_VER}") + set(${OUT_VAR} ${TMP_VER} PARENT_SCOPE) +endfunction() + +match_version("MAJOR" LOVE_VERSION_MAJOR) +match_version("MINOR" LOVE_VERSION_MINOR) +match_version("REV" LOVE_VERSION_REV) + +set(LOVE_VERSION_STR "${LOVE_VERSION_MAJOR}.${LOVE_VERSION_MINOR}") + +message(STATUS "Version: ${LOVE_VERSION_STR}") + +set(LOVE_EXE_NAME love CACHE STRING "The name of the executable, usually 'love'") + +set(LOVE_DEFAULT_LIB_NAME liblove) +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + set(LOVE_DEFAULT_LIB_NAME "${LOVE_EXE_NAME}-${LOVE_VERSION_STR}") +endif() + +set(LOVE_LIB_NAME ${LOVE_DEFAULT_LIB_NAME} CACHE STRING "The name of the lua library, usually 'liblove' or 'love'") +set(LOVE_CONSOLE_EXE_NAME "${LOVE_EXE_NAME}c" CACHE STRING "The name of the console version of the executable, usually 'lovec'") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(LOVE_X64 TRUE) set(LOVE_TARGET_PLATFORM x64) @@ -54,7 +82,7 @@ else() endif() -if(APPLE OR MEGA_ARM64) +if(APPLE) set(LOVE_DEFAULT_JIT FALSE) else() set(LOVE_DEFAULT_JIT TRUE) @@ -73,24 +101,22 @@ endif() message(STATUS "Target platform: ${LOVE_TARGET_PLATFORM}") -if(POLICY CMP0072) - cmake_policy(SET CMP0072 NEW) -endif() - -if(POLICY CMP0063) - cmake_policy(SET CMP0063 NEW) -endif() +add_library(lovedep::SDL INTERFACE IMPORTED) +add_library(lovedep::Freetype INTERFACE IMPORTED) +add_library(lovedep::Harfbuzz INTERFACE IMPORTED) +add_library(lovedep::OpenAL INTERFACE IMPORTED) +add_library(lovedep::Modplug INTERFACE IMPORTED) +add_library(lovedep::Theora INTERFACE IMPORTED) +add_library(lovedep::Vorbis INTERFACE IMPORTED) +add_library(lovedep::Ogg INTERFACE IMPORTED) +add_library(lovedep::Zlib INTERFACE IMPORTED) +add_library(lovedep::Lua INTERFACE IMPORTED) if(MEGA) # LOVE_MSVC_DLLS contains runtime DLLs that should be bundled with the love # binary (in e.g. the installer). Example: msvcp140.dll. set(LOVE_MSVC_DLLS ${MEGA_MSVC_DLLS}) - # LOVE_INCLUDE_DIRS contains the search directories for #include. It's mostly - # not needed for MEGA builds, since almost all the libraries (except LuaJIT) - # are CMake targets, causing include paths to be added automatically. - set(LOVE_INCLUDE_DIRS) - if(APPLE) # Some files do #include , but building with megasource # requires #include . @@ -101,20 +127,6 @@ if(MEGA) # pull those libraries in for linkage because we link with SDL2. set(LOVE_LINK_DIRS ${SDL_LINK_DIR}) - set(LOVE_LINK_LIBRARIES - ${MEGA_FREETYPE} - ${MEGA_HARFBUZZ} - ${MEGA_LIBOGG} - ${MEGA_LIBVORBISFILE} - ${MEGA_LIBVORBIS} - ${MEGA_LIBTHEORA} - ${MEGA_MODPLUG} - ${MEGA_OPENAL} - ${MEGA_SDL2MAIN} - ${MEGA_SDL2} - ${MEGA_ZLIB} - ) - # These DLLs are moved next to the love binary in a post-build step to # love runnable from inside Visual Studio. # @@ -124,6 +136,7 @@ if(MEGA) # action. set(LOVE_MOVE_DLLS ${MEGA_SDL2} + ${MEGA_SDL3} ${MEGA_OPENAL} ) @@ -134,36 +147,33 @@ if(MEGA) set(LOVE_EXTRA_DLLS) endif() + target_link_libraries(lovedep::SDL INTERFACE ${MEGA_SDL2} ${MEGA_SDL2MAIN} ${MEGA_SDL3}) + target_link_libraries(lovedep::Freetype INTERFACE ${MEGA_FREETYPE}) + target_link_libraries(lovedep::Harfbuzz INTERFACE ${MEGA_HARFBUZZ}) + target_link_libraries(lovedep::OpenAL INTERFACE ${MEGA_OPENAL}) + target_link_libraries(lovedep::Modplug INTERFACE ${MEGA_MODPLUG}) + target_link_libraries(lovedep::Theora INTERFACE ${MEGA_LIBTHEORA}) + target_link_libraries(lovedep::Vorbis INTERFACE ${MEGA_LIBVORBIS} ${MEGA_LIBVORBISFILE}) + target_link_libraries(lovedep::Ogg INTERFACE ${MEGA_LIBOGG}) + target_link_libraries(lovedep::Zlib INTERFACE ${MEGA_ZLIB}) + if(LOVE_JIT) - set(LOVE_LUA_LIBRARY ${MEGA_LUAJIT_LIB}) + target_include_directories(lovedep::Lua INTERFACE ${MEGA_LUAJIT_INCLUDE}) + target_link_libraries(lovedep::Lua INTERFACE ${MEGA_LUAJIT_LIB}) set(LOVE_EXTRA_DLLS ${LOVE_EXTRA_DLLS} ${MEGA_LUAJIT_DLL}) set(LOVE_EXTRA_DEPENDECIES luajit) - - set(LOVE_INCLUDE_DIRS - ${LOVE_INCLUDE_DIRS} - ${MEGA_LUAJIT_INCLUDE} - ) - set(LOVE_LINK_LIBRARIES - ${LOVE_LINK_LIBRARIES} - ${LOVE_LUA_LIBRARY} - ) set(LOVE_MOVE_DLLS ${LOVE_MOVE_DLLS} ${MEGA_LUAJIT_DLL} ) else() - set(LOVE_LUA_LIBRARY ${MEGA_LUA51}) - - set(LOVE_LINK_LIBRARIES - ${LOVE_LINK_LIBRARIES} - ${LOVE_LUA_LIBRARY} - ) - set(LOVE_MOVE_DLLS - ${LOVE_MOVE_DLLS} - ${LOVE_LUA_LIBRARY} - ) # MEGA_LUA51 is a CMake target, so includes are handled # automatically. + target_link_libraries(lovedep::Lua INTERFACE ${MEGA_LUA51}) + set(LOVE_MOVE_DLLS + ${LOVE_MOVE_DLLS} + ${MEGA_LUA51} + ) endif() else() if(MSVC OR ANDROID) @@ -173,66 +183,54 @@ Please see https://github.com/love2d/megasource ") endif() - find_package(Freetype REQUIRED) - find_package(Harfbuzz REQUIRED) - find_package(ModPlug REQUIRED) - find_package(OpenAL REQUIRED) - find_package(OpenGL REQUIRED) - find_package(SDL2 2.0.9 REQUIRED) - find_package(Theora REQUIRED) - find_package(Vorbis REQUIRED) - find_package(ZLIB REQUIRED) - find_package(Ogg REQUIRED) - # required for enet add_definitions(-D HAS_SOCKLEN_T) - set(LOVE_INCLUDE_DIRS - ${SDL2_INCLUDE_DIR} - ${FREETYPE_INCLUDE_DIRS} - ${HARFBUZZ_INCLUDE_DIR} - ${VORBIS_INCLUDE_DIR} - ${OPENAL_INCLUDE_DIR} - ${ZLIB_INCLUDE_DIRS} - ${MODPLUG_INCLUDE_DIR} - ${OGG_INCLUDE_DIR} - ${THEORA_INCLUDE_DIR} - ) + find_package(SDL2 2.0.9 REQUIRED CONFIG COMPONENTS SDL2main) + target_include_directories(lovedep::SDL INTERFACE ${SDL2_INCLUDE_DIRS}) + target_link_libraries(lovedep::SDL INTERFACE ${SDL2_LIBRARIES}) - set(LOVE_LINK_LIBRARIES - ${OPENGL_gl_LIBRARY} - ${SDL2_LIBRARY} - ${FREETYPE_LIBRARY} - ${HARFBUZZ_LIBRARY} - ${OPENAL_LIBRARY} - ${MODPLUG_LIBRARY} - ${THEORA_LIBRARY} - ${THEORADEC_LIBRARY} - ${VORBISFILE_LIBRARY} - ${LOVE_LUA_LIBRARY} - ${OGG_LIBRARY} - ${ZLIB_LIBRARY} - ) + find_package(Freetype REQUIRED) + target_include_directories(lovedep::Freetype INTERFACE ${FREETYPE_INCLUDE_DIRS}) + target_link_libraries(lovedep::Freetype INTERFACE ${FREETYPE_LIBRARY}) + + find_package(Harfbuzz REQUIRED) + target_include_directories(lovedep::Harfbuzz INTERFACE ${HARFBUZZ_INCLUDE_DIR}) + target_link_libraries(lovedep::Harfbuzz INTERFACE ${HARFBUZZ_LIBRARY}) + + find_package(OpenAL REQUIRED) + target_include_directories(lovedep::OpenAL INTERFACE ${OPENAL_INCLUDE_DIR}) + target_link_libraries(lovedep::OpenAL INTERFACE ${OPENAL_LIBRARY}) + + find_package(ModPlug REQUIRED) + target_include_directories(lovedep::Modplug INTERFACE ${MODPLUG_INCLUDE_DIR}) + target_link_libraries(lovedep::Modplug INTERFACE ${MODPLUG_LIBRARY}) + + find_package(Theora REQUIRED) + target_include_directories(lovedep::Theora INTERFACE ${THEORA_INCLUDE_DIR}) + target_link_libraries(lovedep::Theora INTERFACE ${THEORA_LIBRARY} ${THEORADEC_LIBRARY}) + + find_package(Vorbis REQUIRED) + target_include_directories(lovedep::Vorbis INTERFACE ${VORBIS_INCLUDE_DIR}) + target_link_libraries(lovedep::Vorbis INTERFACE ${VORBISFILE_LIBRARY}) + + find_package(Ogg REQUIRED) + target_include_directories(lovedep::Ogg INTERFACE ${OGG_INCLUDE_DIR}) + target_link_libraries(lovedep::Ogg INTERFACE ${OGG_LIBRARY}) + + find_package(ZLIB REQUIRED) + target_include_directories(lovedep::Zlib INTERFACE ${ZLIB_INCLUDE_DIRS}) + target_link_libraries(lovedep::Zlib INTERFACE ${ZLIB_LIBRARY}) if(LOVE_JIT) find_package(LuaJIT REQUIRED) - set(LOVE_LUA_LIBRARY ${LUAJIT_LIBRARY}) - set(LOVE_LUA_INCLUDE_DIR ${LUAJIT_INCLUDE_DIR}) + target_include_directories(lovedep::Lua INTERFACE ${LUAJIT_INCLUDE_DIR}) + target_link_libraries(lovedep::Lua INTERFACE ${LUAJIT_LIBRARY}) else() find_package(Lua51 REQUIRED) - set(LOVE_LUA_LIBRARY ${LUA_LIBRARY}) - set(LOVE_LUA_INCLUDE_DIR ${LUA_INCLUDE_DIR}) + target_include_directories(lovedep::Lua INTERFACE ${LUA_INCLUDE_DIR}) + target_link_libraries(lovedep::Lua INTERFACE ${LUA_LIBRARY}) endif() - - set(LOVE_INCLUDE_DIRS - ${LOVE_INCLUDE_DIRS} - ${LOVE_LUA_INCLUDE_DIR} - ) - set(LOVE_LINK_LIBRARIES - ${LOVE_LINK_LIBRARIES} - ${LOVE_LUA_LIBRARY} - ) - endif() ### @@ -246,19 +244,14 @@ else() endif() function(love_disable_warnings ARG_TARGET) - get_target_property(OLD_FLAGS ${ARG_TARGET} COMPILE_FLAGS) - set(NEW_FLAGS ${DISABLE_WARNING_FLAG}) - if(OLD_FLAGS) - set(NEW_FLAGS "${OLD_FLAGS} ${NEW_FLAGS}") - endif() - set_target_properties(${ARG_TARGET} PROPERTIES COMPILE_FLAGS ${NEW_FLAGS}) + target_compile_options(${ARG_TARGET} PRIVATE ${DISABLE_WARNING_FLAG}) endfunction() # # common # -set(LOVE_SRC_COMMON +add_library(love_common STATIC src/common/android.cpp src/common/android.h src/common/b64.cpp @@ -308,23 +301,41 @@ set(LOVE_SRC_COMMON src/common/Vector.h src/common/version.h ) +target_link_libraries(love_common PUBLIC + lovedep::Lua + lovedep::SDL +) if (APPLE) - set(LOVE_SRC_COMMON ${LOVE_SRC_COMMON} - src/common/macos.mm + target_sources(love_common PRIVATE + src/common/apple.mm ) - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} objc) - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} "-framework CoreFoundation") - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} "-framework AppKit") + target_link_libraries(love_common PUBLIC + objc + "-framework CoreFoundation" + ) + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + target_sources(love_common PRIVATE + src/common/macos.mm + ) + target_link_libraries(love_common PUBLIC + "-framework AppKit" + ) + else() + target_sources(love_common PRIVATE + src/common/ios.mm + ) + target_link_libraries(love_common PUBLIC + "-framework UIKit" + ) + endif() endif() -source_group("common" FILES ${LOVE_SRC_COMMON}) - # # love.audio # -set(LOVE_SRC_MODULE_AUDIO_ROOT +add_library(love_audio_root STATIC src/modules/audio/Audio.cpp src/modules/audio/Audio.h src/modules/audio/Source.cpp @@ -342,8 +353,12 @@ set(LOVE_SRC_MODULE_AUDIO_ROOT src/modules/audio/wrap_RecordingDevice.cpp src/modules/audio/wrap_RecordingDevice.h ) +target_link_libraries(love_audio_root PUBLIC + lovedep::Lua + lovedep::OpenAL +) -set(LOVE_SRC_MODULE_AUDIO_NULL +add_library(love_audio_null STATIC src/modules/audio/null/Audio.cpp src/modules/audio/null/Audio.h src/modules/audio/null/Source.cpp @@ -352,7 +367,7 @@ set(LOVE_SRC_MODULE_AUDIO_NULL src/modules/audio/null/RecordingDevice.h ) -set(LOVE_SRC_MODULE_AUDIO_OPENAL +add_library(love_audio_openal STATIC src/modules/audio/openal/Audio.cpp src/modules/audio/openal/Audio.h src/modules/audio/openal/Pool.cpp @@ -366,22 +381,22 @@ set(LOVE_SRC_MODULE_AUDIO_OPENAL src/modules/audio/openal/Effect.cpp src/modules/audio/openal/Effect.h ) - -set(LOVE_SRC_MODULE_AUDIO - ${LOVE_SRC_MODULE_AUDIO_ROOT} - ${LOVE_SRC_MODULE_AUDIO_NULL} - ${LOVE_SRC_MODULE_AUDIO_OPENAL} +target_link_libraries(love_audio_openal PUBLIC + lovedep::OpenAL ) -source_group("modules\\audio" FILES ${LOVE_SRC_MODULE_AUDIO_ROOT}) -source_group("modules\\audio\\null" FILES ${LOVE_SRC_MODULE_AUDIO_NULL}) -source_group("modules\\audio\\openal" FILES ${LOVE_SRC_MODULE_AUDIO_OPENAL}) +add_library(love_audio INTERFACE) +target_link_libraries(love_audio INTERFACE + love_audio_root + love_audio_null + love_audio_openal +) # # love.data # -set(LOVE_SRC_MODULE_DATA +add_library(love_data STATIC src/modules/data/ByteData.cpp src/modules/data/ByteData.h src/modules/data/CompressedData.cpp @@ -402,43 +417,52 @@ set(LOVE_SRC_MODULE_DATA src/modules/data/wrap_CompressedData.h src/modules/data/wrap_Data.cpp src/modules/data/wrap_Data.h + src/modules/data/wrap_Data.lua src/modules/data/wrap_DataModule.cpp src/modules/data/wrap_DataModule.h src/modules/data/wrap_DataView.cpp src/modules/data/wrap_DataView.h ) - -source_group("modules\\data" FILES ${LOVE_SRC_MODULE_DATA}) +target_link_libraries(love_data PUBLIC + lovedep::Lua + lovedep::Zlib +) # # love.event # -set(LOVE_SRC_MODULE_EVENT_ROOT +add_library(love_event_root STATIC src/modules/event/Event.cpp src/modules/event/Event.h src/modules/event/wrap_Event.cpp src/modules/event/wrap_Event.h + src/modules/event/wrap_Event.lua +) +target_link_libraries(love_event_root PUBLIC + lovedep::Lua + lovedep::SDL ) -set(LOVE_SRC_MODULE_EVENT_SDL +add_library(love_event_sdl STATIC src/modules/event/sdl/Event.cpp src/modules/event/sdl/Event.h ) - -set(LOVE_SRC_MODULE_EVENT - ${LOVE_SRC_MODULE_EVENT_ROOT} - ${LOVE_SRC_MODULE_EVENT_SDL} +target_link_libraries(love_event_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\event" FILES ${LOVE_SRC_MODULE_EVENT_ROOT}) -source_group("modules\\event\\sdl" FILES ${LOVE_SRC_MODULE_EVENT_SDL}) +add_library(love_event INTERFACE) +target_link_libraries(love_event INTERFACE + love_event_root + love_event_sdl +) # # love.filesystem # -set(LOVE_SRC_MODULE_FILESYSTEM_ROOT +add_library(love_filesystem_root STATIC src/modules/filesystem/File.cpp src/modules/filesystem/File.h src/modules/filesystem/FileData.cpp @@ -456,8 +480,12 @@ set(LOVE_SRC_MODULE_FILESYSTEM_ROOT src/modules/filesystem/wrap_NativeFile.cpp src/modules/filesystem/wrap_NativeFile.h ) +target_link_libraries(love_filesystem_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_FILESYSTEM_PHYSFS +add_library(love_filesystem_physfs STATIC src/modules/filesystem/physfs/File.cpp src/modules/filesystem/physfs/File.h src/modules/filesystem/physfs/Filesystem.cpp @@ -465,20 +493,23 @@ set(LOVE_SRC_MODULE_FILESYSTEM_PHYSFS src/modules/filesystem/physfs/PhysfsIo.h src/modules/filesystem/physfs/PhysfsIo.cpp ) +if(ANDROID) + target_link_libraries(love_filesystem_physfs PUBLIC + lovedep::SDL + ) +endif() -set(LOVE_SRC_MODULE_FILESYSTEM - ${LOVE_SRC_MODULE_FILESYSTEM_ROOT} - ${LOVE_SRC_MODULE_FILESYSTEM_PHYSFS} +add_library(love_filesystem INTERFACE) +target_link_libraries(love_filesystem INTERFACE + love_filesystem_root + love_filesystem_physfs ) -source_group("modules\\filesystem" FILES ${LOVE_SRC_MODULE_FILESYSTEM_ROOT}) -source_group("modules\\filesystem\\physfs" FILES ${LOVE_SRC_MODULE_FILESYSTEM_PHYSFS}) - # # love.font # -set(LOVE_SRC_MODULE_FONT_ROOT +add_library(love_font_root STATIC src/modules/font/BMFontRasterizer.cpp src/modules/font/BMFontRasterizer.h src/modules/font/Font.cpp @@ -502,8 +533,12 @@ set(LOVE_SRC_MODULE_FONT_ROOT src/modules/font/wrap_Rasterizer.cpp src/modules/font/wrap_Rasterizer.h ) +target_link_libraries(love_font_root PUBLIC + lovedep::Lua + lovedep::Freetype +) -set(LOVE_SRC_MODULE_FONT_FREETYPE +add_library(love_font_freetype STATIC src/modules/font/freetype/Font.cpp src/modules/font/freetype/Font.h src/modules/font/freetype/HarfbuzzShaper.cpp @@ -511,20 +546,22 @@ set(LOVE_SRC_MODULE_FONT_FREETYPE src/modules/font/freetype/TrueTypeRasterizer.cpp src/modules/font/freetype/TrueTypeRasterizer.h ) - -set(LOVE_SRC_MODULE_FONT - ${LOVE_SRC_MODULE_FONT_ROOT} - ${LOVE_SRC_MODULE_FONT_FREETYPE} +target_link_libraries(love_font_freetype PUBLIC + lovedep::Freetype + lovedep::Harfbuzz ) -source_group("modules\\font" FILES ${LOVE_SRC_MODULE_FONT_ROOT}) -source_group("modules\\font\\freetype" FILES ${LOVE_SRC_MODULE_FONT_FREETYPE}) +add_library(love_font INTERFACE) +target_link_libraries(love_font INTERFACE + love_font_root + love_font_freetype +) # # love.graphics # -set(LOVE_SRC_MODULE_GRAPHICS_ROOT +add_library(love_graphics_root STATIC src/modules/graphics/Buffer.cpp src/modules/graphics/Buffer.h src/modules/graphics/Deprecations.cpp @@ -572,6 +609,7 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/wrap_Font.h src/modules/graphics/wrap_Graphics.cpp src/modules/graphics/wrap_Graphics.h + src/modules/graphics/wrap_Graphics.lua src/modules/graphics/wrap_GraphicsReadback.cpp src/modules/graphics/wrap_GraphicsReadback.h src/modules/graphics/wrap_Mesh.cpp @@ -590,9 +628,13 @@ set(LOVE_SRC_MODULE_GRAPHICS_ROOT src/modules/graphics/wrap_TextBatch.h src/modules/graphics/wrap_Video.cpp src/modules/graphics/wrap_Video.h + src/modules/graphics/wrap_Video.lua +) +target_link_libraries(love_graphics_root PUBLIC + lovedep::Lua ) -set(LOVE_SRC_MODULE_GRAPHICS_OPENGL +add_library(love_graphics_opengl STATIC src/modules/graphics/opengl/Buffer.cpp src/modules/graphics/opengl/Buffer.h src/modules/graphics/opengl/FenceSync.cpp @@ -612,41 +654,76 @@ set(LOVE_SRC_MODULE_GRAPHICS_OPENGL src/modules/graphics/opengl/Texture.cpp src/modules/graphics/opengl/Texture.h ) - -set(LOVE_SRC_MODULE_GRAPHICS_VULKAN - src/modules/graphics/vulkan/Graphics.h - src/modules/graphics/vulkan/Graphics.cpp - src/modules/graphics/vulkan/GraphicsReadback.h - src/modules/graphics/vulkan/GraphicsReadback.cpp - src/modules/graphics/vulkan/Shader.h - src/modules/graphics/vulkan/Shader.cpp - src/modules/graphics/vulkan/ShaderStage.h - src/modules/graphics/vulkan/ShaderStage.cpp - src/modules/graphics/vulkan/StreamBuffer.h - src/modules/graphics/vulkan/StreamBuffer.cpp - src/modules/graphics/vulkan/Buffer.h - src/modules/graphics/vulkan/Buffer.cpp - src/modules/graphics/vulkan/Texture.h - src/modules/graphics/vulkan/Texture.cpp - src/modules/graphics/vulkan/Vulkan.h - src/modules/graphics/vulkan/Vulkan.cpp - src/modules/graphics/vulkan/VulkanWrapper.h) - -set(LOVE_SRC_MODULE_GRAPHICS - ${LOVE_SRC_MODULE_GRAPHICS_ROOT} - ${LOVE_SRC_MODULE_GRAPHICS_OPENGL} - ${LOVE_SRC_MODULE_GRAPHICS_VULKAN} +target_link_libraries(love_graphics_opengl PUBLIC + lovedep::SDL ) -source_group("modules\\graphics" FILES ${LOVE_SRC_MODULE_GRAPHICS_ROOT}) -source_group("modules\\graphics\\opengl" FILES ${LOVE_SRC_MODULE_GRAPHICS_OPENGL}) -source_group("modules\\graphics\\vulkan" FILES ${LOVE_SRC_MODULE_GRAPHICS_VULKAN}) +add_library(love_graphics INTERFACE) +target_link_libraries(love_graphics INTERFACE + love_graphics_root + love_graphics_opengl +) + +if(APPLE) + add_library(love_graphics_metal STATIC + src/modules/graphics/metal/Buffer.h + src/modules/graphics/metal/Buffer.mm + src/modules/graphics/metal/Graphics.h + src/modules/graphics/metal/Graphics.mm + src/modules/graphics/metal/GraphicsReadback.h + src/modules/graphics/metal/GraphicsReadback.mm + src/modules/graphics/metal/Metal.h + src/modules/graphics/metal/Metal.mm + src/modules/graphics/metal/Shader.h + src/modules/graphics/metal/Shader.mm + src/modules/graphics/metal/ShaderStage.h + src/modules/graphics/metal/ShaderStage.mm + src/modules/graphics/metal/StreamBuffer.h + src/modules/graphics/metal/StreamBuffer.mm + src/modules/graphics/metal/Texture.h + src/modules/graphics/metal/Texture.mm + ) + target_link_libraries(love_graphics_metal PUBLIC + objc + "-framework Metal" + "-framework QuartzCore" + ) + target_link_libraries(love_graphics INTERFACE + love_graphics_metal + ) +else() + add_library(love_graphics_vulkan STATIC + src/modules/graphics/vulkan/Graphics.h + src/modules/graphics/vulkan/Graphics.cpp + src/modules/graphics/vulkan/GraphicsReadback.h + src/modules/graphics/vulkan/GraphicsReadback.cpp + src/modules/graphics/vulkan/Shader.h + src/modules/graphics/vulkan/Shader.cpp + src/modules/graphics/vulkan/ShaderStage.h + src/modules/graphics/vulkan/ShaderStage.cpp + src/modules/graphics/vulkan/StreamBuffer.h + src/modules/graphics/vulkan/StreamBuffer.cpp + src/modules/graphics/vulkan/Buffer.h + src/modules/graphics/vulkan/Buffer.cpp + src/modules/graphics/vulkan/Texture.h + src/modules/graphics/vulkan/Texture.cpp + src/modules/graphics/vulkan/Vulkan.h + src/modules/graphics/vulkan/Vulkan.cpp + src/modules/graphics/vulkan/VulkanWrapper.h + ) + target_link_libraries(love_graphics_vulkan PUBLIC + lovedep::SDL + ) + target_link_libraries(love_graphics INTERFACE + love_graphics_vulkan + ) +endif() # # love.image # -set(LOVE_SRC_MODULE_IMAGE_ROOT +add_library(love_image_root STATIC src/modules/image/CompressedImageData.cpp src/modules/image/CompressedImageData.h src/modules/image/CompressedSlice.cpp @@ -665,9 +742,13 @@ set(LOVE_SRC_MODULE_IMAGE_ROOT src/modules/image/wrap_Image.h src/modules/image/wrap_ImageData.cpp src/modules/image/wrap_ImageData.h + src/modules/image/wrap_ImageData.lua +) +target_link_libraries(love_image_root PUBLIC + lovedep::Lua ) -set(LOVE_SRC_MODULE_IMAGE_MAGPIE +add_library(love_image_magpie STATIC src/modules/image/magpie/ASTCHandler.cpp src/modules/image/magpie/ASTCHandler.h src/modules/image/magpie/ddsHandler.cpp @@ -685,20 +766,21 @@ set(LOVE_SRC_MODULE_IMAGE_MAGPIE src/modules/image/magpie/STBHandler.cpp src/modules/image/magpie/STBHandler.h ) - -set(LOVE_SRC_MODULE_IMAGE - ${LOVE_SRC_MODULE_IMAGE_ROOT} - ${LOVE_SRC_MODULE_IMAGE_MAGPIE} +target_link_libraries(love_image_magpie PUBLIC + lovedep::Zlib ) -source_group("modules\\image" FILES ${LOVE_SRC_MODULE_IMAGE_ROOT}) -source_group("modules\\image\\magpie" FILES ${LOVE_SRC_MODULE_IMAGE_MAGPIE}) +add_library(love_image INTERFACE) +target_link_libraries(love_image INTERFACE + love_image_root + love_image_magpie +) # # love.joystick # -set(LOVE_SRC_MODULE_JOYSTICK_ROOT +add_library(love_joystick_root STATIC src/modules/joystick/Joystick.cpp src/modules/joystick/Joystick.h src/modules/joystick/JoystickModule.h @@ -707,51 +789,62 @@ set(LOVE_SRC_MODULE_JOYSTICK_ROOT src/modules/joystick/wrap_JoystickModule.cpp src/modules/joystick/wrap_JoystickModule.h ) +target_link_libraries(love_joystick_root PUBLIC + lovedep::Lua +) -set(LOVE_SRC_MODULE_JOYSTICK_SDL +add_library(love_joystick_sdl STATIC src/modules/joystick/sdl/Joystick.cpp src/modules/joystick/sdl/Joystick.h + src/modules/joystick/sdl/JoystickSDL3.cpp + src/modules/joystick/sdl/JoystickSDL3.h src/modules/joystick/sdl/JoystickModule.cpp src/modules/joystick/sdl/JoystickModule.h ) - -set(LOVE_SRC_MODULE_JOYSTICK - ${LOVE_SRC_MODULE_JOYSTICK_ROOT} - ${LOVE_SRC_MODULE_JOYSTICK_SDL} +target_link_libraries(love_joystick_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\joystick" FILES ${LOVE_SRC_MODULE_JOYSTICK_ROOT}) -source_group("modules\\joystick\\sdl" FILES ${LOVE_SRC_MODULE_JOYSTICK_SDL}) +add_library(love_joystick INTERFACE) +target_link_libraries(love_joystick INTERFACE + love_joystick_root + love_joystick_sdl +) # # love.keyboard # -set(LOVE_SRC_MODULE_KEYBOARD_ROOT +add_library(love_keyboard_root STATIC src/modules/keyboard/Keyboard.cpp src/modules/keyboard/Keyboard.h src/modules/keyboard/wrap_Keyboard.cpp src/modules/keyboard/wrap_Keyboard.h ) +target_link_libraries(love_keyboard_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_KEYBOARD_SDL +add_library(love_keyboard_sdl STATIC src/modules/keyboard/sdl/Keyboard.cpp src/modules/keyboard/sdl/Keyboard.h ) - -set(LOVE_SRC_MODULE_KEYBOARD - ${LOVE_SRC_MODULE_KEYBOARD_ROOT} - ${LOVE_SRC_MODULE_KEYBOARD_SDL} +target_link_libraries(love_keyboard_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\keyboard" FILES ${LOVE_SRC_MODULE_KEYBOARD_ROOT}) -source_group("modules\\keyboard\\sdl" FILES ${LOVE_SRC_MODULE_KEYBOARD_SDL}) +add_library(love_keyboard INTERFACE) +target_link_libraries(love_keyboard INTERFACE + love_keyboard_root + love_keyboard_sdl +) # # love.math # -set(LOVE_SRC_MODULE_MATH +add_library(love_math STATIC src/modules/math/BezierCurve.cpp src/modules/math/BezierCurve.h src/modules/math/MathModule.cpp @@ -764,29 +857,22 @@ set(LOVE_SRC_MODULE_MATH src/modules/math/wrap_BezierCurve.h src/modules/math/wrap_Math.cpp src/modules/math/wrap_Math.h + src/modules/math/wrap_Math.lua src/modules/math/wrap_RandomGenerator.cpp src/modules/math/wrap_RandomGenerator.h + src/modules/math/wrap_RandomGenerator.lua src/modules/math/wrap_Transform.cpp src/modules/math/wrap_Transform.h ) - -source_group("modules\\math" FILES ${LOVE_SRC_MODULE_MATH}) - -# -# love (module) -# -set(LOVE_SRC_MODULE_LOVE - src/modules/love/love.cpp - src/modules/love/love.h +target_link_libraries(love_math PUBLIC + lovedep::Lua ) -source_group("modules\\love" FILES ${LOVE_SRC_MODULE_LOVE}) - # # love.mouse # -set(LOVE_SRC_MODULE_MOUSE_ROOT +add_library(love_mouse_root STATIC src/modules/mouse/Cursor.cpp src/modules/mouse/Cursor.h src/modules/mouse/Mouse.h @@ -795,27 +881,32 @@ set(LOVE_SRC_MODULE_MOUSE_ROOT src/modules/mouse/wrap_Mouse.cpp src/modules/mouse/wrap_Mouse.h ) +target_link_libraries(love_mouse_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_MOUSE_SDL +add_library(love_mouse_sdl STATIC src/modules/mouse/sdl/Cursor.cpp src/modules/mouse/sdl/Cursor.h src/modules/mouse/sdl/Mouse.cpp src/modules/mouse/sdl/Mouse.h ) - -set(LOVE_SRC_MODULE_MOUSE - ${LOVE_SRC_MODULE_MOUSE_ROOT} - ${LOVE_SRC_MODULE_MOUSE_SDL} +target_link_libraries(love_mouse_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\mouse" FILES ${LOVE_SRC_MODULE_MOUSE_ROOT}) -source_group("modules\\mouse\\sdl" FILES ${LOVE_SRC_MODULE_MOUSE_SDL}) +add_library(love_mouse INTERFACE) +target_link_libraries(love_mouse INTERFACE + love_mouse_root + love_mouse_sdl +) # # love.physics # -set(LOVE_SRC_MODULE_PHYSICS_ROOT +add_library(love_physics_root STATIC src/modules/physics/Body.cpp src/modules/physics/Body.h src/modules/physics/Joint.cpp @@ -824,7 +915,7 @@ set(LOVE_SRC_MODULE_PHYSICS_ROOT src/modules/physics/Shape.h ) -set(LOVE_SRC_MODULE_PHYSICS_BOX2D +add_library(love_physics_box2d STATIC src/modules/physics/box2d/Body.cpp src/modules/physics/box2d/Body.h src/modules/physics/box2d/ChainShape.cpp @@ -837,8 +928,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/DistanceJoint.h src/modules/physics/box2d/EdgeShape.cpp src/modules/physics/box2d/EdgeShape.h - src/modules/physics/box2d/Fixture.cpp - src/modules/physics/box2d/Fixture.h src/modules/physics/box2d/FrictionJoint.cpp src/modules/physics/box2d/FrictionJoint.h src/modules/physics/box2d/GearJoint.cpp @@ -881,8 +970,6 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/wrap_DistanceJoint.h src/modules/physics/box2d/wrap_EdgeShape.cpp src/modules/physics/box2d/wrap_EdgeShape.h - src/modules/physics/box2d/wrap_Fixture.cpp - src/modules/physics/box2d/wrap_Fixture.h src/modules/physics/box2d/wrap_FrictionJoint.cpp src/modules/physics/box2d/wrap_FrictionJoint.h src/modules/physics/box2d/wrap_GearJoint.cpp @@ -914,44 +1001,50 @@ set(LOVE_SRC_MODULE_PHYSICS_BOX2D src/modules/physics/box2d/wrap_World.cpp src/modules/physics/box2d/wrap_World.h ) - -set(LOVE_SRC_MODULE_PHYSICS - ${LOVE_SRC_MODULE_PHYSICS_ROOT} - ${LOVE_SRC_MODULE_PHYSICS_BOX2D} +target_link_libraries(love_physics_box2d PUBLIC + lovedep::Lua ) -source_group("modules\\physics" FILES ${LOVE_SRC_MODULE_PHYSICS_ROOT}) -source_group("modules\\physics\\box2d" FILES ${LOVE_SRC_MODULE_PHYSICS_BOX2D}) +add_library(love_physics INTERFACE) +target_link_libraries(love_physics INTERFACE + love_physics_root + love_physics_box2d +) # # love.sensor # -set(LOVE_SRC_MODULE_SENSOR_ROOT +add_library(love_sensor_root STATIC src/modules/sensor/Sensor.cpp src/modules/sensor/Sensor.h src/modules/sensor/wrap_Sensor.cpp src/modules/sensor/wrap_Sensor.h ) +target_link_libraries(love_sensor_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_SENSOR_SDL +add_library(love_sensor_sdl STATIC src/modules/sensor/sdl/Sensor.cpp src/modules/sensor/sdl/Sensor.h ) - -set(LOVE_SRC_MODULE_SENSOR - ${LOVE_SRC_MODULE_SENSOR_ROOT} - ${LOVE_SRC_MODULE_SENSOR_SDL} +target_link_libraries(love_sensor_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\sensor" FILES ${LOVE_SRC_MODULE_SENSOR_ROOT}) -source_group("modules\\sensor\\sdl" FILES ${LOVE_SRC_MODULE_SENSOR_SDL}) +add_library(love_sensor INTERFACE) +target_link_libraries(love_sensor INTERFACE + love_sensor_root + love_sensor_sdl +) # # love.sound # -set(LOVE_SRC_MODULE_SOUND_ROOT +add_library(love_sound_root STATIC src/modules/sound/Decoder.cpp src/modules/sound/Decoder.h src/modules/sound/Sound.cpp @@ -964,9 +1057,13 @@ set(LOVE_SRC_MODULE_SOUND_ROOT src/modules/sound/wrap_Sound.h src/modules/sound/wrap_SoundData.cpp src/modules/sound/wrap_SoundData.h + src/modules/sound/wrap_SoundData.lua +) +target_link_libraries(love_sound_root PUBLIC + lovedep::Lua ) -set(LOVE_SRC_MODULE_SOUND_LULLABY +add_library(love_sound_lullaby STATIC src/modules/sound/lullaby/FLACDecoder.cpp src/modules/sound/lullaby/FLACDecoder.h src/modules/sound/lullaby/ModPlugDecoder.cpp @@ -980,44 +1077,52 @@ set(LOVE_SRC_MODULE_SOUND_LULLABY src/modules/sound/lullaby/WaveDecoder.cpp src/modules/sound/lullaby/WaveDecoder.h ) - -set(LOVE_SRC_MODULE_SOUND - ${LOVE_SRC_MODULE_SOUND_ROOT} - ${LOVE_SRC_MODULE_SOUND_LULLABY} +target_link_libraries(love_sound_lullaby PUBLIC + lovedep::Modplug + lovedep::Vorbis + lovedep::Ogg ) -source_group("modules\\sound" FILES ${LOVE_SRC_MODULE_SOUND_ROOT}) -source_group("modules\\sound\\lullaby" FILES ${LOVE_SRC_MODULE_SOUND_LULLABY}) +add_library(love_sound INTERFACE) +target_link_libraries(love_sound INTERFACE + love_sound_root + love_sound_lullaby +) # # love.system # -set(LOVE_SRC_MODULE_SYSTEM_ROOT +add_library(love_system_root STATIC src/modules/system/System.cpp src/modules/system/System.h src/modules/system/wrap_System.cpp src/modules/system/wrap_System.h ) +target_link_libraries(love_system_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_SYSTEM_SDL +add_library(love_system_sdl STATIC src/modules/system/sdl/System.cpp src/modules/system/sdl/System.h ) - -set(LOVE_SRC_MODULE_SYSTEM - ${LOVE_SRC_MODULE_SYSTEM_ROOT} - ${LOVE_SRC_MODULE_SYSTEM_SDL} +target_link_libraries(love_system_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\system" FILES ${LOVE_SRC_MODULE_SYSTEM_ROOT}) -source_group("modules\\system\\sdl" FILES ${LOVE_SRC_MODULE_SYSTEM_SDL}) +add_library(love_system INTERFACE) +target_link_libraries(love_system INTERFACE + love_system_root + love_system_sdl +) # # love.thread # -set(LOVE_SRC_MODULE_THREAD_ROOT +add_library(love_thread_root STATIC src/modules/thread/Channel.cpp src/modules/thread/Channel.h src/modules/thread/LuaThread.cpp @@ -1034,63 +1139,72 @@ set(LOVE_SRC_MODULE_THREAD_ROOT src/modules/thread/wrap_ThreadModule.cpp src/modules/thread/wrap_ThreadModule.h ) +target_link_libraries(love_thread_root PUBLIC + lovedep::Lua +) -set(LOVE_SRC_MODULE_THREAD_SDL +add_library(love_thread_sdl STATIC src/modules/thread/sdl/Thread.cpp src/modules/thread/sdl/Thread.h src/modules/thread/sdl/threads.cpp src/modules/thread/sdl/threads.h ) - -set(LOVE_SRC_MODULE_THREAD - ${LOVE_SRC_MODULE_THREAD_ROOT} - ${LOVE_SRC_MODULE_THREAD_SDL} +target_link_libraries(love_thread_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\thread" FILES ${LOVE_SRC_MODULE_THREAD_ROOT}) -source_group("modules\\thread\\sdl" FILES ${LOVE_SRC_MODULE_THREAD_SDL}) +add_library(love_thread INTERFACE) +target_link_libraries(love_thread INTERFACE + love_thread_root + love_thread_sdl +) # # love.timer # -set(LOVE_SRC_MODULE_TIMER +add_library(love_timer STATIC src/modules/timer/Timer.cpp src/modules/timer/Timer.h src/modules/timer/wrap_Timer.cpp src/modules/timer/wrap_Timer.h ) - -source_group("modules\\timer" FILES ${LOVE_SRC_MODULE_TIMER}) +target_link_libraries(love_timer PUBLIC + lovedep::Lua +) # # love.touch # -set(LOVE_SRC_MODULE_TOUCH_ROOT +add_library(love_touch_root STATIC src/modules/touch/Touch.h src/modules/touch/wrap_Touch.cpp src/modules/touch/wrap_Touch.h ) +target_link_libraries(love_touch_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_TOUCH_SDL +add_library(love_touch_sdl STATIC src/modules/touch/sdl/Touch.cpp src/modules/touch/sdl/Touch.h ) - -set(LOVE_SRC_MODULE_TOUCH - ${LOVE_SRC_MODULE_TOUCH_ROOT} - ${LOVE_SRC_MODULE_TOUCH_SDL} +target_link_libraries(love_touch_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\touch" FILES ${LOVE_SRC_MODULE_TOUCH_ROOT}) -source_group("modules\\touch\\sdl" FILES ${LOVE_SRC_MODULE_TOUCH_SDL}) - +add_library(love_touch INTERFACE) +target_link_libraries(love_touch INTERFACE + love_touch_root + love_touch_sdl +) # # love.video # -set(LOVE_SRC_MODULE_VIDEO_ROOT +add_library(love_video_root STATIC src/modules/video/Video.h src/modules/video/VideoStream.cpp src/modules/video/VideoStream.h @@ -1099,8 +1213,13 @@ set(LOVE_SRC_MODULE_VIDEO_ROOT src/modules/video/wrap_VideoStream.cpp src/modules/video/wrap_VideoStream.h ) +target_link_libraries(love_video_root PUBLIC + lovedep::Lua + lovedep::Theora + lovedep::Ogg +) -set(LOVE_SRC_MODULE_VIDEO_THEORA +add_library(love_video_theora STATIC src/modules/video/theora/Video.cpp src/modules/video/theora/Video.h src/modules/video/theora/OggDemuxer.cpp @@ -1108,38 +1227,45 @@ set(LOVE_SRC_MODULE_VIDEO_THEORA src/modules/video/theora/TheoraVideoStream.cpp src/modules/video/theora/TheoraVideoStream.h ) - -set(LOVE_SRC_MODULE_VIDEO - ${LOVE_SRC_MODULE_VIDEO_ROOT} - ${LOVE_SRC_MODULE_VIDEO_THEORA} +target_link_libraries(love_video_theora PUBLIC + lovedep::Theora + lovedep::Ogg ) -source_group("modules\\video" FILES ${LOVE_SRC_MODULE_VIDEO_ROOT}) -source_group("modules\\video\\theora" FILES ${LOVE_SRC_MODULE_VIDEO_THEORA}) +add_library(love_video INTERFACE) +target_link_libraries(love_video INTERFACE + love_video_root + love_video_theora +) # # love.window # -set(LOVE_SRC_MODULE_WINDOW_ROOT +add_library(love_window_root STATIC src/modules/window/Window.cpp src/modules/window/Window.h src/modules/window/wrap_Window.cpp src/modules/window/wrap_Window.h ) +target_link_libraries(love_window_root PUBLIC + lovedep::Lua + lovedep::SDL +) -set(LOVE_SRC_MODULE_WINDOW_SDL +add_library(love_window_sdl STATIC src/modules/window/sdl/Window.cpp src/modules/window/sdl/Window.h ) - -set(LOVE_SRC_MODULE_WINDOW - ${LOVE_SRC_MODULE_WINDOW_ROOT} - ${LOVE_SRC_MODULE_WINDOW_SDL} +target_link_libraries(love_window_sdl PUBLIC + lovedep::SDL ) -source_group("modules\\window" FILES ${LOVE_SRC_MODULE_WINDOW_ROOT}) -source_group("modules\\window\\sdl" FILES ${LOVE_SRC_MODULE_WINDOW_SDL}) +add_library(love_window INTERFACE) +target_link_libraries(love_window INTERFACE + love_window_root + love_window_sdl +) ################################### # Third-party libraries @@ -1149,128 +1275,100 @@ source_group("modules\\window\\sdl" FILES ${LOVE_SRC_MODULE_WINDOW_SDL}) # Box2D # -set(LOVE_SRC_3P_BOX2D_ROOT +add_library(love_3p_box2d src/libraries/box2d/Box2D.h -) - -set(LOVE_SRC_3P_BOX2D_COLLISION - src/libraries/box2d/collision/b2_broad_phase.cpp - src/libraries/box2d/collision/b2_chain_shape.cpp - src/libraries/box2d/collision/b2_circle_shape.cpp - src/libraries/box2d/collision/b2_collide_circle.cpp - src/libraries/box2d/collision/b2_collide_edge.cpp - src/libraries/box2d/collision/b2_collide_polygon.cpp - src/libraries/box2d/collision/b2_collision.cpp - src/libraries/box2d/collision/b2_distance.cpp - src/libraries/box2d/collision/b2_dynamic_tree.cpp - src/libraries/box2d/collision/b2_edge_shape.cpp - src/libraries/box2d/collision/b2_polygon_shape.cpp - src/libraries/box2d/collision/b2_time_of_impact.cpp -) - -set(LOVE_SRC_3P_BOX2D_COMMON - src/libraries/box2d/common/b2_block_allocator.cpp - src/libraries/box2d/common/b2_draw.cpp - src/libraries/box2d/common/b2_math.cpp - src/libraries/box2d/common/b2_settings.cpp - src/libraries/box2d/common/b2_stack_allocator.cpp - src/libraries/box2d/common/b2_timer.cpp -) - -set(LOVE_SRC_3P_BOX2D_DYNAMICS - src/libraries/box2d/dynamics/b2_body.cpp - src/libraries/box2d/dynamics/b2_chain_circle_contact.cpp - src/libraries/box2d/dynamics/b2_chain_circle_contact.h - src/libraries/box2d/dynamics/b2_chain_polygon_contact.cpp - src/libraries/box2d/dynamics/b2_chain_polygon_contact.h - src/libraries/box2d/dynamics/b2_circle_contact.cpp - src/libraries/box2d/dynamics/b2_circle_contact.h - src/libraries/box2d/dynamics/b2_contact.cpp - src/libraries/box2d/dynamics/b2_contact_manager.cpp - src/libraries/box2d/dynamics/b2_contact_solver.cpp - src/libraries/box2d/dynamics/b2_contact_solver.h - src/libraries/box2d/dynamics/b2_distance_joint.cpp - src/libraries/box2d/dynamics/b2_edge_circle_contact.cpp - src/libraries/box2d/dynamics/b2_edge_circle_contact.h - src/libraries/box2d/dynamics/b2_edge_polygon_contact.cpp - src/libraries/box2d/dynamics/b2_edge_polygon_contact.h - src/libraries/box2d/dynamics/b2_fixture.cpp - src/libraries/box2d/dynamics/b2_friction_joint.cpp - src/libraries/box2d/dynamics/b2_gear_joint.cpp - src/libraries/box2d/dynamics/b2_island.cpp - src/libraries/box2d/dynamics/b2_island.h - src/libraries/box2d/dynamics/b2_joint.cpp - src/libraries/box2d/dynamics/b2_motor_joint.cpp - src/libraries/box2d/dynamics/b2_mouse_joint.cpp - src/libraries/box2d/dynamics/b2_polygon_circle_contact.cpp - src/libraries/box2d/dynamics/b2_polygon_circle_contact.h - src/libraries/box2d/dynamics/b2_polygon_contact.cpp - src/libraries/box2d/dynamics/b2_polygon_contact.h - src/libraries/box2d/dynamics/b2_prismatic_joint.cpp - src/libraries/box2d/dynamics/b2_pulley_joint.cpp - src/libraries/box2d/dynamics/b2_revolute_joint.cpp - src/libraries/box2d/dynamics/b2_weld_joint.cpp - src/libraries/box2d/dynamics/b2_wheel_joint.cpp - src/libraries/box2d/dynamics/b2_world.cpp - src/libraries/box2d/dynamics/b2_world_callbacks.cpp -) - -set(LOVE_SRC_3P_BOX2D_ROPE + src/libraries/box2d/collision/b2_broad_phase.cpp + src/libraries/box2d/collision/b2_chain_shape.cpp + src/libraries/box2d/collision/b2_circle_shape.cpp + src/libraries/box2d/collision/b2_collide_circle.cpp + src/libraries/box2d/collision/b2_collide_edge.cpp + src/libraries/box2d/collision/b2_collide_polygon.cpp + src/libraries/box2d/collision/b2_collision.cpp + src/libraries/box2d/collision/b2_distance.cpp + src/libraries/box2d/collision/b2_dynamic_tree.cpp + src/libraries/box2d/collision/b2_edge_shape.cpp + src/libraries/box2d/collision/b2_polygon_shape.cpp + src/libraries/box2d/collision/b2_time_of_impact.cpp + src/libraries/box2d/common/b2_block_allocator.cpp + src/libraries/box2d/common/b2_draw.cpp + src/libraries/box2d/common/b2_math.cpp + src/libraries/box2d/common/b2_settings.cpp + src/libraries/box2d/common/b2_stack_allocator.cpp + src/libraries/box2d/common/b2_timer.cpp + src/libraries/box2d/dynamics/b2_body.cpp + src/libraries/box2d/dynamics/b2_chain_circle_contact.cpp + src/libraries/box2d/dynamics/b2_chain_circle_contact.h + src/libraries/box2d/dynamics/b2_chain_polygon_contact.cpp + src/libraries/box2d/dynamics/b2_chain_polygon_contact.h + src/libraries/box2d/dynamics/b2_circle_contact.cpp + src/libraries/box2d/dynamics/b2_circle_contact.h + src/libraries/box2d/dynamics/b2_contact.cpp + src/libraries/box2d/dynamics/b2_contact_manager.cpp + src/libraries/box2d/dynamics/b2_contact_solver.cpp + src/libraries/box2d/dynamics/b2_contact_solver.h + src/libraries/box2d/dynamics/b2_distance_joint.cpp + src/libraries/box2d/dynamics/b2_edge_circle_contact.cpp + src/libraries/box2d/dynamics/b2_edge_circle_contact.h + src/libraries/box2d/dynamics/b2_edge_polygon_contact.cpp + src/libraries/box2d/dynamics/b2_edge_polygon_contact.h + src/libraries/box2d/dynamics/b2_fixture.cpp + src/libraries/box2d/dynamics/b2_friction_joint.cpp + src/libraries/box2d/dynamics/b2_gear_joint.cpp + src/libraries/box2d/dynamics/b2_island.cpp + src/libraries/box2d/dynamics/b2_island.h + src/libraries/box2d/dynamics/b2_joint.cpp + src/libraries/box2d/dynamics/b2_motor_joint.cpp + src/libraries/box2d/dynamics/b2_mouse_joint.cpp + src/libraries/box2d/dynamics/b2_polygon_circle_contact.cpp + src/libraries/box2d/dynamics/b2_polygon_circle_contact.h + src/libraries/box2d/dynamics/b2_polygon_contact.cpp + src/libraries/box2d/dynamics/b2_polygon_contact.h + src/libraries/box2d/dynamics/b2_prismatic_joint.cpp + src/libraries/box2d/dynamics/b2_pulley_joint.cpp + src/libraries/box2d/dynamics/b2_revolute_joint.cpp + src/libraries/box2d/dynamics/b2_weld_joint.cpp + src/libraries/box2d/dynamics/b2_wheel_joint.cpp + src/libraries/box2d/dynamics/b2_world.cpp + src/libraries/box2d/dynamics/b2_world_callbacks.cpp src/libraries/box2d/rope/b2_rope.cpp ) - -set(LOVE_SRC_3P_BOX2D - ${LOVE_SRC_3P_BOX2D_ROOT} - ${LOVE_SRC_3P_BOX2D_COLLISION} - ${LOVE_SRC_3P_BOX2D_COMMON} - ${LOVE_SRC_3P_BOX2D_DYNAMICS} - ${LOVE_SRC_3P_BOX2D_ROPE} -) - -add_library(love_3p_box2d ${LOVE_SRC_3P_BOX2D}) +love_disable_warnings(love_3p_box2d) # # ddsparse # -set(LOVE_SRC_3P_DDSPARSE +add_library(love_3p_ddsparse src/libraries/ddsparse/ddsinfo.h src/libraries/ddsparse/ddsparse.cpp src/libraries/ddsparse/ddsparse.h ) -add_library(love_3p_ddsparse ${LOVE_SRC_3P_DDSPARSE}) - # # dr_flac # -set(LOVE_SRC_3P_DRFLAC - src/libraries/dr/dr_flac.h -) - # dr_flac has no implementation files of its own. +#add_library(love_3p_drflac +# src/libraries/dr/dr_flac.h +#) # # dr_mp3 # -set(LOVE_SRC_3P_DRMP3 - src/libraries/dr/dr_mp3.h -) - # dr_mp3 has no implementation files of its own. +#add_library(love_3p_drmp3 +# src/libraries/dr/dr_mp3.h +#) # # enet # -set(LOVE_SRC_3P_ENET_ROOT +add_library(love_3p_enet src/libraries/enet/enet.cpp src/libraries/enet/lua-enet.h -) - -set(LOVE_SRC_3P_ENET_LIBENET src/libraries/enet/libenet/callbacks.c src/libraries/enet/libenet/compress.c src/libraries/enet/libenet/host.c @@ -1280,9 +1378,6 @@ set(LOVE_SRC_3P_ENET_LIBENET src/libraries/enet/libenet/protocol.c src/libraries/enet/libenet/unix.c src/libraries/enet/libenet/win32.c -) - -set(LOVE_SRC_3P_ENET_LIBENET_INCLUDE_ENET src/libraries/enet/libenet/include/enet/enet.h src/libraries/enet/libenet/include/enet/list.h src/libraries/enet/libenet/include/enet/protocol.h @@ -1292,39 +1387,31 @@ set(LOVE_SRC_3P_ENET_LIBENET_INCLUDE_ENET src/libraries/enet/libenet/include/enet/utility.h src/libraries/enet/libenet/include/enet/win32.h ) - -set(LOVE_SRC_3P_ENET - ${LOVE_SRC_3P_ENET_ROOT} - ${LOVE_SRC_3P_ENET_LIBENET} - ${LOVE_SRC_3P_ENET_LIBENET_INCLUDE_ENET} -) - -add_library(love_3p_enet ${LOVE_SRC_3P_ENET}) -target_link_libraries(love_3p_enet ${LOVE_LUA_LIBRARY}) +love_disable_warnings(love_3p_enet) +target_link_libraries(love_3p_enet lovedep::Lua) target_include_directories(love_3p_enet PUBLIC src/libraries/enet/libenet/include) +if(MINGW) + target_link_libraries(love_3p_enet winmm.a) +endif() # # GLAD # -set(LOVE_SRC_3P_GLAD +add_library(love_3p_glad src/libraries/glad/glad.cpp src/libraries/glad/glad.hpp src/libraries/glad/gladfuncs.hpp ) -add_library(love_3p_glad ${LOVE_SRC_3P_GLAD}) - # # glslang # -set(LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN +add_library(love_3p_glslang + src/libraries/glslang/glslang/build_info.h src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp src/libraries/glslang/glslang/GenericCodeGen/Link.cpp -) - -set(LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE src/libraries/glslang/glslang/Include/arrays.h src/libraries/glslang/glslang/Include/BaseTypes.h src/libraries/glslang/glslang/Include/Common.h @@ -1337,9 +1424,6 @@ set(LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE src/libraries/glslang/glslang/Include/ShHandle.h src/libraries/glslang/glslang/Include/SpirvIntrinsics.h src/libraries/glslang/glslang/Include/Types.h -) - -set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpAtom.cpp src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp @@ -1347,10 +1431,6 @@ set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.h -) - -set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT - ${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT_PREPROCESSOR} src/libraries/glslang/glslang/MachineIndependent/attribute.cpp src/libraries/glslang/glslang/MachineIndependent/attribute.h src/libraries/glslang/glslang/MachineIndependent/Constant.cpp @@ -1386,58 +1466,27 @@ set(LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT src/libraries/glslang/glslang/MachineIndependent/Scan.h src/libraries/glslang/glslang/MachineIndependent/ScanContext.h src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp + src/libraries/glslang/glslang/MachineIndependent/span.h src/libraries/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h src/libraries/glslang/glslang/MachineIndependent/Versions.cpp src/libraries/glslang/glslang/MachineIndependent/Versions.h -) - -set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT src/libraries/glslang/glslang/OSDependent/osinclude.h -) - -if(MSVC) - set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT - ${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT} - src/libraries/glslang/glslang/OSDependent/Windows/main.cpp - src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp - ) -else() - set(LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT - ${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT} - src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp - ) -endif() - -set(LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC + src/libraries/glslang/glslang/Public/ResourceLimits.h src/libraries/glslang/glslang/Public/ShaderLang.h -) - -set(LOVE_SRC_3P_GLSLANG_GLSLANG - src/libraries/glslang/glslang/build_info.h - ${LOVE_SRC_3P_GLSLANG_GLSLANG_GENERICCODEGEN} - ${LOVE_SRC_3P_GLSLANG_GLSLANG_INCLUDE} - ${LOVE_SRC_3P_GLSLANG_GLSLANG_MACHINEINDEPENDENT} - ${LOVE_SRC_3P_GLSLANG_GLSLANG_OSDEPENDENT} - ${LOVE_SRC_3P_GLSLANG_GLSLANG_PUBLIC} -) - -set(LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL - src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp - src/libraries/glslang/OGLCompilersDLL/InitializeDll.h -) - -set(LOVE_SRC_3P_GLSLANG_SPIRV + src/libraries/glslang/glslang/ResourceLimits/ResourceLimits.cpp src/libraries/glslang/SPIRV/bitutils.h src/libraries/glslang/SPIRV/disassemble.cpp src/libraries/glslang/SPIRV/disassemble.h src/libraries/glslang/SPIRV/doc.cpp src/libraries/glslang/SPIRV/doc.h src/libraries/glslang/SPIRV/GLSL.ext.AMD.h + src/libraries/glslang/SPIRV/GLSL.ext.ARM.h src/libraries/glslang/SPIRV/GLSL.ext.EXT.h src/libraries/glslang/SPIRV/GLSL.ext.KHR.h src/libraries/glslang/SPIRV/GLSL.ext.NV.h + src/libraries/glslang/SPIRV/GLSL.ext.QCOM.h src/libraries/glslang/SPIRV/GLSL.std.450.h src/libraries/glslang/SPIRV/GlslangToSpv.cpp src/libraries/glslang/SPIRV/GlslangToSpv.h @@ -1446,6 +1495,7 @@ set(LOVE_SRC_3P_GLSLANG_SPIRV src/libraries/glslang/SPIRV/Logger.cpp src/libraries/glslang/SPIRV/Logger.h src/libraries/glslang/SPIRV/NonSemanticDebugPrintf.h + src/libraries/glslang/SPIRV/NonSemanticShaderDebugInfo100.h src/libraries/glslang/SPIRV/spirv.hpp src/libraries/glslang/SPIRV/SpvBuilder.cpp src/libraries/glslang/SPIRV/SpvBuilder.h @@ -1457,35 +1507,38 @@ set(LOVE_SRC_3P_GLSLANG_SPIRV src/libraries/glslang/SPIRV/SpvTools.h ) -set(LOVE_SRC_3P_GLSLANG - ${LOVE_SRC_3P_GLSLANG_GLSLANG} - ${LOVE_SRC_3P_GLSLANG_OGLCOMPILERSDLL} - ${LOVE_SRC_3P_GLSLANG_SPIRV} -) - -add_library(love_3p_glslang ${LOVE_SRC_3P_GLSLANG}) +if(MSVC OR MINGW) + target_sources(love_3p_glslang PRIVATE + src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp + ) +else() + target_sources(love_3p_glslang PRIVATE + src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp + ) +endif() # # LodePNG # -set(LOVE_SRC_3P_LODEPNG +add_library(love_3p_lodepng src/libraries/lodepng/lodepng.cpp src/libraries/lodepng/lodepng.h ) -add_library(love_3p_lodepng ${LOVE_SRC_3P_LODEPNG}) - # # luasocket # -set(LOVE_SRC_3P_LUASOCKET_ROOT +if(MINGW) + set(WIN32_LIB_EXT .a) +else() + set(WIN32_LIB_EXT .lib) +endif() + +add_library(love_3p_luasocket src/libraries/luasocket/luasocket.cpp src/libraries/luasocket/luasocket.h -) - -set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET src/libraries/luasocket/libluasocket/auxiliar.c src/libraries/luasocket/libluasocket/auxiliar.h src/libraries/luasocket/libluasocket/buffer.c @@ -1531,67 +1584,48 @@ set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET src/libraries/luasocket/libluasocket/unixstream.c src/libraries/luasocket/libluasocket/unixstream.h ) +target_link_libraries(love_3p_luasocket lovedep::Lua) +love_disable_warnings(love_3p_luasocket) -set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET) - -if(MSVC) - set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET - ${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET} +if(MSVC OR MINGW) + target_sources(love_3p_luasocket PRIVATE src/libraries/luasocket/libluasocket/wsocket.c src/libraries/luasocket/libluasocket/wsocket.h ) - set(LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET - ${LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET} - ws2_32.lib + target_link_libraries(love_3p_luasocket + ws2_32${WIN32_LIB_EXT} ) else() - set(LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET - ${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET} + target_sources(love_3p_luasocket PRIVATE src/libraries/luasocket/libluasocket/serial.c src/libraries/luasocket/libluasocket/usocket.c src/libraries/luasocket/libluasocket/usocket.h ) endif() -set(LOVE_SRC_3P_LUASOCKET - ${LOVE_SRC_3P_LUASOCKET_ROOT} - ${LOVE_SRC_3P_LUASOCKET_LIBLUASOCKET} -) - -add_library(love_3p_luasocket ${LOVE_SRC_3P_LUASOCKET}) -target_link_libraries(love_3p_luasocket ${LOVE_LUA_LIBRARY} ${LOVE_LINK_L3P_LUASOCKET_LIBLUASOCKET}) - # # APIs from Lua 5.3 # -set(LOVE_SRC_3P_LUA53 +add_library(love_3p_lua53 src/libraries/lua53/lprefix.h src/libraries/lua53/lstrlib.c src/libraries/lua53/lstrlib.h src/libraries/lua53/lutf8lib.c src/libraries/lua53/lutf8lib.h ) - -add_library(love_3p_lua53 ${LOVE_SRC_3P_LUA53}) -target_link_libraries(love_3p_lua53 ${LOVE_LUA_LIBRARY}) +target_link_libraries(love_3p_lua53 lovedep::Lua) # # Lua HTTPS # -set(LOVE_SRC_3P_LUAHTTPS_ANDROID +add_library(love_3p_luahttps + # These are platform-dependent but have ifdef guards to make sure they only + # compile on supported platforms. src/libraries/luahttps/src/android/AndroidClient.cpp src/libraries/luahttps/src/android/AndroidClient.h -) - -set(LOVE_SRC_3P_LUAHTTPS_APPLE - src/libraries/luahttps/src/apple/NSURLClient.mm - src/libraries/luahttps/src/apple/NSURLClient.h -) - -set(LOVE_SRC_3P_LUAHTTPS_COMMON src/libraries/luahttps/src/common/config.h src/libraries/luahttps/src/common/Connection.h src/libraries/luahttps/src/common/ConnectionClient.h @@ -1603,64 +1637,44 @@ set(LOVE_SRC_3P_LUAHTTPS_COMMON src/libraries/luahttps/src/common/HTTPSClient.h src/libraries/luahttps/src/common/PlaintextConnection.cpp src/libraries/luahttps/src/common/PlaintextConnection.h -) - -set(LOVE_SRC_3P_LUAHTTPS_GENERIC src/libraries/luahttps/src/generic/CurlClient.cpp src/libraries/luahttps/src/generic/CurlClient.h src/libraries/luahttps/src/generic/OpenSSLConnection.cpp src/libraries/luahttps/src/generic/OpenSSLConnection.h -) - -set(LOVE_SRC_3P_LUAHTTPS_LUA src/libraries/luahttps/src/lua/main.cpp -) - -set(LOVE_SRC_3P_LUAHTTPS_WINDOWS src/libraries/luahttps/src/windows/SChannelConnection.cpp src/libraries/luahttps/src/windows/SChannelConnection.h src/libraries/luahttps/src/windows/WinINetClient.cpp src/libraries/luahttps/src/windows/WinINetClient.h ) - -# These are platform-dependent but have ifdef guards to make sure they only -# compile on supported platforms. -set(LOVE_SRC_3P_LUAHTTPS - ${LOVE_SRC_3P_LUAHTTPS_ANDROID} - ${LOVE_SRC_3P_LUAHTTPS_COMMON} - ${LOVE_SRC_3P_LUAHTTPS_GENERIC} - ${LOVE_SRC_3P_LUAHTTPS_LUA} - ${LOVE_SRC_3P_LUAHTTPS_WINDOWS} - ) +target_link_libraries(love_3p_luahttps lovedep::Lua) if (APPLE) - set(LOVE_SRC_3P_LUAHTTPS ${LOVE_SRC_3P_LUAHTTPS} ${LOVE_SRC_3P_LUAHTTPS_APPLE}) + target_sources(love_3p_luahttps PRIVATE + src/libraries/luahttps/src/apple/NSURLClient.mm + src/libraries/luahttps/src/apple/NSURLClient.h + ) + target_compile_options(love_3p_luahttps PRIVATE -fobjc-arc) endif() -set(LOVE_LINK_L3P_LUAHTTPS) if(MSVC) - set(LOVE_LINK_L3P_LUAHTTPS - ${LOVE_LINK_L3P_LUAHTTPS} + target_link_libraries(love_3p_luahttps ws2_32 secur32 ) if(NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore") - set(LOVE_LINK_L3P_LUAHTTPS - ${LOVE_LINK_L3P_LUAHTTPS} + target_link_libraries(love_3p_luahttps wininet ) endif() endif() -add_library(love_3p_luahttps ${LOVE_SRC_3P_LUAHTTPS}) -target_link_libraries(love_3p_luahttps ${LOVE_LUA_LIBRARY} ${LOVE_LINK_L3P_LUAHTTPS}) - # # lz4 # -set(LOVE_SRC_3P_LZ4 +add_library(love_3p_lz4 src/libraries/lz4/lz4.c src/libraries/lz4/lz4.h src/libraries/lz4/lz4hc.c @@ -1668,26 +1682,22 @@ set(LOVE_SRC_3P_LZ4 src/libraries/lz4/lz4opt.h ) -add_library(love_3p_lz4 ${LOVE_SRC_3P_LZ4}) - # # noise1234 # -set(LOVE_SRC_3P_NOISE1234 +add_library(love_3p_noise1234 src/libraries/noise1234/noise1234.cpp src/libraries/noise1234/noise1234.h src/libraries/noise1234/simplexnoise1234.cpp src/libraries/noise1234/simplexnoise1234.h ) -add_library(love_3p_noise1234 ${LOVE_SRC_3P_NOISE1234}) - # # physfs # -set(LOVE_SRC_3P_PHYSFS +add_library(love_3p_physfs src/libraries/physfs/physfs_archiver_7z.c src/libraries/physfs/physfs_archiver_dir.c src/libraries/physfs/physfs_archiver_grp.c @@ -1705,6 +1715,7 @@ set(LOVE_SRC_3P_PHYSFS src/libraries/physfs/physfs_internal.h src/libraries/physfs/physfs_lzmasdk.h src/libraries/physfs/physfs_miniz.h + src/libraries/physfs/physfs_platform_android.c src/libraries/physfs/physfs_platform_haiku.cpp src/libraries/physfs/physfs_platform_os2.c src/libraries/physfs/physfs_platform_posix.c @@ -1717,29 +1728,28 @@ set(LOVE_SRC_3P_PHYSFS src/libraries/physfs/physfs.c src/libraries/physfs/physfs.h ) +love_disable_warnings(love_3p_physfs) if(APPLE) - set(LOVE_SRC_3P_PHYSFS ${LOVE_SRC_3P_PHYSFS} + target_sources(love_3p_physfs PRIVATE src/libraries/physfs/physfs_platform_apple.m ) - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} "-framework IOKit") + target_link_libraries(love_3p_physfs INTERFACE + "-framework IOKit" + ) endif() -add_library(love_3p_physfs ${LOVE_SRC_3P_PHYSFS}) - # # spirv_cross # -set(LOVE_SRC_3P_SPIRV_CROSS +add_library(love_3p_spirv_cross src/libraries/spirv_cross/GLSL.std.450.h src/libraries/spirv_cross/spirv_cfg.cpp src/libraries/spirv_cross/spirv_cfg.hpp src/libraries/spirv_cross/spirv_common.hpp src/libraries/spirv_cross/spirv_cpp.cpp src/libraries/spirv_cross/spirv_cpp.hpp - src/libraries/spirv_cross/spirv_cross_c.cpp - src/libraries/spirv_cross/spirv_cross_c.h src/libraries/spirv_cross/spirv_cross_containers.hpp src/libraries/spirv_cross/spirv_cross_error_handling.hpp src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp @@ -1758,116 +1768,103 @@ set(LOVE_SRC_3P_SPIRV_CROSS src/libraries/spirv_cross/spirv_parser.hpp src/libraries/spirv_cross/spirv_reflect.cpp src/libraries/spirv_cross/spirv_reflect.hpp - src/libraries/spirv_cross/spirv.h src/libraries/spirv_cross/spirv.hpp ) -add_library(love_3p_spirv_cross ${LOVE_SRC_3P_SPIRV_CROSS}) - # # stb_image # -set(LOVE_SRC_3P_STB - src/libraries/stb/stb_image.h -) - # stb_image has no implementation files of its own. +#add_library(love_3p_stb +# src/libraries/stb/stb_image.h +#) # # tiny exr # -set(LOVE_SRC_3P_TINYEXR - src/libraries/tinyexr/tinyexr.h -) - # tinyexr has no implementation files of its own. +#add_library(love_3p_tinyexr +# src/libraries/tinyexr/tinyexr.h +#) # # utf8 # -set(LOVE_SRC_3P_UTF8_ROOT src/libraries/utf8/utf8.h) - -set(LOVE_SRC_3P_UTF8_UTF8 - src/libraries/utf8/utf8/checked.h - src/libraries/utf8/utf8/core.h - src/libraries/utf8/utf8/unchecked.h -) - -set(LOVE_SRC_3P_UTF8 - ${LOVE_SRC_3P_UTF8_ROOT} - ${LOVE_SRC_3P_UTF8_UTF8} -) - # This library is all headers ... so there is no need to # add_library() here. +#add_library(love_3p_utf8 +# src/libraries/utf8/utf8.h +# src/libraries/utf8/utf8/checked.h +# src/libraries/utf8/utf8/core.h +# src/libraries/utf8/utf8/unchecked.h +#) # # vma # -set(LOVE_SRC_3P_VMA src/libraries/vma/vk_mem_alloc.h) - # vulkan memory allocatory has no implementation files of its own. +#add_library(love_3p_vma +# src/libraries/vma/vk_mem_alloc.h +#) # # volk # -set(LOVE_SRC_3P_VOLK - src/libraries/volk/volk.h - src/libraries/volk/volk.c) - # since we don't want to use the system vulkan header files we need to # compile this library in the löve source code using VOLK_IMPLEMENTATION. +#add_library(love_3p_volk +# src/libraries/volk/volk.h +# src/libraries/volk/volk.c) # # vulkan headers # -set(LOVE_SRC_3P_VULKAN_HEADERS - src/libraries/vulkanheaders/vk_icd.h - src/libraries/vulkanheaders/vk_layer.h - src/libraries/vulkanheaders/vk_platform.h - src/libraries/vulkanheaders/vk_sdk-platform.h - src/libraries/vulkanheaders/vulkan_android.h - src/libraries/vulkanheaders/vulkan_beta.h - src/libraries/vulkanheaders/vulkan_core.h - src/libraries/vulkanheaders/vulkan_directfb.h - src/libraries/vulkanheaders/vulkan_enums.hpp - src/libraries/vulkanheaders/vulkan_format_traits.hpp - src/libraries/vulkanheaders/vulkan_fuchsia.h - src/libraries/vulkanheaders/vulkan_funcs.h - src/libraries/vulkanheaders/vulkan_ggp.h - src/libraries/vulkanheaders/vulkan_handles.h - src/libraries/vulkanheaders/vulkan_hash.hpp - src/libraries/vulkanheaders/vulkan_ios.h - src/libraries/vulkanheaders/vulkan_macos.h - src/libraries/vulkanheaders/vulkan_metal.h - src/libraries/vulkanheaders/vulkan_raii.hpp - src/libraries/vulkanheaders/vulkan_screen.h - src/libraries/vulkanheaders/vulkan_static_assertions.h - src/libraries/vulkanheaders/vulkan_structs.hpp - src/libraries/vulkanheaders/vulkan_to_string.h - src/libraries/vulkanheaders/vulkan_vi.h - src/libraries/vulkanheaders/vulkan_wayland.h - src/libraries/vulkanheaders/vulkan_win32.h - src/libraries/vulkanheaders/vulkan_xcb.h - src/libraries/vulkanheaders/vulkan_xlib_xrandr.h - src/libraries/vulkanheaders/vulkan_xlib.h - src/libraries/vulkanheaders/vulkan.h - src/libraries/vulkanheaders/vulkan.hpp -) - # vulkan headers has no implementation files of its own. +#add_library(love_3p_vulkan_headers +# src/libraries/vulkanheaders/vk_icd.h +# src/libraries/vulkanheaders/vk_layer.h +# src/libraries/vulkanheaders/vk_platform.h +# src/libraries/vulkanheaders/vk_sdk-platform.h +# src/libraries/vulkanheaders/vulkan_android.h +# src/libraries/vulkanheaders/vulkan_beta.h +# src/libraries/vulkanheaders/vulkan_core.h +# src/libraries/vulkanheaders/vulkan_directfb.h +# src/libraries/vulkanheaders/vulkan_enums.hpp +# src/libraries/vulkanheaders/vulkan_format_traits.hpp +# src/libraries/vulkanheaders/vulkan_fuchsia.h +# src/libraries/vulkanheaders/vulkan_funcs.h +# src/libraries/vulkanheaders/vulkan_ggp.h +# src/libraries/vulkanheaders/vulkan_handles.h +# src/libraries/vulkanheaders/vulkan_hash.hpp +# src/libraries/vulkanheaders/vulkan_ios.h +# src/libraries/vulkanheaders/vulkan_macos.h +# src/libraries/vulkanheaders/vulkan_metal.h +# src/libraries/vulkanheaders/vulkan_raii.hpp +# src/libraries/vulkanheaders/vulkan_screen.h +# src/libraries/vulkanheaders/vulkan_static_assertions.h +# src/libraries/vulkanheaders/vulkan_structs.hpp +# src/libraries/vulkanheaders/vulkan_to_string.h +# src/libraries/vulkanheaders/vulkan_vi.h +# src/libraries/vulkanheaders/vulkan_wayland.h +# src/libraries/vulkanheaders/vulkan_win32.h +# src/libraries/vulkanheaders/vulkan_xcb.h +# src/libraries/vulkanheaders/vulkan_xlib_xrandr.h +# src/libraries/vulkanheaders/vulkan_xlib.h +# src/libraries/vulkanheaders/vulkan.h +# src/libraries/vulkanheaders/vulkan.hpp +#) # # Wuff # -set(LOVE_SRC_3P_WUFF +add_library(love_3p_wuff src/libraries/Wuff/wuff.c src/libraries/Wuff/wuff.h src/libraries/Wuff/wuff_config.h @@ -1878,20 +1875,73 @@ set(LOVE_SRC_3P_WUFF src/libraries/Wuff/wuff_memory.c ) -add_library(love_3p_wuff ${LOVE_SRC_3P_WUFF}) - # # xxHash # -set(LOVE_SRC_3P_XXHASH +add_library(love_3p_xxhash src/libraries/xxHash/xxhash.c src/libraries/xxHash/xxhash.h ) -add_library(love_3p_xxhash ${LOVE_SRC_3P_XXHASH}) +# +# liblove +# +include_directories( + BEFORE + src + src/libraries + src/libraries/box2D + src/modules +) -set(LOVE_3P +link_directories(${LOVE_LINK_DIRS}) + +if(MINGW) + # UTF-16 flags passed to windres. windres invokes gcc as preprocessor + # -> gcc outputs utf8, so windres must read-in codepage 65001 (utf8) + set(CMAKE_RC_FLAGS ${CMAKE_RC_FLAGS} "-c 65001 --preprocessor-arg=-finput-charset=UTF-16LE") +endif() + +add_library(liblove SHARED + src/modules/love/love.cpp + src/modules/love/love.h + # These are here so they show up in Visual Studio: + src/modules/love/arg.lua + src/modules/love/boot.lua + src/modules/love/callbacks.lua + src/modules/love/jitsetup.lua + src/scripts/nogame.lua +) +set_target_properties(liblove PROPERTIES + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + LIBRARY_OUTPUT_NAME "${LOVE_LIB_NAME}") +set(LIBLOVE_DEPENDENCIES + love_common + love_audio + love_data + love_event + love_filesystem + love_font + love_graphics + love_image + love_joystick + love_keyboard + love_math + love_mouse + love_physics + love_sensor + love_sound + love_system + love_thread + love_timer + love_touch + love_video + love_window +) +set(LIBLOVE_LIBRARIES love_3p_box2d love_3p_ddsparse love_3p_enet @@ -1908,258 +1958,226 @@ set(LOVE_3P love_3p_wuff love_3p_xxhash ) +target_link_libraries(liblove ${LIBLOVE_DEPENDENCIES} ${LIBLOVE_LIBRARIES}) -love_disable_warnings(love_3p_box2d love_3p_enet love_3p_luasocket love_3p_physfs) +if(LOVE_EXTRA_DEPENDECIES) + add_dependencies(liblove ${LOVE_EXTRA_DEPENDECIES}) +endif() # -# liblove +# Group projects in Visual Studio # -set(LOVE_LIB_SRC - ${LOVE_SRC_COMMON} - # Modules - ${LOVE_SRC_MODULE_AUDIO} - ${LOVE_SRC_MODULE_DATA} - ${LOVE_SRC_MODULE_EVENT} - ${LOVE_SRC_MODULE_FILESYSTEM} - ${LOVE_SRC_MODULE_FONT} - ${LOVE_SRC_MODULE_GRAPHICS} - ${LOVE_SRC_MODULE_IMAGE} - ${LOVE_SRC_MODULE_JOYSTICK} - ${LOVE_SRC_MODULE_KEYBOARD} - ${LOVE_SRC_MODULE_LOVE} - ${LOVE_SRC_MODULE_MATH} - ${LOVE_SRC_MODULE_MOUSE} - ${LOVE_SRC_MODULE_PHYSICS} - ${LOVE_SRC_MODULE_SENSOR} - ${LOVE_SRC_MODULE_SOUND} - ${LOVE_SRC_MODULE_SYSTEM} - ${LOVE_SRC_MODULE_THREAD} - ${LOVE_SRC_MODULE_TIMER} - ${LOVE_SRC_MODULE_TOUCH} - ${LOVE_SRC_MODULE_VIDEO} - ${LOVE_SRC_MODULE_WINDOW} -) -include_directories( - BEFORE - src - src/libraries - src/libraries/box2D - src/modules - ${LOVE_INCLUDE_DIRS} -) +love_group_projects(NAME "liblove" NESTED TARGETS ${LIBLOVE_DEPENDENCIES}) +love_group_projects(NAME "liblove/libraries" NESTED TARGETS ${LIBLOVE_LIBRARIES}) +love_group_projects(NAME "liblove" TARGETS liblove ${LOVE_EXTRA_DEPENDECIES}) -link_directories(${LOVE_LINK_DIRS}) +love_group_projects(NAME "lovedep" TARGETS lovedep::SDL2 lovedep::Freetype lovedep::Harfbuzz lovedep::OpenAL lovedep::Modplug lovedep::Theora lovedep::Vorbis lovedep::Ogg lovedep::Zlib lovedep::Lua) +love_group_projects(NAME "lovedep" TARGETS lua51 alcommon al-excommon harfbuzz-subset zlib) -set(LOVE_RC) if(MSVC) - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} - ws2_32.lib - winmm.lib - dwmapi.lib + set_target_properties(liblove PROPERTIES RELEASE_OUTPUT_NAME "love" PDB_NAME "liblove" IMPORT_PREFIX "lib") + set_target_properties(liblove PROPERTIES DEBUG_OUTPUT_NAME "love" PDB_NAME "liblove" IMPORT_PREFIX "lib") +endif() + +if(MSVC OR MINGW) + target_link_libraries(liblove + ws2_32${WIN32_LIB_EXT} + winmm${WIN32_LIB_EXT} + dwmapi${WIN32_LIB_EXT} ) - set(LOVE_RC + target_sources(liblove PUBLIC extra/windows/love.rc extra/windows/love.ico ) endif() -if(ANDROID) - # In Android, the LOVE main entrypoint needs to be compiled - # as shared library, so change the library name and add love.cpp - set(LOVE_LIB_NAME ${LOVE_EXE_NAME}) - set(LOVE_LIB_SRC ${LOVE_LIB_SRC} src/love.cpp) - set(LOVE_LINK_LIBRARIES ${LOVE_LINK_LIBRARIES} android) -endif() - -add_library(${LOVE_LIB_NAME} SHARED ${LOVE_LIB_SRC} ${LOVE_RC}) -set_target_properties(${LOVE_LIB_NAME} PROPERTIES C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) -target_link_libraries(${LOVE_LIB_NAME} ${LOVE_LINK_LIBRARIES} ${LOVE_3P}) - -if(LOVE_EXTRA_DEPENDECIES) - add_dependencies(${LOVE_LIB_NAME} ${LOVE_EXTRA_DEPENDECIES}) -endif() - -if(MSVC) - set_target_properties(${LOVE_LIB_NAME} PROPERTIES RELEASE_OUTPUT_NAME "love" PDB_NAME "liblove" IMPORT_PREFIX "lib") - set_target_properties(${LOVE_LIB_NAME} PROPERTIES DEBUG_OUTPUT_NAME "love" PDB_NAME "liblove" IMPORT_PREFIX "lib") -endif() - # # love (executable) # -if(NOT ANDROID) - add_executable(${LOVE_EXE_NAME} WIN32 src/love.cpp ${LOVE_RC}) - target_link_libraries(${LOVE_EXE_NAME} ${LOVE_LIB_NAME}) - set_target_properties(${LOVE_EXE_NAME} PROPERTIES C_VISIBILITY_PRESET hidden CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) +if(ANDROID) + add_library(love SHARED) # On Android, the LOVE main entrypoint needs to be compiled as shared library + target_link_libraries(liblove android) +else() + add_executable(love WIN32) +endif() - if(MSVC) - add_executable(${LOVE_CONSOLE_EXE_NAME} src/love.cpp ${LOVE_RC}) - target_link_libraries(${LOVE_CONSOLE_EXE_NAME} ${LOVE_LIB_NAME}) +target_sources(love PRIVATE src/love.cpp) +target_link_libraries(love liblove) +set_target_properties(love PROPERTIES + C_VISIBILITY_PRESET hidden + CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON + OUTPUT_NAME ${LOVE_EXE_NAME}) + +if(MSVC OR MINGW) + add_executable(lovec src/love.cpp) + target_link_libraries(lovec liblove) + set_target_properties(lovec PROPERTIES + OUTPUT_NAME ${LOVE_CONSOLE_EXE_NAME}) +endif() + +function(post_step_move_dll ARG_POST_TARGET ARG_TARGET_OR_FILE) + if(TARGET ${ARG_TARGET_OR_FILE}) + add_custom_command(TARGET ${ARG_POST_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + $ + ${CMAKE_CURRENT_BINARY_DIR}/$/$) + else() + get_filename_component(TEMP_FILENAME ${ARG_TARGET_OR_FILE} NAME) + add_custom_command(TARGET ${ARG_POST_TARGET} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${ARG_TARGET_OR_FILE} + ${CMAKE_CURRENT_BINARY_DIR}/$/${TEMP_FILENAME}) + endif() +endfunction() + +# Add post build steps to move the DLLs next to the binary. Otherwise +# running/debugging the binary will not work from inside VS. +if(LOVE_MOVE_DLLS) + foreach(DLL ${LOVE_MOVE_DLLS}) + post_step_move_dll(love ${DLL}) + endforeach() +endif() + +if("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + ################################### + # CPack + ################################### + install(TARGETS love lovec liblove RUNTIME DESTINATION .) + + # Our install script (and NSIS) doesn't fully support Windows ARM64 yet. + if(MEGA_ARM64) + set(CPACK_GENERATOR ZIP) + set(CPACK_SYSTEM_NAME woa64) + else() + set(CPACK_GENERATOR ZIP NSIS) endif() - function(post_step_move_dll ARG_POST_TARGET ARG_TARGET_OR_FILE) - if(TARGET ${ARG_TARGET_OR_FILE}) - add_custom_command(TARGET ${ARG_POST_TARGET} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - $ - ${CMAKE_CURRENT_BINARY_DIR}/$/$) - else() - get_filename_component(TEMP_FILENAME ${ARG_TARGET_OR_FILE} NAME) - add_custom_command(TARGET ${ARG_POST_TARGET} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy - ${ARG_TARGET_OR_FILE} - ${CMAKE_CURRENT_BINARY_DIR}/$/${TEMP_FILENAME}) - endif() + # Extra DLLs. + if(LOVE_EXTRA_DLLS) + foreach(DLL ${LOVE_EXTRA_DLLS}) + get_filename_component(DLL_NAME ${DLL} NAME) + message(STATUS "Extra DLL: ${DLL_NAME}") + endforeach() + install(FILES ${LOVE_EXTRA_DLLS} DESTINATION .) + endif() + + # Dynamic runtime libs. + if(LOVE_MSVC_DLLS) + foreach(DLL ${LOVE_MSVC_DLLS}) + get_filename_component(DLL_NAME ${DLL} NAME) + message(STATUS "Runtime DLL: ${DLL_NAME}") + endforeach() + install(FILES ${LOVE_MSVC_DLLS} DESTINATION .) + endif() + + # Copy a text file from CMAKE_CURRENT_SOURCE_DIR to CMAKE_CURRENT_BINARY_DIR. + # On Windows, this function will convert line endings to CR,LF. + function(copy_text_file ARG_FILE_IN ARG_FILE_OUT) + file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_FILE_IN} TMP_TXT_CONTENTS) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_FILE_OUT} ${TMP_TXT_CONTENTS}) endfunction() - # Add post build steps to move the DLLs next to the binary. Otherwise - # running/debugging the binary will not work from inside VS. - if(LOVE_MOVE_DLLS) - foreach(DLL ${LOVE_MOVE_DLLS}) - post_step_move_dll(love ${DLL}) - endforeach() + # Text files. + copy_text_file(readme.md readme.txt) + copy_text_file(license.txt license.txt) + copy_text_file(changes.txt changes.txt) + + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/changes.txt + ${CMAKE_CURRENT_BINARY_DIR}/license.txt + ${CMAKE_CURRENT_BINARY_DIR}/readme.txt + DESTINATION .) + + # Icons + install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis/love.ico + ${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis/game.ico + DESTINATION .) + + set(CPACK_PACKAGE_NAME "love") + set(CPACK_PACKAGE_VENDOR "love2d.org") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LOVE -- It's awesome") + set(CPACK_PACKAGE_VERSION "${LOVE_VERSION_STR}") + set(CPACK_PACKAGE_VERSION_MAJOR "${LOVE_VERSION_MAJOR}") + set(CPACK_PACKAGE_VERSION_MINOR "${LOVE_VERSION_MINOR}") + set(CPACK_PACKAGE_VERSION_PATCH "${LOVE_VERSION_REV}") + set(CPACK_PACKAGE_INSTALL_DIRECTORY "LOVE") + set(CPACK_PACKAGE_EXECUTABLES "${LOVE_EXE_NAME};LOVE") + set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") + set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") + + set(CPACK_NSIS_EXECUTABLES_DIRECTORY .) + set(CPACK_NSIS_PACKAGE_NAME "LOVE") + set(CPACK_NSIS_DISPLAY_NAME "LOVE ${LOVE_VERSION_STR}") + set(CPACK_NSIS_MODIFY_PATH OFF) + + if(LOVE_X64) + set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") + else() + set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") endif() + + set(CPACK_NSIS_MENU_LINKS "http://love2d.org/wiki" "Documentation") + + # Some bug somewhere in NSIS requires "\\\\" somewhere in the path, + # according to The Internet. (And sure enough, it does not work + # without it). + set(NSIS_LEFT_BMP "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\left.bmp") + set(NSIS_TOP_BMP "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\top.bmp") + set(NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\love.ico") + set(NSIS_MUI_UNICON "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\love.ico") + + set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE " + !define MUI_WELCOMEPAGE_TITLE \\\"LOVE ${LOVE_VERSION_STR} Setup\\\" + !define MUI_WELCOMEFINISHPAGE_BITMAP \\\"${NSIS_LEFT_BMP}\\\" + !define MUI_HEADERIMAGE_BITMAP \\\"${NSIS_TOP_BMP}\\\" + !define MUI_ICON \\\"${NSIS_MUI_ICON}\\\" + !define MUI_UNICON \\\"${NSIS_MUI_UNICON}\\\" + ") + + set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS " + WriteRegStr HKCR \\\".love\\\" \\\"\\\" \\\"LOVE\\\" + WriteRegStr HKCR \\\"LOVE\\\" \\\"\\\" \\\"LOVE Game File\\\" + WriteRegStr HKCR \\\"LOVE\\\\DefaultIcon\\\" \\\"\\\" \\\"$INSTDIR\\\\game.ico\\\" + WriteRegStr HKCR \\\"LOVE\\\\shell\\\" \\\"\\\" \\\"open\\\" + WriteRegStr HKCR \\\"LOVE\\\\shell\\\\open\\\" \\\"\\\" \\\"Open in LOVE\\\" + WriteRegStr HKCR \\\"LOVE\\\\shell\\\\open\\\\command\\\" \\\"\\\" \\\"$INSTDIR\\\\love.exe $\\\\\\\"%1$\\\\\\\"\\\" + System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' + ") + + set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS " + DeleteRegKey HKCR \\\"LOVE\\\" + DeleteRegKey HKCR \\\".love\\\" + System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' + ") + + include(CPack) +elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + include(GNUInstallDirs) + + string(TIMESTAMP LOVE_CONFIGURE_TIMESTAMP "%a, %d %b %Y %H:%M:%S +0000" UTC) + + file(COPY platform/unix/debian/ DESTINATION debian PATTERN "*.in" EXCLUDE) + configure_file(platform/unix/debian/control.in debian/control @ONLY) + configure_file(platform/unix/debian/changelog.in debian/changelog @ONLY) + configure_file(platform/unix/debian/rules.in debian/rules @ONLY) + + configure_file(platform/unix/love.desktop.in love.desktop @ONLY) + + install(TARGETS love liblove) + install(FILES platform/unix/love.6 + DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 + RENAME love.1) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/love.desktop + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications) + install(FILES platform/unix/love.xml + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/mime/packages) + install(FILES platform/unix/love.svg + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pixmaps) + install(FILES platform/unix/application-x-love-game.svg + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/mimetypes) endif() - -if (NOT MSVC) - return() -endif() - -################################### -# Version -################################### - -# Extract version.h contents. -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/src/common/version.h LOVE_VERSION_FILE_CONTENTS) - -# Extract one of LOVE_VERSION_MAJOR/MINOR/REV. -function(match_version ARG_STRING OUT_VAR) - string(REGEX MATCH "VERSION_${ARG_STRING} = ([0-9]+);" TMP_VER "${LOVE_VERSION_FILE_CONTENTS}") - string(REGEX MATCH "[0-9]+" TMP_VER "${TMP_VER}") - set(${OUT_VAR} ${TMP_VER} PARENT_SCOPE) -endfunction() - -match_version("MAJOR" LOVE_VERSION_MAJOR) -match_version("MINOR" LOVE_VERSION_MINOR) -match_version("REV" LOVE_VERSION_REV) - -set(LOVE_VERSION_STR "${LOVE_VERSION_MAJOR}.${LOVE_VERSION_MINOR}") - -message(STATUS "Version: ${LOVE_VERSION_STR}") - -################################### -# CPack -################################### -install(TARGETS ${LOVE_EXE_NAME} ${LOVE_CONSOLE_EXE_NAME} ${LOVE_LIB_NAME} RUNTIME DESTINATION .) - -# Our install script (and NSIS) doesn't fully support Windows ARM64 yet. -if(MEGA_ARM64) - set(CPACK_GENERATOR ZIP) - set(CPACK_SYSTEM_NAME woa64) -else() - set(CPACK_GENERATOR ZIP NSIS) -endif() - -# Extra DLLs. -if(LOVE_EXTRA_DLLS) - foreach(DLL ${LOVE_EXTRA_DLLS}) - get_filename_component(DLL_NAME ${DLL} NAME) - message(STATUS "Extra DLL: ${DLL_NAME}") - endforeach() - install(FILES ${LOVE_EXTRA_DLLS} DESTINATION .) -endif() - -# Dynamic runtime libs. -if(LOVE_MSVC_DLLS) - foreach(DLL ${LOVE_MSVC_DLLS}) - get_filename_component(DLL_NAME ${DLL} NAME) - message(STATUS "Runtime DLL: ${DLL_NAME}") - endforeach() - install(FILES ${LOVE_MSVC_DLLS} DESTINATION .) -endif() - -# Copy a text file from CMAKE_CURRENT_SOURCE_DIR to CMAKE_CURRENT_BINARY_DIR. -# On Windows, this function will convert line endings to CR,LF. -function(copy_text_file ARG_FILE_IN ARG_FILE_OUT) - file(READ ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_FILE_IN} TMP_TXT_CONTENTS) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${ARG_FILE_OUT} ${TMP_TXT_CONTENTS}) -endfunction() - -# Text files. -copy_text_file(readme.md readme.txt) -copy_text_file(license.txt license.txt) -copy_text_file(changes.txt changes.txt) - -install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/changes.txt - ${CMAKE_CURRENT_BINARY_DIR}/license.txt - ${CMAKE_CURRENT_BINARY_DIR}/readme.txt - DESTINATION .) - -# Icons -install(FILES - ${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis/love.ico - ${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis/game.ico - DESTINATION .) - -set(CPACK_PACKAGE_NAME "love") -set(CPACK_PACKAGE_VENDOR "love2d.org") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "LOVE -- It's awesome") -set(CPACK_PACKAGE_VERSION "${LOVE_VERSION_STR}") -set(CPACK_PACKAGE_VERSION_MAJOR "${LOVE_VERSION_MAJOR}") -set(CPACK_PACKAGE_VERSION_MINOR "${LOVE_VERSION_MINOR}") -set(CPACK_PACKAGE_VERSION_PATCH "${LOVE_VERSION_REV}") -set(CPACK_PACKAGE_INSTALL_DIRECTORY "LOVE") -set(CPACK_PACKAGE_EXECUTABLES "${LOVE_EXE_NAME};LOVE") -set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/readme.md") -set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/license.txt") - -set(CPACK_NSIS_EXECUTABLES_DIRECTORY .) -set(CPACK_NSIS_PACKAGE_NAME "LOVE") -set(CPACK_NSIS_DISPLAY_NAME "LOVE ${LOVE_VERSION_STR}") -set(CPACK_NSIS_MODIFY_PATH OFF) - -if(LOVE_X64) - set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") -else() - set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") -endif() - -set(CPACK_NSIS_MENU_LINKS "http://love2d.org/wiki" "Documentation") - -# Some bug somewhere in NSIS requires "\\\\" somewhere in the path, -# according to The Internet. (And sure enough, it does not work -# without it). -set(NSIS_LEFT_BMP "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\left.bmp") -set(NSIS_TOP_BMP "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\top.bmp") -set(NSIS_MUI_ICON "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\love.ico") -set(NSIS_MUI_UNICON "${CMAKE_CURRENT_SOURCE_DIR}/extra/nsis\\\\love.ico") - -set(CPACK_NSIS_INSTALLER_MUI_ICON_CODE " - !define MUI_WELCOMEPAGE_TITLE \\\"LOVE ${LOVE_VERSION_STR} Setup\\\" - !define MUI_WELCOMEFINISHPAGE_BITMAP \\\"${NSIS_LEFT_BMP}\\\" - !define MUI_HEADERIMAGE_BITMAP \\\"${NSIS_TOP_BMP}\\\" - !define MUI_ICON \\\"${NSIS_MUI_ICON}\\\" - !define MUI_UNICON \\\"${NSIS_MUI_UNICON}\\\" -") - -set(CPACK_NSIS_EXTRA_INSTALL_COMMANDS " - WriteRegStr HKCR \\\".love\\\" \\\"\\\" \\\"LOVE\\\" - WriteRegStr HKCR \\\"LOVE\\\" \\\"\\\" \\\"LOVE Game File\\\" - WriteRegStr HKCR \\\"LOVE\\\\DefaultIcon\\\" \\\"\\\" \\\"$INSTDIR\\\\game.ico\\\" - WriteRegStr HKCR \\\"LOVE\\\\shell\\\" \\\"\\\" \\\"open\\\" - WriteRegStr HKCR \\\"LOVE\\\\shell\\\\open\\\" \\\"\\\" \\\"Open in LOVE\\\" - WriteRegStr HKCR \\\"LOVE\\\\shell\\\\open\\\\command\\\" \\\"\\\" \\\"$INSTDIR\\\\love.exe $\\\\\\\"%1$\\\\\\\"\\\" - System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' -") - -set(CPACK_NSIS_EXTRA_UNINSTALL_COMMANDS " - DeleteRegKey HKCR \\\"LOVE\\\" - DeleteRegKey HKCR \\\".love\\\" - System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)' -") - -include(CPack) diff --git a/changes.txt b/changes.txt index d5c49c9c9..3835e99b9 100644 --- a/changes.txt +++ b/changes.txt @@ -68,7 +68,8 @@ Released: N/A * Added APIs to override the default orthographic projection: love.graphics.setOrthoProjection, setPerspectiveProjection, and resetProjection. * Added ability to set point size within a vertex shader by setting the 'love_PointSize' variable. * Added love.graphics.setBlendState, which gives lower level control over blend operations than setBlendMode. -* Added love.graphics.setStencilMode and getStencilMode. Replaces love.graphics.stencil as well as setStencilTest. +* Added high level love.graphics.setStencilMode and getStencilMode functions. Replaces love.graphics.stencil and setStencilTest. +* Added lower level love.graphics.setStencilState and getStencilState functions. * Added a variant of love.graphics.setColorMask which accepts a single boolean. * Added new 'clampone' wrap mode. * Added 'clampone', 'texelbuffer', 'indexbuffer32bit', 'mipmaprange', and 'indirectdraw' graphics feature enums. @@ -81,7 +82,6 @@ Released: N/A * Added love.joysticksensorupdated callback. * Added variant for enet peer:send and host:broadcast which accepts a pointer (light userdata) and a size. -* Changed love.filesystem.exists to no longer be deprecated. * Changed the default font from Vera size 12 to Noto Sans size 13. * Changed TrueType and OpenType font handling to have improved kerning and character combining support. * Changed the Texture class and implementation to no longer have separate Canvas and Image subclasses. @@ -100,6 +100,7 @@ Released: N/A * Changed RevoluteJoint:getMotorTorque and WheelJoint:getMotorTorque to take 'dt' as a parameter instead of 'inverse_dt'. * Changed love.math.perlinNoise and simplexNoise to use higher precision numbers for its internal calculations. * Changed t.accelerometerjoystick startup flag in love.conf to unset by default. +* Changed love.data.hash to take in a container type. * Renamed 'display' field to 'displayindex' in love.window.setMode/updateMode/getMode and love.conf. * Renamed love.graphics Text objects to TextBatch. @@ -113,12 +114,13 @@ Released: N/A * Deprecated love.graphics.setNewFont (use love.graphics.newFont and love.graphics.setFont instead). * Deprecated love.graphics.newText (renamed to love.graphics.newTextBatch). * Deprecated love.graphics.getImageFormats and love.graphics.getCanvasFormats (replaced by getTextureFormats). -* Deprecated love.graphics.stencil (replaced by love.graphics.setStencilMode). -* Deprecated love.graphics.setStencilTest and love.graphics.getStencilTest (replaced by love.graphics.setStencilMode and getStencilMode). +* Deprecated love.graphics.stencil (replaced by love.graphics.setStencilMode or love.graphics.setStencilState). +* Deprecated love.graphics.setStencilTest and love.graphics.getStencilTest (replaced by love.graphics.setStencilMode or setStencilState). * Deprecated t.window.highdpi in love.conf and the highdpi flag of love.window.setMode (replaced by t.highdpi in love.conf). * Deprecated t.accelerometerjoystick in love.conf (replaced by love.sensor module). * Deprecated the variants of Mesh:attachAttribute and SpriteBatch:attachAttribute which accept a Mesh (replaced by variants which accept a Buffer). * Deprecated Texture:newImageData (replaced by love.graphics.readbackTexture). +* Deprecated love.data.hash (replaced by function variant, which takes container type). * Removed the variant of SpriteBatch:setColor() which turns off all previously set colors. * Removed the no-argument variant of love.graphics.setColorMask. @@ -145,13 +147,30 @@ Released: N/A LOVE 11.5 [Mysterious Mysteries] -------------------------------- -Released: N/A +Released: 2023-12-03 +* Added "LÖVE Loader" launcher on Android for easier loading of .love files. + +* Changed iOS game selector to alphabetically sort the list of .love files. +* Changed JIT compilation on macOS arm64 (Apple Silicon) to be off by default, since performance and available JIT memory isn't reliable. + +* Fixed inconsistent and buggy behaviour of 'pairs' by updating LuaJIT. +* Fixed "unexpected alignment" errors when running love on some 32 bit Linux systems. +* Fixed running fused games on Windows when the executable has been code-signed. +* Fixed undefined behaviour in love.data.hash's implementation. +* Fixed writing files when a symlink exists in the save directory's path. * Fixed love.threaderror not being called if the error message is an empty string. * Fixed a race condition when a Thread is destroyed immediately after Thread:start. * Fixed unexpectedly slow first frames on macOS. +* Fixed love.joystick.setGamepadMapping when replacing an existing mapping. +* Fixed love.joystick.getGamepadMappingString. +* Fixed duplicate platform fields in love.joystick.saveGamepadMappings. +* Fixed DistanceJoint type information. * Fixed time drift in Source:tell after a Source loops. * Fixed audio not always pausing when the app is minimized on Android. +* Fixed RecordingDevice:start to return false instead of hard-crashing on iOS. +* Fixed identical frames in Ogg Theora videos being skipped. +* Fixed love.font.newBMFontRasterizer's single file parameter variant. * Fixed the original window size not always being restored when exiting fullscreen on Linux. * Fixed some cases of framerate hitches in Windows when vsync is enabled in windowed mode. * Fixed colors appearing over-saturated on P3 displays in macOS. diff --git a/extra/cmake/FindMPG123.cmake b/extra/cmake/FindMPG123.cmake deleted file mode 100644 index 6cda993b2..000000000 --- a/extra/cmake/FindMPG123.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# Sets the following variables: -# -# MPG123_FOUND -# MPG123_INCLUDE_DIR -# MPG123_LIBRARY - -set(MPG123_SEARCH_PATHS - /usr/local - /usr - ) - -find_path(MPG123_INCLUDE_DIR - NAMES mpg123.h - PATH_SUFFIXES include - PATHS ${MPG123_SEARCH_PATHS}) - -find_library(MPG123_LIBRARY - NAMES mpg123 - PATH_SUFFIXES lib - PATHS ${MPG123_SEARCH_PATHS}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(MPG123 DEFAULT_MSG MPG123_LIBRARY MPG123_INCLUDE_DIR) - -mark_as_advanced(MPG123_INCLUDE_DIR MPG123_LIBRARY) diff --git a/extra/cmake/FindOpenAL.cmake b/extra/cmake/FindOpenAL.cmake deleted file mode 100644 index 112beca9b..000000000 --- a/extra/cmake/FindOpenAL.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# FindOpenAL.cmake that comes with CMake expects "#include " to be used -# However, we use "#include " - -# Sets the following variables: -# -# OPENAL_FOUND -# OPENAL_INCLUDE_DIR -# OPENAL_LIBRARY - -set(OPENAL_SEARCH_PATHS - /usr/local - /usr - ) - -find_path(OPENAL_INCLUDE_DIR - NAMES AL/al.h - PATH_SUFFIXES include - PATHS ${OPENAL_SEARCH_PATHS}) - -find_library(OPENAL_LIBRARY - NAMES openal - PATH_SUFFIXES lib - PATHS ${OPENAL_SEARCH_PATHS}) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(OpenAL DEFAULT_MSG OPENAL_LIBRARY OPENAL_INCLUDE_DIR) - -mark_as_advanced(OPENAL_INCLUDE_DIR OPENAL_LIBRARY) diff --git a/extra/cmake/LoveMacros.cmake b/extra/cmake/LoveMacros.cmake new file mode 100644 index 000000000..ac962e78d --- /dev/null +++ b/extra/cmake/LoveMacros.cmake @@ -0,0 +1,33 @@ + +# Group all related stuff in folders in Visual Studio + +function(love_group_projects) + set(options NESTED) + set(oneValueArgs NAME) + set(multiValueArgs TARGETS) + cmake_parse_arguments(LOVE_GROUP "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(TARGET_NAME ${LOVE_GROUP_TARGETS}) + if (TARGET ${TARGET_NAME}) + get_target_property(TARGET_TYPE ${TARGET_NAME} TYPE) + # If this is an interface target, walk the children + if (${TARGET_TYPE} STREQUAL "INTERFACE_LIBRARY") + get_target_property(TARGET_LIBS ${TARGET_NAME} INTERFACE_LINK_LIBRARIES) + foreach(TARGET_LIB ${TARGET_LIBS}) + # Is this a target? (Could also be a .lib file) + if (TARGET ${TARGET_LIB}) + # Do we want to nest per-project? + if (LOVE_GROUP_NESTED) + set_target_properties(${TARGET_LIB} PROPERTIES FOLDER "${LOVE_GROUP_NAME}/${TARGET_NAME}") + else() + set_target_properties(${TARGET_LIB} PROPERTIES FOLDER "${LOVE_GROUP_NAME}") + endif() + endif() + endforeach() + else() + # This is no interface library, so group it under the root 'NAME' node + set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "${LOVE_GROUP_NAME}") + endif() + endif() + endforeach() +endfunction() diff --git a/extra/windows/love.rc b/extra/windows/love.rc index f7e150a58..fd42991c2 100644 Binary files a/extra/windows/love.rc and b/extra/windows/love.rc differ diff --git a/license.txt b/license.txt index a430dab12..f8d51334e 100644 --- a/license.txt +++ b/license.txt @@ -6,7 +6,7 @@ This distribution contains code from the following projects (full license text b - LOVE Website: https://love2d.org/ License: zlib - Copyright (c) 2006-2023 LOVE Development Team + Copyright (c) 2006-2024 LOVE Development Team - ENet Website: http://enet.bespin.org/index.html diff --git a/platform/unix/Makefile.am b/platform/unix/Makefile.am deleted file mode 100644 index f54a08e9c..000000000 --- a/platform/unix/Makefile.am +++ /dev/null @@ -1,24 +0,0 @@ -ACLOCAL_AMFLAGS = -I platform/unix/m4 -SUBDIRS = src -EXTRA_DIST = changes.txt license.txt readme.md \ - platform/unix/love.desktop.in -dist_man1_MANS = platform/unix/love.6 - -applicationsdir=$(datarootdir)/applications -mimeinfodir=$(datarootdir)/mime/packages -pixmapsdir=$(datarootdir)/pixmaps -mimeiconsdir=$(datarootdir)/icons/hicolor/scalable/mimetypes - -applications_DATA = platform/unix/love.desktop -dist_mimeinfo_DATA = platform/unix/love.xml -dist_pixmaps_DATA = platform/unix/love.svg -dist_mimeicons_DATA = platform/unix/application-x-love-game.svg - -platform/unix/love.desktop: platform/unix/love.desktop.in - $(MKDIR_P) platform/unix - rm -f $@ $@.tmp - $(SED) \ - -e "s|@bindir[@]|$(bindir)|" \ - ${srcdir}/$@.in > $@.tmp - chmod a-w $@.tmp - mv $@.tmp $@ diff --git a/platform/unix/automagic b/platform/unix/automagic deleted file mode 100755 index 23acf6266..000000000 --- a/platform/unix/automagic +++ /dev/null @@ -1,71 +0,0 @@ -#!/bin/bash - -log() { - echo "[automagic] " $@ -} - -die() { - log "Fatal: "$@ - exit 1 -} - -if [[ ! -d platform/unix ]]; then - log "Can't find the 'plaform/unix' folder, make sure you run this from the root of the repository." - exit 1 -fi - -AUTOHEADER=${AUTOHEADER:-$(which autoheader)} -AUTOCONF=${AUTOCONF:-$(which autoconf)} -LIBTOOLIZE=${LIBTOOLIZE:-$(which libtoolize)} -ACLOCAL=${ACLOCAL:-$(which aclocal)} -AUTOMAKE=${AUTOMAKE:-$(which automake)} - -[[ -x ${AUTOHEADER} ]] || die "Could not find autoheader. Install autoconf." -[[ -x ${AUTOCONF} ]] || die "Could not find autoconf." -[[ -x ${LIBTOOLIZE} ]] || die "Could not find libtoolize. Install libtool." -[[ -x ${ACLOCAL} ]] || die "Could not find aclocal. Install automake." -[[ -x ${AUTOMAKE} ]] || die "Could not find automake." - -print_errors() { - local output - output="$("$@" 2>&1)" && return 0 - printf "%s\n" "$output" - return 1 -} - -automagic() { - log "Copying files..." - cp platform/unix/configure.ac . - cp platform/unix/Makefile.am . - - log "Running genmodules..." - if ! print_errors bash platform/unix/genmodules "$1"; then - echo "You should be doing this from the root directory of the project." - exit 1 - fi - - log "Running autoheader..." - print_errors ${AUTOHEADER} || return 1 # Gimmie config.h.in - - log "Running libtoolize..." - print_errors ${LIBTOOLIZE} --force || return 1 - - log "Running aclocal..." - print_errors ${ACLOCAL} || return 1 - - log "Running autoconf..." - print_errors ${AUTOCONF} || return 1 - - log "Running automake..." - print_errors ${AUTOMAKE} -a || return 1 -} - -automagic "$@" - -if [[ $? -eq 1 ]]; then - log "Failed, sadface." - log "This is generally a configuration error (I'm looking at you aclocal)" - exit 1 -else - log "Success, carry on configuring." -fi diff --git a/platform/unix/configure.ac b/platform/unix/configure.ac deleted file mode 100644 index b04c5a1ec..000000000 --- a/platform/unix/configure.ac +++ /dev/null @@ -1,140 +0,0 @@ -AC_INIT([love], [12.0]) -AC_CONFIG_HEADERS([config.h]) -AC_CONFIG_AUX_DIR([platform/unix]) -AC_CONFIG_MACRO_DIR([platform/unix/m4]) -AC_CONFIG_SRCDIR([src/love.cpp]) -AM_INIT_AUTOMAKE([foreign -Wall foreign tar-ustar silent-rules]) -AM_SILENT_RULES -AC_PREFIX_DEFAULT([/usr]) -m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) -LT_INIT([disable-static]) -AC_PROG_CC -AC_PROG_CXX -AC_PROG_SED -AC_PROG_MKDIR_P -AC_PROG_OBJCXX -PKG_PROG_PKG_CONFIG -AC_C_BIGENDIAN -AC_LANG([C++]) - -dnl Workaround for old aclocal versions -m4_include([platform/unix/cpp14.m4]) -m4_include([platform/unix/deps.m4]) - -includes= - -AC_DEFUN([LOVE_MSG_ERROR], - [AC_MSG_ERROR([LÖVE needs "$1"[,] please install "$1" with development files and try again])]) - -# C++14 support in cpp14.m4 -ACLOVE_CPP14_TEST - -# Add -fvisibility=hidden and -fvisibility-inlines-hidden -CFLAGS="-fvisibility=hidden $CFLAGS" -CXXFLAGS="-fvisibility=hidden -fvisibility-inlines-hidden $CXXFLAGS" - -# Allow people on OSX to use autotools, they need their platform files -AC_ARG_ENABLE([osx], - AC_HELP_STRING([--enable-osx], [Compile platform-specific files for OSX]), [], [enable_osx=no]) -AS_VAR_IF([enable_osx], [no], [], #else - ac_cv_search_glLoadIdentity="-framework OpenGL" - AC_SUBST([LDFLAGS], ["${LDFLAGS} -framework CoreFoundation -framework Cocoa"]) - AC_SUBST([CPPFLAGS], ["${CPPFLAGS} -I../platform/macosx"])) - -# stb_image sse2 override (https://github.com/nothings/stb/issues/280) -AC_ARG_ENABLE([stbi-sse2-override], - AC_HELP_STRING([--enable-stbi-sse2-override], [Force stb_image SSE2 support]), [], [enable_stbi_sse2_override=no]) -AS_VAR_IF([enable_stbi_sse2_override], [no], [], #else - AC_SUBST([CPPFLAGS], ["${CPPFLAGS} -DLOVE_STBI_SSE2_OVERRIDE"])) - -# --with-lua and --with-luaversion -AC_ARG_WITH([lua], [AS_HELP_STRING([--with-lua], [Select the lua implementation])], - [], [with_lua=luajit]) -AC_ARG_WITH([luaversion], [AS_HELP_STRING([--with-luaversion], [Select the lua version])], - [], [with_luaversion=5.1]) - -with_clean_luaversion=`printf ${with_luaversion} | sed 's/\.//g'` - -# Generated sources for enabling/disabling modules -m4_include([configure-modules-pre.ac]) - -# Dependencies we always use -ACLOVE_DEP_LUA -ACLOVE_DEP_SDL2 -ACLOVE_DEP_LIBM -ACLOVE_DEP_ZLIB -ACLOVE_DEP_PTHREAD - -# Conditional dependencies -AS_VAR_IF([enable_module_audio], [yes], [ACLOVE_DEP_OPENAL], []) -AS_VAR_IF([enable_module_font], [yes], [ - ACLOVE_DEP_FREETYPE2 - ACLOVE_DEP_HARFBUZZ -], []) -AS_VAR_IF([enable_module_sound], [yes], [ - ACLOVE_DEP_LIBMODPLUG - ACLOVE_DEP_VORBISFILE -], []) -AS_VAR_IF([enable_module_video], [yes], [ACLOVE_DEP_THEORA], []) - -# Add flags for optional libraries -AC_ARG_ENABLE([library-enet], [ --disable-library-enet Turn off library enet], [], [enable_library_enet=yes]) -AC_ARG_ENABLE([library-luasocket], [ --disable-library-luasocket Turn off library luasocket], [], [enable_library_luasocket=yes]) -AC_ARG_ENABLE([library-lua53], [ --disable-library-lua53 Turn off library lua53 (lua 5.3 backports, required by love.data)], [], [enable_library_lua53=yes]) -AC_ARG_ENABLE([library-luahttps], [ --disable-library-luahttps Turn off library luahttps], [], [enable_library_luahttps=yes]) - -# Select the libraries we need to build, based on the selected modules -AS_VAR_IF([enable_module_filesystem], [yes], [enable_library_physfs=yes], [enable_library_physfs=no]) -AS_VAR_IF([enable_module_physics], [yes], [enable_library_box2d=yes], [enable_library_box2d=no]) -AS_VAR_IF([enable_module_image], [yes], [enable_library_ddsparse=yes], [enable_library_ddsparse=no]) -AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glad=yes], [enable_library_glad=no]) -AS_VAR_IF([enable_module_graphics], [yes], [enable_library_spirv_cross=yes], [enable_library_spirv_cross=no]) -AS_VAR_IF([enable_module_graphics], [yes], [enable_library_glslang=yes], [enable_library_glslang=no]) -AS_VAR_IF([enable_module_image], [yes], [enable_library_lodepng=yes], [enable_library_lodepng=no]) -AS_VAR_IF([enable_module_data], [yes], [enable_library_lua53=yes], []) -AS_VAR_IF([enable_module_math], [yes], [enable_library_lz4=yes], [enable_library_lz4=no]) -AS_VAR_IF([enable_module_math], [yes], [enable_library_noise1234=yes], [enable_library_noise1234=no]) -AS_VAR_IF([enable_module_image], [yes], [enable_library_stb=yes], [enable_library_stb=no]) -AS_VAR_IF([enable_module_image], [yes], [enable_library_tinyexr=yes], [enable_library_tinyexr=no]) -AS_VAR_IF([enable_module_sound], [yes], [enable_library_Wuff=yes], [enable_library_Wuff=no]) -AS_VAR_IF([enable_module_graphics], [yes], [enable_library_xxHash=yes], [enable_library_xxHash=no]) - -# Utf8 is required by both graphics and font, so enable if either is enabled -enable_library_utf8=no -AS_VAR_IF([enable_module_graphics], [yes], [enable_library_utf8=yes], []) -AS_VAR_IF([enable_module_font], [yes], [enable_library_utf8=yes], []) - -# libenet check for socklen_t -ACLOVE_SOCKLEN_T - -# Generated sources for enabling/disabling modules -m4_include([configure-modules-post.ac]) - -# Optionally build the executable (default on) -AC_ARG_ENABLE([exe], - AC_HELP_STRING([--disable-exe], [Disable building of executable launcher]), [], [enable_exe=yes]) - -AS_VAR_IF([enable_exe], [no], [], #else - AC_DEFINE([LOVE_BUILD_EXE], [], [Skip building launcher])) - -AM_CONDITIONAL([LOVE_BUILD_EXE], [test "x$enable_exe" != xno]) -AM_CONDITIONAL([LOVE_TARGET_OSX], [test "x$enable_osx" != xno]) - -# Automatic script file rebuilding -AC_CHECK_PROGS([LUA_EXECUTABLE], ["${with_lua}${with_luaversion}" "${with_lua}" "lua"], [:]) -AS_VAR_IF([LUA_EXECUTABLE], [:], - [AC_MSG_WARN([Did not find a lua executable, you may need to update the scripts manually if you change them])], []) - -# Set our includes as automake variable -AC_SUBST([LOVE_INCLUDES], ["$includes"]) - -AC_CONFIG_FILES([ - Makefile - src/Makefile - platform/unix/debian/control - platform/unix/debian/changelog - platform/unix/debian/rules -]) -AC_OUTPUT - -chmod 755 platform/unix/debian/rules diff --git a/platform/unix/cpp14.m4 b/platform/unix/cpp14.m4 deleted file mode 100644 index 42a884ecd..000000000 --- a/platform/unix/cpp14.m4 +++ /dev/null @@ -1,68 +0,0 @@ -AC_DEFUN([ACLOVE_CXX_FLAG_TEST], [ dnl WARNING: NOT REENTRANT - aclove_cxx_flag_test_save_cflags="$CXXFLAGS" - CXXFLAGS="$1" - AC_MSG_CHECKING([whether $CXX supports flag $1]) - AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], - [AC_MSG_RESULT([yes])]; $2, - [AC_MSG_RESULT([no]); $3]) - CXXFLAGS="$aclove_cxx_flag_test_save_cflags" -]) - -AC_DEFUN([ACLOVE_GET_GCC_VERSION], [ - aclove_gcc_version_found="yes" - AC_COMPUTE_INT(aclove_gcc_version_major, __GNUC__,, aclove_gcc_version_found="no") - AC_COMPUTE_INT(aclove_gcc_version_minor, __GNUC_MINOR__,, aclove_gcc_version_found="no") - AC_COMPUTE_INT(aclove_gcc_version_patch, __GNUC_PATCHLEVEL__,, aclove_gcc_version_found="no") -]) - -AC_DEFUN([ACLOVE_GET_CLANG_VERSION], [ - aclove_clang_version_found="yes" - AC_COMPUTE_INT(aclove_clang_version_major, __clang_major__,, aclove_clang_version_found="no") - AC_COMPUTE_INT(aclove_clang_version_minor, __clang_minor__,, aclove_clang_version_found="no") - AC_COMPUTE_INT(aclove_clang_version_patch, __clang_patchlevel__,, aclove_clang_version_found="no") -]) - -AC_DEFUN([ACLOVE_CPP14_TEST_FLAG], [ - aclove_cpp14_test_cxx14name="no" - ACLOVE_CXX_FLAG_TEST([-std=c++14], aclove_cpp14_test_cxx14name="c++14", []) - AS_VAR_IF([aclove_cpp14_test_cxx14name], [no], - [AC_MSG_ERROR([LÖVE needs a C++ compiler with C++14 support])], - [CXXFLAGS="$CXXFLAGS -std=$aclove_cpp14_test_cxx14name"]) -]) - -AC_DEFUN([ACLOVE_CPP14_CHECK_VERSION], [ dnl compiler, targetmajor, targetminor, on-failure - aclove_cpp14_check_version_status="no" - AC_MSG_CHECKING([whether $1 version is at least $2.$3]) - AS_IF([test "$aclove_[]$1[]_version_major" -gt $2], aclove_cpp14_check_version_status="yes") - AS_IF([test "$aclove_[]$1[]_version_major" -eq $2 && test "$aclove_[]$1[]_version_minor" -ge $3], aclove_cpp14_check_version_status="yes") - AC_MSG_RESULT([$aclove_cpp14_check_version_status]) - AS_VAR_IF([aclove_cpp14_check_version_status], [no], - [$4]) -]) - -AC_DEFUN([ACLOVE_CPP14_TEST_VERSION_GCC], [ - ACLOVE_CPP14_CHECK_VERSION([gcc], 4, 9, - [AC_MSG_ERROR([LÖVE needs a GCC version of at least 4.9])]) -]) - -AC_DEFUN([ACLOVE_CPP14_TEST_VERSION_CLANG], [ - ACLOVE_CPP14_CHECK_VERSION([clang], 3, 4, - [AC_MSG_ERROR([LÖVE needs a clang version of at least 3.4])]) -]) - -AC_DEFUN([ACLOVE_CPP14_TEST], [ - ACLOVE_CPP14_TEST_FLAG - - ACLOVE_GET_GCC_VERSION - ACLOVE_GET_CLANG_VERSION - - # Since clang also sets gcc headers, check clang after - aclove_cpp14_test_compiler="unknown" - AS_VAR_IF([aclove_gcc_version_found], [yes], aclove_cpp14_test_compiler="gcc") - AS_VAR_IF([aclove_clang_version_found], [yes], aclove_cpp14_test_compiler="clang") - - AS_CASE([$aclove_cpp14_test_compiler], - [gcc], [ACLOVE_CPP14_TEST_VERSION_GCC], - [clang], [ACLOVE_CPP14_TEST_VERSION_CLANG], - [AC_MSG_WARN([Could not determine compiler version])]) -]) diff --git a/platform/unix/debian/changelog.in b/platform/unix/debian/changelog.in index 1d528841a..11210aacb 100644 --- a/platform/unix/debian/changelog.in +++ b/platform/unix/debian/changelog.in @@ -1,5 +1,5 @@ -love@LOVE_SUFFIX@ (11.2~pre3458ppa1) trusty; urgency=medium +@LOVE_EXE_NAME@ (@LOVE_VERSION_STR@ppa1) focal; urgency=medium * Upstream testing release - -- Bart van Strien Tue, 10 Jul 2018 19:22:30 +0200 + -- Bart van Strien @LOVE_CONFIGURE_TIMESTAMP@ diff --git a/platform/unix/debian/control.in b/platform/unix/debian/control.in index e435df0ff..75b8ebab1 100644 --- a/platform/unix/debian/control.in +++ b/platform/unix/debian/control.in @@ -1,11 +1,9 @@ -Source: love@LOVE_SUFFIX@ +Source: @LOVE_EXE_NAME@ Section: games Priority: extra Maintainer: Bart van Strien Build-Depends: debhelper (>= 9), - dh-autoreconf, - pkg-config, - libtool, + cmake, g++ (>= 4.7.0), libfreetype6-dev, libharfbuzz-dev, @@ -22,7 +20,7 @@ Build-Depends: debhelper (>= 9), Standards-Version: 3.9.5 Homepage: http://love2d.org -Package: liblove@LOVE_SUFFIX@0 +Package: @LOVE_LIB_NAME@0 Section: libs Architecture: any Multi-Arch: same @@ -32,20 +30,20 @@ Depends: ${misc:Depends}, Description: 2D game engine - runtime LOVE is a free 2D game engine which enables easy game creation in Lua. -Package: love@LOVE_SUFFIX@ +Package: @LOVE_EXE_NAME@ Architecture: any Depends: ${misc:Depends}, ${shlibs:Depends}, - liblove@LOVE_SUFFIX@0 (= ${binary:Version}) + @LOVE_LIB_NAME@0 (= ${binary:Version}) Description: 2D game engine LOVE is a free 2D game engine which enables easy game creation in Lua. -Package: liblove@LOVE_SUFFIX@-dbg +Package: @LOVE_LIB_NAME@-dbg Priority: extra Section: debug Architecture: any Multi-Arch: same Depends: ${misc:Depends}, - liblove@LOVE_SUFFIX@0 (= ${binary:Version}) + @LOVE_LIB_NAME@0 (= ${binary:Version}) Description: 2D game engine - debug symbols LOVE is a free 2D game engine which enables easy game creation in Lua. diff --git a/platform/unix/debian/rules.in b/platform/unix/debian/rules.in index f55809f6f..ab7bd1434 100755 --- a/platform/unix/debian/rules.in +++ b/platform/unix/debian/rules.in @@ -1,22 +1,14 @@ #!/usr/bin/make -f -commonflags = -Wall -Wno-maybe-uninitialized -Wno-strict-aliasing -CFLAGS += $(commonflags) -CXXFLAGS += $(commonflags) - - %: - dh $@ --parallel --with autoreconf + dh $@ --parallel override_dh_auto_clean: dh_auto_clean rm -f platform/unix/love-unstable.6 -override_dh_auto_configure: - dh_auto_configure -- --with-lua=luajit - override_dh_installdocs: - dh_installdocs --link-doc=liblove@LOVE_SUFFIX@0 + dh_installdocs --link-doc=@LOVE_LIB_NAME@0 override_dh_installchangelogs: dh_installchangelogs changes.txt @@ -26,6 +18,6 @@ override_dh_installman: dh_installman override_dh_strip: - dh_strip -pliblove@LOVE_SUFFIX@0 --dbg-package=liblove@LOVE_SUFFIX@-dbg + dh_strip -p@LOVE_LIB_NAME@0 --dbg-package=@LOVE_LIB_NAME@-dbg dh_strip --remaining-packages diff --git a/platform/unix/deps.m4 b/platform/unix/deps.m4 deleted file mode 100644 index 868bd0244..000000000 --- a/platform/unix/deps.m4 +++ /dev/null @@ -1,77 +0,0 @@ -AC_DEFUN([ACLOVE_DEP_FREETYPE2], [ - PKG_CHECK_MODULES([freetype2], [freetype2], [], [LOVE_MSG_ERROR([FreeType2])])]) - -AC_DEFUN([ACLOVE_DEP_HARFBUZZ], [ - PKG_CHECK_MODULES([harfbuzz], [harfbuzz], [], [LOVE_MSG_ERROR([Harfbuzz])])]) - -AC_DEFUN([ACLOVE_DEP_OPENAL], [ - PKG_CHECK_MODULES([openal], [openal], [], [LOVE_MSG_ERROR([OpenAL])])]) - -AC_DEFUN([ACLOVE_DEP_LIBMODPLUG], [ - PKG_CHECK_MODULES([libmodplug], [libmodplug], [], [LOVE_MSG_ERROR([libmodplug])])]) - -AC_DEFUN([ACLOVE_DEP_VORBISFILE], [ - PKG_CHECK_MODULES([vorbisfile], [vorbisfile], [], [LOVE_MSG_ERROR([libvorbis and libvorbisfile])])]) - -AC_DEFUN([ACLOVE_DEP_ZLIB], [ - PKG_CHECK_MODULES([zlib], [zlib], [], [LOVE_MSG_ERROR([zlib])])]) - -AC_DEFUN([ACLOVE_DEP_THEORA], [ - PKG_CHECK_MODULES([theora], [theoradec], [], [LOVE_MSG_ERROR([libtheora])])]) - -AC_DEFUN([ACLOVE_DEP_LIBM], [ - AC_SEARCH_LIBS([sqrt], [m], [], [LOVE_MSG_ERROR([the C math library])])]) - -AC_DEFUN([ACLOVE_DEP_SDL2], [ - aclove_sdl2_found=no - AM_PATH_SDL2([2.0.9], [aclove_sdl2_found=yes], []) - AS_VAR_IF([aclove_sdl2_found], [no], [LOVE_MSG_ERROR([SDL 2])], [])]) - -AC_DEFUN([ACLOVE_DEP_PTHREAD], [ - AC_SEARCH_LIBS([pthread_create], [pthread], [], [LOVE_MSG_ERROR([the POSIX threads library])])]) - -# does not use pkg-config because of the FILE_OFFSET_BITS.. bit -AC_DEFUN([ACLOVE_DEP_MPG123], [ - AC_SEARCH_LIBS([mpg123_open_feed], [mpg123], [], - [LOVE_MSG_ERROR([libmpg123])]) - AC_SEARCH_LIBS([mpg123_seek_64], [mpg123], - AC_SUBST([FILE_OFFSET],[-D_FILE_OFFSET_BITS=64]), - AC_SUBST([FILE_OFFSET],[]))]) - -# For enet -AC_DEFUN([ACLOVE_SOCKLEN_T], [ - AC_CHECK_TYPE([socklen_t], [AC_DEFINE([HAS_SOCKLEN_T], [1], [Define if socklen_t exists.] )], , - #include - #include - )]) - -# The lua detection is quite annoying because of distro differences and our version selection code -AC_DEFUN([ACLOVE_DEP_LUA_PKGCONFIG], [ - PKG_CHECK_MODULES([lua], [${with_lua}${with_luaversion}], [aclove_lua_found=yes], - [PKG_CHECK_MODULES([lua], [${with_lua}${with_clean_luaversion}], [aclove_lua_found=yes], - [PKG_CHECK_MODULES([lua], [${with_lua}], [aclove_lua_found=yes], [])])]) - - AS_VAR_IF([aclove_lua_found], [yes], - [ - aclove_luaheaders_found=yes - AC_MSG_CHECKING([for library containing lua_call]) - AC_MSG_RESULT([${lua_LIBS}]) - ], [])]) - -AC_DEFUN([ACLOVE_DEP_LUA_FALLBACK], [ - AC_MSG_WARN([Could not find pkg-config definition for ${with_lua}${with_luaversion} or ${with_lua}${with_clean_luaversion}${with_lua}, falling back to manual detection]) - AC_SEARCH_LIBS([lua_call], ["${with_lua}${with_luaversion}" "${with_lua}"], [aclove_lua_found=yes], - [LOVE_MSG_ERROR([$with_lua])]) - - AC_CHECK_HEADER(["${with_lua}${with_luaversion}/lua.h"], [aclove_luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}${with_luaversion}"], []) - AC_CHECK_HEADER(["${with_lua}/lua.h"], [aclove_luaheaders_found=yes includes="$includes -I/usr/include/${with_lua}"], [])]) - -# First, try pkg-config, then fall back to manual detection if not available. -AC_DEFUN([ACLOVE_DEP_LUA], [ dnl Requires with-lua and with-luaversion - aclove_lua_found=no - aclove_luaheaders_found=no - - ACLOVE_DEP_LUA_PKGCONFIG - AS_VAR_IF([aclove_lua_found], [no], [ACLOVE_DEP_LUA_FALLBACK], []) - AS_VAR_IF([aclove_luaheaders_found], [no], - [AC_MSG_WARN([Could not locate lua headers for ${with_lua}${with_luaversion} or ${with_lua}, you probably need to specify them with CPPFLAGS])], [])]) diff --git a/platform/unix/exclude b/platform/unix/exclude deleted file mode 100644 index 95b2573eb..000000000 --- a/platform/unix/exclude +++ /dev/null @@ -1,3 +0,0 @@ -\./libraries/luasocket/libluasocket/wsocket.* -\./love\.cpp -\./libraries/glslang/glslang/OSDependent/Windows diff --git a/platform/unix/genmodules b/platform/unix/genmodules deleted file mode 100644 index 3d7cdca0d..000000000 --- a/platform/unix/genmodules +++ /dev/null @@ -1,157 +0,0 @@ -#!/bin/bash - -love_suffix="$1" -love_amsuffix="$(echo "$love_suffix" | sed 's/\-/_/g' | sed 's/\./_/g')" - -flags=() -upper() -{ - echo "$@" | tr '[:lower:]' '[:upper:]' -} - -sourcefind() -{ - find "$1" $2 -type f \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" -o -iname "*.hpp" -o -iname "*.lch" -o -iname "*.lua" \) | awk "{print \"./$prefix\"\$0\" \\\\\"}" | grep -v -f"$LOVEROOT/platform/unix/exclude" | sort -} - -handlemodule() -{ - module="$1" - DEFINENAME="LOVE_MODULE_$(upper "$module")" - printf "$DEFINENAME" -} - -genmodules() -{ - LOVEROOT="$(pwd)" - cd ./src - - printf "liblove${love_amsuffix}_la_SOURCES = \\\\\n" - sourcefind "common" | sed "s/^/ /" - FILES="$(sourcefind "scripts" | sed "s/^/ /")" - printf "${FILES:0:${#FILES}-2}\n\n" - - local -a modulelist=() - local -a liblist=() - - cd ./modules - prefix="modules/" - for module in *; do - flags+=("module-$module") - - FILES="$(sourcefind "$module" | sed "s/^/ /")" - if [[ "x$FILES" != "x" ]]; then - printf "liblove_module_$module = \\\\\n" - printf "${FILES:0:${#FILES}-2}\n\n" - modulelist+=("$module") - fi - done - - cd ../libraries - prefix="libraries/" - for library in *; do - flags+=("library-$library") - FILES="$(sourcefind "$library" | sed "s/^/ /")" - - if [[ ${#FILES} -gt 2 ]]; then - printf "liblove_library_$library = \\\\\n" - printf "${FILES:0:${#FILES}-2}\n\n" - liblist+=("$library") - fi - done - - for module in "${modulelist[@]}"; do - NAME=$(handlemodule "$module") - printf "if $NAME\n" - printf "liblove${love_amsuffix}_la_SOURCES += \$(liblove_module_$module)\n" - printf "endif\n\n" - done - - for library in "${liblist[@]}"; do - NAME="LOVE_LIBRARY_$(upper "$library")" - printf "if $NAME\n" - printf "liblove${love_amsuffix}_la_SOURCES += \$(liblove_library_$library)\n" - printf "endif\n\n" - done - - cd ../.. -} - -genflags() -{ - printf > configure-modules-pre.ac - printf > configure-modules-post.ac - for flag in "${flags[@]}"; do - prettyflag="$(echo "$flag" | sed -e 's/-/ love./' -e 's/-/./g')" - varflag="enable_$(echo "$flag" | sed -e 's/[^a-zA-Z0-9]/_/')" - defineflag="LOVE_ENABLE_$(upper $(echo $flag | sed -e 's/^[^-]*-//' -e 's/-/_/g'))" - amflag="$(upper $(echo love-$flag | sed 's/-/_/g'))" - - # Don't generate an --enable rule for libraries - if [[ "$(echo $flag | sed -e '/^library-/d')" != "" ]]; then - printf "AC_ARG_ENABLE([$flag], [ --disable-$flag Turn off $prettyflag], [], [$varflag=yes])\n" >> configure-modules-pre.ac - fi - - printf "AH_TEMPLATE([$defineflag], [])\n" >> configure-modules-post.ac - printf "if test x\"\$$varflag\" = xyes; then\n" >> configure-modules-post.ac - printf " AC_DEFINE([$defineflag], [])\n" >> configure-modules-post.ac - printf "fi\n" >> configure-modules-post.ac - printf "AM_CONDITIONAL([$amflag], [test x\$$varflag = xyes])\n\n" >> configure-modules-post.ac - done -} - -echo Generating src/Makefile.am ... -inc_current='$(srcdir)' -inc_modules="$inc_current/modules" -inc_libraries="$inc_current/libraries" - -cat > src/Makefile.am << EOF -AM_CPPFLAGS = -I$inc_current -I$inc_modules -I$inc_libraries -I$inc_libraries/enet/libenet/include -I$inc_libraries/box2d \$(LOVE_INCLUDES) \$(FILE_OFFSET)\ - \$(SDL_CFLAGS) \$(lua_CFLAGS) \$(freetype2_CFLAGS) \$(harfbuzz_CFLAGS)\ - \$(openal_CFLAGS) \$(zlib_CFLAGS) \$(libmodplug_CFLAGS)\ - \$(vorbisfile_CFLAGS) \$(theora_CFLAGS) -AUTOMAKE_OPTIONS = subdir-objects -SUBDIRS = -SUFFIXES = .lua .lua.h - -if LOVE_BUILD_EXE -# LÖVE executable -bin_PROGRAMS = love${love_suffix} -#love_LDFLAGS = -love${love_amsuffix}_LDADD = liblove${love_suffix}.la \$(lua_LIBS) -love${love_amsuffix}_SOURCES = love.cpp - -if LOVE_TARGET_OSX -love${love_amsuffix}_LIBTOOLFLAGS = --tag=OBJCXX -love${love_amsuffix}_SOURCES += \\ - ./common/macosx.mm -else -love${love_amsuffix}_LIBTOOLFLAGS = --tag=CXX -endif -endif - -# Compile scripts -.lua.lua.h: - cd ./scripts; \ - \$(LUA_EXECUTABLE) auto.lua \$< - -# libLÖVE -lib_LTLIBRARIES = liblove${love_suffix}.la -liblove${love_amsuffix}_la_LDFLAGS = -module -export-dynamic \$(LDFLAGS) -release \$(PACKAGE_VERSION) -liblove${love_amsuffix}_la_LIBADD = \ - \$(SDL_LIBS) \$(freetype2_LIBS) \$(harfbuzz_LIBS) \$(lua_LIBS)\ - \$(openal_LIBS) \$(zlib_LIBS) \$(libmodplug_LIBS)\ - \$(vorbisfile_LIBS) \$(theora_LIBS) - -EOF - -genmodules >> src/Makefile.am - -echo "src/Makefile.am is updated! ^.^" - -echo "Generating configure-modules.ac" -genflags -cat >> configure-modules-post.ac << EOF -AC_SUBST([LOVE_SUFFIX], [${love_suffix}]) -EOF -echo "configure-modules.ac is updated! ^.^" diff --git a/platform/unix/love.desktop.in b/platform/unix/love.desktop.in index 94c9bb418..d8322e72c 100644 --- a/platform/unix/love.desktop.in +++ b/platform/unix/love.desktop.in @@ -2,7 +2,7 @@ Name=LÖVE Comment=The unquestionably awesome 2D game engine MimeType=application/x-love-game; -Exec=@bindir@/love %f +Exec=@CMAKE_INSTALL_FULL_BINDIR@/love %f Type=Application Categories=Development;Game; Terminal=false diff --git a/platform/xcode/ios/luajit-iOS.sh b/platform/xcode/ios/luajit-iOS.sh deleted file mode 100755 index 0533b4138..000000000 --- a/platform/xcode/ios/luajit-iOS.sh +++ /dev/null @@ -1,57 +0,0 @@ -mkdir -p include/luajit -mkdir -p libraries/luajit - -if [ ! -d luajit-git ]; then - git clone https://github.com/LuaJIT/LuaJIT.git luajit-git -fi -cd luajit-git -git pull --no-rebase -git checkout v2.1 - -export MACOSX_DEPLOYMENT_TARGET=10.7 - -# iOS device binaries -# LuaJIT does not support building for armv7 on modern macOS versions. - -ISDKP=$(xcrun --sdk iphoneos --show-sdk-path) -ICC=$(xcrun --sdk iphoneos --find clang) - -ISDKF="-arch arm64 -isysroot $ISDKP -mios-version-min=8.0" -make clean TARGET_SYS=iOS -make -j8 CC="clang" CROSS="$(dirname $ICC)/" TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS -cp src/libluajit.a ../libraries/luajit/libluajit_arm64_device.a - - -# iOS simulator binaries - -ISDKP=$(xcrun --sdk iphonesimulator --show-sdk-path) -ICC=$(xcrun --sdk iphonesimulator --find clang) - -ISDKF="-arch x86_64 -isysroot $ISDKP -mios-simulator-version-min=8.0" -make clean TARGET_SYS=iOS -make -j8 CC="clang" CROSS="$(dirname $ICC)/" TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS -cp src/libluajit.a ../libraries/luajit/libluajit_x86_64_sim.a - -ISDKF="-arch arm64 -isysroot $ISDKP -mios-simulator-version-min=8.0" -make clean TARGET_SYS=iOS -make -j8 CC="clang" CROSS="$(dirname $ICC)/" TARGET_FLAGS="$ISDKF" TARGET_SYS=iOS -cp src/libluajit.a ../libraries/luajit/libluajit_arm64_sim.a - - -# copy includes -cp src/lua.hpp ../include/luajit - -cp src/lauxlib.h ../include/luajit -cp src/lua.h ../include/luajit -cp src/luaconf.h ../include/luajit -cp src/lualib.h ../include/luajit -cp src/luajit.h ../include/luajit - -# combine lib -cd ../libraries/luajit -lipo -create -output libluajit_device.a libluajit_arm64_device.a -lipo -create -output libluajit_sim.a libluajit_x86_64_sim.a libluajit_arm64_sim.a - -# create xcframework with all platforms -rm -rf Lua.xcframework -xcodebuild -create-xcframework -library libluajit_device.a -headers ../../include/luajit -library libluajit_sim.a -headers ../../include/luajit -output Lua.xcframework diff --git a/platform/xcode/liblove.xcodeproj/project.pbxproj b/platform/xcode/liblove.xcodeproj/project.pbxproj index 4aab7711e..36561d966 100644 --- a/platform/xcode/liblove.xcodeproj/project.pbxproj +++ b/platform/xcode/liblove.xcodeproj/project.pbxproj @@ -51,6 +51,12 @@ 217DFC111D9F6D490055D849 /* usocket.c in Sources */ = {isa = PBXBuildFile; fileRef = 217DFBD51D9F6D490055D849 /* usocket.c */; }; 217DFC121D9F6D490055D849 /* usocket.h in Headers */ = {isa = PBXBuildFile; fileRef = 217DFBD61D9F6D490055D849 /* usocket.h */; }; D923E7D3296B85B9002FF1B3 /* harfbuzz.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = D923E7D2296B85B9002FF1B3 /* harfbuzz.xcframework */; }; + D943E58E2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; + D943E58F2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; + D943E5902A24D56000D80361 /* PhysfsIo.h in Headers */ = {isa = PBXBuildFile; fileRef = D943E58D2A24D56000D80361 /* PhysfsIo.h */; }; + D99081EE2BB2473900D2B0E4 /* JoystickSDL3.h in Headers */ = {isa = PBXBuildFile; fileRef = D99081EC2BB2473900D2B0E4 /* JoystickSDL3.h */; }; + D99081EF2BB2473900D2B0E4 /* JoystickSDL3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D99081ED2BB2473900D2B0E4 /* JoystickSDL3.cpp */; }; + D99081F02BB2473900D2B0E4 /* JoystickSDL3.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D99081ED2BB2473900D2B0E4 /* JoystickSDL3.cpp */; }; D9DAB9222961F0EE00C64820 /* HarfbuzzShaper.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DAB9202961F0EE00C64820 /* HarfbuzzShaper.h */; }; D9DAB9232961F0EE00C64820 /* HarfbuzzShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */; }; D9DAB9242961F0EE00C64820 /* HarfbuzzShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */; }; @@ -61,9 +67,15 @@ D9DAB92D2961F10000C64820 /* TextShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9282961F10000C64820 /* TextShaper.cpp */; }; D9DAB92E2961F10000C64820 /* TextShaper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DAB9282961F10000C64820 /* TextShaper.cpp */; }; D9DAB9322963CD7500C64820 /* harfbuzz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D9DAB9312963CD7500C64820 /* harfbuzz.framework */; }; - D943E58E2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; - D943E58F2A24D56000D80361 /* PhysfsIo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D943E58C2A24D56000D80361 /* PhysfsIo.cpp */; }; - D943E5902A24D56000D80361 /* PhysfsIo.h in Headers */ = {isa = PBXBuildFile; fileRef = D943E58D2A24D56000D80361 /* PhysfsIo.h */; }; + D9DB6E272B4B40660037A1F6 /* ResourceLimits.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E252B4B40660037A1F6 /* ResourceLimits.h */; }; + D9DB6E292B4B40970037A1F6 /* span.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E282B4B40970037A1F6 /* span.h */; }; + D9DB6E362B4B41100037A1F6 /* ResourceLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DB6E332B4B41100037A1F6 /* ResourceLimits.cpp */; }; + D9DB6E372B4B41100037A1F6 /* ResourceLimits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D9DB6E332B4B41100037A1F6 /* ResourceLimits.cpp */; }; + D9DB6E3E2B4B41580037A1F6 /* NonSemanticDebugPrintf.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E382B4B41570037A1F6 /* NonSemanticDebugPrintf.h */; }; + D9DB6E3F2B4B41580037A1F6 /* NonSemanticShaderDebugInfo100.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E392B4B41570037A1F6 /* NonSemanticShaderDebugInfo100.h */; }; + D9DB6E402B4B41580037A1F6 /* GLSL.ext.ARM.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E3A2B4B41570037A1F6 /* GLSL.ext.ARM.h */; }; + D9DB6E412B4B41580037A1F6 /* GLSL.ext.QCOM.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E3B2B4B41580037A1F6 /* GLSL.ext.QCOM.h */; }; + D9DB6E452B4B80E80037A1F6 /* build_info.h in Headers */ = {isa = PBXBuildFile; fileRef = D9DB6E442B4B80E80037A1F6 /* build_info.h */; }; FA0A3A5F23366CE9001C269E /* floattypes.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0A3A5D23366CE9001C269E /* floattypes.h */; }; FA0A3A6023366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; FA0A3A6123366CE9001C269E /* floattypes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0A3A5E23366CE9001C269E /* floattypes.cpp */; }; @@ -407,9 +419,6 @@ FA0B7E091A95902C000E1D17 /* EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */; }; FA0B7E0A1A95902C000E1D17 /* EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */; }; FA0B7E0B1A95902C000E1D17 /* EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */; }; - FA0B7E0C1A95902C000E1D17 /* Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */; }; - FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */; }; - FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2C1A95902C000E1D17 /* Fixture.h */; }; FA0B7E0F1A95902C000E1D17 /* FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */; }; FA0B7E101A95902C000E1D17 /* FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */; }; FA0B7E111A95902C000E1D17 /* FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */; }; @@ -473,9 +482,6 @@ FA0B7E4B1A95902C000E1D17 /* wrap_EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */; }; FA0B7E4C1A95902C000E1D17 /* wrap_EdgeShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */; }; FA0B7E4D1A95902C000E1D17 /* wrap_EdgeShape.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */; }; - FA0B7E4E1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */; }; - FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */; }; - FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */; }; FA0B7E511A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */; }; FA0B7E521A95902C000E1D17 /* wrap_FrictionJoint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */; }; FA0B7E531A95902C000E1D17 /* wrap_FrictionJoint.h in Headers */ = {isa = PBXBuildFile; fileRef = FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */; }; @@ -676,8 +682,6 @@ FA18CF2B23DCF67900263725 /* spirv_cross_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0423DCF67800263725 /* spirv_cross_util.cpp */; }; FA18CF2C23DCF67900263725 /* spirv_cross.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0523DCF67800263725 /* spirv_cross.cpp */; }; FA18CF2D23DCF67900263725 /* spirv_cross.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0523DCF67800263725 /* spirv_cross.cpp */; }; - FA18CF2E23DCF67900263725 /* spirv_cross_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0623DCF67800263725 /* spirv_cross_c.cpp */; }; - FA18CF2F23DCF67900263725 /* spirv_cross_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0623DCF67800263725 /* spirv_cross_c.cpp */; }; FA18CF3023DCF67900263725 /* spirv_hlsl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0723DCF67800263725 /* spirv_hlsl.cpp */; }; FA18CF3123DCF67900263725 /* spirv_hlsl.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0723DCF67800263725 /* spirv_hlsl.cpp */; }; FA18CF3223DCF67900263725 /* spirv_cfg.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0823DCF67800263725 /* spirv_cfg.hpp */; }; @@ -685,8 +689,6 @@ FA18CF3423DCF67900263725 /* spirv_cpp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0923DCF67800263725 /* spirv_cpp.cpp */; }; FA18CF3523DCF67900263725 /* spirv_cross_parsed_ir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0A23DCF67800263725 /* spirv_cross_parsed_ir.cpp */; }; FA18CF3623DCF67900263725 /* spirv_cross_parsed_ir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA18CF0A23DCF67800263725 /* spirv_cross_parsed_ir.cpp */; }; - FA18CF3723DCF67900263725 /* spirv.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0B23DCF67800263725 /* spirv.h */; }; - FA18CF3823DCF67900263725 /* spirv_cross_c.h in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0C23DCF67800263725 /* spirv_cross_c.h */; }; FA18CF3923DCF67900263725 /* spirv_msl.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0D23DCF67800263725 /* spirv_msl.hpp */; }; FA18CF3A23DCF67900263725 /* spirv_reflect.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0E23DCF67800263725 /* spirv_reflect.hpp */; }; FA18CF3B23DCF67900263725 /* spirv_cross_util.hpp in Headers */ = {isa = PBXBuildFile; fileRef = FA18CF0F23DCF67800263725 /* spirv_cross_util.hpp */; }; @@ -1294,9 +1296,6 @@ FAF140BB1E20934C00F898D2 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140211E20934C00F898D2 /* ossource.cpp */; }; FAF140BC1E20934C00F898D2 /* ossource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF140211E20934C00F898D2 /* ossource.cpp */; }; FAF140C41E20934C00F898D2 /* ShaderLang.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF140291E20934C00F898D2 /* ShaderLang.h */; }; - FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; }; - FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */; }; - FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF1403C1E20934C00F898D2 /* InitializeDll.h */; }; FAF6C9DA23C2DE2900D7B5BC /* SPVRemapper.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF6C9C123C2DE2900D7B5BC /* SPVRemapper.h */; }; FAF6C9DB23C2DE2900D7B5BC /* SpvBuilder.h in Headers */ = {isa = PBXBuildFile; fileRef = FAF6C9C223C2DE2900D7B5BC /* SpvBuilder.h */; }; FAF6C9DC23C2DE2900D7B5BC /* SpvPostProcess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAF6C9C323C2DE2900D7B5BC /* SpvPostProcess.cpp */; }; @@ -1406,6 +1405,10 @@ 217DFBD51D9F6D490055D849 /* usocket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usocket.c; sourceTree = ""; }; 217DFBD61D9F6D490055D849 /* usocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usocket.h; sourceTree = ""; }; D923E7D2296B85B9002FF1B3 /* harfbuzz.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = harfbuzz.xcframework; path = ios/libraries/harfbuzz.xcframework; sourceTree = ""; }; + D943E58C2A24D56000D80361 /* PhysfsIo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PhysfsIo.cpp; sourceTree = ""; }; + D943E58D2A24D56000D80361 /* PhysfsIo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhysfsIo.h; sourceTree = ""; }; + D99081EC2BB2473900D2B0E4 /* JoystickSDL3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JoystickSDL3.h; sourceTree = ""; }; + D99081ED2BB2473900D2B0E4 /* JoystickSDL3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JoystickSDL3.cpp; sourceTree = ""; }; D9DAB9202961F0EE00C64820 /* HarfbuzzShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HarfbuzzShaper.h; sourceTree = ""; }; D9DAB9212961F0EE00C64820 /* HarfbuzzShaper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HarfbuzzShaper.cpp; sourceTree = ""; }; D9DAB9252961F0FF00C64820 /* GenericShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GenericShaper.h; sourceTree = ""; }; @@ -1413,8 +1416,14 @@ D9DAB9272961F0FF00C64820 /* TextShaper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextShaper.h; sourceTree = ""; }; D9DAB9282961F10000C64820 /* TextShaper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TextShaper.cpp; sourceTree = ""; }; D9DAB9312963CD7500C64820 /* harfbuzz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = harfbuzz.framework; path = macosx/Frameworks/harfbuzz.framework; sourceTree = ""; }; - D943E58C2A24D56000D80361 /* PhysfsIo.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PhysfsIo.cpp; sourceTree = ""; }; - D943E58D2A24D56000D80361 /* PhysfsIo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PhysfsIo.h; sourceTree = ""; }; + D9DB6E252B4B40660037A1F6 /* ResourceLimits.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResourceLimits.h; sourceTree = ""; }; + D9DB6E282B4B40970037A1F6 /* span.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = span.h; sourceTree = ""; }; + D9DB6E332B4B41100037A1F6 /* ResourceLimits.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ResourceLimits.cpp; sourceTree = ""; }; + D9DB6E382B4B41570037A1F6 /* NonSemanticDebugPrintf.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NonSemanticDebugPrintf.h; sourceTree = ""; }; + D9DB6E392B4B41570037A1F6 /* NonSemanticShaderDebugInfo100.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NonSemanticShaderDebugInfo100.h; sourceTree = ""; }; + D9DB6E3A2B4B41570037A1F6 /* GLSL.ext.ARM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLSL.ext.ARM.h; sourceTree = ""; }; + D9DB6E3B2B4B41580037A1F6 /* GLSL.ext.QCOM.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GLSL.ext.QCOM.h; sourceTree = ""; }; + D9DB6E442B4B80E80037A1F6 /* build_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = build_info.h; sourceTree = ""; }; FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = ""; }; FA0A3A5D23366CE9001C269E /* floattypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = floattypes.h; sourceTree = ""; }; FA0A3A5E23366CE9001C269E /* floattypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = floattypes.cpp; sourceTree = ""; }; @@ -1652,8 +1661,6 @@ FA0B7C281A95902C000E1D17 /* DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DistanceJoint.h; sourceTree = ""; }; FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EdgeShape.cpp; sourceTree = ""; }; FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EdgeShape.h; sourceTree = ""; }; - FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Fixture.cpp; sourceTree = ""; }; - FA0B7C2C1A95902C000E1D17 /* Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fixture.h; sourceTree = ""; }; FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrictionJoint.cpp; sourceTree = ""; }; FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FrictionJoint.h; sourceTree = ""; }; FA0B7C2F1A95902C000E1D17 /* GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GearJoint.cpp; sourceTree = ""; }; @@ -1696,8 +1703,6 @@ FA0B7C541A95902C000E1D17 /* wrap_DistanceJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_DistanceJoint.h; sourceTree = ""; }; FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_EdgeShape.cpp; sourceTree = ""; }; FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_EdgeShape.h; sourceTree = ""; }; - FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_Fixture.cpp; sourceTree = ""; }; - FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Fixture.h; sourceTree = ""; }; FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_FrictionJoint.cpp; sourceTree = ""; }; FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_FrictionJoint.h; sourceTree = ""; }; FA0B7C5B1A95902C000E1D17 /* wrap_GearJoint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = wrap_GearJoint.cpp; sourceTree = ""; }; @@ -1835,13 +1840,10 @@ FA18CF0323DCF67800263725 /* spirv_msl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_msl.cpp; sourceTree = ""; }; FA18CF0423DCF67800263725 /* spirv_cross_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cross_util.cpp; sourceTree = ""; }; FA18CF0523DCF67800263725 /* spirv_cross.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cross.cpp; sourceTree = ""; }; - FA18CF0623DCF67800263725 /* spirv_cross_c.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cross_c.cpp; sourceTree = ""; }; FA18CF0723DCF67800263725 /* spirv_hlsl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_hlsl.cpp; sourceTree = ""; }; FA18CF0823DCF67800263725 /* spirv_cfg.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_cfg.hpp; sourceTree = ""; }; FA18CF0923DCF67800263725 /* spirv_cpp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cpp.cpp; sourceTree = ""; }; FA18CF0A23DCF67800263725 /* spirv_cross_parsed_ir.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = spirv_cross_parsed_ir.cpp; sourceTree = ""; }; - FA18CF0B23DCF67800263725 /* spirv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv.h; sourceTree = ""; }; - FA18CF0C23DCF67800263725 /* spirv_cross_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spirv_cross_c.h; sourceTree = ""; }; FA18CF0D23DCF67800263725 /* spirv_msl.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_msl.hpp; sourceTree = ""; }; FA18CF0E23DCF67800263725 /* spirv_reflect.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_reflect.hpp; sourceTree = ""; }; FA18CF0F23DCF67800263725 /* spirv_cross_util.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = spirv_cross_util.hpp; sourceTree = ""; }; @@ -1955,8 +1957,6 @@ FA7DA04C1C16874A0056B200 /* wrap_Math.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_Math.lua; sourceTree = ""; }; FA7E9206277E120900C24CB2 /* theora.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = theora.xcframework; path = ios/libraries/theora.xcframework; sourceTree = ""; }; FA84DE5D2778D7DB002674C6 /* SpirvIntrinsics.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SpirvIntrinsics.h; sourceTree = ""; }; - FA84DE5E2778D7DC002674C6 /* glslang_c_interface.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glslang_c_interface.h; sourceTree = ""; }; - FA84DE5F2778D7DC002674C6 /* glslang_c_shader_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = glslang_c_shader_types.h; sourceTree = ""; }; FA84DE602778D7F3002674C6 /* SpirvIntrinsics.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpirvIntrinsics.cpp; sourceTree = ""; }; FA84DE6427791C36002674C6 /* GraphicsReadback.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsReadback.cpp; sourceTree = ""; }; FA84DE6527791C36002674C6 /* GraphicsReadback.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphicsReadback.h; sourceTree = ""; }; @@ -2209,7 +2209,6 @@ FADF543A1E3DAFF700012CC0 /* wrap_Graphics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wrap_Graphics.h; sourceTree = ""; }; FAE272501C05A15B00A67640 /* ParticleSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParticleSystem.cpp; sourceTree = ""; }; FAE272511C05A15B00A67640 /* ParticleSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParticleSystem.h; sourceTree = ""; }; - FAEC229F2534F25100EBD925 /* build_info.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = build_info.h; sourceTree = ""; }; FAECA1B01F3164700095D008 /* CompressedSlice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = CompressedSlice.cpp; sourceTree = ""; }; FAECA1B11F3164700095D008 /* CompressedSlice.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompressedSlice.h; sourceTree = ""; }; FAF13FC21E20934C00F898D2 /* CodeGen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CodeGen.cpp; sourceTree = ""; }; @@ -2271,8 +2270,6 @@ FAF140031E20934C00F898D2 /* osinclude.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = osinclude.h; sourceTree = ""; }; FAF140211E20934C00F898D2 /* ossource.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ossource.cpp; sourceTree = ""; }; FAF140291E20934C00F898D2 /* ShaderLang.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ShaderLang.h; sourceTree = ""; }; - FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InitializeDll.cpp; sourceTree = ""; }; - FAF1403C1E20934C00F898D2 /* InitializeDll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InitializeDll.h; sourceTree = ""; }; FAF1889C1E9DA834008C1479 /* Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optional.h; sourceTree = ""; }; FAF6C9C123C2DE2900D7B5BC /* SPVRemapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPVRemapper.h; sourceTree = ""; }; FAF6C9C223C2DE2900D7B5BC /* SpvBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SpvBuilder.h; sourceTree = ""; }; @@ -2381,6 +2378,14 @@ sourceTree = ""; usesTabs = 1; }; + D9DB6E312B4B41100037A1F6 /* ResourceLimits */ = { + isa = PBXGroup; + children = ( + D9DB6E332B4B41100037A1F6 /* ResourceLimits.cpp */, + ); + path = ResourceLimits; + sourceTree = ""; + }; FA08F5AC16C751BA00F007B5 /* Resources */ = { isa = PBXGroup; children = ( @@ -3047,6 +3052,8 @@ FA0B7BEE1A95902C000E1D17 /* Joystick.h */, FA0B7BEF1A95902C000E1D17 /* JoystickModule.cpp */, FA0B7BF01A95902C000E1D17 /* JoystickModule.h */, + D99081ED2BB2473900D2B0E4 /* JoystickSDL3.cpp */, + D99081EC2BB2473900D2B0E4 /* JoystickSDL3.h */, ); path = sdl; sourceTree = ""; @@ -3165,8 +3172,6 @@ FA0B7C281A95902C000E1D17 /* DistanceJoint.h */, FA0B7C291A95902C000E1D17 /* EdgeShape.cpp */, FA0B7C2A1A95902C000E1D17 /* EdgeShape.h */, - FA0B7C2B1A95902C000E1D17 /* Fixture.cpp */, - FA0B7C2C1A95902C000E1D17 /* Fixture.h */, FA0B7C2D1A95902C000E1D17 /* FrictionJoint.cpp */, FA0B7C2E1A95902C000E1D17 /* FrictionJoint.h */, FA0B7C2F1A95902C000E1D17 /* GearJoint.cpp */, @@ -3209,8 +3214,6 @@ FA0B7C541A95902C000E1D17 /* wrap_DistanceJoint.h */, FA0B7C551A95902C000E1D17 /* wrap_EdgeShape.cpp */, FA0B7C561A95902C000E1D17 /* wrap_EdgeShape.h */, - FA0B7C571A95902C000E1D17 /* wrap_Fixture.cpp */, - FA0B7C581A95902C000E1D17 /* wrap_Fixture.h */, FA0B7C591A95902C000E1D17 /* wrap_FrictionJoint.cpp */, FA0B7C5A1A95902C000E1D17 /* wrap_FrictionJoint.h */, FA0B7C5B1A95902C000E1D17 /* wrap_GearJoint.cpp */, @@ -3455,8 +3458,6 @@ FA18CF1423DCF67800263725 /* spirv_common.hpp */, FA18CF0923DCF67800263725 /* spirv_cpp.cpp */, FA18CF0023DCF67800263725 /* spirv_cpp.hpp */, - FA18CF0623DCF67800263725 /* spirv_cross_c.cpp */, - FA18CF0C23DCF67800263725 /* spirv_cross_c.h */, FA18CF1223DCF67800263725 /* spirv_cross_containers.hpp */, FA18CEF423DCF67800263725 /* spirv_cross_error_handling.hpp */, FA18CF0A23DCF67800263725 /* spirv_cross_parsed_ir.cpp */, @@ -3475,7 +3476,6 @@ FA18CEF223DCF67800263725 /* spirv_parser.hpp */, FA18CF0223DCF67800263725 /* spirv_reflect.cpp */, FA18CF0E23DCF67800263725 /* spirv_reflect.hpp */, - FA18CF0B23DCF67800263725 /* spirv.h */, FA18CEFE23DCF67800263725 /* spirv.hpp */, ); path = spirv_cross; @@ -3884,7 +3884,6 @@ isa = PBXGroup; children = ( FAF13FC01E20934C00F898D2 /* glslang */, - FAF1403A1E20934C00F898D2 /* OGLCompilersDLL */, FAF6C9C023C2DE2900D7B5BC /* SPIRV */, ); path = glslang; @@ -3893,12 +3892,13 @@ FAF13FC01E20934C00F898D2 /* glslang */ = { isa = PBXGroup; children = ( - FAEC229F2534F25100EBD925 /* build_info.h */, + D9DB6E442B4B80E80037A1F6 /* build_info.h */, FAF13FC11E20934C00F898D2 /* GenericCodeGen */, FAF13FC41E20934C00F898D2 /* Include */, FAF13FD21E20934C00F898D2 /* MachineIndependent */, FAF140021E20934C00F898D2 /* OSDependent */, FAF140281E20934C00F898D2 /* Public */, + D9DB6E312B4B41100037A1F6 /* ResourceLimits */, ); path = glslang; sourceTree = ""; @@ -3919,8 +3919,6 @@ FAF13FC61E20934C00F898D2 /* BaseTypes.h */, FAF13FC71E20934C00F898D2 /* Common.h */, FAF13FC81E20934C00F898D2 /* ConstantUnion.h */, - FA84DE5E2778D7DC002674C6 /* glslang_c_interface.h */, - FA84DE5F2778D7DC002674C6 /* glslang_c_shader_types.h */, FAF13FC91E20934C00F898D2 /* InfoSink.h */, FAF13FCA1E20934C00F898D2 /* InitializeGlobals.h */, FAF13FCB1E20934C00F898D2 /* intermediate.h */, @@ -3972,6 +3970,7 @@ FAF13FFB1E20934C00F898D2 /* Scan.h */, FAF13FFC1E20934C00F898D2 /* ScanContext.h */, FAF13FFD1E20934C00F898D2 /* ShaderLang.cpp */, + D9DB6E282B4B40970037A1F6 /* span.h */, FA84DE602778D7F3002674C6 /* SpirvIntrinsics.cpp */, FAF13FFE1E20934C00F898D2 /* SymbolTable.cpp */, FAF13FFF1E20934C00F898D2 /* SymbolTable.h */, @@ -4015,20 +4014,12 @@ FAF140281E20934C00F898D2 /* Public */ = { isa = PBXGroup; children = ( + D9DB6E252B4B40660037A1F6 /* ResourceLimits.h */, FAF140291E20934C00F898D2 /* ShaderLang.h */, ); path = Public; sourceTree = ""; }; - FAF1403A1E20934C00F898D2 /* OGLCompilersDLL */ = { - isa = PBXGroup; - children = ( - FAF1403B1E20934C00F898D2 /* InitializeDll.cpp */, - FAF1403C1E20934C00F898D2 /* InitializeDll.h */, - ); - path = OGLCompilersDLL; - sourceTree = ""; - }; FAF6C9C023C2DE2900D7B5BC /* SPIRV */ = { isa = PBXGroup; children = ( @@ -4038,9 +4029,11 @@ FAF6C9D823C2DE2900D7B5BC /* doc.cpp */, FAF6C9C823C2DE2900D7B5BC /* doc.h */, FAF6C9C723C2DE2900D7B5BC /* GLSL.ext.AMD.h */, + D9DB6E3A2B4B41570037A1F6 /* GLSL.ext.ARM.h */, FAF6C9CB23C2DE2900D7B5BC /* GLSL.ext.EXT.h */, FAF6C9CC23C2DE2900D7B5BC /* GLSL.ext.KHR.h */, FAF6C9CD23C2DE2900D7B5BC /* GLSL.ext.NV.h */, + D9DB6E3B2B4B41580037A1F6 /* GLSL.ext.QCOM.h */, FAF6C9D323C2DE2900D7B5BC /* GLSL.std.450.h */, FAF6C9CE23C2DE2900D7B5BC /* GlslangToSpv.cpp */, FAF6C9D223C2DE2900D7B5BC /* GlslangToSpv.h */, @@ -4048,6 +4041,8 @@ FAF6C9C623C2DE2900D7B5BC /* InReadableOrder.cpp */, FAF6C9D523C2DE2900D7B5BC /* Logger.cpp */, FAF6C9D723C2DE2900D7B5BC /* Logger.h */, + D9DB6E382B4B41570037A1F6 /* NonSemanticDebugPrintf.h */, + D9DB6E392B4B41570037A1F6 /* NonSemanticShaderDebugInfo100.h */, FAF6C9C923C2DE2900D7B5BC /* spirv.hpp */, FAF6C9CA23C2DE2900D7B5BC /* SpvBuilder.cpp */, FAF6C9C223C2DE2900D7B5BC /* SpvBuilder.h */, @@ -4105,6 +4100,7 @@ FAF6C9EF23C2DE2900D7B5BC /* disassemble.h in Headers */, FA18CF4123DCF67900263725 /* spirv_common.hpp in Headers */, FAC7CD901FE35E95006A60C7 /* physfs_miniz.h in Headers */, + D9DB6E3F2B4B41580037A1F6 /* NonSemanticShaderDebugInfo100.h in Headers */, FA0B791D1A958E3B000E1D17 /* b64.h in Headers */, FA0B7DC61A95902C000E1D17 /* wrap_JoystickModule.h in Headers */, FA0B7D201A95902C000E1D17 /* ImageRasterizer.h in Headers */, @@ -4123,6 +4119,7 @@ FAF140871E20934C00F898D2 /* parseVersions.h in Headers */, FA0B7AC61A958EA3000E1D17 /* types.h in Headers */, FA0B7DBD1A95902C000E1D17 /* Joystick.h in Headers */, + D9DB6E452B4B80E80037A1F6 /* build_info.h in Headers */, FA0B7D0E1A95902C000E1D17 /* wrap_Filesystem.h in Headers */, FA0B7EE41A95902D000E1D17 /* Window.h in Headers */, FA0B7CFC1A95902C000E1D17 /* Filesystem.h in Headers */, @@ -4155,7 +4152,6 @@ FAF140AB1E20934C00F898D2 /* SymbolTable.h in Headers */, FA18CF1E23DCF67900263725 /* external_interface.h in Headers */, FA0B7ED71A95902D000E1D17 /* Timer.h in Headers */, - FA18CF3723DCF67900263725 /* spirv.h in Headers */, FA0B7AC31A958EA3000E1D17 /* list.h in Headers */, FA0B7B2D1A958EA3000E1D17 /* core.h in Headers */, FA1E88841DF363DB00E808AA /* Filter.h in Headers */, @@ -4221,6 +4217,7 @@ FABDA9BE2552448300B5C523 /* Box2D.h in Headers */, D9DAB9222961F0EE00C64820 /* HarfbuzzShaper.h in Headers */, FA56AA3A1FAFF02000A43D5F /* memory.h in Headers */, + D99081EE2BB2473900D2B0E4 /* JoystickSDL3.h in Headers */, FA0B7E441A95902C000E1D17 /* wrap_CircleShape.h in Headers */, FA0B7EB41A95902C000E1D17 /* System.h in Headers */, FAF1405A1E20934C00F898D2 /* ConstantUnion.h in Headers */, @@ -4272,7 +4269,6 @@ FAFEB29B28F210550025D7D0 /* unixdgram.h in Headers */, FA0B7E051A95902C000E1D17 /* Contact.h in Headers */, FA4F2BE41DE6650600CA37D7 /* Transform.h in Headers */, - FA0B7E0E1A95902C000E1D17 /* Fixture.h in Headers */, FA6A2B661F5F7B6B0074C308 /* wrap_Data.h in Headers */, FA18CEE423DBC6E000263725 /* Graphics.h in Headers */, 217DFBE81D9F6D490055D849 /* inet.h in Headers */, @@ -4312,12 +4308,14 @@ FA0B7AC81A958EA3000E1D17 /* utility.h in Headers */, FABDA9BA2552448300B5C523 /* b2_weld_joint.h in Headers */, FA522D5323F9FF2A0059EE3C /* dr_mp3.h in Headers */, + D9DB6E272B4B40660037A1F6 /* ResourceLimits.h in Headers */, FA0B791F1A958E3B000E1D17 /* Data.h in Headers */, FA18CF4523DD1A8100263725 /* ShaderStage.h in Headers */, 217DFBE41D9F6D490055D849 /* headers.lua.h in Headers */, FA0B7D021A95902C000E1D17 /* Filesystem.h in Headers */, FA0B7E471A95902C000E1D17 /* wrap_Contact.h in Headers */, FA0B7E021A95902C000E1D17 /* CircleShape.h in Headers */, + D9DB6E3E2B4B41580037A1F6 /* NonSemanticDebugPrintf.h in Headers */, FABDA9E92552448300B5C523 /* b2_timer.h in Headers */, FA0B7E111A95902C000E1D17 /* FrictionJoint.h in Headers */, FA0B7AE01A958EA3000E1D17 /* lodepng.h in Headers */, @@ -4377,6 +4375,7 @@ FA0B7DC31A95902C000E1D17 /* wrap_Joystick.h in Headers */, FA18CF3B23DCF67900263725 /* spirv_cross_util.hpp in Headers */, FAF140631E20934C00F898D2 /* Types.h in Headers */, + D9DB6E292B4B40970037A1F6 /* span.h in Headers */, FACA06AF293EE5CD001A2557 /* Sensor.h in Headers */, FA4F2BE61DE6650600CA37D7 /* wrap_Transform.h in Headers */, FA0B7EE71A95902D000E1D17 /* Window.h in Headers */, @@ -4393,12 +4392,10 @@ FABDA9DD2552448300B5C523 /* b2_contact.h in Headers */, FABDA9802552448200B5C523 /* b2_circle_contact.h in Headers */, 217DFC101D9F6D490055D849 /* url.lua.h in Headers */, - FAF140DD1E20934C00F898D2 /* InitializeDll.h in Headers */, FA0B7DF31A95902C000E1D17 /* wrap_Cursor.h in Headers */, FA18CF2023DCF67900263725 /* spirv_hlsl.hpp in Headers */, FA0B7D271A95902C000E1D17 /* wrap_Font.h in Headers */, FA0B7DAA1A95902C000E1D17 /* PVRHandler.h in Headers */, - FA18CF3823DCF67900263725 /* spirv_cross_c.h in Headers */, FA27B3B51B498151008A9DCE /* wrap_Video.h in Headers */, FABDA9BC2552448300B5C523 /* b2_fixture.h in Headers */, FA0B7D7B1A95902C000E1D17 /* Quad.h in Headers */, @@ -4452,6 +4449,7 @@ 217DFC021D9F6D490055D849 /* tcp.h in Headers */, FA3C5E441F8C368C0003C579 /* ShaderStage.h in Headers */, FA0B79261A958E3B000E1D17 /* Exception.h in Headers */, + D9DB6E402B4B41580037A1F6 /* GLSL.ext.ARM.h in Headers */, FA0B7D4D1A95902C000E1D17 /* Shader.h in Headers */, FA0B793D1A958E3B000E1D17 /* runtime.h in Headers */, FAF6C9E323C2DE2900D7B5BC /* GLSL.ext.AMD.h in Headers */, @@ -4467,7 +4465,6 @@ FA4F2B7A1DE0125B00CA37D7 /* xxhash.h in Headers */, FA0B7DDE1A95902C000E1D17 /* wrap_BezierCurve.h in Headers */, FA0B7DED1A95902C000E1D17 /* Cursor.h in Headers */, - FA0B7E501A95902C000E1D17 /* wrap_Fixture.h in Headers */, FA28EBD71E352DB5003446F4 /* FenceSync.h in Headers */, FADF542C1E3DAADA00012CC0 /* wrap_Mesh.h in Headers */, FAA3A9B01B7D465A00CED060 /* android.h in Headers */, @@ -4479,6 +4476,7 @@ FA6BDF90281219E900240F2A /* DataStream.h in Headers */, FAF6C9DB23C2DE2900D7B5BC /* SpvBuilder.h in Headers */, FA0B7EA21A95902C000E1D17 /* Sound.h in Headers */, + D9DB6E412B4B41580037A1F6 /* GLSL.ext.QCOM.h in Headers */, FA0B7B331A958EA3000E1D17 /* wuff_config.h in Headers */, FA0B7D3B1A95902C000E1D17 /* Graphics.h in Headers */, FA0B7E6E1A95902C000E1D17 /* wrap_RevoluteJoint.h in Headers */, @@ -4652,6 +4650,7 @@ FAF140A81E20934C00F898D2 /* ShaderLang.cpp in Sources */, FA1BA09E1E16CFCE00AA2803 /* Font.cpp in Sources */, FABDA9A12552448300B5C523 /* b2_gear_joint.cpp in Sources */, + D9DB6E372B4B41100037A1F6 /* ResourceLimits.cpp in Sources */, FAE64A8A2071363100BC7981 /* physfs_archiver_wad.c in Sources */, FA18CF4723DD1A8100263725 /* ShaderStage.mm in Sources */, FA0B7ECC1A95902C000E1D17 /* wrap_Channel.cpp in Sources */, @@ -4707,7 +4706,6 @@ FA3C5E431F8C368C0003C579 /* ShaderStage.cpp in Sources */, FA0B7E191A95902C000E1D17 /* MotorJoint.cpp in Sources */, FAF1406F1E20934C00F898D2 /* Initialize.cpp in Sources */, - FA0B7E4F1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */, FA0B7EBF1A95902C000E1D17 /* Thread.cpp in Sources */, FACA02F91F5E39790084B28F /* Compressor.cpp in Sources */, FABDAA002552448300B5C523 /* b2_time_of_impact.cpp in Sources */, @@ -4725,7 +4723,6 @@ FA4F2C111DE936FE00CA37D7 /* unix.c in Sources */, FA1BA0A31E16D97500AA2803 /* wrap_Font.cpp in Sources */, FABDA9842552448200B5C523 /* b2_chain_polygon_contact.cpp in Sources */, - FA0B7E0D1A95902C000E1D17 /* Fixture.cpp in Sources */, FADF53FE1E3D74F200012CC0 /* TextBatch.cpp in Sources */, FA0B7D191A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */, FAC271E723B5B5B400C200D3 /* renderstate.cpp in Sources */, @@ -4746,6 +4743,7 @@ FA0B7CE61A95902C000E1D17 /* wrap_Source.cpp in Sources */, FA9D8DDE1DEF842A002CD881 /* Drawable.cpp in Sources */, FA0B7CCE1A95902C000E1D17 /* Audio.cpp in Sources */, + D99081F02BB2473900D2B0E4 /* JoystickSDL3.cpp in Sources */, FADF54031E3D77B500012CC0 /* wrap_TextBatch.cpp in Sources */, FA0B7DCB1A95902C000E1D17 /* Keyboard.cpp in Sources */, FA0B7DFB1A95902C000E1D17 /* Body.cpp in Sources */, @@ -4764,7 +4762,6 @@ FAF140AD1E20934C00F898D2 /* Versions.cpp in Sources */, FA0B793C1A958E3B000E1D17 /* runtime.cpp in Sources */, FA6BDF8A280B62A000240F2A /* GraphicsReadback.mm in Sources */, - FAF140DC1E20934C00F898D2 /* InitializeDll.cpp in Sources */, FA0B7DBC1A95902C000E1D17 /* Joystick.cpp in Sources */, FA0B7DAF1A95902C000E1D17 /* wrap_CompressedImageData.cpp in Sources */, FA0B7AD51A958EA3000E1D17 /* unix.c in Sources */, @@ -5015,7 +5012,6 @@ FACA02F81F5E39760084B28F /* CompressedData.cpp in Sources */, FA0B7ADA1A958EA3000E1D17 /* glad.cpp in Sources */, FAF140541E20934C00F898D2 /* CodeGen.cpp in Sources */, - FA18CF2F23DCF67900263725 /* spirv_cross_c.cpp in Sources */, FA0B7E1F1A95902C000E1D17 /* Physics.cpp in Sources */, FA6A2B7B1F60B8250074C308 /* wrap_ByteData.cpp in Sources */, FA0B7E821A95902C000E1D17 /* Shape.cpp in Sources */, @@ -5083,6 +5079,7 @@ FA0B7D7C1A95902C000E1D17 /* Texture.cpp in Sources */, FAF140BB1E20934C00F898D2 /* ossource.cpp in Sources */, FA0B7ECB1A95902C000E1D17 /* wrap_Channel.cpp in Sources */, + D9DB6E362B4B41100037A1F6 /* ResourceLimits.cpp in Sources */, FACA02F21F5E396B0084B28F /* HashFunction.cpp in Sources */, FABDA9A02552448300B5C523 /* b2_gear_joint.cpp in Sources */, FAF140A71E20934C00F898D2 /* ShaderLang.cpp in Sources */, @@ -5140,7 +5137,6 @@ FAF140971E20934C00F898D2 /* PpTokens.cpp in Sources */, FAF140A91E20934C00F898D2 /* SymbolTable.cpp in Sources */, FA0B7E181A95902C000E1D17 /* MotorJoint.cpp in Sources */, - FA0B7E4E1A95902C000E1D17 /* wrap_Fixture.cpp in Sources */, FA18CEC523D3AE6700263725 /* wrap_Buffer.cpp in Sources */, FAF6C9F423C2DE2900D7B5BC /* Logger.cpp in Sources */, FABDA9FF2552448300B5C523 /* b2_time_of_impact.cpp in Sources */, @@ -5159,7 +5155,6 @@ FABDA9832552448200B5C523 /* b2_chain_polygon_contact.cpp in Sources */, FA0B7AD61A958EA3000E1D17 /* win32.c in Sources */, FADF54341E3DAE6E00012CC0 /* wrap_SpriteBatch.cpp in Sources */, - FA0B7E0C1A95902C000E1D17 /* Fixture.cpp in Sources */, FA0B7D181A95902C000E1D17 /* TrueTypeRasterizer.cpp in Sources */, FA84DE6627791C36002674C6 /* GraphicsReadback.cpp in Sources */, FA0B7CFA1A95902C000E1D17 /* Filesystem.cpp in Sources */, @@ -5177,6 +5172,7 @@ FA0B7E421A95902C000E1D17 /* wrap_CircleShape.cpp in Sources */, FA0B7CE51A95902C000E1D17 /* wrap_Source.cpp in Sources */, FAC7CD921FE35E95006A60C7 /* physfs_archiver_hog.c in Sources */, + D99081EF2BB2473900D2B0E4 /* JoystickSDL3.cpp in Sources */, FAF140931E20934C00F898D2 /* PpScanner.cpp in Sources */, FA9D53AC1F5307E900125C6B /* Deprecations.cpp in Sources */, FA0B7CCD1A95902C000E1D17 /* Audio.cpp in Sources */, @@ -5206,7 +5202,6 @@ FAC7CD811FE35E95006A60C7 /* physfs_platform_os2.c in Sources */, FABDA9962552448300B5C523 /* b2_distance_joint.cpp in Sources */, FA0B7DBB1A95902C000E1D17 /* Joystick.cpp in Sources */, - FAF140DB1E20934C00F898D2 /* InitializeDll.cpp in Sources */, FA0B7DAE1A95902C000E1D17 /* wrap_CompressedImageData.cpp in Sources */, FA6A2B701F5F845F0074C308 /* wrap_DataView.cpp in Sources */, FAB17BE61ABFAA9000F9BA27 /* lz4.c in Sources */, @@ -5304,7 +5299,6 @@ FA0B7E301A95902C000E1D17 /* Shape.cpp in Sources */, FA93C4541F315B960087CCD4 /* FormatHandler.cpp in Sources */, FA0B7E481A95902C000E1D17 /* wrap_DistanceJoint.cpp in Sources */, - FA18CF2E23DCF67900263725 /* spirv_cross_c.cpp in Sources */, FABDA9A72552448300B5C523 /* b2_motor_joint.cpp in Sources */, FA0B792F1A958E3B000E1D17 /* Module.cpp in Sources */, FA0B7E2A1A95902C000E1D17 /* RevoluteJoint.cpp in Sources */, @@ -5529,9 +5523,9 @@ "\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LIBRARY_SEARCH_PATHS = ""; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = NO; SDKROOT = macosx; USE_HEADERMAP = NO; @@ -5595,9 +5589,9 @@ "\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LIBRARY_SEARCH_PATHS = ""; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; USE_HEADERMAP = NO; @@ -5733,10 +5727,10 @@ "\"$(SRCROOT)/../../src/modules\"", "\"$(SRCROOT)/../../src/libraries/enet/libenet/include\"", ); - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LIBRARY_SEARCH_PATHS = ""; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = NO; SDKROOT = macosx; USE_HEADERMAP = NO; diff --git a/platform/xcode/love.xcodeproj/project.pbxproj b/platform/xcode/love.xcodeproj/project.pbxproj index 0d7b4911a..428cf2f60 100644 --- a/platform/xcode/love.xcodeproj/project.pbxproj +++ b/platform/xcode/love.xcodeproj/project.pbxproj @@ -562,9 +562,9 @@ "\"$(SRCROOT)/../../src/modules\"", ); INFOPLIST_FILE = "love-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = love; SDKROOT = macosx; @@ -637,10 +637,10 @@ "\"$(SRCROOT)/../../src/modules\"", ); INFOPLIST_FILE = "love-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = love; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; @@ -871,10 +871,10 @@ "\"$(SRCROOT)/../../src/modules\"", ); INFOPLIST_FILE = "love-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks"; LLVM_LTO = YES; - MACOSX_DEPLOYMENT_TARGET = 10.9; + MACOSX_DEPLOYMENT_TARGET = 10.15; ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = love; SCAN_ALL_SOURCE_FILES_FOR_INCLUDES = YES; diff --git a/platform/xcode/macosx/love-macosx.plist b/platform/xcode/macosx/love-macosx.plist index 197188f38..e11e7e3dd 100644 --- a/platform/xcode/macosx/love-macosx.plist +++ b/platform/xcode/macosx/love-macosx.plist @@ -70,7 +70,7 @@ NSHighResolutionCapable NSHumanReadableCopyright - © 2006-2023 LÖVE Development Team + © 2006-2024 LÖVE Development Team NSPrincipalClass NSApplication NSSupportsAutomaticGraphicsSwitching diff --git a/readme.md b/readme.md index 81b9f5ad2..5e15b180f 100644 --- a/readme.md +++ b/readme.md @@ -11,12 +11,13 @@ If you need further help, feel free to ask on our [forums][forums], our [Discord Repository ---------- -We use the 'main' branch for patch development of the current major release, and therefore it should not be considered stable. -There may also be a branch for the next major version in development, which is named after that version. +We use the 'main' branch for development of the next major release, and therefore it should not be considered stable. + +There are also branches for currently released major versions, which may have fixes and changes meant for upcoming patch releases within that major version. We tag all our releases (since we started using mercurial and git), and have binary downloads available for them. -Experimental changes are developed in a separate [love-experiments][love-experiments] repository. +Experimental changes are sometimes developed in a separate [love-experiments][love-experiments] repository. Builds ------ @@ -29,6 +30,15 @@ There are also unstable/nightly builds: - For ubuntu linux they are in [ppa:bartbes/love-unstable][unstableppa] - For arch linux there's [love-git][aur] in the AUR. +Test Suite +---------- + +The test suite in `testing/` covers all the LÖVE APIs, and tests them the same way developers use them. You can view current test coverage from any [action][workflows]. +You can run the suite locally like you would run a normal LÖVE project, e.g.: +`love testing` + +See the [readme][testsuite] in the testing folder for more info. + Contributing ------------ @@ -44,13 +54,13 @@ Compilation Follow the instructions at the [megasource][megasource] repository page. ### *nix -Run `platform/unix/automagic` from the repository root, then run ./configure and make. +Because in-tree builds are not allowed, the Makefiles needs to be generated in a separate build directory. In this example, folder named `build` is used: - $ platform/unix/automagic - $ ./configure - $ make + $ cmake -B build -S. --install-prefix $PWD/prefix # this will create the directory `build/`. + $ cmake --build build --target install -j$(nproc) # this will build with all cores and put the files in `prefix/`. -When using a source release, automagic has already been run, and the first step can be skipped. +> [!NOTE] +> CMake 3.15 and earlier doesn't support `--install-prefix`. In that case, use `-DCMAKE_INSTALL_PREFIX=` instead. ### macOS Download or clone [this repository][dependencies-apple] and copy, move, or symlink the `macOS/Frameworks` subfolder into love's `platform/xcode/macosx` folder. @@ -60,7 +70,6 @@ Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the ### iOS Building for iOS requires macOS and Xcode. -#### LÖVE 11.4 and newer Download the `love-apple-dependencies` zip file corresponding to the LÖVE version being used from the [Releases page][dependencies-ios], unzip it, and place the `iOS/libraries` subfolder into love's `platform/xcode/ios` folder. @@ -70,14 +79,6 @@ Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the See `readme-iOS.rtf` for more information. -#### LÖVE 11.3 and older -Download the `ios-libraries` zip file corresponding to the LÖVE version being used from the [Releases page][dependencies-ios], -unzip it, and place the `include` and `libraries` subfolders into love's `platform/xcode/ios` folder. - -Then use the Xcode project found at `platform/xcode/love.xcodeproj` to build the `love-ios` target. - -See `readme-iOS.rtf` for more information. - ### Android Visit the [Android build repository][android-repository] for build instructions. @@ -107,3 +108,5 @@ Dependencies [codestyle]: https://love2d.org/wiki/Code_Style [android-repository]: https://github.com/love2d/love-android [releases]: https://github.com/love2d/love/releases +[testsuite]: https://github.com/love2d/love/tree/main/testing +[workflows]: https://github.com/love2d/love/actions/workflows/main.yml?query=branch%3Amain diff --git a/src/common/Color.h b/src/common/Color.h index dcd4f3c0e..1518553d7 100644 --- a/src/common/Color.h +++ b/src/common/Color.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Data.cpp b/src/common/Data.cpp index 8b31599f4..d3f7bdd6d 100644 --- a/src/common/Data.cpp +++ b/src/common/Data.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -20,10 +20,27 @@ // LOVE #include "Data.h" +#include "thread/threads.h" namespace love { love::Type Data::type("Data", &Object::type); +Data::~Data() +{ + delete mutex; +} + +static void createMutex(love::thread::Mutex **mutexAddress) +{ + *mutexAddress = love::thread::newMutex(); +} + +love::thread::Mutex *Data::getMutex() +{ + std::call_once(mutexCreated, createMutex, &mutex); + return mutex; +} + } // love diff --git a/src/common/Data.h b/src/common/Data.h index 57ffa4b14..bb19b66cb 100644 --- a/src/common/Data.h +++ b/src/common/Data.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -22,15 +22,20 @@ #define LOVE_DATA_H // LOVE -#include "config.h" #include "Object.h" // C #include +#include namespace love { +namespace thread +{ +class Mutex; +} + /** * This class is a simple abstraction over all objects which contain data. **/ @@ -40,10 +45,8 @@ public: static love::Type type; - /** - * Destructor. - **/ - virtual ~Data() {} + Data() {}; + virtual ~Data(); /** * Creates a duplicate of Data derived class instance. @@ -60,6 +63,17 @@ public: **/ virtual size_t getSize() const = 0; + /** + * Gets the Mutex associated with this Data object. Creates it in a thread- + * safe manner if necessary. + **/ + love::thread::Mutex *getMutex(); + +private: + + love::thread::Mutex *mutex = nullptr; + std::once_flag mutexCreated; + }; // Data } // love diff --git a/src/common/EnumMap.h b/src/common/EnumMap.h index 118cf389d..4a1bdd3d0 100644 --- a/src/common/EnumMap.h +++ b/src/common/EnumMap.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Exception.cpp b/src/common/Exception.cpp index eb240e381..f605d08da 100644 --- a/src/common/Exception.cpp +++ b/src/common/Exception.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Exception.h b/src/common/Exception.h index d42c5d180..28942d069 100644 --- a/src/common/Exception.h +++ b/src/common/Exception.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Matrix.cpp b/src/common/Matrix.cpp index e4f57a3d9..fa5e95757 100644 --- a/src/common/Matrix.cpp +++ b/src/common/Matrix.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Matrix.h b/src/common/Matrix.h index 4c7fe5d39..83b607839 100644 --- a/src/common/Matrix.h +++ b/src/common/Matrix.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Module.cpp b/src/common/Module.cpp index f82aad662..6c168df1e 100644 --- a/src/common/Module.cpp +++ b/src/common/Module.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -62,9 +62,12 @@ namespace love love::Type Module::type("Module", &Object::type); Module *Module::instances[] = {}; -Module::Module() +Module::Module(Module::ModuleType moduleType, const char *name) + : moduleType(moduleType) + , name(name) { initDeprecation(); + registerInstance(this); } Module::~Module() diff --git a/src/common/Module.h b/src/common/Module.h index 603c0e0c2..77e95d565 100644 --- a/src/common/Module.h +++ b/src/common/Module.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -62,13 +62,13 @@ public: M_MAX_ENUM }; - Module(); + Module(ModuleType moduleType, const char *name); virtual ~Module(); /** * Gets the base type of the module. **/ - virtual ModuleType getModuleType() const = 0; + ModuleType getModuleType() const { return moduleType; } /** * Gets the name of the module. This is used in case of errors @@ -76,14 +76,7 @@ public: * * @return The full name of the module, eg. love.graphics.opengl. **/ - virtual const char *getName() const = 0; - - /** - * Add module to internal registry. To be used /only/ in - * runtime.cpp:luax_register_module() - * @param instance The module instance. - */ - static void registerInstance(Module *instance); + const char *getName() const { return name.c_str(); } /** * Retrieve module instance from internal registry. May return NULL @@ -106,6 +99,11 @@ public: private: + static void registerInstance(Module *instance); + + ModuleType moduleType; + std::string name; + static Module *instances[M_MAX_ENUM]; }; // Module diff --git a/src/common/Object.cpp b/src/common/Object.cpp index 8d2bc4027..a8bb7fe85 100644 --- a/src/common/Object.cpp +++ b/src/common/Object.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Object.h b/src/common/Object.h index 805f5c0b6..36b8f7a8c 100644 --- a/src/common/Object.h +++ b/src/common/Object.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Optional.h b/src/common/Optional.h index fe3b4b2ef..5a3c347b0 100644 --- a/src/common/Optional.h +++ b/src/common/Optional.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,7 +46,7 @@ struct Optional hasValue = true; } - T get(T defaultVal) + T get(T defaultVal) const { return hasValue ? value : defaultVal; } diff --git a/src/common/Range.h b/src/common/Range.h index 4a2b27a0d..14e274f59 100644 --- a/src/common/Range.h +++ b/src/common/Range.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -61,7 +61,7 @@ struct Range return first <= other.first && last >= other.last; } - bool intersects(const Range &other) + bool intersects(const Range &other) const { return !(first > other.last || last < other.first); } diff --git a/src/common/Reference.cpp b/src/common/Reference.cpp index 54e42e67f..37e6113d6 100644 --- a/src/common/Reference.cpp +++ b/src/common/Reference.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Reference.h b/src/common/Reference.h index 512ba9a51..28d218b90 100644 --- a/src/common/Reference.h +++ b/src/common/Reference.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Stream.cpp b/src/common/Stream.cpp index deffefe93..00b4ab005 100644 --- a/src/common/Stream.cpp +++ b/src/common/Stream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Stream.h b/src/common/Stream.h index 6b75be7c1..6e4b36553 100644 --- a/src/common/Stream.h +++ b/src/common/Stream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/StringMap.cpp b/src/common/StringMap.cpp index 0c018bf40..4d6169e1e 100644 --- a/src/common/StringMap.cpp +++ b/src/common/StringMap.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/StringMap.h b/src/common/StringMap.h index 49c1a06ac..1260249f2 100644 --- a/src/common/StringMap.h +++ b/src/common/StringMap.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Variant.cpp b/src/common/Variant.cpp index e75f765b1..8684b9c48 100644 --- a/src/common/Variant.cpp +++ b/src/common/Variant.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Variant.h b/src/common/Variant.h index 45e9fd6b2..e2c274515 100644 --- a/src/common/Variant.h +++ b/src/common/Variant.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Vector.cpp b/src/common/Vector.cpp index 1870b6a58..890528123 100644 --- a/src/common/Vector.cpp +++ b/src/common/Vector.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/Vector.h b/src/common/Vector.h index d0821679b..e74ad2441 100644 --- a/src/common/Vector.h +++ b/src/common/Vector.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/android.cpp b/src/common/android.cpp index 12a669b55..369258480 100644 --- a/src/common/android.cpp +++ b/src/common/android.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ #ifdef LOVE_ANDROID #include +#include #include #include @@ -121,19 +122,7 @@ bool getSafeArea(int &top, int &left, int &bottom, int &right) bool openURL(const std::string &url) { - JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); - jobject activity = (jobject) SDL_AndroidGetActivity(); - jclass clazz = env->GetObjectClass(activity); - - static jmethodID openURL = env->GetMethodID(clazz, "openURLFromLOVE", "(Ljava/lang/String;)Z"); - - jstring jstringURL = env->NewStringUTF(url.c_str()); - jboolean result = env->CallBooleanMethod(clazz, openURL, jstringURL); - - env->DeleteLocalRef(jstringURL); - env->DeleteLocalRef(clazz); - env->DeleteLocalRef(activity); - return (bool) result; + return SDL_OpenURL(url.c_str()) == 0; } void vibrate(double seconds) @@ -174,31 +163,100 @@ bool directoryExists(const char *path) bool mkdir(const char *path) { - int err = ::mkdir(path, 0770); + int err = ::mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); if (err == -1) { - SDL_Log("Error: Could not create directory %s", path); + const char *error = strerror(errno); + SDL_Log("Error: Could not create directory '%s': %s", path, error); return false; } return true; } +bool chmod(const char *path, int mode) +{ + int err = ::chmod(path, mode); + if (err == -1) + { + const char *error = strerror(errno); + SDL_Log("Error: Could not change mode '%s': %s", path, error); + return false; + } + + return true; +} + +inline bool tryCreateDirectory(const char *path) +{ + SDL_Log("Trying to create directory '%s'", path); + + if (directoryExists(path)) + return true; + else if (mkdir(path)) + return true; + return false; +} + bool createStorageDirectories() { - std::string internal_storage_path = SDL_AndroidGetInternalStoragePath(); + std::string internalStoragePath = SDL_AndroidGetInternalStoragePath(); + std::string externalStoragePath = SDL_AndroidGetExternalStoragePath(); - std::string save_directory = internal_storage_path + "/save"; - if (!directoryExists(save_directory.c_str()) && !mkdir(save_directory.c_str())) + std::string saveDirectoryInternal = internalStoragePath + "/save"; + if (!tryCreateDirectory(saveDirectoryInternal.c_str())) return false; - std::string game_directory = internal_storage_path + "/game"; - if (!directoryExists (game_directory.c_str()) && !mkdir(game_directory.c_str())) + std::string saveDirectoryExternal = externalStoragePath + "/save"; + if (!tryCreateDirectory(saveDirectoryExternal.c_str())) + return false; + + std::string game_directory = externalStoragePath + "/game"; + if (!tryCreateDirectory (game_directory.c_str())) return false; return true; } +void fixupPermissionSingleFile(const std::string &savedir, const std::string &path, int mode) +{ + std::string fixedSavedir = savedir.back() == '/' ? savedir : (savedir + "/"); + std::string target = fixedSavedir + path; + ::chmod(target.c_str(), mode); +} + +void fixupExternalStoragePermission(const std::string &savedir, const std::string &path) +{ + std::set pathsToFix; + size_t start = 0; + + while (true) + { + size_t pos = path.find('/', start); + if (pos == std::string::npos) + { + pathsToFix.insert(path); + break; + } + + pathsToFix.insert(path.substr(0, pos)); + start = pos + 1; + } + + std::string fixedSavedir = savedir.back() == '/' ? savedir : (savedir + "/"); + chmod(savedir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); + + for (const std::string &dir: pathsToFix) + { + const char *realPath = PHYSFS_getRealDir(dir.c_str()); + if (!dir.empty() && strcmp(realPath, savedir.c_str()) == 0) + { + std::string target = fixedSavedir + dir; + chmod(target.c_str(), S_IRWXU | S_IRWXG | S_IRWXO | S_ISGID); + } + } +} + bool hasBackgroundMusic() { JNIEnv *env = (JNIEnv*) SDL_AndroidGetJNIEnv(); @@ -385,18 +443,20 @@ struct AssetInfo: public love::filesystem::physfs::PhysfsIo return 1; } - AssetInfo *duplicate() const + AssetInfo(const AssetInfo &other) + : assetManager(other.assetManager) + , size(strlen(other.filename) + 1) { - AAsset *newAsset = AAssetManager_open(assetManager, filename, AASSET_MODE_RANDOM); + asset = AAssetManager_open(assetManager, other.filename, AASSET_MODE_RANDOM); - if (newAsset == nullptr) + if (asset == nullptr) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return nullptr; + throw new love::Exception("Unable to duplicate AssetInfo"); } - AAsset_seek64(asset, tell(), SEEK_SET); - return fromAAsset(assetManager, filename, asset); + filename = new (std::nothrow) char[size]; + memcpy(filename, other.filename, size); } ~AssetInfo() override @@ -867,10 +927,9 @@ void *getIOFromFD(int fd) const char *getArg0() { - static PHYSFS_AndroidInit androidInit = { - SDL_AndroidGetJNIEnv(), - SDL_AndroidGetActivity() - }; + static PHYSFS_AndroidInit androidInit = {nullptr, nullptr}; + androidInit.jnienv = SDL_AndroidGetJNIEnv(); + androidInit.context = SDL_AndroidGetActivity(); return (const char *) &androidInit; } diff --git a/src/common/android.h b/src/common/android.h index db7fd5fe2..606327f29 100644 --- a/src/common/android.h +++ b/src/common/android.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -65,6 +65,10 @@ bool mkdir(const char *path); bool createStorageDirectories(); +void fixupPermissionSingleFile(const std::string &savedir, const std::string &path, int mode = 0666); + +void fixupExternalStoragePermission(const std::string &savedir, const std::string &path); + bool hasBackgroundMusic(); bool hasRecordingPermission(); diff --git a/src/common/apple.h b/src/common/apple.h index c41681c39..5855a9636 100644 --- a/src/common/apple.h +++ b/src/common/apple.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/apple.mm b/src/common/apple.mm index 7025085ee..0d0dd0444 100644 --- a/src/common/apple.mm +++ b/src/common/apple.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/b64.cpp b/src/common/b64.cpp index ff196cd88..57ce775b1 100644 --- a/src/common/b64.cpp +++ b/src/common/b64.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/b64.h b/src/common/b64.h index a748a0de5..471650de5 100644 --- a/src/common/b64.h +++ b/src/common/b64.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/config.h b/src/common/config.h index 3a50dbcd1..11ede38c9 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -102,7 +102,7 @@ #endif // DLL-stuff. -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(__MINGW32__) # define LOVE_EXPORT __declspec(dllexport) #elif defined(__GNUC__) || defined(__clang__) # define LOVE_EXPORT __attribute__((visibility("default"))) @@ -114,8 +114,10 @@ #ifndef LOVE_WINDOWS_UWP # define LOVE_LEGENDARY_CONSOLE_IO_HACK #endif // LOVE_WINDOWS_UWP +#ifndef __MINGW32__ # define NOMINMAX #endif +#endif #if defined(LOVE_MACOS) || defined(LOVE_IOS) # define LOVE_LEGENDARY_APP_ARGV_HACK diff --git a/src/common/delay.cpp b/src/common/delay.cpp index 06902f73d..e6b0c43a4 100644 --- a/src/common/delay.cpp +++ b/src/common/delay.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,15 +21,21 @@ #include "delay.h" #include +#include namespace love { -void sleep(unsigned int ms) +// TODO: use ns. +void sleep(double ms) { // We don't need to initialize the SDL timer subsystem for SDL_Delay to // function - and doing so causes SDL to create a worker thread. - SDL_Delay(ms); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DelayNS(SDL_MS_TO_NS(ms)); +#else + SDL_Delay((Uint32)ms); +#endif } } // love diff --git a/src/common/delay.h b/src/common/delay.h index 04105cabf..1f8122e8d 100644 --- a/src/common/delay.h +++ b/src/common/delay.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,7 +24,7 @@ namespace love { -void sleep(unsigned int ms); +void sleep(double ms); } // namespace love diff --git a/src/common/deprecation.cpp b/src/common/deprecation.cpp index f0b0cae72..e68e1a27d 100644 --- a/src/common/deprecation.cpp +++ b/src/common/deprecation.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -107,8 +107,12 @@ std::string getDeprecationNotice(const DeprecationInfo &info, bool usewhere) if (info.apiType == API_FUNCTION) notice << "function "; + else if (info.apiType == API_FUNCTION_VARIANT) + notice << "function variant in "; else if (info.apiType == API_METHOD) notice << "method "; + else if (info.apiType == API_METHOD_VARIANT) + notice << "method variant in "; else if (info.apiType == API_CALLBACK) notice << "callback "; else if (info.apiType == API_FIELD) @@ -188,7 +192,9 @@ MarkDeprecated::~MarkDeprecated() STRINGMAP_BEGIN(APIType, API_MAX_ENUM, apiType) { { "function", API_FUNCTION }, + { "functionvariant", API_FUNCTION_VARIANT }, { "method", API_METHOD }, + { "methodvariant", API_METHOD_VARIANT }, { "callback", API_CALLBACK }, { "field", API_FIELD }, { "constant", API_CONSTANT }, diff --git a/src/common/deprecation.h b/src/common/deprecation.h index 7ac407cb3..a7154777d 100644 --- a/src/common/deprecation.h +++ b/src/common/deprecation.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -32,7 +32,9 @@ namespace love enum APIType { API_FUNCTION, + API_FUNCTION_VARIANT, API_METHOD, + API_METHOD_VARIANT, API_CALLBACK, API_FIELD, API_CONSTANT, diff --git a/src/common/floattypes.cpp b/src/common/floattypes.cpp index a387e1cbb..ae30462bb 100644 --- a/src/common/floattypes.cpp +++ b/src/common/floattypes.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/floattypes.h b/src/common/floattypes.h index 79938eab1..7572c06ac 100644 --- a/src/common/floattypes.h +++ b/src/common/floattypes.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/int.h b/src/common/int.h index 11a413607..8700eee9e 100644 --- a/src/common/int.h +++ b/src/common/int.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/ios.h b/src/common/ios.h index 8066aa983..7e6e0685b 100644 --- a/src/common/ios.h +++ b/src/common/ios.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/ios.mm b/src/common/ios.mm index f1fc47908..4d5065aac 100644 --- a/src/common/ios.mm +++ b/src/common/ios.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -149,6 +149,8 @@ static NSArray *getLovesInDocuments() [paths addObject:path.stringByDeletingLastPathComponent]; } + [paths sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + return paths; } diff --git a/src/common/macos.h b/src/common/macos.h index f3697f616..f8f67395f 100644 --- a/src/common/macos.h +++ b/src/common/macos.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/macos.mm b/src/common/macos.mm index 2bb426500..bdb980490 100644 --- a/src/common/macos.mm +++ b/src/common/macos.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,12 +26,9 @@ #import #import -#ifdef LOVE_MACOSX_SDL_DIRECT_INCLUDE #include +#if !SDL_VERSION_ATLEAST(3, 0, 0) #include -#else -#include -#include #endif namespace love @@ -63,6 +60,13 @@ std::string checkDropEvents() SDL_InitSubSystem(SDL_INIT_VIDEO); SDL_PumpEvents(); +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_EVENT_DROP_FILE, SDL_EVENT_DROP_FILE) > 0) + { + if (event.type == SDL_EVENT_DROP_FILE) + dropstr = std::string(event.drop.data); + } +#else if (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_DROPFILE, SDL_DROPFILE) > 0) { if (event.type == SDL_DROPFILE) @@ -71,6 +75,7 @@ std::string checkDropEvents() SDL_free(event.drop.file); } } +#endif SDL_QuitSubSystem(SDL_INIT_VIDEO); @@ -122,9 +127,15 @@ void setWindowSRGBColorSpace(SDL_Window *window) // (at least, it was back when I tested in December 2016). if (@available(macOS 11.0, *)) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_PropertiesID props = SDL_GetWindowProperties(window); + NSWindow *window = (__bridge NSWindow *) SDL_GetProperty(props, SDL_PROP_WINDOW_COCOA_WINDOW_POINTER, nullptr); + window.colorSpace = [NSColorSpace sRGBColorSpace]; +#else SDL_SysWMinfo info = {}; if (SDL_GetWindowWMInfo(window, &info)) info.info.cocoa.window.colorSpace = [NSColorSpace sRGBColorSpace]; +#endif } } } diff --git a/src/common/math.h b/src/common/math.h index 50ff5ad8a..5f2b5e7a9 100644 --- a/src/common/math.h +++ b/src/common/math.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/memory.cpp b/src/common/memory.cpp index 81afca87b..6d883002f 100644 --- a/src/common/memory.cpp +++ b/src/common/memory.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/memory.h b/src/common/memory.h index 924b5e5f9..97cf456a8 100644 --- a/src/common/memory.h +++ b/src/common/memory.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/pixelformat.cpp b/src/common/pixelformat.cpp index fad2611e7..205694d01 100644 --- a/src/common/pixelformat.cpp +++ b/src/common/pixelformat.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,101 +26,126 @@ namespace love static PixelFormatInfo formatInfo[] = { - // components, blockW, blockH, blockSize, color, depth, stencil, compressed, dataType - { 0, 1, 1, 0, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_UNKNOWN + // components, blockW, blockH, blockSize, color, depth, stencil, compressed, sRGB, dataType + { 0, 1, 1, 0, false, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_UNKNOWN - { 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_NORMAL - { 0, 1, 1, 0, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_HDR + { 0, 1, 1, 0, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_NORMAL + { 0, 1, 1, 0, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_HDR - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R8_UNORM - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R8_INT - { 1, 1, 1, 1, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R8_UINT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R16_UNORM - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R16_FLOAT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R16_INT - { 1, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R16_UINT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R32_FLOAT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R32_INT - { 1, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R32_UINT + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R8_UNORM + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R8_INT + { 1, 1, 1, 1, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R8_UINT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_R16_UNORM + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R16_FLOAT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R16_INT + { 1, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R16_UINT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_R32_FLOAT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_R32_INT + { 1, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_R32_UINT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG8_UNORM - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG8_INT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG8_UINT - { 2, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_LA8_UNORM - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG16_UNORM - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG16_FLOAT - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG16_INT - { 2, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG16_UINT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG32_FLOAT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG32_INT - { 2, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG32_UINT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG8_UNORM + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG8_INT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG8_UINT + { 2, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_LA8_UNORM + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RG16_UNORM + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG16_FLOAT + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG16_INT + { 2, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG16_UINT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RG32_FLOAT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RG32_INT + { 2, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RG32_UINT - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM_sRGB - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM_sRGB - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA8_INT - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA8_UINT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA16_UNORM - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA16_FLOAT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA16_INT - { 4, 1, 1, 8, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA16_UINT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA32_FLOAT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA32_INT - { 4, 1, 1, 16, true, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA32_UINT + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_UNORM + { 4, 1, 1, 4, true, false, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA8_sRGB + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_UNORM + { 4, 1, 1, 4, true, false, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BGRA8_sRGB + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA8_INT + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA8_UINT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA16_UNORM + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA16_FLOAT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA16_INT + { 4, 1, 1, 8, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA16_UINT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_RGBA32_FLOAT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_SINT }, // PIXELFORMAT_RGBA32_INT + { 4, 1, 1, 16, true, false, false, false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_RGBA32_UINT - { 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA4_UNORM - { 4, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB5A1_UNORM - { 3, 1, 1, 2, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB565_UNORM - { 4, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB10A2_UNORM - { 3, 1, 1, 4, true, false, false, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_RG11B10_FLOAT + { 4, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGBA4_UNORM + { 4, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB5A1_UNORM + { 3, 1, 1, 2, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB565_UNORM + { 4, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_RGB10A2_UNORM + { 3, 1, 1, 4, true, false, false, false, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_RG11B10_FLOAT - { 1, 1, 1, 1, false, false, true , false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_STENCIL8 - { 1, 1, 1, 2, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH16_UNORM - { 1, 1, 1, 3, false, true, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM - { 1, 1, 1, 4, false, true, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT - { 2, 1, 1, 4, false, true, true , false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8 - { 2, 1, 1, 5, false, true, true , false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 + { 1, 1, 1, 1, false, false, true , false, false, PIXELFORMATTYPE_UINT }, // PIXELFORMAT_STENCIL8 + { 1, 1, 1, 2, false, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH16_UNORM + { 1, 1, 1, 3, false, true, false, false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM + { 1, 1, 1, 4, false, true, false, false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT + { 2, 1, 1, 4, false, true, true , false, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DEPTH24_UNORM_STENCIL8 + { 2, 1, 1, 5, false, true, true , false, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC4_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC4_SNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC5_UNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC5_SNORM - { 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_BC6H_UFLOAT - { 3, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_BC6H_FLOAT - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_UNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_UNORM + { 3, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT1_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT3_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_DXT5_sRGB + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC4_UNORM + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC4_SNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC5_UNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_BC5_SNORM + { 3, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UFLOAT }, // PIXELFORMAT_BC6H_UFLOAT + { 3, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SFLOAT }, // PIXELFORMAT_BC6H_FLOAT + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_BC7_sRGB - { 3, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_UNORM - { 3, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_UNORM - { 4, 16, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_UNORM - { 4, 8, 8, 32, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_UNORM + { 3, 16, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_UNORM + { 3, 16, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB2_sRGB + { 3, 8, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_UNORM + { 3, 8, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGB4_sRGB + { 4, 16, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_UNORM + { 4, 16, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA2_sRGB + { 4, 8, 8, 32, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_UNORM + { 4, 8, 8, 32, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_PVR1_RGBA4_sRGB - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC1_UNORM - { 3, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_UNORM - { 4, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_UNORM - { 4, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_R_UNORM - { 1, 4, 4, 8, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_R_SNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_RG_UNORM - { 2, 4, 4, 16, true, false, false, true, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_RG_SNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC1_UNORM + { 3, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_UNORM + { 3, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGB_sRGB + { 4, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_UNORM + { 4, 4, 4, 16, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA_sRGB + { 4, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_UNORM + { 4, 4, 4, 8, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ETC2_RGBA1_sRGB + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_R_UNORM + { 1, 4, 4, 8, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_R_SNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_EAC_RG_UNORM + { 2, 4, 4, 16, true, false, false, true, false, PIXELFORMATTYPE_SNORM }, // PIXELFORMAT_EAC_RG_SNORM - { 4, 4, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4 - { 4, 5, 4, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4 - { 4, 5, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5 - { 4, 6, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5 - { 4, 6, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6 - { 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5 - { 4, 8, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6 - { 4, 8, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8 - { 4, 8, 5, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5 - { 4, 10, 6, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6 - { 4, 10, 8, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8 - { 4, 10, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10 - { 4, 12, 10, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10 - { 4, 12, 12, 1, true, false, false, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12 + { 4, 4, 4, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4_UNORM + { 4, 5, 4, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4_UNORM + { 4, 5, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5_UNORM + { 4, 6, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5_UNORM + { 4, 6, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6_UNORM + { 4, 8, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5_UNORM + { 4, 8, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6_UNORM + { 4, 8, 8, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8_UNORM + { 4, 8, 5, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5_UNORM + { 4, 10, 6, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6_UNORM + { 4, 10, 8, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8_UNORM + { 4, 10, 10, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10_UNORM + { 4, 12, 10, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10_UNORM + { 4, 12, 12, 1, true, false, false, true, false, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12_UNORM + { 4, 4, 4, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_4x4_sRGB + { 4, 5, 4, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x4_sRGB + { 4, 5, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_5x5_sRGB + { 4, 6, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x5_sRGB + { 4, 6, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_6x6_sRGB + { 4, 8, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x5_sRGB + { 4, 8, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x6_sRGB + { 4, 8, 8, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_8x8_sRGB + { 4, 8, 5, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x5_sRGB + { 4, 10, 6, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x6_sRGB + { 4, 10, 8, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x8_sRGB + { 4, 10, 10, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_10x10_sRGB + { 4, 12, 10, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x10_sRGB + { 4, 12, 12, 1, true, false, false, true, true, PIXELFORMATTYPE_UNORM }, // PIXELFORMAT_ASTC_12x12_sRGB }; static_assert(sizeof(formatInfo) / sizeof(PixelFormatInfo) == PIXELFORMAT_MAX_ENUM, "Update the formatInfo array when adding or removing a PixelFormat"); @@ -155,19 +180,19 @@ static StringMap::Entry formatEntries[] = { "rg32i", PIXELFORMAT_RG32_INT }, { "rg32ui", PIXELFORMAT_RG32_UINT }, - { "rgba8", PIXELFORMAT_RGBA8_UNORM }, - { "srgba8", PIXELFORMAT_RGBA8_UNORM_sRGB }, - { "bgra8", PIXELFORMAT_BGRA8_UNORM }, - { "bgra8srgb", PIXELFORMAT_BGRA8_UNORM_sRGB }, - { "rgba8i", PIXELFORMAT_RGBA8_INT }, - { "rgba8ui", PIXELFORMAT_RGBA8_UINT }, - { "rgba16", PIXELFORMAT_RGBA16_UNORM }, - { "rgba16f", PIXELFORMAT_RGBA16_FLOAT }, - { "rgba16i", PIXELFORMAT_RGBA16_INT }, - { "rgba16ui", PIXELFORMAT_RGBA16_UINT }, - { "rgba32f", PIXELFORMAT_RGBA32_FLOAT }, - { "rgba32i", PIXELFORMAT_RGBA32_INT }, - { "rgba32ui", PIXELFORMAT_RGBA32_UINT }, + { "rgba8", PIXELFORMAT_RGBA8_UNORM }, + { "srgba8", PIXELFORMAT_RGBA8_sRGB }, + { "bgra8", PIXELFORMAT_BGRA8_UNORM }, + { "bgra8srgb", PIXELFORMAT_BGRA8_sRGB }, + { "rgba8i", PIXELFORMAT_RGBA8_INT }, + { "rgba8ui", PIXELFORMAT_RGBA8_UINT }, + { "rgba16", PIXELFORMAT_RGBA16_UNORM }, + { "rgba16f", PIXELFORMAT_RGBA16_FLOAT }, + { "rgba16i", PIXELFORMAT_RGBA16_INT }, + { "rgba16ui", PIXELFORMAT_RGBA16_UINT }, + { "rgba32f", PIXELFORMAT_RGBA32_FLOAT }, + { "rgba32i", PIXELFORMAT_RGBA32_INT }, + { "rgba32ui", PIXELFORMAT_RGBA32_UINT }, { "rgba4", PIXELFORMAT_RGBA4_UNORM }, { "rgb5a1", PIXELFORMAT_RGB5A1_UNORM }, @@ -182,43 +207,70 @@ static StringMap::Entry formatEntries[] = { "depth24stencil8", PIXELFORMAT_DEPTH24_UNORM_STENCIL8 }, { "depth32fstencil8", PIXELFORMAT_DEPTH32_FLOAT_STENCIL8 }, - { "DXT1", PIXELFORMAT_DXT1_UNORM }, - { "DXT3", PIXELFORMAT_DXT3_UNORM }, - { "DXT5", PIXELFORMAT_DXT5_UNORM }, - { "BC4", PIXELFORMAT_BC4_UNORM }, - { "BC4s", PIXELFORMAT_BC4_SNORM }, - { "BC5", PIXELFORMAT_BC5_UNORM }, - { "BC5s", PIXELFORMAT_BC5_SNORM }, - { "BC6h", PIXELFORMAT_BC6H_UFLOAT }, - { "BC6hs", PIXELFORMAT_BC6H_FLOAT }, - { "BC7", PIXELFORMAT_BC7_UNORM }, - { "PVR1rgb2", PIXELFORMAT_PVR1_RGB2_UNORM }, - { "PVR1rgb4", PIXELFORMAT_PVR1_RGB4_UNORM }, - { "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2_UNORM }, - { "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4_UNORM }, - { "ETC1", PIXELFORMAT_ETC1_UNORM }, - { "ETC2rgb", PIXELFORMAT_ETC2_RGB_UNORM }, - { "ETC2rgba", PIXELFORMAT_ETC2_RGBA_UNORM }, - { "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1_UNORM }, - { "EACr", PIXELFORMAT_EAC_R_UNORM }, - { "EACrs", PIXELFORMAT_EAC_R_SNORM }, - { "EACrg", PIXELFORMAT_EAC_RG_UNORM }, - { "EACrgs", PIXELFORMAT_EAC_RG_SNORM }, + { "DXT1", PIXELFORMAT_DXT1_UNORM }, + { "DXT1srgb", PIXELFORMAT_DXT1_sRGB }, + { "DXT3", PIXELFORMAT_DXT3_UNORM }, + { "DXT3srgb", PIXELFORMAT_DXT3_sRGB }, + { "DXT5", PIXELFORMAT_DXT5_UNORM }, + { "DXT5srgb", PIXELFORMAT_DXT5_sRGB }, + { "BC4", PIXELFORMAT_BC4_UNORM }, + { "BC4s", PIXELFORMAT_BC4_SNORM }, + { "BC5", PIXELFORMAT_BC5_UNORM }, + { "BC5s", PIXELFORMAT_BC5_SNORM }, + { "BC6h", PIXELFORMAT_BC6H_UFLOAT }, + { "BC6hs", PIXELFORMAT_BC6H_FLOAT }, + { "BC7", PIXELFORMAT_BC7_UNORM }, + { "BC7srgb", PIXELFORMAT_BC7_sRGB }, - { "ASTC4x4", PIXELFORMAT_ASTC_4x4 }, - { "ASTC5x4", PIXELFORMAT_ASTC_5x4 }, - { "ASTC5x5", PIXELFORMAT_ASTC_5x5 }, - { "ASTC6x5", PIXELFORMAT_ASTC_6x5 }, - { "ASTC6x6", PIXELFORMAT_ASTC_6x6 }, - { "ASTC8x5", PIXELFORMAT_ASTC_8x5 }, - { "ASTC8x6", PIXELFORMAT_ASTC_8x6 }, - { "ASTC8x8", PIXELFORMAT_ASTC_8x8 }, - { "ASTC10x5", PIXELFORMAT_ASTC_10x5 }, - { "ASTC10x6", PIXELFORMAT_ASTC_10x6 }, - { "ASTC10x8", PIXELFORMAT_ASTC_10x8 }, - { "ASTC10x10", PIXELFORMAT_ASTC_10x10 }, - { "ASTC12x10", PIXELFORMAT_ASTC_12x10 }, - { "ASTC12x12", PIXELFORMAT_ASTC_12x12 }, + { "PVR1rgb2", PIXELFORMAT_PVR1_RGB2_UNORM }, + { "PVR1rgb2srgb", PIXELFORMAT_PVR1_RGB2_sRGB }, + { "PVR1rgb4", PIXELFORMAT_PVR1_RGB4_UNORM }, + { "PVR1rgb4srgb", PIXELFORMAT_PVR1_RGB4_sRGB }, + { "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2_UNORM }, + { "PVR1rgba2srgb", PIXELFORMAT_PVR1_RGBA2_sRGB }, + { "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4_UNORM }, + { "PVR1rgba4srgb", PIXELFORMAT_PVR1_RGBA4_sRGB }, + + { "ETC1", PIXELFORMAT_ETC1_UNORM }, + { "ETC2rgb", PIXELFORMAT_ETC2_RGB_UNORM }, + { "ETC2srgb", PIXELFORMAT_ETC2_RGB_sRGB }, + { "ETC2rgba", PIXELFORMAT_ETC2_RGBA_UNORM }, + { "ETC2srgba", PIXELFORMAT_ETC2_RGBA_sRGB }, + { "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1_UNORM }, + { "ETC2srgba1", PIXELFORMAT_ETC2_RGBA1_sRGB }, + { "EACr", PIXELFORMAT_EAC_R_UNORM }, + { "EACrs", PIXELFORMAT_EAC_R_SNORM }, + { "EACrg", PIXELFORMAT_EAC_RG_UNORM }, + { "EACrgs", PIXELFORMAT_EAC_RG_SNORM }, + + { "ASTC4x4", PIXELFORMAT_ASTC_4x4_UNORM }, + { "ASTC5x4", PIXELFORMAT_ASTC_5x4_UNORM }, + { "ASTC5x5", PIXELFORMAT_ASTC_5x5_UNORM }, + { "ASTC6x5", PIXELFORMAT_ASTC_6x5_UNORM }, + { "ASTC6x6", PIXELFORMAT_ASTC_6x6_UNORM }, + { "ASTC8x5", PIXELFORMAT_ASTC_8x5_UNORM }, + { "ASTC8x6", PIXELFORMAT_ASTC_8x6_UNORM }, + { "ASTC8x8", PIXELFORMAT_ASTC_8x8_UNORM }, + { "ASTC10x5", PIXELFORMAT_ASTC_10x5_UNORM }, + { "ASTC10x6", PIXELFORMAT_ASTC_10x6_UNORM }, + { "ASTC10x8", PIXELFORMAT_ASTC_10x8_UNORM }, + { "ASTC10x10", PIXELFORMAT_ASTC_10x10_UNORM }, + { "ASTC12x10", PIXELFORMAT_ASTC_12x10_UNORM }, + { "ASTC12x12", PIXELFORMAT_ASTC_12x12_UNORM }, + { "ASTC4x4srgb", PIXELFORMAT_ASTC_4x4_sRGB }, + { "ASTC5x4srgb", PIXELFORMAT_ASTC_5x4_sRGB }, + { "ASTC5x5srgb", PIXELFORMAT_ASTC_5x5_sRGB }, + { "ASTC6x5srgb", PIXELFORMAT_ASTC_6x5_sRGB }, + { "ASTC6x6srgb", PIXELFORMAT_ASTC_6x6_sRGB }, + { "ASTC8x5srgb", PIXELFORMAT_ASTC_8x5_sRGB }, + { "ASTC8x6srgb", PIXELFORMAT_ASTC_8x6_sRGB }, + { "ASTC8x8srgb", PIXELFORMAT_ASTC_8x8_sRGB }, + { "ASTC10x5srgb", PIXELFORMAT_ASTC_10x5_sRGB }, + { "ASTC10x6srgb", PIXELFORMAT_ASTC_10x6_sRGB }, + { "ASTC10x8srgb", PIXELFORMAT_ASTC_10x8_sRGB }, + { "ASTC10x10srgb", PIXELFORMAT_ASTC_10x10_sRGB }, + { "ASTC12x10srgb", PIXELFORMAT_ASTC_12x10_sRGB }, + { "ASTC12x12srgb", PIXELFORMAT_ASTC_12x12_sRGB }, }; static_assert(sizeof(formatEntries) / sizeof(formatEntries[0]) == (size_t) PIXELFORMAT_MAX_ENUM, "pixel format string map is missing entries!"); @@ -275,7 +327,7 @@ bool isPixelFormatStencil(PixelFormat format) bool isPixelFormatSRGB(PixelFormat format) { - return format == PIXELFORMAT_RGBA8_UNORM_sRGB || format == PIXELFORMAT_BGRA8_UNORM_sRGB; + return formatInfo[format].sRGB; } bool isPixelFormatInteger(PixelFormat format) @@ -286,20 +338,73 @@ bool isPixelFormatInteger(PixelFormat format) PixelFormat getSRGBPixelFormat(PixelFormat format) { - if (format == PIXELFORMAT_RGBA8_UNORM) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else if (format == PIXELFORMAT_BGRA8_UNORM) - return PIXELFORMAT_BGRA8_UNORM_sRGB; - return format; + switch (format) + { + case PIXELFORMAT_RGBA8_UNORM: return PIXELFORMAT_RGBA8_sRGB; + case PIXELFORMAT_BGRA8_UNORM: return PIXELFORMAT_BGRA8_sRGB; + case PIXELFORMAT_DXT1_UNORM: return PIXELFORMAT_DXT1_sRGB; + case PIXELFORMAT_DXT3_UNORM: return PIXELFORMAT_DXT3_sRGB; + case PIXELFORMAT_DXT5_UNORM: return PIXELFORMAT_DXT5_sRGB; + case PIXELFORMAT_BC7_UNORM: return PIXELFORMAT_BC7_sRGB; + case PIXELFORMAT_PVR1_RGB2_UNORM: return PIXELFORMAT_PVR1_RGB2_sRGB; + case PIXELFORMAT_PVR1_RGB4_UNORM: return PIXELFORMAT_PVR1_RGB4_sRGB; + case PIXELFORMAT_PVR1_RGBA2_UNORM: return PIXELFORMAT_PVR1_RGBA2_sRGB; + case PIXELFORMAT_PVR1_RGBA4_UNORM: return PIXELFORMAT_PVR1_RGBA4_sRGB; + case PIXELFORMAT_ETC1_UNORM: return PIXELFORMAT_ETC2_RGB_sRGB; // ETC2 can load ETC1 data. + case PIXELFORMAT_ETC2_RGB_UNORM: return PIXELFORMAT_ETC2_RGB_sRGB; + case PIXELFORMAT_ETC2_RGBA_UNORM: return PIXELFORMAT_ETC2_RGBA_sRGB; + case PIXELFORMAT_ETC2_RGBA1_UNORM: return PIXELFORMAT_ETC2_RGBA1_sRGB; + case PIXELFORMAT_ASTC_4x4_UNORM: return PIXELFORMAT_ASTC_4x4_sRGB; + case PIXELFORMAT_ASTC_5x4_UNORM: return PIXELFORMAT_ASTC_5x4_sRGB; + case PIXELFORMAT_ASTC_5x5_UNORM: return PIXELFORMAT_ASTC_5x5_sRGB; + case PIXELFORMAT_ASTC_6x5_UNORM: return PIXELFORMAT_ASTC_6x5_sRGB; + case PIXELFORMAT_ASTC_6x6_UNORM: return PIXELFORMAT_ASTC_6x6_sRGB; + case PIXELFORMAT_ASTC_8x5_UNORM: return PIXELFORMAT_ASTC_8x5_sRGB; + case PIXELFORMAT_ASTC_8x6_UNORM: return PIXELFORMAT_ASTC_8x6_sRGB; + case PIXELFORMAT_ASTC_8x8_UNORM: return PIXELFORMAT_ASTC_8x8_sRGB; + case PIXELFORMAT_ASTC_10x5_UNORM: return PIXELFORMAT_ASTC_10x5_sRGB; + case PIXELFORMAT_ASTC_10x6_UNORM: return PIXELFORMAT_ASTC_10x6_sRGB; + case PIXELFORMAT_ASTC_10x8_UNORM: return PIXELFORMAT_ASTC_10x8_sRGB; + case PIXELFORMAT_ASTC_10x10_UNORM: return PIXELFORMAT_ASTC_10x10_sRGB; + case PIXELFORMAT_ASTC_12x10_UNORM: return PIXELFORMAT_ASTC_12x10_sRGB; + case PIXELFORMAT_ASTC_12x12_UNORM: return PIXELFORMAT_ASTC_12x12_sRGB; + default: return format; + } } PixelFormat getLinearPixelFormat(PixelFormat format) { - if (format == PIXELFORMAT_RGBA8_UNORM_sRGB) - return PIXELFORMAT_RGBA8_UNORM; - else if (format == PIXELFORMAT_BGRA8_UNORM_sRGB) - return PIXELFORMAT_BGRA8_UNORM; - return format; + switch (format) + { + case PIXELFORMAT_RGBA8_sRGB: return PIXELFORMAT_RGBA8_UNORM; + case PIXELFORMAT_BGRA8_sRGB: return PIXELFORMAT_BGRA8_UNORM; + case PIXELFORMAT_DXT1_sRGB: return PIXELFORMAT_DXT1_UNORM; + case PIXELFORMAT_DXT3_sRGB: return PIXELFORMAT_DXT3_UNORM; + case PIXELFORMAT_DXT5_sRGB: return PIXELFORMAT_DXT5_UNORM; + case PIXELFORMAT_BC7_sRGB: return PIXELFORMAT_BC7_UNORM; + case PIXELFORMAT_PVR1_RGB2_sRGB: return PIXELFORMAT_PVR1_RGB2_UNORM; + case PIXELFORMAT_PVR1_RGB4_sRGB: return PIXELFORMAT_PVR1_RGB4_UNORM; + case PIXELFORMAT_PVR1_RGBA2_sRGB: return PIXELFORMAT_PVR1_RGBA2_UNORM; + case PIXELFORMAT_PVR1_RGBA4_sRGB: return PIXELFORMAT_PVR1_RGBA4_UNORM; + case PIXELFORMAT_ETC2_RGB_sRGB: return PIXELFORMAT_ETC2_RGB_UNORM; + case PIXELFORMAT_ETC2_RGBA_sRGB: return PIXELFORMAT_ETC2_RGBA_UNORM; + case PIXELFORMAT_ETC2_RGBA1_sRGB: return PIXELFORMAT_ETC2_RGBA1_UNORM; + case PIXELFORMAT_ASTC_4x4_sRGB: return PIXELFORMAT_ASTC_4x4_UNORM; + case PIXELFORMAT_ASTC_5x4_sRGB: return PIXELFORMAT_ASTC_5x4_UNORM; + case PIXELFORMAT_ASTC_5x5_sRGB: return PIXELFORMAT_ASTC_5x5_UNORM; + case PIXELFORMAT_ASTC_6x5_sRGB: return PIXELFORMAT_ASTC_6x5_UNORM; + case PIXELFORMAT_ASTC_6x6_sRGB: return PIXELFORMAT_ASTC_6x6_UNORM; + case PIXELFORMAT_ASTC_8x5_sRGB: return PIXELFORMAT_ASTC_8x5_UNORM; + case PIXELFORMAT_ASTC_8x6_sRGB: return PIXELFORMAT_ASTC_8x6_UNORM; + case PIXELFORMAT_ASTC_8x8_sRGB: return PIXELFORMAT_ASTC_8x8_UNORM; + case PIXELFORMAT_ASTC_10x5_sRGB: return PIXELFORMAT_ASTC_10x5_UNORM; + case PIXELFORMAT_ASTC_10x6_sRGB: return PIXELFORMAT_ASTC_10x6_UNORM; + case PIXELFORMAT_ASTC_10x8_sRGB: return PIXELFORMAT_ASTC_10x8_UNORM; + case PIXELFORMAT_ASTC_10x10_sRGB: return PIXELFORMAT_ASTC_10x10_UNORM; + case PIXELFORMAT_ASTC_12x10_sRGB: return PIXELFORMAT_ASTC_12x10_UNORM; + case PIXELFORMAT_ASTC_12x12_sRGB: return PIXELFORMAT_ASTC_12x12_UNORM; + default: return format; + } } size_t getPixelFormatBlockSize(PixelFormat format) diff --git a/src/common/pixelformat.h b/src/common/pixelformat.h index a2f52a4db..37ddc93e6 100644 --- a/src/common/pixelformat.h +++ b/src/common/pixelformat.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -60,9 +60,9 @@ enum PixelFormat // 4-channel normal formats PIXELFORMAT_RGBA8_UNORM, - PIXELFORMAT_RGBA8_UNORM_sRGB, + PIXELFORMAT_RGBA8_sRGB, PIXELFORMAT_BGRA8_UNORM, - PIXELFORMAT_BGRA8_UNORM_sRGB, + PIXELFORMAT_BGRA8_sRGB, PIXELFORMAT_RGBA8_INT, PIXELFORMAT_RGBA8_UINT, PIXELFORMAT_RGBA16_UNORM, @@ -90,8 +90,11 @@ enum PixelFormat // compressed formats PIXELFORMAT_DXT1_UNORM, + PIXELFORMAT_DXT1_sRGB, PIXELFORMAT_DXT3_UNORM, + PIXELFORMAT_DXT3_sRGB, PIXELFORMAT_DXT5_UNORM, + PIXELFORMAT_DXT5_sRGB, PIXELFORMAT_BC4_UNORM, PIXELFORMAT_BC4_SNORM, PIXELFORMAT_BC5_UNORM, @@ -99,32 +102,57 @@ enum PixelFormat PIXELFORMAT_BC6H_UFLOAT, PIXELFORMAT_BC6H_FLOAT, PIXELFORMAT_BC7_UNORM, + PIXELFORMAT_BC7_sRGB, + PIXELFORMAT_PVR1_RGB2_UNORM, + PIXELFORMAT_PVR1_RGB2_sRGB, PIXELFORMAT_PVR1_RGB4_UNORM, + PIXELFORMAT_PVR1_RGB4_sRGB, PIXELFORMAT_PVR1_RGBA2_UNORM, + PIXELFORMAT_PVR1_RGBA2_sRGB, PIXELFORMAT_PVR1_RGBA4_UNORM, + PIXELFORMAT_PVR1_RGBA4_sRGB, + PIXELFORMAT_ETC1_UNORM, PIXELFORMAT_ETC2_RGB_UNORM, + PIXELFORMAT_ETC2_RGB_sRGB, PIXELFORMAT_ETC2_RGBA_UNORM, + PIXELFORMAT_ETC2_RGBA_sRGB, PIXELFORMAT_ETC2_RGBA1_UNORM, + PIXELFORMAT_ETC2_RGBA1_sRGB, PIXELFORMAT_EAC_R_UNORM, PIXELFORMAT_EAC_R_SNORM, PIXELFORMAT_EAC_RG_UNORM, PIXELFORMAT_EAC_RG_SNORM, - PIXELFORMAT_ASTC_4x4, - PIXELFORMAT_ASTC_5x4, - PIXELFORMAT_ASTC_5x5, - PIXELFORMAT_ASTC_6x5, - PIXELFORMAT_ASTC_6x6, - PIXELFORMAT_ASTC_8x5, - PIXELFORMAT_ASTC_8x6, - PIXELFORMAT_ASTC_8x8, - PIXELFORMAT_ASTC_10x5, - PIXELFORMAT_ASTC_10x6, - PIXELFORMAT_ASTC_10x8, - PIXELFORMAT_ASTC_10x10, - PIXELFORMAT_ASTC_12x10, - PIXELFORMAT_ASTC_12x12, + + PIXELFORMAT_ASTC_4x4_UNORM, + PIXELFORMAT_ASTC_5x4_UNORM, + PIXELFORMAT_ASTC_5x5_UNORM, + PIXELFORMAT_ASTC_6x5_UNORM, + PIXELFORMAT_ASTC_6x6_UNORM, + PIXELFORMAT_ASTC_8x5_UNORM, + PIXELFORMAT_ASTC_8x6_UNORM, + PIXELFORMAT_ASTC_8x8_UNORM, + PIXELFORMAT_ASTC_10x5_UNORM, + PIXELFORMAT_ASTC_10x6_UNORM, + PIXELFORMAT_ASTC_10x8_UNORM, + PIXELFORMAT_ASTC_10x10_UNORM, + PIXELFORMAT_ASTC_12x10_UNORM, + PIXELFORMAT_ASTC_12x12_UNORM, + PIXELFORMAT_ASTC_4x4_sRGB, + PIXELFORMAT_ASTC_5x4_sRGB, + PIXELFORMAT_ASTC_5x5_sRGB, + PIXELFORMAT_ASTC_6x5_sRGB, + PIXELFORMAT_ASTC_6x6_sRGB, + PIXELFORMAT_ASTC_8x5_sRGB, + PIXELFORMAT_ASTC_8x6_sRGB, + PIXELFORMAT_ASTC_8x8_sRGB, + PIXELFORMAT_ASTC_10x5_sRGB, + PIXELFORMAT_ASTC_10x6_sRGB, + PIXELFORMAT_ASTC_10x8_sRGB, + PIXELFORMAT_ASTC_10x10_sRGB, + PIXELFORMAT_ASTC_12x10_sRGB, + PIXELFORMAT_ASTC_12x12_sRGB, PIXELFORMAT_MAX_ENUM }; @@ -149,6 +177,7 @@ struct PixelFormatInfo bool depth; bool stencil; bool compressed; + bool sRGB; PixelFormatType dataType; }; diff --git a/src/common/runtime.cpp b/src/common/runtime.cpp index 633da62a1..0e2fe2045 100644 --- a/src/common/runtime.cpp +++ b/src/common/runtime.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -473,9 +473,6 @@ int luax_register_module(lua_State *L, const WrappedModule &m) lua_setfield(L, -3, m.name); // love.graphics = table lua_remove(L, -2); // love - // Register module instance - Module::registerInstance(m.module); - return 1; } @@ -550,6 +547,10 @@ int luax_register_type(lua_State *L, love::Type *type, ...) lua_pushcfunction(L, w__release); lua_setfield(L, -2, "release"); + // Add __close for lua 5.4 (just calls release) + lua_pushcfunction(L, w__release); + lua_setfield(L, -2, "__close"); + va_list fs; va_start(fs, type); for (const luaL_Reg *f = va_arg(fs, const luaL_Reg *); f; f = va_arg(fs, const luaL_Reg *)) diff --git a/src/common/runtime.h b/src/common/runtime.h index a851de2fd..747c38e86 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -629,22 +629,29 @@ T *luax_optmodule(lua_State *L) } /** - * Converts the value at idx to the specified type without checking that - * this conversion is valid. If the type has been previously verified with - * luax_istype, then this can be safely used. Otherwise, use luax_checktype. + * Converts the value at idx to the specified type. Returns null if the type + * doesn't match. * @param L The Lua state. * @param idx The index on the stack. * @param type The type of the object. **/ template -T *luax_totype(lua_State *L, int idx, const love::Type& /*type*/) +T *luax_totype(lua_State *L, int idx, const love::Type &type) { - T *o = (T *)(((Proxy *)lua_touserdata(L, idx))->object); + if (lua_type(L, idx) != LUA_TUSERDATA) + return nullptr; - if (o == nullptr) - luaL_error(L, "Cannot use object after it has been released."); + Proxy *p = (Proxy *) lua_touserdata(L, idx); - return o; + if (p->type != nullptr && p->type->isa(type)) + { + if (p->object == nullptr) + luaL_error(L, "Cannot use object after it has been released."); + + return (T *) p->object; + } + + return nullptr; } template diff --git a/src/common/types.cpp b/src/common/types.cpp index d188321f7..69a4f703d 100644 --- a/src/common/types.cpp +++ b/src/common/types.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/types.h b/src/common/types.h index d9948b984..536bc0590 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp index dfc1909f6..20daa9bc7 100644 --- a/src/common/utf8.cpp +++ b/src/common/utf8.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/utf8.h b/src/common/utf8.h index ff17ac1c2..fc5bcfbb3 100644 --- a/src/common/utf8.h +++ b/src/common/utf8.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/common/version.h b/src/common/version.h index aa34b0117..72742ba10 100644 --- a/src/common/version.h +++ b/src/common/version.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/ddsparse/ddsinfo.h b/src/libraries/ddsparse/ddsinfo.h index 929a13b92..81c1b98fd 100644 --- a/src/libraries/ddsparse/ddsinfo.h +++ b/src/libraries/ddsparse/ddsinfo.h @@ -1,7 +1,7 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013-2023 Sasha Szpakowski + * Copyright (c) 2013-2024 Sasha Szpakowski * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/ddsparse/ddsparse.cpp b/src/libraries/ddsparse/ddsparse.cpp index 59d770aa7..5827ceeb9 100644 --- a/src/libraries/ddsparse/ddsparse.cpp +++ b/src/libraries/ddsparse/ddsparse.cpp @@ -1,7 +1,7 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013-2023 Sasha Szpakowski + * Copyright (c) 2013-2024 Sasha Szpakowski * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/ddsparse/ddsparse.h b/src/libraries/ddsparse/ddsparse.h index 17d8b7f38..8b9544a2e 100644 --- a/src/libraries/ddsparse/ddsparse.h +++ b/src/libraries/ddsparse/ddsparse.h @@ -1,7 +1,7 @@ /** * Simple DDS data parser for compressed 2D textures. * - * Copyright (c) 2013-2023 Sasha Szpakowski + * Copyright (c) 2013-2024 Sasha Szpakowski * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/enet/lua-enet.h b/src/libraries/enet/lua-enet.h index 2112c8dd5..b2fe08152 100644 --- a/src/libraries/enet/lua-enet.h +++ b/src/libraries/enet/lua-enet.h @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp b/src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp deleted file mode 100644 index abea9108b..000000000 --- a/src/libraries/glslang/OGLCompilersDLL/InitializeDll.cpp +++ /dev/null @@ -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 - -#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 diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.ARM.h b/src/libraries/glslang/SPIRV/GLSL.ext.ARM.h new file mode 100644 index 000000000..14425be1e --- /dev/null +++ b/src/libraries/glslang/SPIRV/GLSL.ext.ARM.h @@ -0,0 +1,35 @@ +/* +** Copyright (c) 2022 ARM Limited +** +** 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 GLSLextARM_H +#define GLSLextARM_H + +static const int GLSLextARMVersion = 100; +static const int GLSLextARMRevision = 1; + +static const char * const E_SPV_ARM_core_builtins = "SPV_ARM_core_builtins"; + +#endif // #ifndef GLSLextARM_H diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h b/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h index f48f1304d..caab27938 100644 --- a/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h +++ b/src/libraries/glslang/SPIRV/GLSL.ext.EXT.h @@ -39,5 +39,7 @@ static const char* const E_SPV_EXT_shader_atomic_float_add = "SPV_EXT_shader_ato static const char* const E_SPV_EXT_shader_atomic_float16_add = "SPV_EXT_shader_atomic_float16_add"; static const char* const E_SPV_EXT_shader_atomic_float_min_max = "SPV_EXT_shader_atomic_float_min_max"; static const char* const E_SPV_EXT_shader_image_int64 = "SPV_EXT_shader_image_int64"; +static const char* const E_SPV_EXT_shader_tile_image = "SPV_EXT_shader_tile_image"; +static const char* const E_SPV_EXT_mesh_shader = "SPV_EXT_mesh_shader"; #endif // #ifndef GLSLextEXT_H diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h b/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h index 5eb3e9448..1d3af1403 100644 --- a/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h +++ b/src/libraries/glslang/SPIRV/GLSL.ext.KHR.h @@ -1,5 +1,6 @@ /* ** Copyright (c) 2014-2020 The Khronos Group Inc. +** Copyright (C) 2022-2024 Arm Limited. ** Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,7 +30,7 @@ #define GLSLextKHR_H static const int GLSLextKHRVersion = 100; -static const int GLSLextKHRRevision = 2; +static const int GLSLextKHRRevision = 3; 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"; @@ -52,5 +53,13 @@ static const char* const E_SPV_KHR_fragment_shading_rate = "SPV_KHR_fragm static const char* const E_SPV_KHR_terminate_invocation = "SPV_KHR_terminate_invocation"; static const char* const E_SPV_KHR_workgroup_memory_explicit_layout = "SPV_KHR_workgroup_memory_explicit_layout"; static const char* const E_SPV_KHR_subgroup_uniform_control_flow = "SPV_KHR_subgroup_uniform_control_flow"; +static const char* const E_SPV_KHR_fragment_shader_barycentric = "SPV_KHR_fragment_shader_barycentric"; +static const char* const E_SPV_KHR_quad_control = "SPV_KHR_quad_control"; +static const char* const E_SPV_AMD_shader_early_and_late_fragment_tests = "SPV_AMD_shader_early_and_late_fragment_tests"; +static const char* const E_SPV_KHR_ray_tracing_position_fetch = "SPV_KHR_ray_tracing_position_fetch"; +static const char* const E_SPV_KHR_cooperative_matrix = "SPV_KHR_cooperative_matrix"; +static const char* const E_SPV_KHR_maximal_reconvergence = "SPV_KHR_maximal_reconvergence"; +static const char* const E_SPV_KHR_subgroup_rotate = "SPV_KHR_subgroup_rotate"; +static const char* const E_SPV_KHR_expect_assume = "SPV_KHR_expect_assume"; #endif // #ifndef GLSLextKHR_H diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.NV.h b/src/libraries/glslang/SPIRV/GLSL.ext.NV.h index 93c98bf62..e4f11e4bf 100644 --- a/src/libraries/glslang/SPIRV/GLSL.ext.NV.h +++ b/src/libraries/glslang/SPIRV/GLSL.ext.NV.h @@ -81,4 +81,13 @@ 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"; +//SPV_NV_shader_execution_reorder +const char* const E_SPV_NV_shader_invocation_reorder = "SPV_NV_shader_invocation_reorder"; + +//SPV_NV_displacement_micromap +const char* const E_SPV_NV_displacement_micromap = "SPV_NV_displacement_micromap"; + +//SPV_NV_shader_atomic_fp16_vector +const char* const E_SPV_NV_shader_atomic_fp16_vector = "SPV_NV_shader_atomic_fp16_vector"; + #endif // #ifndef GLSLextNV_H diff --git a/src/libraries/glslang/SPIRV/GLSL.ext.QCOM.h b/src/libraries/glslang/SPIRV/GLSL.ext.QCOM.h new file mode 100644 index 000000000..b52990f02 --- /dev/null +++ b/src/libraries/glslang/SPIRV/GLSL.ext.QCOM.h @@ -0,0 +1,43 @@ +/* +** Copyright (c) 2021 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 GLSLextQCOM_H +#define GLSLextQCOM_H + +enum BuiltIn; +enum Decoration; +enum Op; +enum Capability; + +static const int GLSLextQCOMVersion = 100; +static const int GLSLextQCOMRevision = 1; + +//SPV_QCOM_image_processing +const char* const E_SPV_QCOM_image_processing = "SPV_QCOM_image_processing"; +//SPV_QCOM_image_processing2 +const char* const E_SPV_QCOM_image_processing2 = "SPV_QCOM_image_processing2"; + +#endif // #ifndef GLSLextQCOM_H diff --git a/src/libraries/glslang/SPIRV/GLSL.std.450.h b/src/libraries/glslang/SPIRV/GLSL.std.450.h index df31092be..86d3da806 100644 --- a/src/libraries/glslang/SPIRV/GLSL.std.450.h +++ b/src/libraries/glslang/SPIRV/GLSL.std.450.h @@ -13,7 +13,7 @@ ** ** 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/ +** 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, diff --git a/src/libraries/glslang/SPIRV/GlslangToSpv.cpp b/src/libraries/glslang/SPIRV/GlslangToSpv.cpp old mode 100644 new mode 100755 index 5f18677b5..740a831ed --- a/src/libraries/glslang/SPIRV/GlslangToSpv.cpp +++ b/src/libraries/glslang/SPIRV/GlslangToSpv.cpp @@ -1,7 +1,7 @@ // // Copyright (C) 2014-2016 LunarG, Inc. // Copyright (C) 2015-2020 Google, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. @@ -43,12 +43,15 @@ #include "spirv.hpp" #include "GlslangToSpv.h" #include "SpvBuilder.h" +#include "SpvTools.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" + #include "GLSL.ext.ARM.h" + #include "GLSL.ext.QCOM.h" #include "NonSemanticDebugPrintf.h" } @@ -64,6 +67,7 @@ namespace spv { #include #include #include +#include #include #include #include @@ -94,26 +98,18 @@ struct OpDecorations { public: OpDecorations(spv::Decoration precision, spv::Decoration noContraction, spv::Decoration nonUniform) : precision(precision) -#ifndef GLSLANG_WEB , noContraction(noContraction), nonUniform(nonUniform) -#endif { } spv::Decoration precision; -#ifdef GLSLANG_WEB - void addNoContraction(spv::Builder&, spv::Id) const { } - void addNonUniform(spv::Builder&, spv::Id) const { } -#else void addNoContraction(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, noContraction); } void addNonUniform(spv::Builder& builder, spv::Id t) { builder.addDecoration(t, nonUniform); } protected: spv::Decoration noContraction; spv::Decoration nonUniform; -#endif - }; } // namespace @@ -139,7 +135,7 @@ public: bool visitLoop(glslang::TVisit, glslang::TIntermLoop*); bool visitBranch(glslang::TVisit visit, glslang::TIntermBranch*); - void finishSpv(); + void finishSpv(bool compileOnly); void dumpSpv(std::vector& out); protected: @@ -170,12 +166,14 @@ protected: spv::Id convertGlslangToSpvType(const glslang::TType& type, bool forwardReferenceOnly = false); spv::Id convertGlslangToSpvType(const glslang::TType& type, glslang::TLayoutPacking, const glslang::TQualifier&, bool lastBufferBlockMember, bool forwardReferenceOnly = false); + void applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional member); bool filterMember(const glslang::TType& member); spv::Id convertGlslangStructToSpvType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, const glslang::TQualifier&); + spv::LinkageType convertGlslangLinkageToSpv(glslang::TLinkType glslangLinkType); void decorateStructType(const glslang::TType&, const glslang::TTypeList* glslangStruct, glslang::TLayoutPacking, - const glslang::TQualifier&, spv::Id); - spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim); + const glslang::TQualifier&, spv::Id, const std::vector& spvMembers); + spv::Id makeArraySizeId(const glslang::TArraySizes&, int dim, bool allowZero = false); spv::Id accessChainLoad(const glslang::TType& type); void accessChainStore(const glslang::TType& type, spv::Id rvalue); void multiTypeStore(const glslang::TType&, spv::Id rValue); @@ -206,16 +204,18 @@ protected: spv::Id createBinaryMatrixOperation(spv::Op, OpDecorations&, spv::Id typeId, spv::Id left, spv::Id right); spv::Id createUnaryOperation(glslang::TOperator op, OpDecorations&, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy, - const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, + const glslang::TType &opType); spv::Id createUnaryMatrixOperation(spv::Op op, OpDecorations&, spv::Id typeId, spv::Id operand, glslang::TBasicType typeProxy); spv::Id createConversion(glslang::TOperator op, OpDecorations&, spv::Id destTypeId, spv::Id operand, glslang::TBasicType typeProxy); - spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize); + spv::Id createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType); spv::Id makeSmearedConstant(spv::Id constant, int vectorSize); spv::Id createAtomicOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, - const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags); + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, + const glslang::TType &opType); spv::Id createInvocationsOperation(glslang::TOperator op, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy); spv::Id CreateInvocationsVectorOperation(spv::Op op, spv::GroupOperation groupOperation, @@ -227,6 +227,8 @@ protected: spv::Id createNoArgOperation(glslang::TOperator op, spv::Decoration precision, spv::Id typeId); spv::Id getSymbolId(const glslang::TIntermSymbol* node); void addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier & qualifier); + void addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor); + void addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather); spv::Id createSpvConstant(const glslang::TIntermTyped&); spv::Id createSpvConstantFromConstUnionArray(const glslang::TType& type, const glslang::TConstUnionArray&, int& nextConst, bool specConstant); @@ -260,6 +262,7 @@ protected: std::unordered_map extBuiltinMap; std::unordered_map symbolValues; + std::unordered_map builtInVariableIds; std::unordered_set rValueParameters; // set of formal function parameters passed as rValues, // rather than a pointer std::unordered_map functionMap; @@ -276,9 +279,10 @@ protected: // requiring local translation to and from SPIR-V type on every access. // Maps AST-required-type-id> std::unordered_map forceType; - - // Used later for generating OpTraceKHR/OpExecuteCallableKHR - std::unordered_map locationToSymbol[2]; + // Used by Task shader while generating opearnds for OpEmitMeshTasksEXT + spv::Id taskPayloadID; + // Used later for generating OpTraceKHR/OpExecuteCallableKHR/OpHitObjectRecordHit*/OpHitObjectGetShaderBindingTableData + std::unordered_map locationToSymbol[4]; }; // @@ -288,12 +292,6 @@ protected: // Translate glslang profile to SPIR-V source language. spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile profile) { -#ifdef GLSLANG_WEB - return spv::SourceLanguageESSL; -#elif defined(GLSLANG_ANGLE) - return spv::SourceLanguageGLSL; -#endif - switch (source) { case glslang::EShSourceGlsl: switch (profile) { @@ -314,13 +312,12 @@ spv::SourceLanguage TranslateSourceLanguage(glslang::EShSource source, EProfile } // Translate glslang language (stage) to SPIR-V execution model. -spv::ExecutionModel TranslateExecutionModel(EShLanguage stage) +spv::ExecutionModel TranslateExecutionModel(EShLanguage stage, bool isMeshShaderEXT = false) { switch (stage) { case EShLangVertex: return spv::ExecutionModelVertex; case EShLangFragment: return spv::ExecutionModelFragment; case EShLangCompute: return spv::ExecutionModelGLCompute; -#ifndef GLSLANG_WEB case EShLangTessControl: return spv::ExecutionModelTessellationControl; case EShLangTessEvaluation: return spv::ExecutionModelTessellationEvaluation; case EShLangGeometry: return spv::ExecutionModelGeometry; @@ -330,9 +327,8 @@ spv::ExecutionModel TranslateExecutionModel(EShLanguage stage) case EShLangClosestHit: return spv::ExecutionModelClosestHitKHR; case EShLangMiss: return spv::ExecutionModelMissKHR; case EShLangCallable: return spv::ExecutionModelCallableKHR; - case EShLangTaskNV: return spv::ExecutionModelTaskNV; - case EShLangMeshNV: return spv::ExecutionModelMeshNV; -#endif + case EShLangTask: return (isMeshShaderEXT)? spv::ExecutionModelTaskEXT : spv::ExecutionModelTaskNV; + case EShLangMesh: return (isMeshShaderEXT)? spv::ExecutionModelMeshEXT: spv::ExecutionModelMeshNV; default: assert(0); return spv::ExecutionModelFragment; @@ -350,6 +346,7 @@ spv::Dim TranslateDimensionality(const glslang::TSampler& sampler) case glslang::EsdRect: return spv::DimRect; case glslang::EsdBuffer: return spv::DimBuffer; case glslang::EsdSubpass: return spv::DimSubpassData; + case glslang::EsdAttachmentEXT: return spv::DimTileImageDataEXT; default: assert(0); return spv::Dim2D; @@ -374,26 +371,23 @@ spv::Decoration TranslatePrecisionDecoration(const glslang::TType& type) } // Translate glslang type to SPIR-V block decorations. -spv::Decoration TranslateBlockDecoration(const glslang::TType& type, bool useStorageBuffer) +spv::Decoration TranslateBlockDecoration(const glslang::TStorageQualifier storage, bool useStorageBuffer) { - if (type.getBasicType() == glslang::EbtBlock) { - switch (type.getQualifier().storage) { - case glslang::EvqUniform: return spv::DecorationBlock; - case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; - case glslang::EvqVaryingIn: return spv::DecorationBlock; - case glslang::EvqVaryingOut: return spv::DecorationBlock; - case glslang::EvqShared: return spv::DecorationBlock; -#ifndef GLSLANG_WEB - case glslang::EvqPayload: return spv::DecorationBlock; - case glslang::EvqPayloadIn: return spv::DecorationBlock; - case glslang::EvqHitAttr: return spv::DecorationBlock; - case glslang::EvqCallableData: return spv::DecorationBlock; - case glslang::EvqCallableDataIn: return spv::DecorationBlock; -#endif - default: - assert(0); - break; - } + switch (storage) { + case glslang::EvqUniform: return spv::DecorationBlock; + case glslang::EvqBuffer: return useStorageBuffer ? spv::DecorationBlock : spv::DecorationBufferBlock; + case glslang::EvqVaryingIn: return spv::DecorationBlock; + case glslang::EvqVaryingOut: return spv::DecorationBlock; + case glslang::EvqShared: return spv::DecorationBlock; + case glslang::EvqPayload: return spv::DecorationBlock; + case glslang::EvqPayloadIn: return spv::DecorationBlock; + case glslang::EvqHitAttr: return spv::DecorationBlock; + case glslang::EvqCallableData: return spv::DecorationBlock; + case glslang::EvqCallableDataIn: return spv::DecorationBlock; + case glslang::EvqHitObjectAttrNV: return spv::DecorationBlock; + default: + assert(0); + break; } return spv::DecorationMax; @@ -460,14 +454,13 @@ spv::Decoration TranslateLayoutDecoration(const glslang::TType& type, glslang::T assert(type.getQualifier().layoutPacking == glslang::ElpNone); } return spv::DecorationMax; -#ifndef GLSLANG_WEB case glslang::EvqPayload: case glslang::EvqPayloadIn: case glslang::EvqHitAttr: case glslang::EvqCallableData: case glslang::EvqCallableDataIn: + case glslang::EvqHitObjectAttrNV: return spv::DecorationMax; -#endif default: assert(0); return spv::DecorationMax; @@ -503,14 +496,12 @@ spv::Decoration TGlslangToSpvTraverser::TranslateAuxiliaryStorageDecoration(cons { if (qualifier.centroid) return spv::DecorationCentroid; -#ifndef GLSLANG_WEB else if (qualifier.patch) return spv::DecorationPatch; else if (qualifier.sample) { builder.addCapability(spv::CapabilitySampleRateShading); return spv::DecorationSample; } -#endif return spv::DecorationMax; } @@ -527,24 +518,20 @@ spv::Decoration TranslateInvariantDecoration(const glslang::TQualifier& qualifie // If glslang type is noContraction, return SPIR-V NoContraction decoration. spv::Decoration TranslateNoContractionDecoration(const glslang::TQualifier& qualifier) { -#ifndef GLSLANG_WEB if (qualifier.isNoContraction()) return spv::DecorationNoContraction; else -#endif return spv::DecorationMax; } // If glslang type is nonUniform, return SPIR-V NonUniform decoration. spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glslang::TQualifier& qualifier) { -#ifndef GLSLANG_WEB if (qualifier.isNonUniform()) { builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); builder.addCapability(spv::CapabilityShaderNonUniformEXT); return spv::DecorationNonUniformEXT; } else -#endif return spv::DecorationMax; } @@ -552,13 +539,11 @@ spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration(const glsl spv::Decoration TGlslangToSpvTraverser::TranslateNonUniformDecoration( const spv::Builder::AccessChain::CoherentFlags& coherentFlags) { -#ifndef GLSLANG_WEB if (coherentFlags.isNonUniform()) { builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); builder.addCapability(spv::CapabilityShaderNonUniformEXT); return spv::DecorationNonUniformEXT; } else -#endif return spv::DecorationMax; } @@ -567,7 +552,6 @@ spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( { spv::MemoryAccessMask mask = spv::MemoryAccessMaskNone; -#ifndef GLSLANG_WEB if (!glslangIntermediate->usingVulkanMemoryModel() || coherentFlags.isImage) return mask; @@ -585,7 +569,6 @@ spv::MemoryAccessMask TGlslangToSpvTraverser::TranslateMemoryAccess( if (mask != spv::MemoryAccessMaskNone) { builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } -#endif return mask; } @@ -595,7 +578,6 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( { spv::ImageOperandsMask mask = spv::ImageOperandsMaskNone; -#ifndef GLSLANG_WEB if (!glslangIntermediate->usingVulkanMemoryModel()) return mask; @@ -613,7 +595,6 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( if (mask != spv::ImageOperandsMaskNone) { builder.addCapability(spv::CapabilityVulkanMemoryModelKHR); } -#endif return mask; } @@ -621,7 +602,6 @@ spv::ImageOperandsMask TGlslangToSpvTraverser::TranslateImageOperands( spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCoherent(const glslang::TType& type) { spv::Builder::AccessChain::CoherentFlags flags = {}; -#ifndef GLSLANG_WEB flags.coherent = type.getQualifier().coherent; flags.devicecoherent = type.getQualifier().devicecoherent; flags.queuefamilycoherent = type.getQualifier().queuefamilycoherent; @@ -636,7 +616,6 @@ spv::Builder::AccessChain::CoherentFlags TGlslangToSpvTraverser::TranslateCohere flags.anyCoherent() || flags.volatil; flags.isImage = type.getBasicType() == glslang::EbtSampler; -#endif flags.nonUniform = type.getQualifier().nonUniform; return flags; } @@ -646,7 +625,6 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( { spv::Scope scope = spv::ScopeMax; -#ifndef GLSLANG_WEB if (coherentFlags.volatil || coherentFlags.coherent) { // coherent defaults to Device scope in the old model, QueueFamilyKHR scope in the new model scope = glslangIntermediate->usingVulkanMemoryModel() ? spv::ScopeQueueFamilyKHR : spv::ScopeDevice; @@ -664,7 +642,6 @@ spv::Scope TGlslangToSpvTraverser::TranslateMemoryScope( if (glslangIntermediate->usingVulkanMemoryModel() && scope == spv::ScopeDevice) { builder.addCapability(spv::CapabilityVulkanMemoryModelDeviceScopeKHR); } -#endif return scope; } @@ -679,7 +656,6 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI { switch (builtIn) { case glslang::EbvPointSize: -#ifndef GLSLANG_WEB // Defer adding the capability until the built-in is actually used. if (! memberDeclaration) { switch (glslangIntermediate->getStage()) { @@ -694,7 +670,6 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI break; } } -#endif return spv::BuiltInPointSize; case glslang::EbvPosition: return spv::BuiltInPosition; @@ -715,7 +690,6 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI case glslang::EbvLocalInvocationIndex: return spv::BuiltInLocalInvocationIndex; case glslang::EbvGlobalInvocationId: return spv::BuiltInGlobalInvocationId; -#ifndef GLSLANG_WEB // These *Distance capabilities logically belong here, but if the member is declared and // then never used, consumers of SPIR-V prefer the capability not be declared. // They are now generated when used, rather than here when declared. @@ -762,7 +736,7 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInSampleMask; case glslang::EbvLayer: - if (glslangIntermediate->getStage() == EShLangMeshNV) { + if (glslangIntermediate->getStage() == EShLangMesh) { return spv::BuiltInLayer; } if (glslangIntermediate->getStage() == EShLangGeometry || @@ -1007,6 +981,10 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI return spv::BuiltInRayTminKHR; case glslang::EbvRayTmax: return spv::BuiltInRayTmaxKHR; + case glslang::EbvCullMask: + return spv::BuiltInCullMaskKHR; + case glslang::EbvPositionFetch: + return spv::BuiltInHitTriangleVertexPositionsKHR; case glslang::EbvInstanceCustomIndex: return spv::BuiltInInstanceCustomIndexKHR; case glslang::EbvHitT: @@ -1037,6 +1015,22 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI builder.addExtension(spv::E_SPV_NV_ray_tracing_motion_blur); builder.addCapability(spv::CapabilityRayTracingMotionBlurNV); return spv::BuiltInCurrentRayTimeNV; + case glslang::EbvMicroTrianglePositionNV: + builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV); + builder.addExtension("SPV_NV_displacement_micromap"); + return spv::BuiltInHitMicroTriangleVertexPositionsNV; + case glslang::EbvMicroTriangleBaryNV: + builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV); + builder.addExtension("SPV_NV_displacement_micromap"); + return spv::BuiltInHitMicroTriangleVertexBarycentricsNV; + case glslang::EbvHitKindFrontFacingMicroTriangleNV: + builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV); + builder.addExtension("SPV_NV_displacement_micromap"); + return spv::BuiltInHitKindFrontFacingMicroTriangleNV; + case glslang::EbvHitKindBackFacingMicroTriangleNV: + builder.addCapability(spv::CapabilityRayTracingDisplacementMicromapNV); + builder.addExtension("SPV_NV_displacement_micromap"); + return spv::BuiltInHitKindBackFacingMicroTriangleNV; // barycentrics case glslang::EbvBaryCoordNV: @@ -1048,6 +1042,15 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI builder.addCapability(spv::CapabilityFragmentBarycentricNV); return spv::BuiltInBaryCoordNoPerspNV; + case glslang::EbvBaryCoordEXT: + builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric); + builder.addCapability(spv::CapabilityFragmentBarycentricKHR); + return spv::BuiltInBaryCoordKHR; + case glslang::EbvBaryCoordNoPerspEXT: + builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric); + builder.addCapability(spv::CapabilityFragmentBarycentricKHR); + return spv::BuiltInBaryCoordNoPerspKHR; + // mesh shaders case glslang::EbvTaskCountNV: return spv::BuiltInTaskCountNV; @@ -1066,6 +1069,16 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI case glslang::EbvMeshViewIndicesNV: return spv::BuiltInMeshViewIndicesNV; + // SPV_EXT_mesh_shader + case glslang::EbvPrimitivePointIndicesEXT: + return spv::BuiltInPrimitivePointIndicesEXT; + case glslang::EbvPrimitiveLineIndicesEXT: + return spv::BuiltInPrimitiveLineIndicesEXT; + case glslang::EbvPrimitiveTriangleIndicesEXT: + return spv::BuiltInPrimitiveTriangleIndicesEXT; + case glslang::EbvCullPrimitiveEXT: + return spv::BuiltInCullPrimitiveEXT; + // sm builtins case glslang::EbvWarpsPerSM: builder.addExtension(spv::E_SPV_NV_shader_sm_builtins); @@ -1083,7 +1096,28 @@ spv::BuiltIn TGlslangToSpvTraverser::TranslateBuiltInDecoration(glslang::TBuiltI builder.addExtension(spv::E_SPV_NV_shader_sm_builtins); builder.addCapability(spv::CapabilityShaderSMBuiltinsNV); return spv::BuiltInSMIDNV; -#endif + + // ARM builtins + case glslang::EbvCoreCountARM: + builder.addExtension(spv::E_SPV_ARM_core_builtins); + builder.addCapability(spv::CapabilityCoreBuiltinsARM); + return spv::BuiltInCoreCountARM; + case glslang::EbvCoreIDARM: + builder.addExtension(spv::E_SPV_ARM_core_builtins); + builder.addCapability(spv::CapabilityCoreBuiltinsARM); + return spv::BuiltInCoreIDARM; + case glslang::EbvCoreMaxIDARM: + builder.addExtension(spv::E_SPV_ARM_core_builtins); + builder.addCapability(spv::CapabilityCoreBuiltinsARM); + return spv::BuiltInCoreMaxIDARM; + case glslang::EbvWarpIDARM: + builder.addExtension(spv::E_SPV_ARM_core_builtins); + builder.addCapability(spv::CapabilityCoreBuiltinsARM); + return spv::BuiltInWarpIDARM; + case glslang::EbvWarpMaxIDARM: + builder.addExtension(spv::E_SPV_ARM_core_builtins); + builder.addCapability(spv::CapabilityCoreBuiltinsARM); + return spv::BuiltInWarpMaxIDARM; default: return spv::BuiltInMax; @@ -1095,10 +1129,6 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy { assert(type.getBasicType() == glslang::EbtSampler); -#ifdef GLSLANG_WEB - return spv::ImageFormatUnknown; -#endif - // Check for capabilities switch (type.getQualifier().getFormat()) { case glslang::ElfRg32f: @@ -1136,6 +1166,7 @@ spv::ImageFormat TGlslangToSpvTraverser::TranslateImageFormat(const glslang::TTy case glslang::ElfR64i: builder.addExtension(spv::E_SPV_EXT_shader_image_int64); builder.addCapability(spv::CapabilityInt64ImageEXT); + break; default: break; } @@ -1253,24 +1284,27 @@ spv::LoopControlMask TGlslangToSpvTraverser::TranslateLoopControl(const glslang: // Translate glslang type to SPIR-V storage class. spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::TType& type) { - if (type.getBasicType() == glslang::EbtRayQuery) + if (type.getBasicType() == glslang::EbtRayQuery || type.getBasicType() == glslang::EbtHitObjectNV) return spv::StorageClassPrivate; -#ifndef GLSLANG_WEB if (type.getQualifier().isSpirvByReference()) { if (type.getQualifier().isParamInput() || type.getQualifier().isParamOutput()) return spv::StorageClassFunction; } -#endif if (type.getQualifier().isPipeInput()) return spv::StorageClassInput; if (type.getQualifier().isPipeOutput()) return spv::StorageClassOutput; + if (type.getQualifier().storage == glslang::EvqTileImageEXT || type.isAttachmentEXT()) { + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT); + return spv::StorageClassTileImageEXT; + } if (glslangIntermediate->getSource() != glslang::EShSourceHlsl || type.getQualifier().storage == glslang::EvqUniform) { if (type.isAtomic()) return spv::StorageClassAtomicCounter; - if (type.containsOpaque()) + if (type.containsOpaque() && !glslangIntermediate->getBindlessMode()) return spv::StorageClassUniformConstant; } @@ -1303,14 +1337,14 @@ spv::StorageClass TGlslangToSpvTraverser::TranslateStorageClass(const glslang::T case glslang::EvqConstReadOnly: return spv::StorageClassFunction; case glslang::EvqTemporary: return spv::StorageClassFunction; case glslang::EvqShared: return spv::StorageClassWorkgroup; -#ifndef GLSLANG_WEB case glslang::EvqPayload: return spv::StorageClassRayPayloadKHR; case glslang::EvqPayloadIn: return spv::StorageClassIncomingRayPayloadKHR; case glslang::EvqHitAttr: return spv::StorageClassHitAttributeKHR; case glslang::EvqCallableData: return spv::StorageClassCallableDataKHR; case glslang::EvqCallableDataIn: return spv::StorageClassIncomingCallableDataKHR; + case glslang::EvqtaskPayloadSharedEXT : return spv::StorageClassTaskPayloadWorkgroupEXT; + case glslang::EvqHitObjectAttrNV: return spv::StorageClassHitObjectAttributeNV; case glslang::EvqSpirvStorageClass: return static_cast(type.getQualifier().spirvStorageClass); -#endif default: assert(0); break; @@ -1326,7 +1360,9 @@ void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVectorgetBasicType() == glslang::EbtFloat) { float floatValue = static_cast(constant->getConstArray()[0].getDConst()); - unsigned literal = *reinterpret_cast(&floatValue); + unsigned literal; + static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)"); + memcpy(&literal, &floatValue, sizeof(literal)); literals.push_back(literal); } else if (constant->getBasicType() == glslang::EbtInt) { unsigned literal = constant->getConstArray()[0].getIConst(); @@ -1369,7 +1405,6 @@ void TGlslangToSpvTraverser::TranslateLiterals(const glslang::TVectorgetNanMinMaxClamp()), - nonSemanticDebugPrintf(0) + nonSemanticDebugPrintf(0), + taskPayloadID(0) { - spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage()); + bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) != + glslangIntermediate->getRequestedExtensions().end()); + spv::ExecutionModel executionModel = TranslateExecutionModel(glslangIntermediate->getStage(), isMeshShaderExt); builder.clearAccessChain(); builder.setSource(TranslateSourceLanguage(glslangIntermediate->getSource(), glslangIntermediate->getProfile()), glslangIntermediate->getVersion()); - if (options.generateDebugInfo) { - builder.setEmitOpLines(); - builder.setSourceFile(glslangIntermediate->getSourceFile()); + if (options.emitNonSemanticShaderDebugSource) + this->options.emitNonSemanticShaderDebugInfo = true; + if (options.emitNonSemanticShaderDebugInfo) + this->options.generateDebugInfo = true; + + if (this->options.generateDebugInfo) { + if (this->options.emitNonSemanticShaderDebugInfo) { + builder.setEmitNonSemanticShaderDebugInfo(this->options.emitNonSemanticShaderDebugSource); + } + else { + builder.setEmitSpirvDebugInfo(); + } + builder.setDebugSourceFile(glslangIntermediate->getSourceFile()); // Set the source shader's text. If for SPV version 1.0, include // a preamble in comments stating the OpModuleProcessed instructions. @@ -1545,6 +1592,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, for (auto iItr = include_txt.begin(); iItr != include_txt.end(); ++iItr) builder.addInclude(iItr->first, iItr->second); } + stdBuiltins = builder.import("GLSL.std.450"); spv::AddressingModel addressingModel = spv::AddressingModelLogical; @@ -1566,8 +1614,12 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityVariablePointers); } - shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str()); - entryPoint = builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str()); + // If not linking, there is no entry point + if (!options.compileOnly) { + shaderEntry = builder.makeEntryPoint(glslangIntermediate->getEntryPointName().c_str()); + entryPoint = + builder.addEntryPoint(executionModel, shaderEntry, glslangIntermediate->getEntryPointName().c_str()); + } // Add the source extensions const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); @@ -1585,12 +1637,28 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityRayTraversalPrimitiveCullingKHR); } -#ifndef GLSLANG_WEB if (glslangIntermediate->getSubgroupUniformControlFlow()) { builder.addExtension(spv::E_SPV_KHR_subgroup_uniform_control_flow); builder.addExecutionMode(shaderEntry, spv::ExecutionModeSubgroupUniformControlFlowKHR); } -#endif + if (glslangIntermediate->getMaximallyReconverges()) { + builder.addExtension(spv::E_SPV_KHR_maximal_reconvergence); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeMaximallyReconvergesKHR); + } + + if (glslangIntermediate->getQuadDerivMode()) + { + builder.addCapability(spv::CapabilityQuadControlKHR); + builder.addExtension(spv::E_SPV_KHR_quad_control); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeQuadDerivativesKHR); + } + + if (glslangIntermediate->getReqFullQuadsMode()) + { + builder.addCapability(spv::CapabilityQuadControlKHR); + builder.addExtension(spv::E_SPV_KHR_quad_control); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeRequireFullQuadsKHR); + } unsigned int mode; switch (glslangIntermediate->getStage()) { @@ -1611,16 +1679,41 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, if (glslangIntermediate->getEarlyFragmentTests()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyFragmentTests); + if (glslangIntermediate->getEarlyAndLateFragmentTestsAMD()) + { + builder.addExecutionMode(shaderEntry, spv::ExecutionModeEarlyAndLateFragmentTestsAMD); + builder.addExtension(spv::E_SPV_AMD_shader_early_and_late_fragment_tests); + } + if (glslangIntermediate->getPostDepthCoverage()) { builder.addCapability(spv::CapabilitySampleMaskPostDepthCoverage); builder.addExecutionMode(shaderEntry, spv::ExecutionModePostDepthCoverage); builder.addExtension(spv::E_SPV_KHR_post_depth_coverage); } + if (glslangIntermediate->getNonCoherentColorAttachmentReadEXT()) { + builder.addCapability(spv::CapabilityTileImageColorReadAccessEXT); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentColorAttachmentReadEXT); + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + } + + if (glslangIntermediate->getNonCoherentDepthAttachmentReadEXT()) { + builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentDepthAttachmentReadEXT); + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + } + + if (glslangIntermediate->getNonCoherentStencilAttachmentReadEXT()) { + builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeNonCoherentStencilAttachmentReadEXT); + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + } + if (glslangIntermediate->isDepthReplacing()) builder.addExecutionMode(shaderEntry, spv::ExecutionModeDepthReplacing); -#ifndef GLSLANG_WEB + if (glslangIntermediate->isStencilReplacing()) + builder.addExecutionMode(shaderEntry, spv::ExecutionModeStencilRefReplacingEXT); switch(glslangIntermediate->getDepth()) { case glslang::EldGreater: mode = spv::ExecutionModeDepthGreater; break; @@ -1628,6 +1721,20 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, case glslang::EldUnchanged: mode = spv::ExecutionModeDepthUnchanged; break; default: mode = spv::ExecutionModeMax; break; } + + if (mode != spv::ExecutionModeMax) + builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); + + switch (glslangIntermediate->getStencil()) { + case glslang::ElsRefUnchangedFrontAMD: mode = spv::ExecutionModeStencilRefUnchangedFrontAMD; break; + case glslang::ElsRefGreaterFrontAMD: mode = spv::ExecutionModeStencilRefGreaterFrontAMD; break; + case glslang::ElsRefLessFrontAMD: mode = spv::ExecutionModeStencilRefLessFrontAMD; break; + case glslang::ElsRefUnchangedBackAMD: mode = spv::ExecutionModeStencilRefUnchangedBackAMD; break; + case glslang::ElsRefGreaterBackAMD: mode = spv::ExecutionModeStencilRefGreaterBackAMD; break; + case glslang::ElsRefLessBackAMD: mode = spv::ExecutionModeStencilRefLessBackAMD; break; + default: mode = spv::ExecutionModeMax; break; + } + if (mode != spv::ExecutionModeMax) builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); switch (glslangIntermediate->getInterlockOrdering()) { @@ -1659,26 +1766,33 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, } builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); } -#endif break; - case EShLangCompute: + case EShLangCompute: { builder.addCapability(spv::CapabilityShader); - if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) { - std::vector dimConstId; - for (int dim = 0; dim < 3; ++dim) { - bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet); - dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst)); - if (specConst) { - builder.addDecoration(dimConstId.back(), spv::DecorationSpecId, - glslangIntermediate->getLocalSizeSpecId(dim)); + bool needSizeId = false; + for (int dim = 0; dim < 3; ++dim) { + if ((glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet)) { + needSizeId = true; + break; } - } - builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId); + } + if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && needSizeId) { + std::vector dimConstId; + for (int dim = 0; dim < 3; ++dim) { + bool specConst = (glslangIntermediate->getLocalSizeSpecId(dim) != glslang::TQualifier::layoutNotSet); + dimConstId.push_back(builder.makeUintConstant(glslangIntermediate->getLocalSize(dim), specConst)); + if (specConst) { + builder.addDecoration(dimConstId.back(), spv::DecorationSpecId, + glslangIntermediate->getLocalSizeSpecId(dim)); + needSizeId = true; + } + } + builder.addExecutionModeId(shaderEntry, spv::ExecutionModeLocalSizeId, dimConstId); } else { - builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0), - glslangIntermediate->getLocalSize(1), - glslangIntermediate->getLocalSize(2)); + builder.addExecutionMode(shaderEntry, spv::ExecutionModeLocalSize, glslangIntermediate->getLocalSize(0), + glslangIntermediate->getLocalSize(1), + glslangIntermediate->getLocalSize(2)); } if (glslangIntermediate->getLayoutDerivativeModeNone() == glslang::LayoutDerivativeGroupQuads) { builder.addCapability(spv::CapabilityComputeDerivativeGroupQuadsNV); @@ -1690,7 +1804,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExtension(spv::E_SPV_NV_compute_shader_derivatives); } break; -#ifndef GLSLANG_WEB + } case EShLangTessEvaluation: case EShLangTessControl: builder.addCapability(spv::CapabilityTessellation); @@ -1766,7 +1880,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, case EShLangAnyHit: case EShLangClosestHit: case EShLangMiss: - case EShLangCallable: + case EShLangCallable: { auto& extensions = glslangIntermediate->getRequestedExtensions(); if (extensions.find("GL_NV_ray_tracing") == extensions.end()) { @@ -1777,12 +1891,27 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addCapability(spv::CapabilityRayTracingNV); builder.addExtension("SPV_NV_ray_tracing"); } + if (glslangIntermediate->getStage() != EShLangRayGen && glslangIntermediate->getStage() != EShLangCallable) { + if (extensions.find("GL_EXT_ray_cull_mask") != extensions.end()) { + builder.addCapability(spv::CapabilityRayCullMaskKHR); + builder.addExtension("SPV_KHR_ray_cull_mask"); + } + if (extensions.find("GL_EXT_ray_tracing_position_fetch") != extensions.end()) { + builder.addCapability(spv::CapabilityRayTracingPositionFetchKHR); + builder.addExtension("SPV_KHR_ray_tracing_position_fetch"); + } + } break; } - case EShLangTaskNV: - case EShLangMeshNV: - builder.addCapability(spv::CapabilityMeshShadingNV); - builder.addExtension(spv::E_SPV_NV_mesh_shader); + case EShLangTask: + case EShLangMesh: + if(isMeshShaderExt) { + builder.addCapability(spv::CapabilityMeshShadingEXT); + builder.addExtension(spv::E_SPV_EXT_mesh_shader); + } else { + builder.addCapability(spv::CapabilityMeshShadingNV); + builder.addExtension(spv::E_SPV_NV_mesh_shader); + } if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) { std::vector dimConstId; for (int dim = 0; dim < 3; ++dim) { @@ -1799,7 +1928,7 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, glslangIntermediate->getLocalSize(1), glslangIntermediate->getLocalSize(2)); } - if (glslangIntermediate->getStage() == EShLangMeshNV) { + if (glslangIntermediate->getStage() == EShLangMesh) { builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputVertices, glslangIntermediate->getVertices()); builder.addExecutionMode(shaderEntry, spv::ExecutionModeOutputPrimitivesNV, @@ -1815,13 +1944,11 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExecutionMode(shaderEntry, (spv::ExecutionMode)mode); } break; -#endif default: break; } -#ifndef GLSLANG_WEB // // Add SPIR-V requirements (GL_EXT_spirv_intrinsics) // @@ -1866,27 +1993,29 @@ TGlslangToSpvTraverser::TGlslangToSpvTraverser(unsigned int spvVersion, builder.addExecutionModeId(shaderEntry, static_cast(modeId.first), operandIds); } } -#endif } // Finish creating SPV, after the traversal is complete. -void TGlslangToSpvTraverser::finishSpv() +void TGlslangToSpvTraverser::finishSpv(bool compileOnly) { - // Finish the entry point function - if (! entryPointTerminated) { - builder.setBuildPoint(shaderEntry->getLastBlock()); - builder.leaveFunction(); - } + // If not linking, an entry point is not expected + if (!compileOnly) { + // Finish the entry point function + if (!entryPointTerminated) { + builder.setBuildPoint(shaderEntry->getLastBlock()); + builder.leaveFunction(); + } - // finish off the entry-point SPV instruction by adding the Input/Output - for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it) - entryPoint->addIdOperand(*it); + // finish off the entry-point SPV instruction by adding the Input/Output + for (auto it = iOSet.cbegin(); it != iOSet.cend(); ++it) + entryPoint->addIdOperand(*it); + } // Add capabilities, extensions, remove unneeded decorations, etc., // based on the resulting SPIR-V. // Note: WebGPU code generation must have the opportunity to aggressively // prune unreachable merge blocks and continue targets. - builder.postProcess(); + builder.postProcess(compileOnly); } // Write the SPV into 'out'. @@ -1912,13 +2041,18 @@ void TGlslangToSpvTraverser::dumpSpv(std::vector& out) // void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) { + // We update the line information even though no code might be generated here + // This is helpful to yield correct lines for control flow instructions + if (!linkageOnly) { + builder.setDebugSourceLocation(symbol->getLoc().line, symbol->getLoc().getFilename()); + } + SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (symbol->getType().isStruct()) glslangTypeToIdMap[symbol->getType().getStruct()] = symbol->getId(); if (symbol->getType().getQualifier().isSpecConstant()) spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); - #ifdef ENABLE_HLSL // Skip symbol handling if it is string-typed if (symbol->getBasicType() == glslang::EbtString) @@ -1929,6 +2063,9 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) // Formal function parameters were mapped during makeFunctions(). spv::Id id = getSymbolId(symbol); + if (symbol->getType().getQualifier().isTaskPayload()) + taskPayloadID = id; // cache the taskPayloadID to be used it as operand for OpEmitMeshTasksEXT + if (builder.isPointer(id)) { if (!symbol->getType().getQualifier().isParamInput() && !symbol->getType().getQualifier().isParamOutput()) { @@ -1939,7 +2076,7 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) spv::StorageClass sc = builder.getStorageClass(id); // Before SPIR-V 1.4, we only want to include Input and Output. // Starting with SPIR-V 1.4, we want all globals. - if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalStorage(id)) || + if ((glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4 && builder.isGlobalVariable(id)) || (sc == spv::StorageClassInput || sc == spv::StorageClassOutput)) { iOSet.insert(id); } @@ -2017,7 +2154,7 @@ void TGlslangToSpvTraverser::visitSymbol(glslang::TIntermSymbol* symbol) bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::TIntermBinary* node) { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); if (node->getLeft()->getAsSymbolNode() != nullptr && node->getLeft()->getType().isStruct()) { glslangTypeToIdMap[node->getLeft()->getType().getStruct()] = node->getLeft()->getAsSymbolNode()->getId(); } @@ -2061,6 +2198,9 @@ bool TGlslangToSpvTraverser::visitBinary(glslang::TVisit /* visit */, glslang::T node->getRight()->traverse(this); spv::Id rValue = accessChainLoad(node->getRight()->getType()); + // reset line number for assignment + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); + if (node->getOp() != glslang::EOpAssign) { // the left is also an r-value builder.setAccessChain(lValue); @@ -2392,7 +2532,7 @@ spv::Id TGlslangToSpvTraverser::translateForcedType(spv::Id object) bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TIntermUnary* node) { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); SpecConstantOpModeGuard spec_constant_op_mode_setter(&builder); if (node->getType().getQualifier().isSpecConstant()) @@ -2425,12 +2565,15 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Id length; if (node->getOperand()->getType().isCoopMat()) { - spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); - spv::Id typeId = convertGlslangToSpvType(node->getOperand()->getType()); assert(builder.isCooperativeMatrixType(typeId)); - length = builder.createCooperativeMatrixLength(typeId); + if (node->getOperand()->getType().isCoopMatKHR()) { + length = builder.createCooperativeMatrixLengthKHR(typeId); + } else { + spec_constant_op_mode_setter.turnOnSpecConstantOpMode(); + length = builder.createCooperativeMatrixLengthNV(typeId); + } } else { glslang::TIntermTyped* block = node->getOperand()->getAsBinaryNode()->getLeft(); block->traverse(this); @@ -2456,6 +2599,14 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI return false; } + // Force variable declaration - Debug Mode Only + if (node->getOp() == glslang::EOpDeclare) { + builder.clearAccessChain(); + node->getOperand()->traverse(this); + builder.clearAccessChain(); + return false; + } + // Start by evaluating the operand // Does it need a swizzle inversion? If so, evaluation is inverted; @@ -2472,14 +2623,42 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI operandNode = node->getOperand()->getAsBinaryNode()->getLeft(); else operandNode = node->getOperand(); - + operandNode->traverse(this); spv::Id operand = spv::NoResult; spv::Builder::AccessChain::CoherentFlags lvalueCoherentFlags; -#ifndef GLSLANG_WEB + const auto hitObjectOpsWithLvalue = [](glslang::TOperator op) { + switch(op) { + case glslang::EOpReorderThreadNV: + case glslang::EOpHitObjectGetCurrentTimeNV: + case glslang::EOpHitObjectGetHitKindNV: + case glslang::EOpHitObjectGetPrimitiveIndexNV: + case glslang::EOpHitObjectGetGeometryIndexNV: + case glslang::EOpHitObjectGetInstanceIdNV: + case glslang::EOpHitObjectGetInstanceCustomIndexNV: + case glslang::EOpHitObjectGetObjectRayDirectionNV: + case glslang::EOpHitObjectGetObjectRayOriginNV: + case glslang::EOpHitObjectGetWorldRayDirectionNV: + case glslang::EOpHitObjectGetWorldRayOriginNV: + case glslang::EOpHitObjectGetWorldToObjectNV: + case glslang::EOpHitObjectGetObjectToWorldNV: + case glslang::EOpHitObjectGetRayTMaxNV: + case glslang::EOpHitObjectGetRayTMinNV: + case glslang::EOpHitObjectIsEmptyNV: + case glslang::EOpHitObjectIsHitNV: + case glslang::EOpHitObjectIsMissNV: + case glslang::EOpHitObjectRecordEmptyNV: + case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: + case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: + return true; + default: + return false; + } + }; + if (node->getOp() == glslang::EOpAtomicCounterIncrement || node->getOp() == glslang::EOpAtomicCounterDecrement || node->getOp() == glslang::EOpAtomicCounter || @@ -2493,16 +2672,15 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI node->getOp() == glslang::EOpRayQueryGetIntersectionCandidateAABBOpaque || node->getOp() == glslang::EOpRayQueryTerminate || node->getOp() == glslang::EOpRayQueryConfirmIntersection || - (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference())) { + (node->getOp() == glslang::EOpSpirvInst && operandNode->getAsTyped()->getQualifier().isSpirvByReference()) || + hitObjectOpsWithLvalue(node->getOp())) { operand = builder.accessChainGetLValue(); // Special case l-value operands lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(operandNode->getAsTyped()->getType()); } else if (operandNode->getAsTyped()->getQualifier().isSpirvLiteral()) { // Will be translated to a literal value, make a placeholder here operand = spv::NoResult; - } else -#endif - { + } else { operand = accessChainLoad(node->getOperand()->getType()); } @@ -2518,9 +2696,8 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI // if not, then possibly an operation if (! result) result = createUnaryOperation(node->getOp(), decorations, resultType(), operand, - node->getOperand()->getBasicType(), lvalueCoherentFlags); + node->getOperand()->getBasicType(), lvalueCoherentFlags, node->getType()); -#ifndef GLSLANG_WEB // it could be attached to a SPIR-V intruction if (!result) { if (node->getOp() == glslang::EOpSpirvInst) { @@ -2550,7 +2727,6 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI return false; // done with this node } } -#endif if (result) { if (invertedType) { @@ -2575,7 +2751,6 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI spv::Id one = 0; if (node->getBasicType() == glslang::EbtFloat) one = builder.makeFloatConstant(1.0F); -#ifndef GLSLANG_WEB else if (node->getBasicType() == glslang::EbtDouble) one = builder.makeDoubleConstant(1.0); else if (node->getBasicType() == glslang::EbtFloat16) @@ -2586,7 +2761,6 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI one = builder.makeInt16Constant(1); else if (node->getBasicType() == glslang::EbtInt64 || node->getBasicType() == glslang::EbtUint64) one = builder.makeInt64Constant(1); -#endif else one = builder.makeIntConstant(1); glslang::TOperator op; @@ -2615,7 +2789,11 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI return false; -#ifndef GLSLANG_WEB + case glslang::EOpAssumeEXT: + builder.addCapability(spv::CapabilityExpectAssumeKHR); + builder.addExtension(spv::E_SPV_KHR_expect_assume); + builder.createNoResultOp(spv::OpAssumeTrueKHR, operand); + return false; case glslang::EOpEmitStreamVertex: builder.createNoResultOp(spv::OpEmitStreamVertex, operand); return false; @@ -2628,7 +2806,12 @@ bool TGlslangToSpvTraverser::visitUnary(glslang::TVisit /* visit */, glslang::TI case glslang::EOpRayQueryConfirmIntersection: builder.createNoResultOp(spv::OpRayQueryConfirmIntersectionKHR, operand); return false; -#endif + case glslang::EOpReorderThreadNV: + builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operand); + return false; + case glslang::EOpHitObjectRecordEmptyNV: + builder.createNoResultOp(spv::OpHitObjectRecordEmptyNV, operand); + return false; default: logger->missingFunctionality("unknown glslang unary"); @@ -2693,15 +2876,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.setAccessChainRValue(result); return false; - } -#ifndef GLSLANG_WEB - else if (node->getOp() == glslang::EOpImageStore || + } else if (node->getOp() == glslang::EOpImageStore || node->getOp() == glslang::EOpImageStoreLod || node->getOp() == glslang::EOpImageAtomicStore) { // "imageStore" is a special case, which has no result return false; } -#endif glslang::TOperator binOp = glslang::EOpNull; bool reduceComparison = true; @@ -2716,32 +2896,41 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spv::Decoration precision = TranslatePrecisionDecoration(node->getOperationPrecision()); switch (node->getOp()) { + case glslang::EOpScope: case glslang::EOpSequence: { - if (preVisit) + if (visit == glslang::EvPreVisit) { ++sequenceDepth; - else + if (sequenceDepth == 1) { + // If this is the parent node of all the functions, we want to see them + // early, so all call points have actual SPIR-V functions to reference. + // In all cases, still let the traverser visit the children for us. + makeFunctions(node->getAsAggregate()->getSequence()); + + // Global initializers is specific to the shader entry point, which does not exist in compile-only mode + if (!options.compileOnly) { + // Also, we want all globals initializers to go into the beginning of the entry point, before + // anything else gets there, so visit out of order, doing them all now. + makeGlobalInitializers(node->getAsAggregate()->getSequence()); + } + + //Pre process linker objects for ray tracing stages + if (glslangIntermediate->isRayTracingStage()) + collectRayTracingLinkerObjects(); + + // Initializers are done, don't want to visit again, but functions and link objects need to be processed, + // so do them manually. + visitFunctions(node->getAsAggregate()->getSequence()); + + return false; + } else { + if (node->getOp() == glslang::EOpScope) + builder.enterLexicalBlock(0); + } + } else { + if (sequenceDepth > 1 && node->getOp() == glslang::EOpScope) + builder.leaveLexicalBlock(); --sequenceDepth; - - if (sequenceDepth == 1) { - // If this is the parent node of all the functions, we want to see them - // early, so all call points have actual SPIR-V functions to reference. - // In all cases, still let the traverser visit the children for us. - makeFunctions(node->getAsAggregate()->getSequence()); - - // Also, we want all globals initializers to go into the beginning of the entry point, before - // anything else gets there, so visit out of order, doing them all now. - makeGlobalInitializers(node->getAsAggregate()->getSequence()); - - //Pre process linker objects for ray tracing stages - if (glslangIntermediate->isRayTracingStage()) - collectRayTracingLinkerObjects(); - - // Initializers are done, don't want to visit again, but functions and link objects need to be processed, - // so do them manually. - visitFunctions(node->getAsAggregate()->getSequence()); - - return false; } return true; @@ -2767,13 +2956,23 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt } case glslang::EOpFunction: if (visit == glslang::EvPreVisit) { + if (options.generateDebugInfo) { + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); + } if (isShaderEntryPoint(node)) { inEntryPoint = true; builder.setBuildPoint(shaderEntry->getLastBlock()); + builder.enterFunction(shaderEntry); currentFunction = shaderEntry; } else { handleFunctionEntry(node); } + if (options.generateDebugInfo && !options.emitNonSemanticShaderDebugInfo) { + const auto& loc = node->getLoc(); + const char* sourceFileName = loc.getFilename(); + spv::Id sourceFileId = sourceFileName ? builder.getStringId(sourceFileName) : builder.getMainFileId(); + currentFunction->setDebugLineInfo(sourceFileId, loc.line, loc.column); + } } else { if (inEntryPoint) entryPointTerminated = true; @@ -2789,7 +2988,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt return false; case glslang::EOpFunctionCall: { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); if (node->isUserDefined()) result = handleUserFunctionCall(node); if (result) { @@ -2855,7 +3054,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructF16Mat4x3: case glslang::EOpConstructF16Mat4x4: isMatrix = true; - // fall through + [[fallthrough]]; case glslang::EOpConstructFloat: case glslang::EOpConstructVec2: case glslang::EOpConstructVec3: @@ -2907,16 +3106,26 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpConstructStruct: case glslang::EOpConstructTextureSampler: case glslang::EOpConstructReference: - case glslang::EOpConstructCooperativeMatrix: + case glslang::EOpConstructCooperativeMatrixNV: + case glslang::EOpConstructCooperativeMatrixKHR: { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); std::vector arguments; translateArguments(*node, arguments, lvalueCoherentFlags); spv::Id constructed; - if (node->getOp() == glslang::EOpConstructTextureSampler) - constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments); - else if (node->getOp() == glslang::EOpConstructStruct || - node->getOp() == glslang::EOpConstructCooperativeMatrix || + if (node->getOp() == glslang::EOpConstructTextureSampler) { + const glslang::TType& texType = node->getSequence()[0]->getAsTyped()->getType(); + if (glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6 && + texType.getSampler().isBuffer()) { + // SamplerBuffer is not supported in spirv1.6 so + // `samplerBuffer(textureBuffer, sampler)` is a no-op + // and textureBuffer is the result going forward + constructed = arguments[0]; + } else + constructed = builder.createOp(spv::OpSampledImage, resultType(), arguments); + } else if (node->getOp() == glslang::EOpConstructStruct || + node->getOp() == glslang::EOpConstructCooperativeMatrixNV || + node->getOp() == glslang::EOpConstructCooperativeMatrixKHR || node->getType().isArray()) { std::vector constituents; for (int c = 0; c < (int)arguments.size(); ++c) @@ -3014,10 +3223,9 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt atomic = true; break; -#ifndef GLSLANG_WEB case glslang::EOpAtomicStore: noReturnValue = true; - // fallthrough + [[fallthrough]]; case glslang::EOpAtomicLoad: atomic = true; break; @@ -3047,6 +3255,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt binOp = node->getOp(); break; + case glslang::EOpExpectEXT: + builder.addCapability(spv::CapabilityExpectAssumeKHR); + builder.addExtension(spv::E_SPV_KHR_expect_assume); + binOp = node->getOp(); + break; + case glslang::EOpIgnoreIntersectionNV: case glslang::EOpTerminateRayNV: case glslang::EOpTraceNV: @@ -3055,6 +3269,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt case glslang::EOpExecuteCallableNV: case glslang::EOpExecuteCallableKHR: case glslang::EOpWritePackedPrimitiveIndices4x8NV: + case glslang::EOpEmitMeshTasksEXT: + case glslang::EOpSetMeshOutputsEXT: noReturnValue = true; break; case glslang::EOpRayQueryInitialize: @@ -3089,6 +3305,8 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case glslang::EOpCooperativeMatrixLoad: case glslang::EOpCooperativeMatrixStore: + case glslang::EOpCooperativeMatrixLoadNV: + case glslang::EOpCooperativeMatrixStoreNV: noReturnValue = true; break; case glslang::EOpBeginInvocationInterlock: @@ -3096,7 +3314,82 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt builder.addExtension(spv::E_SPV_EXT_fragment_shader_interlock); noReturnValue = true; break; -#endif + + case glslang::EOpHitObjectTraceRayNV: + case glslang::EOpHitObjectTraceRayMotionNV: + case glslang::EOpHitObjectGetAttributesNV: + case glslang::EOpHitObjectExecuteShaderNV: + case glslang::EOpHitObjectRecordEmptyNV: + case glslang::EOpHitObjectRecordMissNV: + case glslang::EOpHitObjectRecordMissMotionNV: + case glslang::EOpHitObjectRecordHitNV: + case glslang::EOpHitObjectRecordHitMotionNV: + case glslang::EOpHitObjectRecordHitWithIndexNV: + case glslang::EOpHitObjectRecordHitWithIndexMotionNV: + case glslang::EOpReorderThreadNV: + noReturnValue = true; + [[fallthrough]]; + case glslang::EOpHitObjectIsEmptyNV: + case glslang::EOpHitObjectIsMissNV: + case glslang::EOpHitObjectIsHitNV: + case glslang::EOpHitObjectGetRayTMinNV: + case glslang::EOpHitObjectGetRayTMaxNV: + case glslang::EOpHitObjectGetObjectRayOriginNV: + case glslang::EOpHitObjectGetObjectRayDirectionNV: + case glslang::EOpHitObjectGetWorldRayOriginNV: + case glslang::EOpHitObjectGetWorldRayDirectionNV: + case glslang::EOpHitObjectGetObjectToWorldNV: + case glslang::EOpHitObjectGetWorldToObjectNV: + case glslang::EOpHitObjectGetInstanceCustomIndexNV: + case glslang::EOpHitObjectGetInstanceIdNV: + case glslang::EOpHitObjectGetGeometryIndexNV: + case glslang::EOpHitObjectGetPrimitiveIndexNV: + case glslang::EOpHitObjectGetHitKindNV: + case glslang::EOpHitObjectGetCurrentTimeNV: + case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: + case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: + builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder); + builder.addCapability(spv::CapabilityShaderInvocationReorderNV); + break; + case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: + builder.addExtension(spv::E_SPV_KHR_ray_tracing_position_fetch); + builder.addCapability(spv::CapabilityRayQueryPositionFetchKHR); + noReturnValue = true; + break; + + case glslang::EOpImageSampleWeightedQCOM: + builder.addCapability(spv::CapabilityTextureSampleWeightedQCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing); + break; + case glslang::EOpImageBoxFilterQCOM: + builder.addCapability(spv::CapabilityTextureBoxFilterQCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing); + break; + case glslang::EOpImageBlockMatchSADQCOM: + case glslang::EOpImageBlockMatchSSDQCOM: + builder.addCapability(spv::CapabilityTextureBlockMatchQCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing); + break; + + case glslang::EOpImageBlockMatchWindowSSDQCOM: + case glslang::EOpImageBlockMatchWindowSADQCOM: + builder.addCapability(spv::CapabilityTextureBlockMatchQCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing); + builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing2); + break; + + case glslang::EOpImageBlockMatchGatherSSDQCOM: + case glslang::EOpImageBlockMatchGatherSADQCOM: + builder.addCapability(spv::CapabilityTextureBlockMatch2QCOM); + builder.addExtension(spv::E_SPV_QCOM_image_processing2); + break; + + case glslang::EOpFetchMicroTriangleVertexPositionNV: + case glslang::EOpFetchMicroTriangleVertexBarycentricNV: + builder.addExtension(spv::E_SPV_NV_displacement_micromap); + builder.addCapability(spv::CapabilityDisplacementMicromapNV); + break; case glslang::EOpDebugPrintf: noReturnValue = true; @@ -3122,7 +3415,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt right->traverse(this); spv::Id rightId = accessChainLoad(right->getType()); - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); OpDecorations decorations = { precision, TranslateNoContractionDecoration(node->getType().getQualifier()), TranslateNonUniformDecoration(node->getType().getQualifier()) }; @@ -3153,6 +3446,22 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; + + + case glslang::EOpHitObjectRecordHitNV: + case glslang::EOpHitObjectRecordHitMotionNV: + case glslang::EOpHitObjectRecordHitWithIndexNV: + case glslang::EOpHitObjectRecordHitWithIndexMotionNV: + case glslang::EOpHitObjectTraceRayNV: + case glslang::EOpHitObjectTraceRayMotionNV: + case glslang::EOpHitObjectExecuteShaderNV: + case glslang::EOpHitObjectRecordMissNV: + case glslang::EOpHitObjectRecordMissMotionNV: + case glslang::EOpHitObjectGetAttributesNV: + if (arg == 0) + lvalue = true; + break; + case glslang::EOpRayQueryInitialize: case glslang::EOpRayQueryTerminate: case glslang::EOpRayQueryConfirmIntersection: @@ -3188,7 +3497,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; -#ifndef GLSLANG_WEB case glslang::EOpFrexp: if (arg == 1) lvalue = true; @@ -3242,10 +3550,12 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalue = true; break; case glslang::EOpCooperativeMatrixLoad: + case glslang::EOpCooperativeMatrixLoadNV: if (arg == 0 || arg == 1) lvalue = true; break; case glslang::EOpCooperativeMatrixStore: + case glslang::EOpCooperativeMatrixStoreNV: if (arg == 1) lvalue = true; break; @@ -3253,7 +3563,15 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvByReference()) lvalue = true; break; -#endif + case glslang::EOpReorderThreadNV: + //Three variants of reorderThreadNV, two of them use hitObjectNV + if (arg == 0 && glslangOperands.size() != 2) + lvalue = true; + break; + case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: + if (arg == 0 || arg == 2) + lvalue = true; + break; default: break; } @@ -3263,9 +3581,10 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt else glslangOperands[arg]->traverse(this); -#ifndef GLSLANG_WEB if (node->getOp() == glslang::EOpCooperativeMatrixLoad || - node->getOp() == glslang::EOpCooperativeMatrixStore) { + node->getOp() == glslang::EOpCooperativeMatrixStore || + node->getOp() == glslang::EOpCooperativeMatrixLoadNV || + node->getOp() == glslang::EOpCooperativeMatrixStoreNV) { if (arg == 1) { // fold "element" parameter into the access chain @@ -3286,9 +3605,11 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt unsigned int alignment = builder.getAccessChain().alignment; int memoryAccess = TranslateMemoryAccess(coherentFlags); - if (node->getOp() == glslang::EOpCooperativeMatrixLoad) + if (node->getOp() == glslang::EOpCooperativeMatrixLoad || + node->getOp() == glslang::EOpCooperativeMatrixLoadNV) memoryAccess &= ~spv::MemoryAccessMakePointerAvailableKHRMask; - if (node->getOp() == glslang::EOpCooperativeMatrixStore) + if (node->getOp() == glslang::EOpCooperativeMatrixStore || + node->getOp() == glslang::EOpCooperativeMatrixStoreNV) memoryAccess &= ~spv::MemoryAccessMakePointerVisibleKHRMask; if (builder.getStorageClass(builder.getAccessChain().base) == spv::StorageClassPhysicalStorageBufferEXT) { @@ -3310,7 +3631,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt continue; } } -#endif // for l-values, pass the address, for r-values, pass the value if (lvalue) { @@ -3330,7 +3650,7 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt lvalueCoherentFlags = builder.getAccessChain().coherentFlags; lvalueCoherentFlags |= TranslateCoherent(glslangOperands[arg]->getAsTyped()->getType()); } else { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); glslang::TOperator glslangOp = node->getOp(); if (arg == 1 && (glslangOp == glslang::EOpRayQueryGetIntersectionType || @@ -3345,69 +3665,135 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayDirection || glslangOp == glslang::EOpRayQueryGetIntersectionObjectRayOrigin || glslangOp == glslang::EOpRayQueryGetIntersectionObjectToWorld || - glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject + glslangOp == glslang::EOpRayQueryGetIntersectionWorldToObject || + glslangOp == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT )) { bool cond = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getBConst(); operands.push_back(builder.makeIntConstant(cond ? 1 : 0)); } else if ((arg == 10 && glslangOp == glslang::EOpTraceKHR) || (arg == 11 && glslangOp == glslang::EOpTraceRayMotionNV) || - (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR)) { - const int opdNum = glslangOp == glslang::EOpTraceKHR ? 10 : (glslangOp == glslang::EOpTraceRayMotionNV ? 11 : 1); + (arg == 1 && glslangOp == glslang::EOpExecuteCallableKHR) || + (arg == 1 && glslangOp == glslang::EOpHitObjectExecuteShaderNV) || + (arg == 11 && glslangOp == glslang::EOpHitObjectTraceRayNV) || + (arg == 12 && glslangOp == glslang::EOpHitObjectTraceRayMotionNV)) { const int set = glslangOp == glslang::EOpExecuteCallableKHR ? 1 : 0; - - const int location = glslangOperands[opdNum]->getAsConstantUnion()->getConstArray()[0].getUConst(); + const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst(); + auto itNode = locationToSymbol[set].find(location); + visitSymbol(itNode->second); + spv::Id symId = getSymbolId(itNode->second); + operands.push_back(symId); + } else if ((arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitNV) || + (arg == 13 && glslangOp == glslang::EOpHitObjectRecordHitMotionNV) || + (arg == 11 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexNV) || + (arg == 12 && glslangOp == glslang::EOpHitObjectRecordHitWithIndexMotionNV) || + (arg == 1 && glslangOp == glslang::EOpHitObjectGetAttributesNV)) { + const int location = glslangOperands[arg]->getAsConstantUnion()->getConstArray()[0].getUConst(); + const int set = 2; auto itNode = locationToSymbol[set].find(location); visitSymbol(itNode->second); spv::Id symId = getSymbolId(itNode->second); operands.push_back(symId); -#ifndef GLSLANG_WEB } else if (glslangOperands[arg]->getAsTyped()->getQualifier().isSpirvLiteral()) { // Will be translated to a literal value, make a placeholder here operands.push_back(spv::NoResult); -#endif } else { operands.push_back(accessChainLoad(glslangOperands[arg]->getAsTyped()->getType())); } } } - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); -#ifndef GLSLANG_WEB - if (node->getOp() == glslang::EOpCooperativeMatrixLoad) { + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); + if (node->getOp() == glslang::EOpCooperativeMatrixLoad || + node->getOp() == glslang::EOpCooperativeMatrixLoadNV) { std::vector idImmOps; idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor + if (node->getOp() == glslang::EOpCooperativeMatrixLoad) { + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + } else { + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor + } idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); // get the pointee type spv::Id typeId = builder.getContainedTypeId(builder.getTypeId(operands[0])); assert(builder.isCooperativeMatrixType(typeId)); // do the op - spv::Id result = builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps); + spv::Id result = node->getOp() == glslang::EOpCooperativeMatrixLoad + ? builder.createOp(spv::OpCooperativeMatrixLoadKHR, typeId, idImmOps) + : builder.createOp(spv::OpCooperativeMatrixLoadNV, typeId, idImmOps); // store the result to the pointer (out param 'm') builder.createStore(result, operands[0]); result = 0; - } else if (node->getOp() == glslang::EOpCooperativeMatrixStore) { + } else if (node->getOp() == glslang::EOpCooperativeMatrixStore || + node->getOp() == glslang::EOpCooperativeMatrixStoreNV) { std::vector idImmOps; idImmOps.push_back(spv::IdImmediate(true, operands[1])); // buf idImmOps.push_back(spv::IdImmediate(true, operands[0])); // object - idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride - idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor + if (node->getOp() == glslang::EOpCooperativeMatrixStore) { + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // matrixLayout + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + } else { + idImmOps.push_back(spv::IdImmediate(true, operands[2])); // stride + idImmOps.push_back(spv::IdImmediate(true, operands[3])); // colMajor + } idImmOps.insert(idImmOps.end(), memoryAccessOperands.begin(), memoryAccessOperands.end()); - builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps); + if (node->getOp() == glslang::EOpCooperativeMatrixStore) + builder.createNoResultOp(spv::OpCooperativeMatrixStoreKHR, idImmOps); + else + builder.createNoResultOp(spv::OpCooperativeMatrixStoreNV, idImmOps); result = 0; - } else -#endif - if (atomic) { + } else if (node->getOp() == glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT) { + std::vector idImmOps; + + idImmOps.push_back(spv::IdImmediate(true, operands[0])); // q + idImmOps.push_back(spv::IdImmediate(true, operands[1])); // committed + + spv::Id typeId = builder.makeArrayType(builder.makeVectorType(builder.makeFloatType(32), 3), + builder.makeUintConstant(3), 0); + // do the op + + spv::Op spvOp = spv::OpRayQueryGetIntersectionTriangleVertexPositionsKHR; + + spv::Id result = builder.createOp(spvOp, typeId, idImmOps); + // store the result to the pointer (out param 'm') + builder.createStore(result, operands[2]); + result = 0; + } else if (node->getOp() == glslang::EOpCooperativeMatrixMulAdd) { + uint32_t matrixOperands = 0; + + // If the optional operand is present, initialize matrixOperands to that value. + if (glslangOperands.size() == 4 && glslangOperands[3]->getAsConstantUnion()) { + matrixOperands = glslangOperands[3]->getAsConstantUnion()->getConstArray()[0].getIConst(); + } + + // Determine Cooperative Matrix Operands bits from the signedness of the types. + if (isTypeSignedInt(glslangOperands[0]->getAsTyped()->getBasicType())) + matrixOperands |= spv::CooperativeMatrixOperandsMatrixASignedComponentsKHRMask; + if (isTypeSignedInt(glslangOperands[1]->getAsTyped()->getBasicType())) + matrixOperands |= spv::CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask; + if (isTypeSignedInt(glslangOperands[2]->getAsTyped()->getBasicType())) + matrixOperands |= spv::CooperativeMatrixOperandsMatrixCSignedComponentsKHRMask; + if (isTypeSignedInt(node->getBasicType())) + matrixOperands |= spv::CooperativeMatrixOperandsMatrixResultSignedComponentsKHRMask; + + std::vector idImmOps; + idImmOps.push_back(spv::IdImmediate(true, operands[0])); + idImmOps.push_back(spv::IdImmediate(true, operands[1])); + idImmOps.push_back(spv::IdImmediate(true, operands[2])); + if (matrixOperands != 0) + idImmOps.push_back(spv::IdImmediate(false, matrixOperands)); + + result = builder.createOp(spv::OpCooperativeMatrixMulAddKHR, resultType(), idImmOps); + } else if (atomic) { // Handle all atomics glslang::TBasicType typeProxy = (node->getOp() == glslang::EOpAtomicStore) ? node->getSequence()[0]->getAsTyped()->getBasicType() : node->getBasicType(); result = createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy, - lvalueCoherentFlags); -#ifndef GLSLANG_WEB + lvalueCoherentFlags, node->getType()); } else if (node->getOp() == glslang::EOpSpirvInst) { const auto& spirvInst = node->getSpirvInstruction(); if (spirvInst.set == "") { @@ -3434,7 +3820,6 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt spirvInst.id, operands); } noReturnValue = node->getBasicType() == glslang::EbtVoid; -#endif } else if (node->getOp() == glslang::EOpDebugPrintf) { if (!nonSemanticDebugPrintf) { nonSemanticDebugPrintf = builder.import("NonSemantic.DebugPrintf"); @@ -3449,13 +3834,13 @@ bool TGlslangToSpvTraverser::visitAggregate(glslang::TVisit visit, glslang::TInt break; case 1: { - OpDecorations decorations = { precision, + OpDecorations decorations = { precision, TranslateNoContractionDecoration(node->getType().getQualifier()), TranslateNonUniformDecoration(node->getType().getQualifier()) }; result = createUnaryOperation( node->getOp(), decorations, resultType(), operands.front(), - glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags); + glslangOperands[0]->getAsTyped()->getBasicType(), lvalueCoherentFlags, node->getType()); } break; default: @@ -3551,35 +3936,44 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // Find a way of executing both sides and selecting the right result. const auto executeBothSides = [&]() -> void { // execute both sides + spv::Id resultType = convertGlslangToSpvType(node->getType()); node->getTrueBlock()->traverse(this); spv::Id trueValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); node->getFalseBlock()->traverse(this); - spv::Id falseValue = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); + spv::Id falseValue = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()); - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); // done if void if (node->getBasicType() == glslang::EbtVoid) return; // emit code to select between trueValue and falseValue - - // see if OpSelect can handle it + // see if OpSelect can handle the result type, and that the SPIR-V types + // of the inputs match the result type. if (isOpSelectable()) { // Emit OpSelect for this selection. // smear condition to vector, if necessary (AST is always scalar) // Before 1.4, smear like for mix(), starting with 1.4, keep it scalar if (glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_4 && builder.isVector(trueValue)) { - condition = builder.smearScalar(spv::NoPrecision, condition, + condition = builder.smearScalar(spv::NoPrecision, condition, builder.makeVectorType(builder.makeBoolType(), builder.getNumComponents(trueValue))); } + // If the types do not match, it is because of mismatched decorations on aggregates. + // Since isOpSelectable only lets us get here for SPIR-V >= 1.4, we can use OpCopyObject + // to get matching types. + if (builder.getTypeId(trueValue) != resultType) { + trueValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, trueValue); + } + if (builder.getTypeId(falseValue) != resultType) { + falseValue = builder.createUnaryOp(spv::OpCopyLogical, resultType, falseValue); + } + // OpSelect - result = builder.createTriOp(spv::OpSelect, - convertGlslangToSpvType(node->getType()), condition, - trueValue, falseValue); + result = builder.createTriOp(spv::OpSelect, resultType, condition, trueValue, falseValue); builder.clearAccessChain(); builder.setAccessChainRValue(result); @@ -3587,7 +3981,7 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // We need control flow to select the result. // TODO: Once SPIR-V OpSelect allows arbitrary types, eliminate this path. result = builder.createVariable(TranslatePrecisionDecoration(node->getType()), - spv::StorageClassFunction, convertGlslangToSpvType(node->getType())); + spv::StorageClassFunction, resultType); // Selection control: const spv::SelectionControlMask control = TranslateSelectionControl(*node); @@ -3596,10 +3990,15 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang spv::Builder::If ifBuilder(condition, control, builder); // emit the "then" statement - builder.createStore(trueValue, result); + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + multiTypeStore(node->getType(), trueValue); + ifBuilder.makeBeginElse(); // emit the "else" statement - builder.createStore(falseValue, result); + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + multiTypeStore(node->getType(), falseValue); // finish off the control flow ifBuilder.makeEndIf(); @@ -3626,16 +4025,26 @@ bool TGlslangToSpvTraverser::visitSelection(glslang::TVisit /* visit */, glslang // emit the "then" statement if (node->getTrueBlock() != nullptr) { node->getTrueBlock()->traverse(this); - if (result != spv::NoResult) - builder.createStore(accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()), result); + if (result != spv::NoResult) { + spv::Id load = accessChainLoad(node->getTrueBlock()->getAsTyped()->getType()); + + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + multiTypeStore(node->getType(), load); + } } if (node->getFalseBlock() != nullptr) { ifBuilder.makeBeginElse(); // emit the "else" statement node->getFalseBlock()->traverse(this); - if (result != spv::NoResult) - builder.createStore(accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()), result); + if (result != spv::NoResult) { + spv::Id load = accessChainLoad(node->getFalseBlock()->getAsTyped()->getType()); + + builder.clearAccessChain(); + builder.setAccessChainLValue(result); + multiTypeStore(node->getType(), load); + } } // finish off the control flow @@ -3715,10 +4124,8 @@ bool TGlslangToSpvTraverser::visitSwitch(glslang::TVisit /* visit */, glslang::T void TGlslangToSpvTraverser::visitConstantUnion(glslang::TIntermConstantUnion* node) { -#ifndef GLSLANG_WEB if (node->getQualifier().isSpirvLiteral()) return; // Translated to a literal value, skip further processing -#endif int nextConst = 0; spv::Id constant = createSpvConstantFromConstUnionArray(node->getType(), node->getConstArray(), nextConst, false); @@ -3742,8 +4149,8 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn // by a block-ending branch. But we don't want to put any other body/test // instructions in it, since the body/test may have arbitrary instructions, // including merges of its own. - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); builder.setBuildPoint(&blocks.head); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); builder.createLoopMerge(&blocks.merge, &blocks.continue_target, control, operands); if (node->testFirst() && node->getTest()) { spv::Block& test = builder.makeNewBlock(); @@ -3766,7 +4173,7 @@ bool TGlslangToSpvTraverser::visitLoop(glslang::TVisit /* visit */, glslang::TIn node->getTerminal()->traverse(this); builder.createBranch(&blocks.head); } else { - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); builder.createBranch(&blocks.body); breakForLoop.push(true); @@ -3801,7 +4208,7 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T if (node->getExpression()) node->getExpression()->traverse(this); - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); switch (node->getFlowOp()) { case glslang::EOpKill: @@ -3849,7 +4256,6 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T builder.clearAccessChain(); break; -#ifndef GLSLANG_WEB case glslang::EOpDemote: builder.createNoResultOp(spv::OpDemoteToHelperInvocationEXT); builder.addExtension(spv::E_SPV_EXT_demote_to_helper_invocation); @@ -3861,7 +4267,6 @@ bool TGlslangToSpvTraverser::visitBranch(glslang::TVisit /* visit */, glslang::T case glslang::EOpIgnoreIntersectionKHR: builder.makeStatementTerminator(spv::OpIgnoreIntersectionKHR, "post-ignoreIntersectionKHR"); break; -#endif default: assert(0); @@ -3903,7 +4308,6 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* else builder.addCapability(spv::CapabilityStorageUniform16); break; -#ifndef GLSLANG_WEB case spv::StorageClassPushConstant: builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3); builder.addCapability(spv::CapabilityStoragePushConstant16); @@ -3913,7 +4317,6 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* builder.addIncorporatedExtension(spv::E_SPV_KHR_16bit_storage, spv::Spv_1_3); builder.addCapability(spv::CapabilityStorageUniformBufferBlock16); break; -#endif default: if (storageClass == spv::StorageClassWorkgroup && node->getType().getBasicType() == glslang::EbtBlock) { @@ -3962,7 +4365,7 @@ spv::Id TGlslangToSpvTraverser::createSpvVariable(const glslang::TIntermSymbol* initializer = builder.makeNullConstant(spvType); } - return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer); + return builder.createVariable(spv::NoPrecision, storageClass, spvType, name, initializer, false); } // Return type Id of the sampled type. @@ -3972,7 +4375,6 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) case glslang::EbtInt: return builder.makeIntType(32); case glslang::EbtUint: return builder.makeUintType(32); case glslang::EbtFloat: return builder.makeFloatType(32); -#ifndef GLSLANG_WEB case glslang::EbtFloat16: builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float_fetch); builder.addCapability(spv::CapabilityFloat16ImageAMD); @@ -3985,7 +4387,6 @@ spv::Id TGlslangToSpvTraverser::getSampledType(const glslang::TSampler& sampler) builder.addExtension(spv::E_SPV_EXT_shader_image_int64); builder.addCapability(spv::CapabilityInt64ImageEXT); return builder.makeUintType(64); -#endif default: assert(0); return builder.makeFloatType(32); @@ -4030,6 +4431,16 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty return convertGlslangToSpvType(type, getExplicitLayout(type), type.getQualifier(), false, forwardReferenceOnly); } +spv::LinkageType TGlslangToSpvTraverser::convertGlslangLinkageToSpv(glslang::TLinkType linkType) +{ + switch (linkType) { + case glslang::ELinkExport: + return spv::LinkageTypeExport; + default: + return spv::LinkageTypeMax; + } +} + // Do full recursive conversion of an arbitrary glslang type to a SPIR-V Id. // explicitLayout can be kept the same throughout the hierarchical recursive walk. // Mutually recursive with convertGlslangStructToSpvType(). @@ -4061,7 +4472,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtFloat: spvType = builder.makeFloatType(32); break; -#ifndef GLSLANG_WEB case glslang::EbtDouble: spvType = builder.makeFloatType(64); break; @@ -4139,7 +4549,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty } } break; -#endif case glslang::EbtSampler: { const glslang::TSampler& sampler = type.getSampler(); @@ -4150,8 +4559,10 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty spvType = builder.makeImageType(getSampledType(sampler), TranslateDimensionality(sampler), sampler.isShadow(), sampler.isArrayed(), sampler.isMultiSample(), sampler.isImageClass() ? 2 : 1, TranslateImageFormat(type)); - if (sampler.isCombined()) { - // already has both image and sampler, make the combined type + if (sampler.isCombined() && + (!sampler.isBuffer() || glslangIntermediate->getSpv().spv < glslang::EShTargetSpv_1_6)) { + // Already has both image and sampler, make the combined type. Only combine sampler to + // buffer if before SPIR-V 1.6. spvType = builder.makeSampledImageType(spvType); } } @@ -4179,7 +4590,13 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty case glslang::EbtString: // no type used for OpString return 0; -#ifndef GLSLANG_WEB + + case glslang::EbtHitObjectNV: { + builder.addExtension(spv::E_SPV_NV_shader_invocation_reorder); + builder.addCapability(spv::CapabilityShaderInvocationReorderNV); + spvType = builder.makeHitObjectNVType(); + } + break; case glslang::EbtSpirvType: { // GL_EXT_spirv_intrinsics const auto& spirvType = type.getSpirvType(); @@ -4187,48 +4604,57 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty std::vector operands; for (const auto& typeParam : spirvType.typeParams) { - // Constant expression - if (typeParam.constant->isLiteral()) { - if (typeParam.constant->getBasicType() == glslang::EbtFloat) { - float floatValue = static_cast(typeParam.constant->getConstArray()[0].getDConst()); - unsigned literal = *reinterpret_cast(&floatValue); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtInt) { - unsigned literal = typeParam.constant->getConstArray()[0].getIConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtUint) { - unsigned literal = typeParam.constant->getConstArray()[0].getUConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtBool) { - unsigned literal = typeParam.constant->getConstArray()[0].getBConst(); - operands.push_back({false, literal}); - } else if (typeParam.constant->getBasicType() == glslang::EbtString) { - auto str = typeParam.constant->getConstArray()[0].getSConst()->c_str(); - unsigned literal = 0; - char* literalPtr = reinterpret_cast(&literal); - unsigned charCount = 0; - char ch = 0; - do { - ch = *(str++); - *(literalPtr++) = ch; - ++charCount; - if (charCount == 4) { - operands.push_back({false, literal}); - literalPtr = reinterpret_cast(&literal); - charCount = 0; - } - } while (ch != 0); - - // Partial literal is padded with 0 - if (charCount > 0) { - for (; charCount < 4; ++charCount) - *(literalPtr++) = 0; + if (typeParam.getAsConstant() != nullptr) { + // Constant expression + auto constant = typeParam.getAsConstant(); + if (constant->isLiteral()) { + if (constant->getBasicType() == glslang::EbtFloat) { + float floatValue = static_cast(constant->getConstArray()[0].getDConst()); + unsigned literal; + static_assert(sizeof(literal) == sizeof(floatValue), "sizeof(unsigned) != sizeof(float)"); + memcpy(&literal, &floatValue, sizeof(literal)); operands.push_back({false, literal}); - } + } else if (constant->getBasicType() == glslang::EbtInt) { + unsigned literal = constant->getConstArray()[0].getIConst(); + operands.push_back({false, literal}); + } else if (constant->getBasicType() == glslang::EbtUint) { + unsigned literal = constant->getConstArray()[0].getUConst(); + operands.push_back({false, literal}); + } else if (constant->getBasicType() == glslang::EbtBool) { + unsigned literal = constant->getConstArray()[0].getBConst(); + operands.push_back({false, literal}); + } else if (constant->getBasicType() == glslang::EbtString) { + auto str = constant->getConstArray()[0].getSConst()->c_str(); + unsigned literal = 0; + char* literalPtr = reinterpret_cast(&literal); + unsigned charCount = 0; + char ch = 0; + do { + ch = *(str++); + *(literalPtr++) = ch; + ++charCount; + if (charCount == 4) { + operands.push_back({false, literal}); + literalPtr = reinterpret_cast(&literal); + charCount = 0; + } + } while (ch != 0); + + // Partial literal is padded with 0 + if (charCount > 0) { + for (; charCount < 4; ++charCount) + *(literalPtr++) = 0; + operands.push_back({false, literal}); + } + } else + assert(0); // Unexpected type } else - assert(0); // Unexpected type - } else - operands.push_back({true, createSpvConstant(*typeParam.constant)}); + operands.push_back({true, createSpvConstant(*constant)}); + } else { + // Type specifier + assert(typeParam.getAsType() != nullptr); + operands.push_back({true, convertGlslangToSpvType(*typeParam.getAsType())}); + } } assert(spirvInst.set == ""); // Currently, couldn't be extended instructions. @@ -4236,7 +4662,6 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty break; } -#endif default: assert(0); break; @@ -4250,9 +4675,10 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty spvType = builder.makeVectorType(spvType, type.getVectorSize()); } - if (type.isCoopMat()) { + if (type.isCoopMatNV()) { builder.addCapability(spv::CapabilityCooperativeMatrixNV); builder.addExtension(spv::E_SPV_NV_cooperative_matrix); + if (type.getBasicType() == glslang::EbtFloat16) builder.addCapability(spv::CapabilityFloat16); if (type.getBasicType() == glslang::EbtUint8 || @@ -4260,11 +4686,29 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty builder.addCapability(spv::CapabilityInt8); } - spv::Id scope = makeArraySizeId(*type.getTypeParameters(), 1); - spv::Id rows = makeArraySizeId(*type.getTypeParameters(), 2); - spv::Id cols = makeArraySizeId(*type.getTypeParameters(), 3); + spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1); + spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2); + spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 3); - spvType = builder.makeCooperativeMatrixType(spvType, scope, rows, cols); + spvType = builder.makeCooperativeMatrixTypeNV(spvType, scope, rows, cols); + } + + if (type.isCoopMatKHR()) { + builder.addCapability(spv::CapabilityCooperativeMatrixKHR); + builder.addExtension(spv::E_SPV_KHR_cooperative_matrix); + + if (type.getBasicType() == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityFloat16); + if (type.getBasicType() == glslang::EbtUint8 || type.getBasicType() == glslang::EbtInt8) { + builder.addCapability(spv::CapabilityInt8); + } + + spv::Id scope = makeArraySizeId(*type.getTypeParameters()->arraySizes, 0); + spv::Id rows = makeArraySizeId(*type.getTypeParameters()->arraySizes, 1); + spv::Id cols = makeArraySizeId(*type.getTypeParameters()->arraySizes, 2); + spv::Id use = builder.makeUintConstant(type.getCoopMatKHRuse()); + + spvType = builder.makeCooperativeMatrixTypeKHR(spvType, scope, rows, cols, use); } if (type.isArray()) { @@ -4305,12 +4749,10 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty if (type.isSizedArray()) spvType = builder.makeArrayType(spvType, makeArraySizeId(*type.getArraySizes(), 0), stride); else { -#ifndef GLSLANG_WEB if (!lastBufferBlockMember) { builder.addIncorporatedExtension("SPV_EXT_descriptor_indexing", spv::Spv_1_5); builder.addCapability(spv::CapabilityRuntimeDescriptorArrayEXT); } -#endif spvType = builder.makeRuntimeArray(spvType); } if (stride > 0) @@ -4320,13 +4762,70 @@ spv::Id TGlslangToSpvTraverser::convertGlslangToSpvType(const glslang::TType& ty return spvType; } +// Apply SPIR-V decorations to the SPIR-V object (provided by SPIR-V ID). If member index is provided, the +// decorations are applied to this member. +void TGlslangToSpvTraverser::applySpirvDecorate(const glslang::TType& type, spv::Id id, std::optional member) +{ + assert(type.getQualifier().hasSpirvDecorate()); + + const glslang::TSpirvDecorate& spirvDecorate = type.getQualifier().getSpirvDecorate(); + + // Add spirv_decorate + for (auto& decorate : spirvDecorate.decorates) { + if (!decorate.second.empty()) { + std::vector literals; + TranslateLiterals(decorate.second, literals); + if (member.has_value()) + builder.addMemberDecoration(id, *member, static_cast(decorate.first), literals); + else + builder.addDecoration(id, static_cast(decorate.first), literals); + } else { + if (member.has_value()) + builder.addMemberDecoration(id, *member, static_cast(decorate.first)); + else + builder.addDecoration(id, static_cast(decorate.first)); + } + } + + // Add spirv_decorate_id + if (member.has_value()) { + // spirv_decorate_id not applied to members + assert(spirvDecorate.decorateIds.empty()); + } else { + for (auto& decorateId : spirvDecorate.decorateIds) { + std::vector operandIds; + assert(!decorateId.second.empty()); + for (auto extraOperand : decorateId.second) { + if (extraOperand->getQualifier().isFrontEndConstant()) + operandIds.push_back(createSpvConstant(*extraOperand)); + else + operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode())); + } + builder.addDecorationId(id, static_cast(decorateId.first), operandIds); + } + } + + // Add spirv_decorate_string + for (auto& decorateString : spirvDecorate.decorateStrings) { + std::vector strings; + assert(!decorateString.second.empty()); + for (auto extraOperand : decorateString.second) { + const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); + strings.push_back(string); + } + if (member.has_value()) + builder.addMemberDecoration(id, *member, static_cast(decorateString.first), strings); + else + builder.addDecoration(id, static_cast(decorateString.first), strings); + } +} + // TODO: this functionality should exist at a higher level, in creating the AST // // Identify interface members that don't have their required extension turned on. // bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member) { -#ifndef GLSLANG_WEB auto& extensions = glslangIntermediate->getRequestedExtensions(); if (member.getFieldName() == "gl_SecondaryViewportMaskNV" && @@ -4336,7 +4835,13 @@ bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member) extensions.find("GL_NV_stereo_view_rendering") == extensions.end()) return true; - if (glslangIntermediate->getStage() != EShLangMeshNV) { + if (glslangIntermediate->getStage() == EShLangMesh) { + if (member.getFieldName() == "gl_PrimitiveShadingRateEXT" && + extensions.find("GL_EXT_fragment_shading_rate") == extensions.end()) + return true; + } + + if (glslangIntermediate->getStage() != EShLangMesh) { if (member.getFieldName() == "gl_ViewportMask" && extensions.find("GL_NV_viewport_array2") == extensions.end()) return true; @@ -4347,7 +4852,6 @@ bool TGlslangToSpvTraverser::filterMember(const glslang::TType& member) extensions.find("GL_NVX_multiview_per_view_attributes") == extensions.end()) return true; } -#endif return false; }; @@ -4366,14 +4870,14 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy // except sometimes for blocks std::vector > deferredForwardPointers; for (int i = 0; i < (int)glslangMembers->size(); i++) { - glslang::TType& glslangMember = *(*glslangMembers)[i].type; - if (glslangMember.hiddenMember()) { + auto& glslangMember = (*glslangMembers)[i]; + if (glslangMember.type->hiddenMember()) { ++memberDelta; if (type.getBasicType() == glslang::EbtBlock) memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1; } else { if (type.getBasicType() == glslang::EbtBlock) { - if (filterMember(glslangMember)) { + if (filterMember(*glslangMember.type)) { memberDelta++; memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = -1; continue; @@ -4381,7 +4885,7 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy memberRemapper[glslangTypeToIdMap[glslangMembers]][i] = i - memberDelta; } // modify just this child's view of the qualifier - glslang::TQualifier memberQualifier = glslangMember.getQualifier(); + glslang::TQualifier memberQualifier = glslangMember.type->getQualifier(); InheritQualifiers(memberQualifier, qualifier); // manually inherit location @@ -4392,30 +4896,43 @@ spv::Id TGlslangToSpvTraverser::convertGlslangStructToSpvType(const glslang::TTy bool lastBufferBlockMember = qualifier.storage == glslang::EvqBuffer && i == (int)glslangMembers->size() - 1; - // Make forward pointers for any pointer members, and create a list of members to - // convert to spirv types after creating the struct. - if (glslangMember.isReference()) { - if (forwardPointers.find(glslangMember.getReferentType()) == forwardPointers.end()) { - deferredForwardPointers.push_back(std::make_pair(&glslangMember, memberQualifier)); - } - spvMembers.push_back( - convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, - true)); - } else { - spvMembers.push_back( - convertGlslangToSpvType(glslangMember, explicitLayout, memberQualifier, lastBufferBlockMember, - false)); + // Make forward pointers for any pointer members. + if (glslangMember.type->isReference() && + forwardPointers.find(glslangMember.type->getReferentType()) == forwardPointers.end()) { + deferredForwardPointers.push_back(std::make_pair(glslangMember.type, memberQualifier)); + } + + // Create the member type. + auto const spvMember = convertGlslangToSpvType(*glslangMember.type, explicitLayout, memberQualifier, lastBufferBlockMember, + glslangMember.type->isReference()); + spvMembers.push_back(spvMember); + + // Update the builder with the type's location so that we can create debug types for the structure members. + // There doesn't exist a "clean" entry point for this information to be passed along to the builder so, for now, + // it is stored in the builder and consumed during the construction of composite debug types. + // TODO: This probably warrants further investigation. This approach was decided to be the least ugly of the + // quick and dirty approaches that were tried. + // Advantages of this approach: + // + Relatively clean. No direct calls into debug type system. + // + Handles nested recursive structures. + // Disadvantages of this approach: + // + Not as clean as desired. Traverser queries/sets persistent state. This is fragile. + // + Table lookup during creation of composite debug types. This really shouldn't be necessary. + if(options.emitNonSemanticShaderDebugInfo) { + builder.debugTypeLocs[spvMember].name = glslangMember.type->getFieldName().c_str(); + builder.debugTypeLocs[spvMember].line = glslangMember.loc.line; + builder.debugTypeLocs[spvMember].column = glslangMember.loc.column; } } } // Make the SPIR-V type - spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str()); + spv::Id spvType = builder.makeStructType(spvMembers, type.getTypeName().c_str(), false); if (! HasNonLayoutQualifiers(type, qualifier)) structMap[explicitLayout][qualifier.layoutMatrix][glslangMembers] = spvType; // Decorate it - decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType); + decorateStructType(type, glslangMembers, explicitLayout, qualifier, spvType, spvMembers); for (int i = 0; i < (int)deferredForwardPointers.size(); ++i) { auto it = deferredForwardPointers[i]; @@ -4429,7 +4946,8 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, const glslang::TTypeList* glslangMembers, glslang::TLayoutPacking explicitLayout, const glslang::TQualifier& qualifier, - spv::Id spvType) + spv::Id spvType, + const std::vector& spvMembers) { // Name and decorate the non-hidden members int offset = -1; @@ -4464,14 +4982,11 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, glslangIntermediate->getSource() == glslang::EShSourceHlsl) { builder.addMemberDecoration(spvType, member, TranslateInterpolationDecoration(memberQualifier)); builder.addMemberDecoration(spvType, member, TranslateAuxiliaryStorageDecoration(memberQualifier)); -#ifndef GLSLANG_WEB addMeshNVDecoration(spvType, member, memberQualifier); -#endif } } builder.addMemberDecoration(spvType, member, TranslateInvariantDecoration(memberQualifier)); -#ifndef GLSLANG_WEB if (type.getBasicType() == glslang::EbtBlock && qualifier.storage == glslang::EvqBuffer) { // Add memory decorations only to top-level members of shader storage block @@ -4481,8 +4996,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, builder.addMemberDecoration(spvType, member, memory[i]); } -#endif - // Location assignment was already completed correctly by the front end, // just track whether a member needs to be decorated. // Ignore member locations if the container is an array, as that's @@ -4515,7 +5028,6 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, if (builtIn != spv::BuiltInMax) builder.addMemberDecoration(spvType, member, spv::DecorationBuiltIn, (int)builtIn); -#ifndef GLSLANG_WEB // nonuniform builder.addMemberDecoration(spvType, member, TranslateNonUniformDecoration(glslangMember.getQualifier())); @@ -4546,50 +5058,33 @@ void TGlslangToSpvTraverser::decorateStructType(const glslang::TType& type, builder.addExtension(spv::E_SPV_NV_geometry_shader_passthrough); } - // - // Add SPIR-V decorations for members (GL_EXT_spirv_intrinsics) - // - if (glslangMember.getQualifier().hasSprivDecorate()) { - const glslang::TSpirvDecorate& spirvDecorate = glslangMember.getQualifier().getSpirvDecorate(); - - // Add spirv_decorate - for (auto& decorate : spirvDecorate.decorates) { - if (!decorate.second.empty()) { - std::vector literals; - TranslateLiterals(decorate.second, literals); - builder.addMemberDecoration(spvType, member, static_cast(decorate.first), literals); - } - else - builder.addMemberDecoration(spvType, member, static_cast(decorate.first)); - } - - // spirv_decorate_id not applied to members - assert(spirvDecorate.decorateIds.empty()); - - // Add spirv_decorate_string - for (auto& decorateString : spirvDecorate.decorateStrings) { - std::vector strings; - assert(!decorateString.second.empty()); - for (auto extraOperand : decorateString.second) { - const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); - strings.push_back(string); - } - builder.addDecoration(spvType, static_cast(decorateString.first), strings); - } - } -#endif + // Add SPIR-V decorations (GL_EXT_spirv_intrinsics) + if (glslangMember.getQualifier().hasSpirvDecorate()) + applySpirvDecorate(glslangMember, spvType, member); } // Decorate the structure builder.addDecoration(spvType, TranslateLayoutDecoration(type, qualifier.layoutMatrix)); - builder.addDecoration(spvType, TranslateBlockDecoration(type, glslangIntermediate->usingStorageBuffer())); + const auto basicType = type.getBasicType(); + const auto typeStorageQualifier = type.getQualifier().storage; + if (basicType == glslang::EbtBlock) { + builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer())); + } else if (basicType == glslang::EbtStruct && glslangIntermediate->getSpv().vulkan > 0) { + const auto hasRuntimeArray = !spvMembers.empty() && builder.getOpCode(spvMembers.back()) == spv::OpTypeRuntimeArray; + if (hasRuntimeArray) { + builder.addDecoration(spvType, TranslateBlockDecoration(typeStorageQualifier, glslangIntermediate->usingStorageBuffer())); + } + } + + if (qualifier.hasHitObjectShaderRecordNV()) + builder.addDecoration(spvType, spv::DecorationHitObjectShaderRecordBufferNV); } // Turn the expression forming the array size into an id. // This is not quite trivial, because of specialization constants. // Sometimes, a raw constant is turned into an Id, and sometimes // a specialization constant expression is. -spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim) +spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arraySizes, int dim, bool allowZero) { // First, see if this is sized with a node, meaning a specialization constant: glslang::TIntermTyped* specNode = arraySizes.getDimNode(dim); @@ -4603,7 +5098,10 @@ spv::Id TGlslangToSpvTraverser::makeArraySizeId(const glslang::TArraySizes& arra // Otherwise, need a compile-time (front end) size, get it: int size = arraySizes.getDimSize(dim); - assert(size > 0); + + if (!allowZero) + assert(size > 0); + return builder.makeUintConstant(size); } @@ -4619,6 +5117,16 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) spv::Builder::AccessChain::CoherentFlags coherentFlags = builder.getAccessChain().coherentFlags; coherentFlags |= TranslateCoherent(type); + spv::MemoryAccessMask accessMask = spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask); + // If the value being loaded is HelperInvocation, SPIR-V 1.6 is being generated (so that + // SPV_EXT_demote_to_helper_invocation is in core) and the memory model is in use, add + // the Volatile MemoryAccess semantic. + if (type.getQualifier().builtIn == glslang::EbvHelperInvocation && + glslangIntermediate->usingVulkanMemoryModel() && + glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) { + accessMask = spv::MemoryAccessMask(accessMask | spv::MemoryAccessVolatileMask); + } + unsigned int alignment = builder.getAccessChain().alignment; alignment |= type.getBufferReferenceAlignment(); @@ -4626,7 +5134,7 @@ spv::Id TGlslangToSpvTraverser::accessChainLoad(const glslang::TType& type) TranslateNonUniformDecoration(builder.getAccessChain().coherentFlags), TranslateNonUniformDecoration(type.getQualifier()), nominalTypeId, - spv::MemoryAccessMask(TranslateMemoryAccess(coherentFlags) & ~spv::MemoryAccessMakePointerAvailableKHRMask), + accessMask, TranslateMemoryScope(coherentFlags), alignment); @@ -4898,7 +5406,6 @@ void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& switch (glslangBuiltIn) { case glslang::EbvPointSize: -#ifndef GLSLANG_WEB case glslang::EbvClipDistance: case glslang::EbvCullDistance: case glslang::EbvViewportMaskNV: @@ -4914,7 +5421,6 @@ void TGlslangToSpvTraverser::declareUseOfStructMember(const glslang::TTypeList& case glslang::EbvLayerPerViewNV: case glslang::EbvMeshViewCountNV: case glslang::EbvMeshViewIndicesNV: -#endif // Generate the associated capability. Delegate to TranslateBuiltInDecoration. // Alternately, we could just call this for any glslang built-in, since the // capability already guards against duplicates. @@ -4953,10 +5459,8 @@ bool TGlslangToSpvTraverser::originalParam(glslang::TStorageQualifier qualifier, return true; if (glslangIntermediate->getSource() == glslang::EShSourceHlsl) return paramType.getBasicType() == glslang::EbtBlock; - return paramType.containsOpaque() || // sampler, etc. -#ifndef GLSLANG_WEB + return (paramType.containsOpaque() && !glslangIntermediate->getBindlessMode()) || // sampler, etc. paramType.getQualifier().isSpirvByReference() || // spirv_by_reference -#endif (paramType.getBasicType() == glslang::EbtBlock && qualifier == glslang::EvqBuffer); // SSBO } @@ -4986,9 +5490,17 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF for (int f = 0; f < (int)glslFunctions.size(); ++f) { glslang::TIntermAggregate* glslFunction = glslFunctions[f]->getAsAggregate(); - if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction || isShaderEntryPoint(glslFunction)) + if (! glslFunction || glslFunction->getOp() != glslang::EOpFunction) continue; - + if (isShaderEntryPoint(glslFunction)) { + if (glslangIntermediate->getSource() != glslang::EShSourceHlsl) { + builder.setupDebugFunctionEntry(shaderEntry, glslangIntermediate->getEntryPointMangledName().c_str(), + glslFunction->getLoc().line, + std::vector(), // main function has no param + std::vector()); + } + continue; + } // We're on a user function. Set up the basic interface for the function now, // so that it's available to call. Translating the body will happen later. // @@ -5004,6 +5516,7 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF // GLSL has copy-in/copy-out semantics. They can be handled though with a pointer to a copy. std::vector paramTypes; + std::vector paramNames; std::vector> paramDecorations; // list of decorations per parameter glslang::TIntermSequence& parameters = glslFunction->getSequence()[0]->getAsAggregate()->getSequence(); @@ -5028,11 +5541,17 @@ void TGlslangToSpvTraverser::makeFunctions(const glslang::TIntermSequence& glslF paramTypes.push_back(typeId); } + for (auto const parameter:parameters) { + paramNames.push_back(parameter->getAsSymbolNode()->getName().c_str()); + } + spv::Block* functionBlock; - spv::Function *function = builder.makeFunctionEntry(TranslatePrecisionDecoration(glslFunction->getType()), - convertGlslangToSpvType(glslFunction->getType()), - glslFunction->getName().c_str(), paramTypes, - paramDecorations, &functionBlock); + spv::Function* function = builder.makeFunctionEntry( + TranslatePrecisionDecoration(glslFunction->getType()), convertGlslangToSpvType(glslFunction->getType()), + glslFunction->getName().c_str(), convertGlslangLinkageToSpv(glslFunction->getLinkType()), paramTypes, + paramDecorations, &functionBlock); + builder.setupDebugFunctionEntry(function, glslFunction->getName().c_str(), glslFunction->getLoc().line, + paramTypes, paramNames); if (implicitThis) function->setImplicitThis(); @@ -5095,6 +5614,10 @@ void TGlslangToSpvTraverser::collectRayTracingLinkerObjects() set = 1; break; + case glslang::EvqHitObjectAttrNV: + set = 2; + break; + default: set = -1; } @@ -5121,6 +5644,7 @@ void TGlslangToSpvTraverser::handleFunctionEntry(const glslang::TIntermAggregate currentFunction = functionMap[node->getName().c_str()]; spv::Block* functionBlock = currentFunction->getEntryBlock(); builder.setBuildPoint(functionBlock); + builder.enterFunction(currentFunction); } void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& node, std::vector& arguments, @@ -5130,23 +5654,18 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& glslang::TSampler sampler = {}; bool cubeCompare = false; -#ifndef GLSLANG_WEB bool f16ShadowCompare = false; -#endif if (node.isTexture() || node.isImage()) { sampler = glslangArguments[0]->getAsTyped()->getType().getSampler(); cubeCompare = sampler.dim == glslang::EsdCube && sampler.arrayed && sampler.shadow; -#ifndef GLSLANG_WEB f16ShadowCompare = sampler.shadow && glslangArguments[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16; -#endif } for (int i = 0; i < (int)glslangArguments.size(); ++i) { builder.clearAccessChain(); glslangArguments[i]->traverse(this); -#ifndef GLSLANG_WEB // Special case l-value operands bool lvalue = false; switch (node.getOp()) { @@ -5242,6 +5761,10 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& if (i == 7) lvalue = true; break; + case glslang::EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: + if (i == 2) + lvalue = true; + break; default: break; } @@ -5253,7 +5776,6 @@ void TGlslangToSpvTraverser::translateArguments(const glslang::TIntermAggregate& builder.addDecoration(lvalue_id, TranslateNonUniformDecoration(lvalueCoherentFlags)); lvalueCoherentFlags |= TranslateCoherent(glslangArguments[i]->getAsTyped()->getType()); } else -#endif arguments.push_back(accessChainLoad(glslangArguments[i]->getAsTyped()->getType())); } } @@ -5270,7 +5792,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO if (! node->isImage() && ! node->isTexture()) return spv::NoResult; - builder.setLine(node->getLoc().line, node->getLoc().getFilename()); + builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename()); // Process a GLSL texturing op (will be SPV image) @@ -5278,13 +5800,9 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO ? node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType() : node->getAsUnaryNode()->getOperand()->getAsTyped()->getType(); const glslang::TSampler sampler = imageType.getSampler(); -#ifdef GLSLANG_WEB - const bool f16ShadowCompare = false; -#else bool f16ShadowCompare = (sampler.shadow && node->getAsAggregate()) ? node->getAsAggregate()->getSequence()[1]->getAsTyped()->getType().getBasicType() == glslang::EbtFloat16 : false; -#endif const auto signExtensionMask = [&]() { if (builder.getSpvVersion() >= spv::Spv_1_4) { @@ -5330,7 +5848,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO return builder.createTextureQueryCall(spv::OpImageQuerySizeLod, params, isUnsignedResult); } else return builder.createTextureQueryCall(spv::OpImageQuerySize, params, isUnsignedResult); -#ifndef GLSLANG_WEB case glslang::EOpImageQuerySamples: case glslang::EOpTextureQuerySamples: return builder.createTextureQueryCall(spv::OpImageQuerySamples, params, isUnsignedResult); @@ -5341,7 +5858,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO return builder.createTextureQueryCall(spv::OpImageQueryLevels, params, isUnsignedResult); case glslang::EOpSparseTexelsResident: return builder.createUnaryOp(spv::OpImageSparseTexelsResident, builder.makeBoolType(), arguments[0]); -#endif default: assert(0); break; @@ -5401,6 +5917,17 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO return result; } + if (cracked.attachmentEXT) { + if (opIt != arguments.end()) { + spv::IdImmediate sample = { true, *opIt }; + operands.push_back(sample); + } + spv::Id result = builder.createOp(spv::OpColorAttachmentReadEXT, resultType(), operands); + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + builder.setPrecision(result, precision); + return result; + } + spv::IdImmediate coord = { true, *(opIt++) }; operands.push_back(coord); if (node->getOp() == glslang::EOpImageLoad || node->getOp() == glslang::EOpImageLoadLod) { @@ -5548,10 +6075,12 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO operands.push_back(sample); spv::Id resultTypeId; + glslang::TBasicType typeProxy = node->getBasicType(); // imageAtomicStore has a void return type so base the pointer type on // the type of the value operand. if (node->getOp() == glslang::EOpImageAtomicStore) { resultTypeId = builder.makePointer(spv::StorageClassImage, builder.getTypeId(*opIt)); + typeProxy = node->getAsAggregate()->getSequence()[0]->getAsTyped()->getType().getSampler().type; } else { resultTypeId = builder.makePointer(spv::StorageClassImage, resultType()); } @@ -5565,12 +6094,11 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO for (; opIt != arguments.end(); ++opIt) operands.push_back(*opIt); - return createAtomicOperation(node->getOp(), precision, resultType(), operands, node->getBasicType(), - lvalueCoherentFlags); + return createAtomicOperation(node->getOp(), precision, resultType(), operands, typeProxy, + lvalueCoherentFlags, node->getType()); } } -#ifndef GLSLANG_WEB // Check for fragment mask functions other than queries if (cracked.fragMask) { assert(sampler.ms); @@ -5604,7 +6132,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO builder.addCapability(spv::CapabilityFragmentMaskAMD); return builder.createOp(fragMaskOp, resultType(), operands); } -#endif // Check for texture functions other than queries bool sparse = node->isSparseTexture(); @@ -5638,7 +6165,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO bias = true; } -#ifndef GLSLANG_WEB if (cracked.gather) { const auto& sourceExtensions = glslangIntermediate->getRequestedExtensions(); if (bias || cracked.lod || @@ -5647,7 +6173,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO builder.addCapability(spv::CapabilityImageGatherBiasLodAMD); } } -#endif // set the rest of the arguments @@ -5707,7 +6232,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO ++extraArgs; } -#ifndef GLSLANG_WEB // lod clamp if (cracked.lodClamp) { params.lodClamp = arguments[2 + extraArgs]; @@ -5736,14 +6260,13 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO resultStruct = arguments[4 + extraArgs]; extraArgs += 3; } -#endif + // bias if (bias) { params.bias = arguments[2 + extraArgs]; ++extraArgs; } -#ifndef GLSLANG_WEB if (imageFootprint) { builder.addExtension(spv::E_SPV_NV_shader_image_footprint); builder.addCapability(spv::CapabilityImageFootprintNV); @@ -5769,10 +6292,10 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO assert(builder.isStructType(resultStructType)); //resType (SPIR-V type) contains 6 elements: - //Member 0 must be a Boolean type scalar(LOD), - //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor), - //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), - //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), + //Member 0 must be a Boolean type scalar(LOD), + //Member 1 must be a vector of integer type, whose Signedness operand is 0(anchor), + //Member 2 must be a vector of integer type, whose Signedness operand is 0(offset), + //Member 3 must be a vector of integer type, whose Signedness operand is 0(mask), //Member 4 must be a scalar of integer type, whose Signedness operand is 0(lod), //Member 5 must be a scalar of integer type, whose Signedness operand is 0(granularity). std::vector members; @@ -5785,7 +6308,7 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO //call ImageFootprintNV spv::Id res = builder.createTextureCall(precision, resType, sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params, signExtensionMask()); - + //copy resType (SPIR-V type) to resultStructType(OpenGL type) for (int i = 0; i < 5; i++) { builder.clearAccessChain(); @@ -5801,7 +6324,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } return builder.createCompositeExtract(res, resultType(), 0); } -#endif // projective component (might not to move) // GLSL: "The texture coordinates consumed from P, not including the last component of P, @@ -5826,7 +6348,6 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO } } -#ifndef GLSLANG_WEB // nonprivate if (imageType.getQualifier().nonprivate) { params.nonprivate = true; @@ -5836,9 +6357,8 @@ spv::Id TGlslangToSpvTraverser::createImageTextureFunctionCall(glslang::TIntermO if (imageType.getQualifier().volatil) { params.volatil = true; } -#endif - std::vector result( 1, + std::vector result( 1, builder.createTextureCall(precision, resultType(), sparse, cracked.fetch, cracked.proj, cracked.gather, noImplicitLod, params, signExtensionMask()) ); @@ -6100,6 +6620,10 @@ spv::Id TGlslangToSpvTraverser::createBinaryOperation(glslang::TOperator op, OpD binOp = isUnsigned ? spv::OpUMul32x16INTEL : spv::OpIMul32x16INTEL; break; + case glslang::EOpExpectEXT: + binOp = spv::OpExpectKHR; + break; + case glslang::EOpLessThan: case glslang::EOpGreaterThan: case glslang::EOpLessThanEqual: @@ -6322,7 +6846,8 @@ spv::Id TGlslangToSpvTraverser::createBinaryMatrixOperation(spv::Op op, OpDecora } spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDecorations& decorations, spv::Id typeId, - spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) + spv::Id operand, glslang::TBasicType typeProxy, const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, + const glslang::TType &opType) { spv::Op unaryOp = spv::OpNop; int extBuiltins = -1; @@ -6490,7 +7015,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpUnpackHalf2x16: libCall = spv::GLSLstd450UnpackHalf2x16; break; -#ifndef GLSLANG_WEB case glslang::EOpPackSnorm4x8: libCall = spv::GLSLstd450PackSnorm4x8; break; @@ -6509,7 +7033,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpUnpackDouble2x32: libCall = spv::GLSLstd450UnpackDouble2x32; break; -#endif case glslang::EOpPackInt2x32: case glslang::EOpUnpackInt2x32: @@ -6564,7 +7087,6 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe libCall = spv::GLSLstd450SSign; break; -#ifndef GLSLANG_WEB case glslang::EOpDPdxFine: unaryOp = spv::OpDPdxFine; break; @@ -6613,7 +7135,7 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe // Handle all of the atomics in one place, in createAtomicOperation() std::vector operands; operands.push_back(operand); - return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags); + return createAtomicOperation(op, decorations.precision, typeId, operands, typeProxy, lvalueCoherentFlags, opType); } case glslang::EOpBitFieldReverse: @@ -6706,7 +7228,9 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpSubgroupExclusiveXor: case glslang::EOpSubgroupQuadSwapHorizontal: case glslang::EOpSubgroupQuadSwapVertical: - case glslang::EOpSubgroupQuadSwapDiagonal: { + case glslang::EOpSubgroupQuadSwapDiagonal: + case glslang::EOpSubgroupQuadAll: + case glslang::EOpSubgroupQuadAny: { std::vector operands; operands.push_back(operand); return createSubgroupOperation(op, typeId, operands, typeProxy); @@ -6736,12 +7260,108 @@ spv::Id TGlslangToSpvTraverser::createUnaryOperation(glslang::TOperator op, OpDe case glslang::EOpConvUvec2ToAccStruct: unaryOp = spv::OpConvertUToAccelerationStructureKHR; break; -#endif + + case glslang::EOpHitObjectIsEmptyNV: + unaryOp = spv::OpHitObjectIsEmptyNV; + break; + + case glslang::EOpHitObjectIsMissNV: + unaryOp = spv::OpHitObjectIsMissNV; + break; + + case glslang::EOpHitObjectIsHitNV: + unaryOp = spv::OpHitObjectIsHitNV; + break; + + case glslang::EOpHitObjectGetObjectRayOriginNV: + unaryOp = spv::OpHitObjectGetObjectRayOriginNV; + break; + + case glslang::EOpHitObjectGetObjectRayDirectionNV: + unaryOp = spv::OpHitObjectGetObjectRayDirectionNV; + break; + + case glslang::EOpHitObjectGetWorldRayOriginNV: + unaryOp = spv::OpHitObjectGetWorldRayOriginNV; + break; + + case glslang::EOpHitObjectGetWorldRayDirectionNV: + unaryOp = spv::OpHitObjectGetWorldRayDirectionNV; + break; + + case glslang::EOpHitObjectGetObjectToWorldNV: + unaryOp = spv::OpHitObjectGetObjectToWorldNV; + break; + + case glslang::EOpHitObjectGetWorldToObjectNV: + unaryOp = spv::OpHitObjectGetWorldToObjectNV; + break; + + case glslang::EOpHitObjectGetRayTMinNV: + unaryOp = spv::OpHitObjectGetRayTMinNV; + break; + + case glslang::EOpHitObjectGetRayTMaxNV: + unaryOp = spv::OpHitObjectGetRayTMaxNV; + break; + + case glslang::EOpHitObjectGetPrimitiveIndexNV: + unaryOp = spv::OpHitObjectGetPrimitiveIndexNV; + break; + + case glslang::EOpHitObjectGetInstanceIdNV: + unaryOp = spv::OpHitObjectGetInstanceIdNV; + break; + + case glslang::EOpHitObjectGetInstanceCustomIndexNV: + unaryOp = spv::OpHitObjectGetInstanceCustomIndexNV; + break; + + case glslang::EOpHitObjectGetGeometryIndexNV: + unaryOp = spv::OpHitObjectGetGeometryIndexNV; + break; + + case glslang::EOpHitObjectGetHitKindNV: + unaryOp = spv::OpHitObjectGetHitKindNV; + break; + + case glslang::EOpHitObjectGetCurrentTimeNV: + unaryOp = spv::OpHitObjectGetCurrentTimeNV; + break; + + case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: + unaryOp = spv::OpHitObjectGetShaderBindingTableRecordIndexNV; + break; + + case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: + unaryOp = spv::OpHitObjectGetShaderRecordBufferHandleNV; + break; + + case glslang::EOpFetchMicroTriangleVertexPositionNV: + unaryOp = spv::OpFetchMicroTriangleVertexPositionNV; + break; + + case glslang::EOpFetchMicroTriangleVertexBarycentricNV: + unaryOp = spv::OpFetchMicroTriangleVertexBarycentricNV; + break; case glslang::EOpCopyObject: unaryOp = spv::OpCopyObject; break; + case glslang::EOpDepthAttachmentReadEXT: + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT); + unaryOp = spv::OpDepthAttachmentReadEXT; + decorations.precision = spv::NoPrecision; + break; + case glslang::EOpStencilAttachmentReadEXT: + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT); + unaryOp = spv::OpStencilAttachmentReadEXT; + decorations.precision = spv::DecorationRelaxedPrecision; + break; + default: return 0; } @@ -6798,7 +7418,9 @@ spv::Id TGlslangToSpvTraverser::createUnaryMatrixOperation(spv::Op op, OpDecorat // For converting integers where both the bitwidth and the signedness could // change, but only do the width change here. The caller is still responsible // for the signedness conversion. -spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize) +// destType is the final type that will be converted to, but this function +// may only be doing part of that conversion. +spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, spv::Id operand, int vectorSize, spv::Id destType) { // Get the result type width, based on the type to convert to. int width = 32; @@ -6869,6 +7491,11 @@ spv::Id TGlslangToSpvTraverser::createIntWidthConversion(glslang::TOperator op, if (vectorSize > 0) type = builder.makeVectorType(type, vectorSize); + else if (builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixKHR || + builder.getOpCode(destType) == spv::OpTypeCooperativeMatrixNV) { + + type = builder.makeCooperativeMatrixTypeWithSameShape(type, destType); + } return builder.createUnaryOp(convOp, type, operand); } @@ -6900,13 +7527,10 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvBoolToInt: case glslang::EOpConvBoolToInt64: -#ifndef GLSLANG_WEB if (op == glslang::EOpConvBoolToInt64) { zero = builder.makeInt64Constant(0); one = builder.makeInt64Constant(1); - } else -#endif - { + } else { zero = builder.makeIntConstant(0); one = builder.makeIntConstant(1); } @@ -6916,13 +7540,10 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvBoolToUint: case glslang::EOpConvBoolToUint64: -#ifndef GLSLANG_WEB if (op == glslang::EOpConvBoolToUint64) { zero = builder.makeUint64Constant(0); one = builder.makeUint64Constant(1); - } else -#endif - { + } else { zero = builder.makeUintConstant(0); one = builder.makeUintConstant(1); } @@ -6985,16 +7606,13 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvInt64ToUint64: if (builder.isInSpecConstCodeGenMode()) { // Build zero scalar or vector for OpIAdd. -#ifndef GLSLANG_WEB if(op == glslang::EOpConvUint8ToInt8 || op == glslang::EOpConvInt8ToUint8) { zero = builder.makeUint8Constant(0); } else if (op == glslang::EOpConvUint16ToInt16 || op == glslang::EOpConvInt16ToUint16) { zero = builder.makeUint16Constant(0); } else if (op == glslang::EOpConvUint64ToInt64 || op == glslang::EOpConvInt64ToUint64) { zero = builder.makeUint64Constant(0); - } else -#endif - { + } else { zero = builder.makeUintConstant(0); } zero = makeSmearedConstant(zero, vectorSize); @@ -7021,7 +7639,6 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora convOp = spv::OpConvertFToU; break; -#ifndef GLSLANG_WEB case glslang::EOpConvInt8ToBool: case glslang::EOpConvUint8ToBool: zero = builder.makeUint8Constant(0); @@ -7141,7 +7758,7 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvUint64ToInt16: case glslang::EOpConvUint64ToInt: // OpSConvert/OpUConvert + OpBitCast - operand = createIntWidthConversion(op, operand, vectorSize); + operand = createIntWidthConversion(op, operand, vectorSize, destType); if (builder.isInSpecConstCodeGenMode()) { // Build zero scalar or vector for OpIAdd. @@ -7200,7 +7817,6 @@ spv::Id TGlslangToSpvTraverser::createConversion(glslang::TOperator op, OpDecora case glslang::EOpConvUvec2ToPtr: convOp = spv::OpBitcast; break; -#endif default: break; @@ -7237,7 +7853,7 @@ spv::Id TGlslangToSpvTraverser::makeSmearedConstant(spv::Id constant, int vector // For glslang ops that map to SPV atomic opCodes spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv::Decoration /*precision*/, spv::Id typeId, std::vector& operands, glslang::TBasicType typeProxy, - const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags) + const spv::Builder::AccessChain::CoherentFlags &lvalueCoherentFlags, const glslang::TType &opType) { spv::Op opCode = spv::OpNop; @@ -7248,14 +7864,20 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv opCode = spv::OpAtomicIAdd; if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { opCode = spv::OpAtomicFAddEXT; - builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add); - if (typeProxy == glslang::EbtFloat16) { - builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add); - builder.addCapability(spv::CapabilityAtomicFloat16AddEXT); - } else if (typeProxy == glslang::EbtFloat) { - builder.addCapability(spv::CapabilityAtomicFloat32AddEXT); + if (typeProxy == glslang::EbtFloat16 && + (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) { + builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector); + builder.addCapability(spv::CapabilityAtomicFloat16VectorNV); } else { - builder.addCapability(spv::CapabilityAtomicFloat64AddEXT); + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_add); + if (typeProxy == glslang::EbtFloat16) { + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float16_add); + builder.addCapability(spv::CapabilityAtomicFloat16AddEXT); + } else if (typeProxy == glslang::EbtFloat) { + builder.addCapability(spv::CapabilityAtomicFloat32AddEXT); + } else { + builder.addCapability(spv::CapabilityAtomicFloat64AddEXT); + } } } break; @@ -7268,13 +7890,19 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv case glslang::EOpAtomicCounterMin: if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { opCode = spv::OpAtomicFMinEXT; - builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); - if (typeProxy == glslang::EbtFloat16) - builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); - else if (typeProxy == glslang::EbtFloat) - builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); - else - builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + if (typeProxy == glslang::EbtFloat16 && + (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) { + builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector); + builder.addCapability(spv::CapabilityAtomicFloat16VectorNV); + } else { + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { opCode = spv::OpAtomicUMin; } else { @@ -7286,13 +7914,19 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv case glslang::EOpAtomicCounterMax: if (typeProxy == glslang::EbtFloat16 || typeProxy == glslang::EbtFloat || typeProxy == glslang::EbtDouble) { opCode = spv::OpAtomicFMaxEXT; - builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); - if (typeProxy == glslang::EbtFloat16) - builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); - else if (typeProxy == glslang::EbtFloat) - builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); - else - builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + if (typeProxy == glslang::EbtFloat16 && + (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) { + builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector); + builder.addCapability(spv::CapabilityAtomicFloat16VectorNV); + } else { + builder.addExtension(spv::E_SPV_EXT_shader_atomic_float_min_max); + if (typeProxy == glslang::EbtFloat16) + builder.addCapability(spv::CapabilityAtomicFloat16MinMaxEXT); + else if (typeProxy == glslang::EbtFloat) + builder.addCapability(spv::CapabilityAtomicFloat32MinMaxEXT); + else + builder.addCapability(spv::CapabilityAtomicFloat64MinMaxEXT); + } } else if (typeProxy == glslang::EbtUint || typeProxy == glslang::EbtUint64) { opCode = spv::OpAtomicUMax; } else { @@ -7317,6 +7951,12 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv case glslang::EOpAtomicExchange: case glslang::EOpImageAtomicExchange: case glslang::EOpAtomicCounterExchange: + if ((typeProxy == glslang::EbtFloat16) && + (opType.getVectorSize() == 2 || opType.getVectorSize() == 4)) { + builder.addExtension(spv::E_SPV_NV_shader_atomic_fp16_vector); + builder.addCapability(spv::CapabilityAtomicFloat16VectorNV); + } + opCode = spv::OpAtomicExchange; break; case glslang::EOpAtomicCompSwap: @@ -7361,7 +8001,7 @@ spv::Id TGlslangToSpvTraverser::createAtomicOperation(glslang::TOperator op, spv } else { scopeId = builder.makeUintConstant(spv::ScopeDevice); } - // semantics default to relaxed + // semantics default to relaxed spv::Id semanticsId = builder.makeUintConstant(lvalueCoherentFlags.isVolatile() && glslangIntermediate->usingVulkanMemoryModel() ? spv::MemorySemanticsVolatileMask : @@ -7719,6 +8359,11 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s case glslang::EOpSubgroupElect: builder.addCapability(spv::CapabilityGroupNonUniform); break; + case glslang::EOpSubgroupQuadAll: + case glslang::EOpSubgroupQuadAny: + builder.addExtension(spv::E_SPV_KHR_quad_control); + builder.addCapability(spv::CapabilityQuadControlKHR); + [[fallthrough]]; case glslang::EOpSubgroupAll: case glslang::EOpSubgroupAny: case glslang::EOpSubgroupAllEqual: @@ -7738,6 +8383,11 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s builder.addCapability(spv::CapabilityGroupNonUniform); builder.addCapability(spv::CapabilityGroupNonUniformBallot); break; + case glslang::EOpSubgroupRotate: + case glslang::EOpSubgroupClusteredRotate: + builder.addExtension(spv::E_SPV_KHR_subgroup_rotate); + builder.addCapability(spv::CapabilityGroupNonUniformRotateKHR); + break; case glslang::EOpSubgroupShuffle: case glslang::EOpSubgroupShuffleXor: builder.addCapability(spv::CapabilityGroupNonUniform); @@ -7826,7 +8476,9 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s // Figure out which opcode to use. switch (op) { case glslang::EOpSubgroupElect: opCode = spv::OpGroupNonUniformElect; break; + case glslang::EOpSubgroupQuadAll: opCode = spv::OpGroupNonUniformQuadAllKHR; break; case glslang::EOpSubgroupAll: opCode = spv::OpGroupNonUniformAll; break; + case glslang::EOpSubgroupQuadAny: opCode = spv::OpGroupNonUniformQuadAnyKHR; break; case glslang::EOpSubgroupAny: opCode = spv::OpGroupNonUniformAny; break; case glslang::EOpSubgroupAllEqual: opCode = spv::OpGroupNonUniformAllEqual; break; case glslang::EOpSubgroupBroadcast: opCode = spv::OpGroupNonUniformBroadcast; break; @@ -7843,6 +8495,8 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s case glslang::EOpSubgroupShuffleXor: opCode = spv::OpGroupNonUniformShuffleXor; break; case glslang::EOpSubgroupShuffleUp: opCode = spv::OpGroupNonUniformShuffleUp; break; case glslang::EOpSubgroupShuffleDown: opCode = spv::OpGroupNonUniformShuffleDown; break; + case glslang::EOpSubgroupRotate: + case glslang::EOpSubgroupClusteredRotate: opCode = spv::OpGroupNonUniformRotateKHR; break; case glslang::EOpSubgroupAdd: case glslang::EOpSubgroupInclusiveAdd: case glslang::EOpSubgroupExclusiveAdd: @@ -8023,7 +8677,10 @@ spv::Id TGlslangToSpvTraverser::createSubgroupOperation(glslang::TOperator op, s // Every operation begins with the Execution Scope operand. spv::IdImmediate executionScope = { true, builder.makeUintConstant(spv::ScopeSubgroup) }; - spvGroupOperands.push_back(executionScope); + // All other ops need the execution scope. Quad Control Ops don't need scope, it's always Quad. + if (opCode != spv::OpGroupNonUniformQuadAllKHR && opCode != spv::OpGroupNonUniformQuadAnyKHR) { + spvGroupOperands.push_back(executionScope); + } // Next, for all operations that use a Group Operation, push that as an operand. if (groupOperation != spv::GroupOperationMax) { @@ -8192,7 +8849,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: } break; -#ifndef GLSLANG_WEB case glslang::EOpInterpolateAtSample: if (typeProxy == glslang::EbtFloat16) builder.addExtension(spv::E_SPV_AMD_gpu_shader_half_float); @@ -8267,6 +8923,8 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: case glslang::EOpSubgroupShuffleXor: case glslang::EOpSubgroupShuffleUp: case glslang::EOpSubgroupShuffleDown: + case glslang::EOpSubgroupRotate: + case glslang::EOpSubgroupClusteredRotate: case glslang::EOpSubgroupClusteredAdd: case glslang::EOpSubgroupClusteredMul: case glslang::EOpSubgroupClusteredMin: @@ -8465,10 +9123,190 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: case glslang::EOpWritePackedPrimitiveIndices4x8NV: builder.createNoResultOp(spv::OpWritePackedPrimitiveIndices4x8NV, operands); return 0; - case glslang::EOpCooperativeMatrixMulAdd: + case glslang::EOpEmitMeshTasksEXT: + if (taskPayloadID) + operands.push_back(taskPayloadID); + // As per SPV_EXT_mesh_shader make it a terminating instruction in the current block + builder.makeStatementTerminator(spv::OpEmitMeshTasksEXT, operands, "post-OpEmitMeshTasksEXT"); + return 0; + case glslang::EOpSetMeshOutputsEXT: + builder.createNoResultOp(spv::OpSetMeshOutputsEXT, operands); + return 0; + case glslang::EOpCooperativeMatrixMulAddNV: opCode = spv::OpCooperativeMatrixMulAddNV; break; -#endif // GLSLANG_WEB + case glslang::EOpHitObjectTraceRayNV: + builder.createNoResultOp(spv::OpHitObjectTraceRayNV, operands); + return 0; + case glslang::EOpHitObjectTraceRayMotionNV: + builder.createNoResultOp(spv::OpHitObjectTraceRayMotionNV, operands); + return 0; + case glslang::EOpHitObjectRecordHitNV: + builder.createNoResultOp(spv::OpHitObjectRecordHitNV, operands); + return 0; + case glslang::EOpHitObjectRecordHitMotionNV: + builder.createNoResultOp(spv::OpHitObjectRecordHitMotionNV, operands); + return 0; + case glslang::EOpHitObjectRecordHitWithIndexNV: + builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexNV, operands); + return 0; + case glslang::EOpHitObjectRecordHitWithIndexMotionNV: + builder.createNoResultOp(spv::OpHitObjectRecordHitWithIndexMotionNV, operands); + return 0; + case glslang::EOpHitObjectRecordMissNV: + builder.createNoResultOp(spv::OpHitObjectRecordMissNV, operands); + return 0; + case glslang::EOpHitObjectRecordMissMotionNV: + builder.createNoResultOp(spv::OpHitObjectRecordMissMotionNV, operands); + return 0; + case glslang::EOpHitObjectExecuteShaderNV: + builder.createNoResultOp(spv::OpHitObjectExecuteShaderNV, operands); + return 0; + case glslang::EOpHitObjectIsEmptyNV: + typeId = builder.makeBoolType(); + opCode = spv::OpHitObjectIsEmptyNV; + break; + case glslang::EOpHitObjectIsMissNV: + typeId = builder.makeBoolType(); + opCode = spv::OpHitObjectIsMissNV; + break; + case glslang::EOpHitObjectIsHitNV: + typeId = builder.makeBoolType(); + opCode = spv::OpHitObjectIsHitNV; + break; + case glslang::EOpHitObjectGetRayTMinNV: + typeId = builder.makeFloatType(32); + opCode = spv::OpHitObjectGetRayTMinNV; + break; + case glslang::EOpHitObjectGetRayTMaxNV: + typeId = builder.makeFloatType(32); + opCode = spv::OpHitObjectGetRayTMaxNV; + break; + case glslang::EOpHitObjectGetObjectRayOriginNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpHitObjectGetObjectRayOriginNV; + break; + case glslang::EOpHitObjectGetObjectRayDirectionNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpHitObjectGetObjectRayDirectionNV; + break; + case glslang::EOpHitObjectGetWorldRayOriginNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpHitObjectGetWorldRayOriginNV; + break; + case glslang::EOpHitObjectGetWorldRayDirectionNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpHitObjectGetWorldRayDirectionNV; + break; + case glslang::EOpHitObjectGetWorldToObjectNV: + typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3); + opCode = spv::OpHitObjectGetWorldToObjectNV; + break; + case glslang::EOpHitObjectGetObjectToWorldNV: + typeId = builder.makeMatrixType(builder.makeFloatType(32), 4, 3); + opCode = spv::OpHitObjectGetObjectToWorldNV; + break; + case glslang::EOpHitObjectGetInstanceCustomIndexNV: + typeId = builder.makeIntegerType(32, 1); + opCode = spv::OpHitObjectGetInstanceCustomIndexNV; + break; + case glslang::EOpHitObjectGetInstanceIdNV: + typeId = builder.makeIntegerType(32, 1); + opCode = spv::OpHitObjectGetInstanceIdNV; + break; + case glslang::EOpHitObjectGetGeometryIndexNV: + typeId = builder.makeIntegerType(32, 1); + opCode = spv::OpHitObjectGetGeometryIndexNV; + break; + case glslang::EOpHitObjectGetPrimitiveIndexNV: + typeId = builder.makeIntegerType(32, 1); + opCode = spv::OpHitObjectGetPrimitiveIndexNV; + break; + case glslang::EOpHitObjectGetHitKindNV: + typeId = builder.makeIntegerType(32, 0); + opCode = spv::OpHitObjectGetHitKindNV; + break; + case glslang::EOpHitObjectGetCurrentTimeNV: + typeId = builder.makeFloatType(32); + opCode = spv::OpHitObjectGetCurrentTimeNV; + break; + case glslang::EOpHitObjectGetShaderBindingTableRecordIndexNV: + typeId = builder.makeIntegerType(32, 0); + opCode = spv::OpHitObjectGetShaderBindingTableRecordIndexNV; + return 0; + case glslang::EOpHitObjectGetAttributesNV: + builder.createNoResultOp(spv::OpHitObjectGetAttributesNV, operands); + return 0; + case glslang::EOpHitObjectGetShaderRecordBufferHandleNV: + typeId = builder.makeVectorType(builder.makeUintType(32), 2); + opCode = spv::OpHitObjectGetShaderRecordBufferHandleNV; + break; + case glslang::EOpReorderThreadNV: { + if (operands.size() == 2) { + builder.createNoResultOp(spv::OpReorderThreadWithHintNV, operands); + } else { + builder.createNoResultOp(spv::OpReorderThreadWithHitObjectNV, operands); + } + return 0; + + } + + case glslang::EOpImageSampleWeightedQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageSampleWeightedQCOM; + addImageProcessingQCOMDecoration(operands[2], spv::DecorationWeightTextureQCOM); + break; + case glslang::EOpImageBoxFilterQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBoxFilterQCOM; + break; + case glslang::EOpImageBlockMatchSADQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchSADQCOM; + addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM); + addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM); + break; + case glslang::EOpImageBlockMatchSSDQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchSSDQCOM; + addImageProcessingQCOMDecoration(operands[0], spv::DecorationBlockMatchTextureQCOM); + addImageProcessingQCOMDecoration(operands[2], spv::DecorationBlockMatchTextureQCOM); + break; + + case glslang::EOpFetchMicroTriangleVertexBarycentricNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 2); + opCode = spv::OpFetchMicroTriangleVertexBarycentricNV; + break; + + case glslang::EOpFetchMicroTriangleVertexPositionNV: + typeId = builder.makeVectorType(builder.makeFloatType(32), 3); + opCode = spv::OpFetchMicroTriangleVertexPositionNV; + break; + + case glslang::EOpImageBlockMatchWindowSSDQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchWindowSSDQCOM; + addImageProcessing2QCOMDecoration(operands[0], false); + addImageProcessing2QCOMDecoration(operands[2], false); + break; + case glslang::EOpImageBlockMatchWindowSADQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchWindowSADQCOM; + addImageProcessing2QCOMDecoration(operands[0], false); + addImageProcessing2QCOMDecoration(operands[2], false); + break; + case glslang::EOpImageBlockMatchGatherSSDQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchGatherSSDQCOM; + addImageProcessing2QCOMDecoration(operands[0], true); + addImageProcessing2QCOMDecoration(operands[2], true); + break; + case glslang::EOpImageBlockMatchGatherSADQCOM: + typeId = builder.makeVectorType(builder.makeFloatType(32), 4); + opCode = spv::OpImageBlockMatchGatherSADQCOM; + addImageProcessing2QCOMDecoration(operands[0], true); + addImageProcessing2QCOMDecoration(operands[2], true); + break; default: return 0; } @@ -8512,7 +9350,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: } } -#ifndef GLSLANG_WEB // Decode the return types that were structures switch (op) { case glslang::EOpAddCarry: @@ -8542,7 +9379,6 @@ spv::Id TGlslangToSpvTraverser::createMiscOperation(glslang::TOperator op, spv:: default: break; } -#endif return builder.setPrecision(id, precision); } @@ -8587,7 +9423,6 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv: builder.createMemoryBarrier(spv::ScopeWorkgroup, spv::MemorySemanticsAllMemory | spv::MemorySemanticsAcquireReleaseMask); return 0; -#ifndef GLSLANG_WEB case glslang::EOpMemoryBarrierAtomicCounter: builder.createMemoryBarrier(memoryBarrierScope, spv::MemorySemanticsAtomicCounterMemoryMask | spv::MemorySemanticsAcquireReleaseMask); @@ -8706,7 +9541,30 @@ spv::Id TGlslangToSpvTraverser::createNoArgOperation(glslang::TOperator op, spv: builder.addCapability(spv::CapabilityShaderClockKHR); return builder.createOp(spv::OpReadClockKHR, typeId, args); } -#endif + case glslang::EOpStencilAttachmentReadEXT: + case glslang::EOpDepthAttachmentReadEXT: + { + builder.addExtension(spv::E_SPV_EXT_shader_tile_image); + + spv::Decoration precision; + spv::Op spv_op; + if (op == glslang::EOpStencilAttachmentReadEXT) + { + precision = spv::DecorationRelaxedPrecision; + spv_op = spv::OpStencilAttachmentReadEXT; + builder.addCapability(spv::CapabilityTileImageStencilReadAccessEXT); + } + else + { + precision = spv::NoPrecision; + spv_op = spv::OpDepthAttachmentReadEXT; + builder.addCapability(spv::CapabilityTileImageDepthReadAccessEXT); + } + + std::vector args; // Dummy args + spv::Id result = builder.createOp(spv_op, typeId, args); + return builder.setPrecision(result, precision); + } default: break; } @@ -8728,7 +9586,32 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol // it was not found, create it spv::BuiltIn builtIn = TranslateBuiltInDecoration(symbol->getQualifier().builtIn, false); auto forcedType = getForcedType(symbol->getQualifier().builtIn, symbol->getType()); + + // There are pairs of symbols that map to the same SPIR-V built-in: + // gl_ObjectToWorldEXT and gl_ObjectToWorld3x4EXT, and gl_WorldToObjectEXT + // and gl_WorldToObject3x4EXT. SPIR-V forbids having two OpVariables + // with the same BuiltIn in the same storage class, so we must re-use one. + const bool mayNeedToReuseBuiltIn = + builtIn == spv::BuiltInObjectToWorldKHR || + builtIn == spv::BuiltInWorldToObjectKHR; + + if (mayNeedToReuseBuiltIn) { + auto iter = builtInVariableIds.find(uint32_t(builtIn)); + if (builtInVariableIds.end() != iter) { + id = iter->second; + symbolValues[symbol->getId()] = id; + if (forcedType.second != spv::NoType) + forceType[id] = forcedType.second; + return id; + } + } + id = createSpvVariable(symbol, forcedType.first); + + if (mayNeedToReuseBuiltIn) { + builtInVariableIds.insert({uint32_t(builtIn), id}); + } + symbolValues[symbol->getId()] = id; if (forcedType.second != spv::NoType) forceType[id] = forcedType.second; @@ -8737,13 +9620,11 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol builder.addDecoration(id, TranslatePrecisionDecoration(symbol->getType())); builder.addDecoration(id, TranslateInterpolationDecoration(symbol->getType().getQualifier())); builder.addDecoration(id, TranslateAuxiliaryStorageDecoration(symbol->getType().getQualifier())); -#ifndef GLSLANG_WEB addMeshNVDecoration(id, /*member*/ -1, symbol->getType().getQualifier()); if (symbol->getQualifier().hasComponent()) builder.addDecoration(id, spv::DecorationComponent, symbol->getQualifier().layoutComponent); if (symbol->getQualifier().hasIndex()) builder.addDecoration(id, spv::DecorationIndex, symbol->getQualifier().layoutIndex); -#endif if (symbol->getType().getQualifier().hasSpecConstantId()) builder.addDecoration(id, spv::DecorationSpecId, symbol->getType().getQualifier().layoutSpecConstantId); // atomic counters use this: @@ -8752,13 +9633,17 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol } if (symbol->getQualifier().hasLocation()) { - if (!(glslangIntermediate->isRayTracingStage() && glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) + if (!(glslangIntermediate->isRayTracingStage() && + (glslangIntermediate->IsRequestedExtension(glslang::E_GL_EXT_ray_tracing) || + glslangIntermediate->IsRequestedExtension(glslang::E_GL_NV_shader_invocation_reorder)) && (builder.getStorageClass(id) == spv::StorageClassRayPayloadKHR || builder.getStorageClass(id) == spv::StorageClassIncomingRayPayloadKHR || builder.getStorageClass(id) == spv::StorageClassCallableDataKHR || - builder.getStorageClass(id) == spv::StorageClassIncomingCallableDataKHR))) { - // Location values are used to link TraceRayKHR and ExecuteCallableKHR to corresponding variables - // but are not valid in SPIRV since they are supported only for Input/Output Storage classes. + builder.getStorageClass(id) == spv::StorageClassIncomingCallableDataKHR || + builder.getStorageClass(id) == spv::StorageClassHitObjectAttributeNV))) { + // Location values are used to link TraceRayKHR/ExecuteCallableKHR/HitObjectGetAttributesNV + // to corresponding variables but are not valid in SPIRV since they are supported only + // for Input/Output Storage classes. builder.addDecoration(id, spv::DecorationLocation, symbol->getQualifier().layoutLocation); } } @@ -8804,11 +9689,11 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol // Add volatile decoration to HelperInvocation for spirv1.6 and beyond if (builtIn == spv::BuiltInHelperInvocation && + !glslangIntermediate->usingVulkanMemoryModel() && glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_6) { builder.addDecoration(id, spv::DecorationVolatile); } -#ifndef GLSLANG_WEB // Subgroup builtins which have input storage class are volatile for ray tracing stages. if (symbol->getType().isImage() || symbol->getQualifier().isPipeInput()) { std::vector memory; @@ -8857,6 +9742,12 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol builder.addExtension(spv::E_SPV_NV_fragment_shader_barycentric); } + if (symbol->getQualifier().pervertexEXT) { + builder.addDecoration(id, spv::DecorationPerVertexKHR); + builder.addCapability(spv::CapabilityFragmentBarycentricKHR); + builder.addExtension(spv::E_SPV_KHR_fragment_shader_barycentric); + } + if (glslangIntermediate->getHlslFunctionality1() && symbol->getType().getQualifier().semanticName != nullptr) { builder.addExtension("SPV_GOOGLE_hlsl_functionality1"); builder.addDecoration(id, (spv::Decoration)spv::DecorationHlslSemanticGOOGLE, @@ -8868,63 +9759,31 @@ spv::Id TGlslangToSpvTraverser::getSymbolId(const glslang::TIntermSymbol* symbol spv::DecorationRestrictPointerEXT : spv::DecorationAliasedPointerEXT); } - // - // Add SPIR-V decorations for structure (GL_EXT_spirv_intrinsics) - // - if (symbol->getType().getQualifier().hasSprivDecorate()) { - const glslang::TSpirvDecorate& spirvDecorate = symbol->getType().getQualifier().getSpirvDecorate(); - - // Add spirv_decorate - for (auto& decorate : spirvDecorate.decorates) { - if (!decorate.second.empty()) { - std::vector literals; - TranslateLiterals(decorate.second, literals); - builder.addDecoration(id, static_cast(decorate.first), literals); - } - else - builder.addDecoration(id, static_cast(decorate.first)); - } - - // Add spirv_decorate_id - for (auto& decorateId : spirvDecorate.decorateIds) { - std::vector operandIds; - assert(!decorateId.second.empty()); - for (auto extraOperand : decorateId.second) { - if (extraOperand->getQualifier().isSpecConstant()) - operandIds.push_back(getSymbolId(extraOperand->getAsSymbolNode())); - else - operandIds.push_back(createSpvConstant(*extraOperand)); - } - builder.addDecorationId(id, static_cast(decorateId.first), operandIds); - } - - // Add spirv_decorate_string - for (auto& decorateString : spirvDecorate.decorateStrings) { - std::vector strings; - assert(!decorateString.second.empty()); - for (auto extraOperand : decorateString.second) { - const char* string = extraOperand->getConstArray()[0].getSConst()->c_str(); - strings.push_back(string); - } - builder.addDecoration(id, static_cast(decorateString.first), strings); - } - } -#endif + // Add SPIR-V decorations (GL_EXT_spirv_intrinsics) + if (symbol->getType().getQualifier().hasSpirvDecorate()) + applySpirvDecorate(symbol->getType(), id, {}); return id; } -#ifndef GLSLANG_WEB // add per-primitive, per-view. per-task decorations to a struct member (member >= 0) or an object void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const glslang::TQualifier& qualifier) { + bool isMeshShaderExt = (glslangIntermediate->getRequestedExtensions().find(glslang::E_GL_EXT_mesh_shader) != + glslangIntermediate->getRequestedExtensions().end()); + if (member >= 0) { if (qualifier.perPrimitiveNV) { // Need to add capability/extension for fragment shader. // Mesh shader already adds this by default. if (glslangIntermediate->getStage() == EShLangFragment) { - builder.addCapability(spv::CapabilityMeshShadingNV); - builder.addExtension(spv::E_SPV_NV_mesh_shader); + if(isMeshShaderExt) { + builder.addCapability(spv::CapabilityMeshShadingEXT); + builder.addExtension(spv::E_SPV_EXT_mesh_shader); + } else { + builder.addCapability(spv::CapabilityMeshShadingNV); + builder.addExtension(spv::E_SPV_NV_mesh_shader); + } } builder.addMemberDecoration(id, (unsigned)member, spv::DecorationPerPrimitiveNV); } @@ -8937,8 +9796,13 @@ void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const g // Need to add capability/extension for fragment shader. // Mesh shader already adds this by default. if (glslangIntermediate->getStage() == EShLangFragment) { - builder.addCapability(spv::CapabilityMeshShadingNV); - builder.addExtension(spv::E_SPV_NV_mesh_shader); + if(isMeshShaderExt) { + builder.addCapability(spv::CapabilityMeshShadingEXT); + builder.addExtension(spv::E_SPV_EXT_mesh_shader); + } else { + builder.addCapability(spv::CapabilityMeshShadingNV); + builder.addExtension(spv::E_SPV_NV_mesh_shader); + } } builder.addDecoration(id, spv::DecorationPerPrimitiveNV); } @@ -8948,7 +9812,50 @@ void TGlslangToSpvTraverser::addMeshNVDecoration(spv::Id id, int member, const g builder.addDecoration(id, spv::DecorationPerTaskNV); } } -#endif + +void TGlslangToSpvTraverser::addImageProcessingQCOMDecoration(spv::Id id, spv::Decoration decor) +{ + spv::Op opc = builder.getOpCode(id); + if (opc == spv::OpSampledImage) { + id = builder.getIdOperand(id, 0); + opc = builder.getOpCode(id); + } + + if (opc == spv::OpLoad) { + spv::Id texid = builder.getIdOperand(id, 0); + builder.addDecoration(texid, decor); + } +} + +void TGlslangToSpvTraverser::addImageProcessing2QCOMDecoration(spv::Id id, bool isForGather) +{ + if (isForGather) { + return addImageProcessingQCOMDecoration(id, spv::DecorationBlockMatchTextureQCOM); + } + + auto addDecor = + [this](spv::Id id, spv::Decoration decor) { + spv::Id tsopc = this->builder.getOpCode(id); + if (tsopc == spv::OpLoad) { + spv::Id tsid = this->builder.getIdOperand(id, 0); + if (this->glslangIntermediate->getSpv().spv >= glslang::EShTargetSpv_1_4) { + assert(iOSet.count(tsid) > 0); + } + this->builder.addDecoration(tsid, decor); + } + }; + + spv::Id opc = builder.getOpCode(id); + bool isInterfaceObject = (opc != spv::OpSampledImage); + + if (!isInterfaceObject) { + addDecor(builder.getIdOperand(id, 0), spv::DecorationBlockMatchTextureQCOM); + addDecor(builder.getIdOperand(id, 1), spv::DecorationBlockMatchSamplerQCOM); + } else { + addDecor(id, spv::DecorationBlockMatchTextureQCOM); + addDecor(id, spv::DecorationBlockMatchSamplerQCOM); + } +} // Make a full tree of instructions to build a SPIR-V specialization constant, // or regular constant if possible. @@ -9076,17 +9983,20 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla case glslang::EbtBool: spvConsts.push_back(builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst())); break; -#ifndef GLSLANG_WEB case glslang::EbtInt8: + builder.addCapability(spv::CapabilityInt8); spvConsts.push_back(builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const())); break; case glslang::EbtUint8: + builder.addCapability(spv::CapabilityInt8); spvConsts.push_back(builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const())); break; case glslang::EbtInt16: + builder.addCapability(spv::CapabilityInt16); spvConsts.push_back(builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const())); break; case glslang::EbtUint16: + builder.addCapability(spv::CapabilityInt16); spvConsts.push_back(builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const())); break; case glslang::EbtInt64: @@ -9099,9 +10009,9 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla spvConsts.push_back(builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst())); break; case glslang::EbtFloat16: + builder.addCapability(spv::CapabilityFloat16); spvConsts.push_back(builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst())); break; -#endif default: assert(0); break; @@ -9125,17 +10035,20 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla case glslang::EbtBool: scalar = builder.makeBoolConstant(zero ? false : consts[nextConst].getBConst(), specConstant); break; -#ifndef GLSLANG_WEB case glslang::EbtInt8: + builder.addCapability(spv::CapabilityInt8); scalar = builder.makeInt8Constant(zero ? 0 : consts[nextConst].getI8Const(), specConstant); break; case glslang::EbtUint8: + builder.addCapability(spv::CapabilityInt8); scalar = builder.makeUint8Constant(zero ? 0 : consts[nextConst].getU8Const(), specConstant); break; case glslang::EbtInt16: + builder.addCapability(spv::CapabilityInt16); scalar = builder.makeInt16Constant(zero ? 0 : consts[nextConst].getI16Const(), specConstant); break; case glslang::EbtUint16: + builder.addCapability(spv::CapabilityInt16); scalar = builder.makeUint16Constant(zero ? 0 : consts[nextConst].getU16Const(), specConstant); break; case glslang::EbtInt64: @@ -9148,13 +10061,13 @@ spv::Id TGlslangToSpvTraverser::createSpvConstantFromConstUnionArray(const glsla scalar = builder.makeDoubleConstant(zero ? 0.0 : consts[nextConst].getDConst(), specConstant); break; case glslang::EbtFloat16: + builder.addCapability(spv::CapabilityFloat16); scalar = builder.makeFloat16Constant(zero ? 0.0F : (float)consts[nextConst].getDConst(), specConstant); break; case glslang::EbtReference: scalar = builder.makeUint64Constant(zero ? 0 : consts[nextConst].getU64Const(), specConstant); scalar = builder.createUnaryOp(spv::OpBitcast, typeId, scalar); break; -#endif case glslang::EbtString: scalar = builder.getStringId(consts[nextConst].getSConst()->c_str()); break; @@ -9302,7 +10215,6 @@ spv::Id TGlslangToSpvTraverser::createShortCircuit(glslang::TOperator op, glslan return builder.createOp(spv::OpPhi, boolTypeId, phiOperands); } -#ifndef GLSLANG_WEB // Return type Id of the imported set of extended instructions corresponds to the name. // Import this set if it has not been imported yet. spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name) @@ -9310,13 +10222,11 @@ spv::Id TGlslangToSpvTraverser::getExtBuiltins(const char* name) if (extBuiltinMap.find(name) != extBuiltinMap.end()) return extBuiltinMap[name]; else { - builder.addExtension(name); spv::Id extBuiltins = builder.import(name); extBuiltinMap[name] = extBuiltins; return extBuiltins; } } -#endif }; // end anonymous namespace @@ -9345,31 +10255,36 @@ int GetSpirvGeneratorVersion() // return 7; // GLSL volatile keyword maps to both SPIR-V decorations Volatile and Coherent // return 8; // switch to new dead block eliminator; use OpUnreachable // return 9; // don't include opaque function parameters in OpEntryPoint global's operand list - return 10; // Generate OpFUnordNotEqual for != comparisons + // return 10; // Generate OpFUnordNotEqual for != comparisons + return 11; // Make OpEmitMeshTasksEXT a terminal instruction } // Write SPIR-V out to a binary file -void OutputSpvBin(const std::vector& spirv, const char* baseName) +bool OutputSpvBin(const std::vector& spirv, const char* baseName) { std::ofstream out; out.open(baseName, std::ios::binary | std::ios::out); - if (out.fail()) + if (out.fail()) { printf("ERROR: Failed to open file: %s\n", baseName); + return false; + } for (int i = 0; i < (int)spirv.size(); ++i) { unsigned int word = spirv[i]; out.write((const char*)&word, 4); } out.close(); + return true; } // Write SPIR-V out to a text file with 32-bit hexadecimal words -void OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName) +bool OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName) { -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) std::ofstream out; out.open(baseName, std::ios::binary | std::ios::out); - if (out.fail()) + if (out.fail()) { printf("ERROR: Failed to open file: %s\n", baseName); + return false; + } out << "\t// " << GetSpirvGeneratorVersion() << GLSLANG_VERSION_MAJOR << "." << GLSLANG_VERSION_MINOR << "." << GLSLANG_VERSION_PATCH << @@ -9395,7 +10310,7 @@ void OutputSpvHex(const std::vector& spirv, const char* baseName, out << std::endl; } out.close(); -#endif + return true; } // @@ -9412,7 +10327,7 @@ void GlslangToSpv(const TIntermediate& intermediate, std::vector& { TIntermNode* root = intermediate.getTreeRoot(); - if (root == 0) + if (root == nullptr) return; SpvOptions defaultOptions; @@ -9423,7 +10338,7 @@ void GlslangToSpv(const TIntermediate& intermediate, std::vector& TGlslangToSpvTraverser it(intermediate.getSpv().spv, &intermediate, logger, *options); root->traverse(&it); - it.finishSpv(); + it.finishSpv(options->compileOnly); it.dumpSpv(spirv); #if ENABLE_OPT diff --git a/src/libraries/glslang/SPIRV/GlslangToSpv.h b/src/libraries/glslang/SPIRV/GlslangToSpv.h index 86e1c23bf..1b9ef3c51 100644 --- a/src/libraries/glslang/SPIRV/GlslangToSpv.h +++ b/src/libraries/glslang/SPIRV/GlslangToSpv.h @@ -35,19 +35,25 @@ #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 #include #include "Logger.h" namespace glslang { +class TIntermediate; + +struct SpvOptions { + bool generateDebugInfo {false}; + bool stripDebugInfo {false}; + bool disableOptimizer {true}; + bool optimizeSize {false}; + bool disassemble {false}; + bool validate {false}; + bool emitNonSemanticShaderDebugInfo {false}; + bool emitNonSemanticShaderDebugSource{ false }; + bool compileOnly{false}; +}; void GetSpirvVersion(std::string&); int GetSpirvGeneratorVersion(); @@ -55,7 +61,7 @@ void GlslangToSpv(const glslang::TIntermediate& intermediate, std::vector& spirv, spv::SpvBuildLogger* logger, SpvOptions* options = nullptr); -void OutputSpvBin(const std::vector& spirv, const char* baseName); -void OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName); +bool OutputSpvBin(const std::vector& spirv, const char* baseName); +bool OutputSpvHex(const std::vector& spirv, const char* baseName, const char* varName); } diff --git a/src/libraries/glslang/SPIRV/Logger.cpp b/src/libraries/glslang/SPIRV/Logger.cpp index cdc8469c4..48bd4e3ad 100644 --- a/src/libraries/glslang/SPIRV/Logger.cpp +++ b/src/libraries/glslang/SPIRV/Logger.cpp @@ -32,8 +32,6 @@ // 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 @@ -68,5 +66,3 @@ std::string SpvBuildLogger::getAllMessages() const { } } // end spv namespace - -#endif diff --git a/src/libraries/glslang/SPIRV/Logger.h b/src/libraries/glslang/SPIRV/Logger.h index 411367c03..2e4ddaf51 100644 --- a/src/libraries/glslang/SPIRV/Logger.h +++ b/src/libraries/glslang/SPIRV/Logger.h @@ -46,14 +46,6 @@ 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. @@ -67,7 +59,6 @@ public: // Returns all messages accumulated in the order of: // TBD functionalities, missing functionalities, warnings, errors. std::string getAllMessages() const; -#endif private: SpvBuildLogger(const SpvBuildLogger&); diff --git a/src/libraries/glslang/SPIRV/NonSemanticDebugPrintf.h b/src/libraries/glslang/SPIRV/NonSemanticDebugPrintf.h index 83796d75e..3ca7247f2 100644 --- a/src/libraries/glslang/SPIRV/NonSemanticDebugPrintf.h +++ b/src/libraries/glslang/SPIRV/NonSemanticDebugPrintf.h @@ -1,5 +1,5 @@ // 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 @@ -7,15 +7,15 @@ // 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. @@ -23,7 +23,7 @@ // 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_ diff --git a/src/libraries/glslang/SPIRV/NonSemanticShaderDebugInfo100.h b/src/libraries/glslang/SPIRV/NonSemanticShaderDebugInfo100.h new file mode 100644 index 000000000..f74abcb64 --- /dev/null +++ b/src/libraries/glslang/SPIRV/NonSemanticShaderDebugInfo100.h @@ -0,0 +1,171 @@ +// Copyright (c) 2018 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_NonSemanticShaderDebugInfo100_H_ +#define SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + NonSemanticShaderDebugInfo100Version = 100, + NonSemanticShaderDebugInfo100Version_BitWidthPadding = 0x7fffffff +}; +enum { + NonSemanticShaderDebugInfo100Revision = 6, + NonSemanticShaderDebugInfo100Revision_BitWidthPadding = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100Instructions { + NonSemanticShaderDebugInfo100DebugInfoNone = 0, + NonSemanticShaderDebugInfo100DebugCompilationUnit = 1, + NonSemanticShaderDebugInfo100DebugTypeBasic = 2, + NonSemanticShaderDebugInfo100DebugTypePointer = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifier = 4, + NonSemanticShaderDebugInfo100DebugTypeArray = 5, + NonSemanticShaderDebugInfo100DebugTypeVector = 6, + NonSemanticShaderDebugInfo100DebugTypedef = 7, + NonSemanticShaderDebugInfo100DebugTypeFunction = 8, + NonSemanticShaderDebugInfo100DebugTypeEnum = 9, + NonSemanticShaderDebugInfo100DebugTypeComposite = 10, + NonSemanticShaderDebugInfo100DebugTypeMember = 11, + NonSemanticShaderDebugInfo100DebugTypeInheritance = 12, + NonSemanticShaderDebugInfo100DebugTypePtrToMember = 13, + NonSemanticShaderDebugInfo100DebugTypeTemplate = 14, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameter = 15, + NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter = 16, + NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack = 17, + NonSemanticShaderDebugInfo100DebugGlobalVariable = 18, + NonSemanticShaderDebugInfo100DebugFunctionDeclaration = 19, + NonSemanticShaderDebugInfo100DebugFunction = 20, + NonSemanticShaderDebugInfo100DebugLexicalBlock = 21, + NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator = 22, + NonSemanticShaderDebugInfo100DebugScope = 23, + NonSemanticShaderDebugInfo100DebugNoScope = 24, + NonSemanticShaderDebugInfo100DebugInlinedAt = 25, + NonSemanticShaderDebugInfo100DebugLocalVariable = 26, + NonSemanticShaderDebugInfo100DebugInlinedVariable = 27, + NonSemanticShaderDebugInfo100DebugDeclare = 28, + NonSemanticShaderDebugInfo100DebugValue = 29, + NonSemanticShaderDebugInfo100DebugOperation = 30, + NonSemanticShaderDebugInfo100DebugExpression = 31, + NonSemanticShaderDebugInfo100DebugMacroDef = 32, + NonSemanticShaderDebugInfo100DebugMacroUndef = 33, + NonSemanticShaderDebugInfo100DebugImportedEntity = 34, + NonSemanticShaderDebugInfo100DebugSource = 35, + NonSemanticShaderDebugInfo100DebugFunctionDefinition = 101, + NonSemanticShaderDebugInfo100DebugSourceContinued = 102, + NonSemanticShaderDebugInfo100DebugLine = 103, + NonSemanticShaderDebugInfo100DebugNoLine = 104, + NonSemanticShaderDebugInfo100DebugBuildIdentifier = 105, + NonSemanticShaderDebugInfo100DebugStoragePath = 106, + NonSemanticShaderDebugInfo100DebugEntryPoint = 107, + NonSemanticShaderDebugInfo100DebugTypeMatrix = 108, + NonSemanticShaderDebugInfo100InstructionsMax = 0x7fffffff +}; + + +enum NonSemanticShaderDebugInfo100DebugInfoFlags { + NonSemanticShaderDebugInfo100None = 0x0000, + NonSemanticShaderDebugInfo100FlagIsProtected = 0x01, + NonSemanticShaderDebugInfo100FlagIsPrivate = 0x02, + NonSemanticShaderDebugInfo100FlagIsPublic = 0x03, + NonSemanticShaderDebugInfo100FlagIsLocal = 0x04, + NonSemanticShaderDebugInfo100FlagIsDefinition = 0x08, + NonSemanticShaderDebugInfo100FlagFwdDecl = 0x10, + NonSemanticShaderDebugInfo100FlagArtificial = 0x20, + NonSemanticShaderDebugInfo100FlagExplicit = 0x40, + NonSemanticShaderDebugInfo100FlagPrototyped = 0x80, + NonSemanticShaderDebugInfo100FlagObjectPointer = 0x100, + NonSemanticShaderDebugInfo100FlagStaticMember = 0x200, + NonSemanticShaderDebugInfo100FlagIndirectVariable = 0x400, + NonSemanticShaderDebugInfo100FlagLValueReference = 0x800, + NonSemanticShaderDebugInfo100FlagRValueReference = 0x1000, + NonSemanticShaderDebugInfo100FlagIsOptimized = 0x2000, + NonSemanticShaderDebugInfo100FlagIsEnumClass = 0x4000, + NonSemanticShaderDebugInfo100FlagTypePassByValue = 0x8000, + NonSemanticShaderDebugInfo100FlagTypePassByReference = 0x10000, + NonSemanticShaderDebugInfo100FlagUnknownPhysicalLayout = 0x20000, + NonSemanticShaderDebugInfo100DebugInfoFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100BuildIdentifierFlags { + NonSemanticShaderDebugInfo100IdentifierPossibleDuplicates = 0x01, + NonSemanticShaderDebugInfo100BuildIdentifierFlagsMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncoding { + NonSemanticShaderDebugInfo100Unspecified = 0, + NonSemanticShaderDebugInfo100Address = 1, + NonSemanticShaderDebugInfo100Boolean = 2, + NonSemanticShaderDebugInfo100Float = 3, + NonSemanticShaderDebugInfo100Signed = 4, + NonSemanticShaderDebugInfo100SignedChar = 5, + NonSemanticShaderDebugInfo100Unsigned = 6, + NonSemanticShaderDebugInfo100UnsignedChar = 7, + NonSemanticShaderDebugInfo100DebugBaseTypeAttributeEncodingMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugCompositeType { + NonSemanticShaderDebugInfo100Class = 0, + NonSemanticShaderDebugInfo100Structure = 1, + NonSemanticShaderDebugInfo100Union = 2, + NonSemanticShaderDebugInfo100DebugCompositeTypeMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugTypeQualifier { + NonSemanticShaderDebugInfo100ConstType = 0, + NonSemanticShaderDebugInfo100VolatileType = 1, + NonSemanticShaderDebugInfo100RestrictType = 2, + NonSemanticShaderDebugInfo100AtomicType = 3, + NonSemanticShaderDebugInfo100DebugTypeQualifierMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugOperation { + NonSemanticShaderDebugInfo100Deref = 0, + NonSemanticShaderDebugInfo100Plus = 1, + NonSemanticShaderDebugInfo100Minus = 2, + NonSemanticShaderDebugInfo100PlusUconst = 3, + NonSemanticShaderDebugInfo100BitPiece = 4, + NonSemanticShaderDebugInfo100Swap = 5, + NonSemanticShaderDebugInfo100Xderef = 6, + NonSemanticShaderDebugInfo100StackValue = 7, + NonSemanticShaderDebugInfo100Constu = 8, + NonSemanticShaderDebugInfo100Fragment = 9, + NonSemanticShaderDebugInfo100DebugOperationMax = 0x7fffffff +}; + +enum NonSemanticShaderDebugInfo100DebugImportedEntity { + NonSemanticShaderDebugInfo100ImportedModule = 0, + NonSemanticShaderDebugInfo100ImportedDeclaration = 1, + NonSemanticShaderDebugInfo100DebugImportedEntityMax = 0x7fffffff +}; + + +#ifdef __cplusplus +} +#endif + +#endif // SPIRV_UNIFIED1_NonSemanticShaderDebugInfo100_H_ diff --git a/src/libraries/glslang/SPIRV/SPVRemapper.cpp b/src/libraries/glslang/SPIRV/SPVRemapper.cpp index 56d6d5d4a..f8f50a951 100644 --- a/src/libraries/glslang/SPIRV/SPVRemapper.cpp +++ b/src/libraries/glslang/SPIRV/SPVRemapper.cpp @@ -36,10 +36,6 @@ #include "SPVRemapper.h" #include "doc.h" -#if !defined (use_cpp11) -// ... not supported before C++11 -#else // defined (use_cpp11) - #include #include #include "../glslang/Include/Common.h" @@ -160,15 +156,29 @@ namespace spv { } // Is this an opcode we should remove when using --strip? - bool spirvbin_t::isStripOp(spv::Op opCode) const + bool spirvbin_t::isStripOp(spv::Op opCode, unsigned start) const { switch (opCode) { case spv::OpSource: case spv::OpSourceExtension: case spv::OpName: case spv::OpMemberName: - case spv::OpLine: return true; - default: return false; + case spv::OpLine : + { + const std::string name = literalString(start + 2); + + std::vector::const_iterator it; + for (it = stripWhiteList.begin(); it < stripWhiteList.end(); it++) + { + if (name.find(*it) != std::string::npos) { + return false; + } + } + + return true; + } + default : + return false; } } @@ -297,15 +307,21 @@ namespace spv { std::string spirvbin_t::literalString(unsigned word) const { std::string literal; + const spirword_t * pos = spv.data() + word; literal.reserve(16); - const char* bytes = reinterpret_cast(spv.data() + word); - - while (bytes && *bytes) - literal += *bytes++; - - return literal; + do { + spirword_t word = *pos; + for (int i = 0; i < 4; i++) { + char c = word & 0xff; + if (c == '\0') + return literal; + literal += c; + word >>= 8; + } + pos++; + } while (true); } void spirvbin_t::applyMap() @@ -366,7 +382,7 @@ namespace spv { process( [&](spv::Op opCode, unsigned start) { // remember opcodes we want to strip later - if (isStripOp(opCode)) + if (isStripOp(opCode, start)) stripInst(start); return true; }, @@ -664,6 +680,7 @@ namespace spv { case spv::OperandKernelEnqueueFlags: case spv::OperandKernelProfilingInfo: case spv::OperandCapability: + case spv::OperandCooperativeMatrixOperands: ++word; break; @@ -1488,14 +1505,23 @@ namespace spv { } // remap from a memory image - void spirvbin_t::remap(std::vector& in_spv, std::uint32_t opts) + void spirvbin_t::remap(std::vector& in_spv, const std::vector& whiteListStrings, + std::uint32_t opts) { + stripWhiteList = whiteListStrings; spv.swap(in_spv); remap(opts); spv.swap(in_spv); } + // remap from a memory image - legacy interface without white list + void spirvbin_t::remap(std::vector& in_spv, std::uint32_t opts) + { + stripWhiteList.clear(); + spv.swap(in_spv); + remap(opts); + spv.swap(in_spv); + } + } // namespace SPV -#endif // defined (use_cpp11) - diff --git a/src/libraries/glslang/SPIRV/SPVRemapper.h b/src/libraries/glslang/SPIRV/SPVRemapper.h index d6b9c346d..33efe331e 100644 --- a/src/libraries/glslang/SPIRV/SPVRemapper.h +++ b/src/libraries/glslang/SPIRV/SPVRemapper.h @@ -43,12 +43,6 @@ 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: @@ -74,27 +68,6 @@ public: } // namespace SPV -#if !defined (use_cpp11) -#include -#include - -namespace spv { -class spirvbin_t : public spirvbin_base_t -{ -public: - spirvbin_t(int /*verbose = 0*/) { } - - void remap(std::vector& /*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 #include #include @@ -104,9 +77,9 @@ public: #include #include "spirv.hpp" -#include "spvIR.h" namespace spv { +const Id NoResult = 0; // class to hold SPIR-V binary data for remapping, DCE, and debug stripping class spirvbin_t : public spirvbin_base_t @@ -118,6 +91,10 @@ public: virtual ~spirvbin_t() { } // remap on an existing binary in memory + void remap(std::vector& spv, const std::vector& whiteListStrings, + std::uint32_t opts = DO_EVERYTHING); + + // remap on an existing binary in memory - legacy interface without white list void remap(std::vector& spv, std::uint32_t opts = DO_EVERYTHING); // Type for error/log handler functions @@ -180,6 +157,8 @@ private: unsigned typeSizeInWords(spv::Id id) const; unsigned idTypeSizeInWords(spv::Id id) const; + bool isStripOp(spv::Op opCode, unsigned start) 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]); } @@ -249,6 +228,8 @@ private: std::vector spv; // SPIR words + std::vector stripWhiteList; + namemap_t nameMap; // ID names from OpName // Since we want to also do binary ops, we can't use std::vector. we could use @@ -300,5 +281,4 @@ private: } // namespace SPV -#endif // defined (use_cpp11) #endif // SPIRVREMAPPER_H diff --git a/src/libraries/glslang/SPIRV/SpvBuilder.cpp b/src/libraries/glslang/SPIRV/SpvBuilder.cpp index 838f916a0..062a7c79b 100644 --- a/src/libraries/glslang/SPIRV/SpvBuilder.cpp +++ b/src/libraries/glslang/SPIRV/SpvBuilder.cpp @@ -46,10 +46,7 @@ #include #include "SpvBuilder.h" - -#ifndef GLSLANG_WEB #include "hex_float.h" -#endif #ifndef _WIN32 #include @@ -59,18 +56,14 @@ namespace spv { Builder::Builder(unsigned int spvVersion, unsigned int magicNumber, SpvBuildLogger* buildLogger) : spvVersion(spvVersion), - source(SourceLanguageUnknown), + sourceLang(SourceLanguageUnknown), sourceVersion(0), - sourceFileStringId(NoResult), - currentLine(0), - currentFile(nullptr), - emitOpLines(false), addressModel(AddressingModelLogical), memoryModel(MemoryModelGLSL450), builderNumber(magicNumber), - buildPoint(0), + buildPoint(nullptr), uniqueId(0), - entryPointFunction(0), + entryPointFunction(nullptr), generatingOpCodeForSpecConst(false), logger(buildLogger) { @@ -91,56 +84,19 @@ Id Builder::import(const char* name) return import->getResultId(); } -// Emit instruction for non-filename-based #line directives (ie. no filename -// seen yet): emit an OpLine if we've been asked to emit OpLines and the line -// number has changed since the last time, and is a valid line number. -void Builder::setLine(int lineNum) -{ - if (lineNum != 0 && lineNum != currentLine) { - currentLine = lineNum; - if (emitOpLines) - addLine(sourceFileStringId, currentLine, 0); - } -} - -// If no filename, do non-filename-based #line emit. Else do filename-based emit. -// Emit OpLine if we've been asked to emit OpLines and the line number or filename -// has changed since the last time, and line number is valid. -void Builder::setLine(int lineNum, const char* filename) -{ - if (filename == nullptr) { - setLine(lineNum); - return; - } - if ((lineNum != 0 && lineNum != currentLine) || currentFile == nullptr || - strncmp(filename, currentFile, strlen(currentFile) + 1) != 0) { - currentLine = lineNum; - currentFile = filename; - if (emitOpLines) { - spv::Id strId = getStringId(filename); - addLine(strId, currentLine, 0); - } - } -} - -void Builder::addLine(Id fileName, int lineNum, int column) -{ - Instruction* line = new Instruction(OpLine); - line->addIdOperand(fileName); - line->addImmediateOperand(lineNum); - line->addImmediateOperand(column); - buildPoint->addInstruction(std::unique_ptr(line)); -} - // For creating new groupedTypes (will return old type if the requested one was already made). Id Builder::makeVoidType() { Instruction* type; if (groupedTypes[OpTypeVoid].size() == 0) { - type = new Instruction(getUniqueId(), NoType, OpTypeVoid); + Id typeId = getUniqueId(); + type = new Instruction(typeId, NoType, OpTypeVoid); groupedTypes[OpTypeVoid].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + // Core OpTypeVoid used for debug void type + if (emitNonSemanticShaderDebugInfo) + debugId[typeId] = typeId; } else type = groupedTypes[OpTypeVoid].back(); @@ -155,9 +111,16 @@ Id Builder::makeBoolType() groupedTypes[OpTypeBool].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + + if (emitNonSemanticShaderDebugInfo) { + auto const debugResultId = makeBoolDebugType(32); + debugId[type->getResultId()] = debugResultId; + } + } else type = groupedTypes[OpTypeBool].back(); + return type->getResultId(); } @@ -172,6 +135,12 @@ Id Builder::makeSamplerType() } else type = groupedTypes[OpTypeSampler].back(); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeCompositeDebugType({}, "type.sampler", NonSemanticShaderDebugInfo100Structure, true); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -194,6 +163,11 @@ Id Builder::makePointer(StorageClass storageClass, Id pointee) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) { + const Id debugResultId = makePointerDebugType(storageClass, pointee); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -233,11 +207,6 @@ Id Builder::makePointerFromForwardPointer(StorageClass storageClass, Id forwardP Id Builder::makeIntegerType(int width, bool hasSign) { -#ifdef GLSLANG_WEB - assert(width == 32); - width = 32; -#endif - // try to find it Instruction* type; for (int t = 0; t < (int)groupedTypes[OpTypeInt].size(); ++t) { @@ -268,16 +237,17 @@ Id Builder::makeIntegerType(int width, bool hasSign) break; } + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeIntegerDebugType(width, hasSign); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } Id Builder::makeFloatType(int width) { -#ifdef GLSLANG_WEB - assert(width == 32); - width = 32; -#endif - // try to find it Instruction* type; for (int t = 0; t < (int)groupedTypes[OpTypeFloat].size(); ++t) { @@ -305,6 +275,12 @@ Id Builder::makeFloatType(int width) break; } + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeFloatDebugType(width); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -312,7 +288,7 @@ Id Builder::makeFloatType(int width) // See makeStructResultType() for non-decorated structs // needed as the result of some instructions, which does // check for duplicates. -Id Builder::makeStructType(const std::vector& members, const char* name) +Id Builder::makeStructType(const std::vector& members, const char* name, bool const compilerGenerated) { // Don't look for previous one, because in the general case, // structs can be duplicated except for decorations. @@ -326,6 +302,12 @@ Id Builder::makeStructType(const std::vector& members, const char* name) module.mapInstruction(type); addName(type->getResultId(), name); + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) + { + auto const debugResultId = makeCompositeDebugType(members, name, NonSemanticShaderDebugInfo100Structure); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -372,6 +354,12 @@ Id Builder::makeVectorType(Id component, int size) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeVectorDebugType(component, size); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -398,18 +386,50 @@ Id Builder::makeMatrixType(Id component, int cols, int rows) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeMatrixDebugType(column, cols); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } -Id Builder::makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols) +Id Builder::makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixKHR].size(); ++t) { + type = groupedTypes[OpTypeCooperativeMatrixKHR][t]; + if (type->getIdOperand(0) == component && + type->getIdOperand(1) == scope && + type->getIdOperand(2) == rows && + type->getIdOperand(3) == cols && + type->getIdOperand(4) == use) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), NoType, OpTypeCooperativeMatrixKHR); + type->addIdOperand(component); + type->addIdOperand(scope); + type->addIdOperand(rows); + type->addIdOperand(cols); + type->addIdOperand(use); + groupedTypes[OpTypeCooperativeMatrixKHR].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols) { // try to find it Instruction* type; for (int t = 0; t < (int)groupedTypes[OpTypeCooperativeMatrixNV].size(); ++t) { type = groupedTypes[OpTypeCooperativeMatrixNV][t]; - if (type->getIdOperand(0) == component && - type->getIdOperand(1) == scope && - type->getIdOperand(2) == rows && + if (type->getIdOperand(0) == component && type->getIdOperand(1) == scope && type->getIdOperand(2) == rows && type->getIdOperand(3) == cols) return type->getResultId(); } @@ -427,17 +447,28 @@ Id Builder::makeCooperativeMatrixType(Id component, Id scope, Id rows, Id cols) return type->getResultId(); } +Id Builder::makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType) +{ + Instruction* instr = module.getInstruction(otherType); + if (instr->getOpCode() == OpTypeCooperativeMatrixNV) { + return makeCooperativeMatrixTypeNV(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3)); + } else { + assert(instr->getOpCode() == OpTypeCooperativeMatrixKHR); + return makeCooperativeMatrixTypeKHR(component, instr->getIdOperand(1), instr->getIdOperand(2), instr->getIdOperand(3), instr->getIdOperand(4)); + } +} + Id Builder::makeGenericType(spv::Op opcode, std::vector& operands) { // try to find it Instruction* type; for (int t = 0; t < (int)groupedTypes[opcode].size(); ++t) { type = groupedTypes[opcode][t]; - if (type->getNumOperands() != operands.size()) + if (static_cast(type->getNumOperands()) != operands.size()) continue; // Number mismatch, find next bool match = true; - for (int op = 0; match && op < operands.size(); ++op) { + for (int op = 0; match && op < (int)operands.size(); ++op) { match = (operands[op].isId ? type->getIdOperand(op) : type->getImmediateOperand(op)) == operands[op].word; } if (match) @@ -446,7 +477,7 @@ Id Builder::makeGenericType(spv::Op opcode, std::vector& opera // not found, make it type = new Instruction(getUniqueId(), NoType, opcode); - for (int op = 0; op < operands.size(); ++op) { + for (size_t op = 0; op < operands.size(); ++op) { if (operands[op].isId) type->addIdOperand(operands[op].word); else @@ -484,6 +515,12 @@ Id Builder::makeArrayType(Id element, Id sizeId, int stride) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeArrayDebugType(element, sizeId); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -494,6 +531,12 @@ Id Builder::makeRuntimeArray(Id element) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeArrayDebugType(element, makeUintConstant(0)); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } @@ -513,11 +556,25 @@ Id Builder::makeFunctionType(Id returnType, const std::vector& paramTypes) } } if (! mismatch) + { + // If compiling HLSL, glslang will create a wrapper function around the entrypoint. Accordingly, a void(void) + // function type is created for the wrapper function. However, nonsemantic shader debug information is disabled + // while creating the HLSL wrapper. Consequently, if we encounter another void(void) function, we need to create + // the associated debug function type if it hasn't been created yet. + if(emitNonSemanticShaderDebugInfo && debugId[type->getResultId()] == 0) { + assert(sourceLang == spv::SourceLanguageHLSL); + assert(getTypeClass(returnType) == OpTypeVoid && paramTypes.size() == 0); + + Id debugTypeId = makeDebugFunctionType(returnType, {}); + debugId[type->getResultId()] = debugTypeId; + } return type->getResultId(); + } } // not found, make it - type = new Instruction(getUniqueId(), NoType, OpTypeFunction); + Id typeId = getUniqueId(); + type = new Instruction(typeId, NoType, OpTypeFunction); type->addIdOperand(returnType); for (int p = 0; p < (int)paramTypes.size(); ++p) type->addIdOperand(paramTypes[p]); @@ -525,9 +582,38 @@ Id Builder::makeFunctionType(Id returnType, const std::vector& paramTypes) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + // make debug type and map it + if (emitNonSemanticShaderDebugInfo) { + Id debugTypeId = makeDebugFunctionType(returnType, paramTypes); + debugId[typeId] = debugTypeId; + } + return type->getResultId(); } +Id Builder::makeDebugFunctionType(Id returnType, const std::vector& paramTypes) +{ + assert(debugId[returnType] != 0); + + Id typeId = getUniqueId(); + auto type = new Instruction(typeId, makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeFunction); + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); + type->addIdOperand(debugId[returnType]); + for (auto const paramType : paramTypes) { + if (isPointerType(paramType) || isArrayType(paramType)) { + type->addIdOperand(debugId[getContainedTypeId(paramType)]); + } + else { + type->addIdOperand(debugId[paramType]); + } + } + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + return typeId; +} + Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, bool ms, unsigned sampled, ImageFormat format) { @@ -561,7 +647,6 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); -#ifndef GLSLANG_WEB // deal with capabilities switch (dim) { case DimBuffer: @@ -607,7 +692,22 @@ Id Builder::makeImageType(Id sampledType, Dim dim, bool depth, bool arrayed, boo addCapability(CapabilityImageMSArray); } } -#endif + + if (emitNonSemanticShaderDebugInfo) + { + auto TypeName = [&dim]() -> char const* { + switch (dim) { + case Dim1D: return "type.1d.image"; + case Dim2D: return "type.2d.image"; + case Dim3D: return "type.3d.image"; + case DimCube: return "type.cube.image"; + default: return "type.image"; + } + }; + + auto const debugResultId = makeCompositeDebugType({}, TypeName(), NonSemanticShaderDebugInfo100Class, true); + debugId[type->getResultId()] = debugResultId; + } return type->getResultId(); } @@ -630,10 +730,444 @@ Id Builder::makeSampledImageType(Id imageType) constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = makeCompositeDebugType({}, "type.sampled.image", NonSemanticShaderDebugInfo100Class, true); + debugId[type->getResultId()] = debugResultId; + } + return type->getResultId(); } -#ifndef GLSLANG_WEB +Id Builder::makeDebugInfoNone() +{ + if (debugInfoNone != 0) + return debugInfoNone; + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugInfoNone); + + constantsTypesGlobals.push_back(std::unique_ptr(inst)); + module.mapInstruction(inst); + + debugInfoNone = inst->getResultId(); + + return debugInfoNone; +} + +Id Builder::makeBoolDebugType(int const size) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == getStringId("bool") && + type->getIdOperand(1) == static_cast(size) && + type->getIdOperand(2) == NonSemanticShaderDebugInfo100Boolean) + return type->getResultId(); + } + + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + + type->addIdOperand(getStringId("bool")); // name id + type->addIdOperand(makeUintConstant(size)); // size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Boolean)); // encoding id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeIntegerDebugType(int const width, bool const hasSign) +{ + const char* typeName = nullptr; + switch (width) { + case 8: typeName = hasSign ? "int8_t" : "uint8_t"; break; + case 16: typeName = hasSign ? "int16_t" : "uint16_t"; break; + case 64: typeName = hasSign ? "int64_t" : "uint64_t"; break; + default: typeName = hasSign ? "int" : "uint"; + } + auto nameId = getStringId(typeName); + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == nameId && + type->getIdOperand(1) == static_cast(width) && + type->getIdOperand(2) == (hasSign ? NonSemanticShaderDebugInfo100Signed : NonSemanticShaderDebugInfo100Unsigned)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + type->addIdOperand(nameId); // name id + type->addIdOperand(makeUintConstant(width)); // size id + if(hasSign == true) { + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Signed)); // encoding id + } else { + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Unsigned)); // encoding id + } + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeFloatDebugType(int const width) +{ + const char* typeName = nullptr; + switch (width) { + case 16: typeName = "float16_t"; break; + case 64: typeName = "double"; break; + default: typeName = "float"; break; + } + auto nameId = getStringId(typeName); + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic][t]; + if (type->getIdOperand(0) == nameId && + type->getIdOperand(1) == static_cast(width) && + type->getIdOperand(2) == NonSemanticShaderDebugInfo100Float) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeBasic); + type->addIdOperand(nameId); // name id + type->addIdOperand(makeUintConstant(width)); // size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100Float)); // encoding id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100None)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeBasic].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType) +{ + assert(sequenceType == NonSemanticShaderDebugInfo100DebugTypeArray || + sequenceType == NonSemanticShaderDebugInfo100DebugTypeVector); + + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[sequenceType].size(); ++t) { + type = groupedDebugTypes[sequenceType][t]; + if (type->getIdOperand(0) == baseType && + type->getIdOperand(1) == makeUintConstant(componentCount)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(sequenceType); + type->addIdOperand(debugId[baseType]); // base type + type->addIdOperand(componentCount); // component count + + groupedDebugTypes[sequenceType].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeArrayDebugType(Id const baseType, Id const componentCount) +{ + return makeSequentialDebugType(baseType, componentCount, NonSemanticShaderDebugInfo100DebugTypeArray); +} + +Id Builder::makeVectorDebugType(Id const baseType, int const componentCount) +{ + return makeSequentialDebugType(baseType, makeUintConstant(componentCount), NonSemanticShaderDebugInfo100DebugTypeVector); +} + +Id Builder::makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor) +{ + // try to find it + Instruction* type; + for (int t = 0; t < (int)groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].size(); ++t) { + type = groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix][t]; + if (type->getIdOperand(0) == vectorType && + type->getIdOperand(1) == makeUintConstant(vectorCount)) + return type->getResultId(); + } + + // not found, make it + type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMatrix); + type->addIdOperand(debugId[vectorType]); // vector type id + type->addIdOperand(makeUintConstant(vectorCount)); // component count id + type->addIdOperand(makeBoolConstant(columnMajor)); // column-major id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMatrix].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc) +{ + assert(debugId[memberType] != 0); + + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeMember); + type->addIdOperand(getStringId(debugTypeLoc.name)); // name id + type->addIdOperand(debugId[memberType]); // type id + type->addIdOperand(makeDebugSource(currentFileId)); // source id + type->addIdOperand(makeUintConstant(debugTypeLoc.line)); // line id TODO: currentLine is always zero + type->addIdOperand(makeUintConstant(debugTypeLoc.column)); // TODO: column id + type->addIdOperand(makeUintConstant(0)); // TODO: offset id + type->addIdOperand(makeUintConstant(0)); // TODO: size id + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeMember].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +// Note: To represent a source language opaque type, this instruction must have no Members operands, Size operand must be +// DebugInfoNone, and Name must start with @ to avoid clashes with user defined names. +Id Builder::makeCompositeDebugType(std::vector const& memberTypes, char const*const name, + NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType) +{ + // Create the debug member types. + std::vector memberDebugTypes; + for(auto const memberType : memberTypes) { + assert(debugTypeLocs.find(memberType) != debugTypeLocs.end()); + + // There _should_ be debug types for all the member types but currently buffer references + // do not have member debug info generated. + if (debugId[memberType]) + memberDebugTypes.emplace_back(makeMemberDebugType(memberType, debugTypeLocs[memberType])); + + // TODO: Need to rethink this method of passing location information. + // debugTypeLocs.erase(memberType); + } + + // Create The structure debug type. + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypeComposite); + type->addIdOperand(getStringId(name)); // name id + type->addIdOperand(makeUintConstant(tag)); // tag id + type->addIdOperand(makeDebugSource(currentFileId)); // source id + type->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? + type->addIdOperand(makeUintConstant(0)); // TODO: column id + type->addIdOperand(makeDebugCompilationUnit()); // scope id + if(isOpaqueType == true) { + // Prepend '@' to opaque types. + type->addIdOperand(getStringId('@' + std::string(name))); // linkage name id + type->addIdOperand(makeDebugInfoNone()); // size id + } else { + type->addIdOperand(getStringId(name)); // linkage name id + type->addIdOperand(makeUintConstant(0)); // TODO: size id + } + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); // flags id + assert(isOpaqueType == false || (isOpaqueType == true && memberDebugTypes.empty())); + for(auto const memberDebugType : memberDebugTypes) { + type->addIdOperand(memberDebugType); + } + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypeComposite].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makePointerDebugType(StorageClass storageClass, Id const baseType) +{ + const Id debugBaseType = debugId[baseType]; + if (!debugBaseType) { + return makeDebugInfoNone(); + } + const Id scID = makeUintConstant(storageClass); + for (Instruction* otherType : groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypePointer]) { + if (otherType->getIdOperand(2) == debugBaseType && + otherType->getIdOperand(3) == scID) { + return otherType->getResultId(); + } + } + + Instruction* type = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugTypePointer); + type->addIdOperand(debugBaseType); + type->addIdOperand(scID); + type->addIdOperand(makeUintConstant(0)); + + groupedDebugTypes[NonSemanticShaderDebugInfo100DebugTypePointer].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + + return type->getResultId(); +} + +Id Builder::makeDebugSource(const Id fileName) { + if (debugSourceId.find(fileName) != debugSourceId.end()) + return debugSourceId[fileName]; + spv::Id resultId = getUniqueId(); + Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst); + sourceInst->addIdOperand(nonSemanticShaderDebugInfo); + sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugSource); + sourceInst->addIdOperand(fileName); + if (emitNonSemanticShaderDebugSource) { + spv::Id sourceId = 0; + if (fileName == mainFileId) { + sourceId = getStringId(sourceText); + } else { + auto incItr = includeFiles.find(fileName); + if (incItr != includeFiles.end()) { + sourceId = getStringId(*incItr->second); + } + } + + // We omit the optional source text item if not available in glslang + if (sourceId != 0) { + sourceInst->addIdOperand(sourceId); + } + } + constantsTypesGlobals.push_back(std::unique_ptr(sourceInst)); + module.mapInstruction(sourceInst); + debugSourceId[fileName] = resultId; + return resultId; +} + +Id Builder::makeDebugCompilationUnit() { + if (nonSemanticShaderCompilationUnitId != 0) + return nonSemanticShaderCompilationUnitId; + spv::Id resultId = getUniqueId(); + Instruction* sourceInst = new Instruction(resultId, makeVoidType(), OpExtInst); + sourceInst->addIdOperand(nonSemanticShaderDebugInfo); + sourceInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugCompilationUnit); + sourceInst->addIdOperand(makeUintConstant(1)); // TODO(greg-lunarg): Get rid of magic number + sourceInst->addIdOperand(makeUintConstant(4)); // TODO(greg-lunarg): Get rid of magic number + sourceInst->addIdOperand(makeDebugSource(mainFileId)); + sourceInst->addIdOperand(makeUintConstant(sourceLang)); + constantsTypesGlobals.push_back(std::unique_ptr(sourceInst)); + module.mapInstruction(sourceInst); + nonSemanticShaderCompilationUnitId = resultId; + + // We can reasonably assume that makeDebugCompilationUnit will be called before any of + // debug-scope stack. Function scopes and lexical scopes will occur afterward. + assert(currentDebugScopeId.empty()); + currentDebugScopeId.push(nonSemanticShaderCompilationUnitId); + + return resultId; +} + +Id Builder::createDebugGlobalVariable(Id const type, char const*const name, Id const variable) +{ + assert(type != 0); + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugGlobalVariable); + inst->addIdOperand(getStringId(name)); // name id + inst->addIdOperand(type); // type id + inst->addIdOperand(makeDebugSource(currentFileId)); // source id + inst->addIdOperand(makeUintConstant(currentLine)); // line id TODO: currentLine always zero? + inst->addIdOperand(makeUintConstant(0)); // TODO: column id + inst->addIdOperand(makeDebugCompilationUnit()); // scope id + inst->addIdOperand(getStringId(name)); // linkage name id + inst->addIdOperand(variable); // variable id + inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsDefinition)); // flags id + + constantsTypesGlobals.push_back(std::unique_ptr(inst)); + module.mapInstruction(inst); + + return inst->getResultId(); +} + +Id Builder::createDebugLocalVariable(Id type, char const*const name, size_t const argNumber) +{ + assert(name != nullptr); + assert(!currentDebugScopeId.empty()); + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLocalVariable); + inst->addIdOperand(getStringId(name)); // name id + inst->addIdOperand(type); // type id + inst->addIdOperand(makeDebugSource(currentFileId)); // source id + inst->addIdOperand(makeUintConstant(currentLine)); // line id + inst->addIdOperand(makeUintConstant(0)); // TODO: column id + inst->addIdOperand(currentDebugScopeId.top()); // scope id + inst->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsLocal)); // flags id + if(argNumber != 0) { + inst->addIdOperand(makeUintConstant(argNumber)); + } + + constantsTypesGlobals.push_back(std::unique_ptr(inst)); + module.mapInstruction(inst); + + return inst->getResultId(); +} + +Id Builder::makeDebugExpression() +{ + if (debugExpression != 0) + return debugExpression; + + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugExpression); + + constantsTypesGlobals.push_back(std::unique_ptr(inst)); + module.mapInstruction(inst); + + debugExpression = inst->getResultId(); + + return debugExpression; +} + +Id Builder::makeDebugDeclare(Id const debugLocalVariable, Id const pointer) +{ + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugDeclare); + inst->addIdOperand(debugLocalVariable); // debug local variable id + inst->addIdOperand(pointer); // pointer to local variable id + inst->addIdOperand(makeDebugExpression()); // expression id + addInstruction(std::unique_ptr(inst)); + + return inst->getResultId(); +} + +Id Builder::makeDebugValue(Id const debugLocalVariable, Id const value) +{ + Instruction* inst = new Instruction(getUniqueId(), makeVoidType(), OpExtInst); + inst->addIdOperand(nonSemanticShaderDebugInfo); + inst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugValue); + inst->addIdOperand(debugLocalVariable); // debug local variable id + inst->addIdOperand(value); // value of local variable id + inst->addIdOperand(makeDebugExpression()); // expression id + addInstruction(std::unique_ptr(inst)); + + return inst->getResultId(); +} + Id Builder::makeAccelerationStructureType() { Instruction *type; @@ -642,6 +1176,10 @@ Id Builder::makeAccelerationStructureType() groupedTypes[OpTypeAccelerationStructureKHR].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) { + spv::Id debugType = makeCompositeDebugType({}, "accelerationStructure", NonSemanticShaderDebugInfo100Structure, true); + debugId[type->getResultId()] = debugType; + } } else { type = groupedTypes[OpTypeAccelerationStructureKHR].back(); } @@ -657,13 +1195,31 @@ Id Builder::makeRayQueryType() groupedTypes[OpTypeRayQueryKHR].push_back(type); constantsTypesGlobals.push_back(std::unique_ptr(type)); module.mapInstruction(type); + if (emitNonSemanticShaderDebugInfo) { + spv::Id debugType = makeCompositeDebugType({}, "rayQuery", NonSemanticShaderDebugInfo100Structure, true); + debugId[type->getResultId()] = debugType; + } } else { type = groupedTypes[OpTypeRayQueryKHR].back(); } return type->getResultId(); } -#endif + +Id Builder::makeHitObjectNVType() +{ + Instruction *type; + if (groupedTypes[OpTypeHitObjectNV].size() == 0) { + type = new Instruction(getUniqueId(), NoType, OpTypeHitObjectNV); + groupedTypes[OpTypeHitObjectNV].push_back(type); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + } else { + type = groupedTypes[OpTypeHitObjectNV].back(); + } + + return type->getResultId(); +} Id Builder::getDerefTypeId(Id resultId) const { @@ -713,6 +1269,7 @@ int Builder::getNumTypeConstituents(Id typeId) const } case OpTypeStruct: return instr->getNumOperands(); + case OpTypeCooperativeMatrixKHR: case OpTypeCooperativeMatrixNV: // has only one constituent when used with OpCompositeConstruct. return 1; @@ -762,6 +1319,7 @@ Id Builder::getContainedTypeId(Id typeId, int member) const case OpTypeMatrix: case OpTypeArray: case OpTypeRuntimeArray: + case OpTypeCooperativeMatrixKHR: case OpTypeCooperativeMatrixNV: return instr->getIdOperand(0); case OpTypePointer: @@ -832,7 +1390,7 @@ bool Builder::containsType(Id typeId, spv::Op typeOp, unsigned int width) const } // return true if the type is a pointer to PhysicalStorageBufferEXT or an -// array of such pointers. These require restrict/aliased decorations. +// contains such a pointer. These require restrict/aliased decorations. bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const { const Instruction& instr = *module.getInstruction(typeId); @@ -844,6 +1402,12 @@ bool Builder::containsPhysicalStorageBufferOrArray(Id typeId) const return getTypeStorageClass(typeId) == StorageClassPhysicalStorageBufferEXT; case OpTypeArray: return containsPhysicalStorageBufferOrArray(getContainedTypeId(typeId)); + case OpTypeStruct: + for (int m = 0; m < instr.getNumOperands(); ++m) { + if (containsPhysicalStorageBufferOrArray(instr.getIdOperand(m))) + return true; + } + return false; default: return false; } @@ -1046,10 +1610,6 @@ Id Builder::makeFloatConstant(float f, bool specConstant) Id Builder::makeDoubleConstant(double d, bool specConstant) { -#ifdef GLSLANG_WEB - assert(0); - return NoResult; -#else Op opcode = specConstant ? OpSpecConstant : OpConstant; Id typeId = makeFloatType(64); union { double db; unsigned long long ull; } u; @@ -1074,15 +1634,10 @@ Id Builder::makeDoubleConstant(double d, bool specConstant) module.mapInstruction(c); return c->getResultId(); -#endif } Id Builder::makeFloat16Constant(float f16, bool specConstant) { -#ifdef GLSLANG_WEB - assert(0); - return NoResult; -#else Op opcode = specConstant ? OpSpecConstant : OpConstant; Id typeId = makeFloatType(16); @@ -1107,17 +1662,11 @@ Id Builder::makeFloat16Constant(float f16, bool specConstant) module.mapInstruction(c); return c->getResultId(); -#endif } Id Builder::makeFpConstant(Id type, double d, bool specConstant) { -#ifdef GLSLANG_WEB - const int width = 32; - assert(width == getScalarTypeWidth(type)); -#else const int width = getScalarTypeWidth(type); -#endif assert(isFloatType(type)); @@ -1136,9 +1685,22 @@ Id Builder::makeFpConstant(Id type, double d, bool specConstant) return NoResult; } +Id Builder::importNonSemanticShaderDebugInfoInstructions() +{ + assert(emitNonSemanticShaderDebugInfo == true); + + if(nonSemanticShaderDebugInfo == 0) + { + this->addExtension(spv::E_SPV_KHR_non_semantic_info); + nonSemanticShaderDebugInfo = this->import("NonSemantic.Shader.DebugInfo.100"); + } + + return nonSemanticShaderDebugInfo; +} + Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector& comps) { - Instruction* constant = 0; + Instruction* constant = nullptr; bool found = false; for (int i = 0; i < (int)groupedConstants[typeClass].size(); ++i) { constant = groupedConstants[typeClass][i]; @@ -1165,7 +1727,7 @@ Id Builder::findCompositeConstant(Op typeClass, Id typeId, const std::vector Id Builder::findStructConstant(Id typeId, const std::vector& comps) { - Instruction* constant = 0; + Instruction* constant = nullptr; bool found = false; for (int i = 0; i < (int)groupedStructConstants[typeId].size(); ++i) { constant = groupedStructConstants[typeId][i]; @@ -1198,6 +1760,7 @@ Id Builder::makeCompositeConstant(Id typeId, const std::vector& members, boo case OpTypeVector: case OpTypeArray: case OpTypeMatrix: + case OpTypeCooperativeMatrixKHR: case OpTypeCooperativeMatrixNV: if (! specConstant) { Id existing = findCompositeConstant(typeClass, typeId, members); @@ -1245,6 +1808,10 @@ Instruction* Builder::addEntryPoint(ExecutionModel model, Function* function, co // Currently relying on the fact that all 'value' of interest are small non-negative values. void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int value1, int value2, int value3) { + // entryPoint can be null if we are in compile-only mode + if (!entryPoint) + return; + Instruction* instr = new Instruction(OpExecutionMode); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); @@ -1260,6 +1827,10 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, int val void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const std::vector& literals) { + // entryPoint can be null if we are in compile-only mode + if (!entryPoint) + return; + Instruction* instr = new Instruction(OpExecutionMode); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); @@ -1271,6 +1842,10 @@ void Builder::addExecutionMode(Function* entryPoint, ExecutionMode mode, const s void Builder::addExecutionModeId(Function* entryPoint, ExecutionMode mode, const std::vector& operandIds) { + // entryPoint can be null if we are in compile-only mode + if (!entryPoint) + return; + Instruction* instr = new Instruction(OpExecutionModeId); instr->addIdOperand(entryPoint->getId()); instr->addImmediateOperand(mode); @@ -1354,6 +1929,16 @@ void Builder::addDecoration(Id id, Decoration decoration, const std::vector(dec)); } +void Builder::addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType) { + Instruction* dec = new Instruction(OpDecorate); + dec->addIdOperand(id); + dec->addImmediateOperand(spv::DecorationLinkageAttributes); + dec->addStringOperand(name); + dec->addImmediateOperand(linkType); + + decorations.push_back(std::unique_ptr(dec)); +} + void Builder::addDecorationId(Id id, Decoration decoration, Id idDecoration) { if (decoration == spv::DecorationMax) @@ -1441,29 +2026,79 @@ void Builder::addMemberDecoration(Id id, unsigned int member, Decoration decorat decorations.push_back(std::unique_ptr(dec)); } +void Builder::addInstruction(std::unique_ptr inst) { + // Optionally insert OpDebugScope + if (emitNonSemanticShaderDebugInfo && dirtyScopeTracker) { + if (buildPoint->updateDebugScope(currentDebugScopeId.top())) { + auto scopeInst = std::make_unique(getUniqueId(), makeVoidType(), OpExtInst); + scopeInst->addIdOperand(nonSemanticShaderDebugInfo); + scopeInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugScope); + scopeInst->addIdOperand(currentDebugScopeId.top()); + buildPoint->addInstruction(std::move(scopeInst)); + } + + dirtyScopeTracker = false; + } + + // Insert OpLine/OpDebugLine if the debug source location has changed + if (trackDebugInfo && dirtyLineTracker) { + if (buildPoint->updateDebugSourceLocation(currentLine, 0, currentFileId)) { + if (emitSpirvDebugInfo) { + auto lineInst = std::make_unique(OpLine); + lineInst->addIdOperand(currentFileId); + lineInst->addImmediateOperand(currentLine); + lineInst->addImmediateOperand(0); + buildPoint->addInstruction(std::move(lineInst)); + } + if (emitNonSemanticShaderDebugInfo) { + auto lineInst = std::make_unique(getUniqueId(), makeVoidType(), OpExtInst); + lineInst->addIdOperand(nonSemanticShaderDebugInfo); + lineInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLine); + lineInst->addIdOperand(makeDebugSource(currentFileId)); + lineInst->addIdOperand(makeUintConstant(currentLine)); + lineInst->addIdOperand(makeUintConstant(currentLine)); + lineInst->addIdOperand(makeUintConstant(0)); + lineInst->addIdOperand(makeUintConstant(0)); + buildPoint->addInstruction(std::move(lineInst)); + } + } + + dirtyLineTracker = false; + } + + buildPoint->addInstruction(std::move(inst)); +} + // Comments in header Function* Builder::makeEntryPoint(const char* entryPoint) { assert(! entryPointFunction); - Block* entry; - std::vector params; - std::vector> decorations; + auto const returnType = makeVoidType(); - entryPointFunction = makeFunctionEntry(NoPrecision, makeVoidType(), entryPoint, params, decorations, &entry); + restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo; + if(sourceLang == spv::SourceLanguageHLSL) { + emitNonSemanticShaderDebugInfo = false; + } + + Block* entry = nullptr; + entryPointFunction = makeFunctionEntry(NoPrecision, returnType, entryPoint, LinkageTypeMax, {}, {}, &entry); + + emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo; return entryPointFunction; } // Comments in header -Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, +Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType, const std::vector& paramTypes, - const std::vector>& decorations, Block **entry) + const std::vector>& decorations, Block** entry) { // Make the function and initial instructions in it Id typeId = makeFunctionType(returnType, paramTypes); Id firstParamId = paramTypes.size() == 0 ? 0 : getUniqueIds((int)paramTypes.size()); - Function* function = new Function(getUniqueId(), returnType, typeId, firstParamId, module); + Id funcId = getUniqueId(); + Function* function = new Function(funcId, returnType, typeId, firstParamId, linkType, name, module); // Set up the precisions setPrecision(function->getId(), precision); @@ -1475,13 +2110,17 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const } } - // CFG - if (entry) { - *entry = new Block(getUniqueId(), *function); - function->addBlock(*entry); - setBuildPoint(*entry); + // reset last debug scope + if (emitNonSemanticShaderDebugInfo) { + dirtyScopeTracker = true; } + // CFG + assert(entry != nullptr); + *entry = new Block(getUniqueId(), *function); + function->addBlock(*entry); + setBuildPoint(*entry); + if (name) addName(function->getId(), name); @@ -1490,20 +2129,173 @@ Function* Builder::makeFunctionEntry(Decoration precision, Id returnType, const return function; } +void Builder::setupDebugFunctionEntry(Function* function, const char* name, int line, const std::vector& paramTypes, + const std::vector& paramNames) +{ + + if (!emitNonSemanticShaderDebugInfo) + return; + + currentLine = line; + Id nameId = getStringId(unmangleFunctionName(name)); + Id funcTypeId = function->getFuncTypeId(); + assert(debugId[funcTypeId] != 0); + Id funcId = function->getId(); + + assert(funcId != 0); + + // Make the debug function instruction + Id debugFuncId = makeDebugFunction(function, nameId, funcTypeId); + debugId[funcId] = debugFuncId; + currentDebugScopeId.push(debugFuncId); + + // DebugScope and DebugLine for parameter DebugDeclares + assert(paramTypes.size() == paramNames.size()); + if ((int)paramTypes.size() > 0) { + Id firstParamId = function->getParamId(0); + + for (size_t p = 0; p < paramTypes.size(); ++p) { + bool passByRef = false; + Id paramTypeId = paramTypes[p]; + + // For pointer-typed parameters, they are actually passed by reference and we need unwrap the pointer to get the actual parameter type. + if (isPointerType(paramTypeId) || isArrayType(paramTypeId)) { + passByRef = true; + paramTypeId = getContainedTypeId(paramTypeId); + } + + auto const& paramName = paramNames[p]; + auto const debugLocalVariableId = createDebugLocalVariable(debugId[paramTypeId], paramName, p + 1); + auto const paramId = static_cast(firstParamId + p); + debugId[paramId] = debugLocalVariableId; + + if (passByRef) { + makeDebugDeclare(debugLocalVariableId, paramId); + } else { + makeDebugValue(debugLocalVariableId, paramId); + } + } + } + + // Clear debug scope stack + if (emitNonSemanticShaderDebugInfo) + currentDebugScopeId.pop(); +} + +Id Builder::makeDebugFunction([[maybe_unused]] Function* function, Id nameId, Id funcTypeId) +{ + assert(function != nullptr); + assert(nameId != 0); + assert(funcTypeId != 0); + assert(debugId[funcTypeId] != 0); + + Id funcId = getUniqueId(); + auto type = new Instruction(funcId, makeVoidType(), OpExtInst); + type->addIdOperand(nonSemanticShaderDebugInfo); + type->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunction); + type->addIdOperand(nameId); + type->addIdOperand(debugId[funcTypeId]); + type->addIdOperand(makeDebugSource(currentFileId)); // TODO: This points to file of definition instead of declaration + type->addIdOperand(makeUintConstant(currentLine)); // TODO: This points to line of definition instead of declaration + type->addIdOperand(makeUintConstant(0)); // column + type->addIdOperand(makeDebugCompilationUnit()); // scope + type->addIdOperand(nameId); // linkage name + type->addIdOperand(makeUintConstant(NonSemanticShaderDebugInfo100FlagIsPublic)); + type->addIdOperand(makeUintConstant(currentLine)); + constantsTypesGlobals.push_back(std::unique_ptr(type)); + module.mapInstruction(type); + return funcId; +} + +Id Builder::makeDebugLexicalBlock(uint32_t line) { + assert(!currentDebugScopeId.empty()); + + Id lexId = getUniqueId(); + auto lex = new Instruction(lexId, makeVoidType(), OpExtInst); + lex->addIdOperand(nonSemanticShaderDebugInfo); + lex->addImmediateOperand(NonSemanticShaderDebugInfo100DebugLexicalBlock); + lex->addIdOperand(makeDebugSource(currentFileId)); + lex->addIdOperand(makeUintConstant(line)); + lex->addIdOperand(makeUintConstant(0)); // column + lex->addIdOperand(currentDebugScopeId.top()); // scope + constantsTypesGlobals.push_back(std::unique_ptr(lex)); + module.mapInstruction(lex); + return lexId; +} + +std::string Builder::unmangleFunctionName(std::string const& name) const +{ + assert(name.length() > 0); + + if(name.rfind('(') != std::string::npos) { + return name.substr(0, name.rfind('(')); + } else { + return name; + } +} + // Comments in header void Builder::makeReturn(bool implicit, Id retVal) { if (retVal) { Instruction* inst = new Instruction(NoResult, NoType, OpReturnValue); inst->addIdOperand(retVal); - buildPoint->addInstruction(std::unique_ptr(inst)); + addInstruction(std::unique_ptr(inst)); } else - buildPoint->addInstruction(std::unique_ptr(new Instruction(NoResult, NoType, OpReturn))); + addInstruction(std::unique_ptr(new Instruction(NoResult, NoType, OpReturn))); if (! implicit) createAndSetNoPredecessorBlock("post-return"); } +// Comments in header +void Builder::enterLexicalBlock(uint32_t line) +{ + // Generate new lexical scope debug instruction + Id lexId = makeDebugLexicalBlock(line); + currentDebugScopeId.push(lexId); + dirtyScopeTracker = true; +} + +// Comments in header +void Builder::leaveLexicalBlock() +{ + // Pop current scope from stack and clear current scope + currentDebugScopeId.pop(); + dirtyScopeTracker = true; +} + +// Comments in header +void Builder::enterFunction(Function const* function) +{ + // Save and disable debugInfo for HLSL entry point function. It is a wrapper + // function with no user code in it. + restoreNonSemanticShaderDebugInfo = emitNonSemanticShaderDebugInfo; + if (sourceLang == spv::SourceLanguageHLSL && function == entryPointFunction) { + emitNonSemanticShaderDebugInfo = false; + } + + if (emitNonSemanticShaderDebugInfo) { + // Initialize scope state + Id funcId = function->getFuncId(); + currentDebugScopeId.push(debugId[funcId]); + // Create DebugFunctionDefinition + spv::Id resultId = getUniqueId(); + Instruction* defInst = new Instruction(resultId, makeVoidType(), OpExtInst); + defInst->addIdOperand(nonSemanticShaderDebugInfo); + defInst->addImmediateOperand(NonSemanticShaderDebugInfo100DebugFunctionDefinition); + defInst->addIdOperand(debugId[funcId]); + defInst->addIdOperand(funcId); + addInstruction(std::unique_ptr(defInst)); + } + + if (auto linkType = function->getLinkType(); linkType != LinkageTypeMax) { + Id funcId = function->getFuncId(); + addCapability(CapabilityLinkage); + addLinkageDecoration(funcId, function->getExportName(), linkType); + } +} + // Comments in header void Builder::leaveFunction() { @@ -1519,17 +2311,34 @@ void Builder::leaveFunction() makeReturn(true, createUndefined(function.getReturnType())); } } + + // Clear function scope from debug scope stack + if (emitNonSemanticShaderDebugInfo) + currentDebugScopeId.pop(); + + emitNonSemanticShaderDebugInfo = restoreNonSemanticShaderDebugInfo; } // Comments in header void Builder::makeStatementTerminator(spv::Op opcode, const char *name) { - buildPoint->addInstruction(std::unique_ptr(new Instruction(opcode))); + addInstruction(std::unique_ptr(new Instruction(opcode))); createAndSetNoPredecessorBlock(name); } // Comments in header -Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer) +void Builder::makeStatementTerminator(spv::Op opcode, const std::vector& operands, const char* name) +{ + // It's assumed that the terminator instruction is always of void return type + // However in future if there is a need for non void return type, new helper + // methods can be created. + createNoResultOp(opcode, operands); + createAndSetNoPredecessorBlock(name); +} + +// Comments in header +Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name, Id initializer, + bool const compilerGenerated) { Id pointerType = makePointer(storageClass, type); Instruction* inst = new Instruction(getUniqueId(), pointerType, OpVariable); @@ -1541,11 +2350,26 @@ Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id t case StorageClassFunction: // Validation rules require the declaration in the entry block buildPoint->getParent().addLocalVariable(std::unique_ptr(inst)); + + if (emitNonSemanticShaderDebugInfo && !compilerGenerated) + { + auto const debugLocalVariableId = createDebugLocalVariable(debugId[type], name); + debugId[inst->getResultId()] = debugLocalVariableId; + + makeDebugDeclare(debugLocalVariableId, inst->getResultId()); + } + break; default: constantsTypesGlobals.push_back(std::unique_ptr(inst)); module.mapInstruction(inst); + + if (emitNonSemanticShaderDebugInfo) + { + auto const debugResultId = createDebugGlobalVariable(debugId[type], name, inst->getResultId()); + debugId[inst->getResultId()] = debugResultId; + } break; } @@ -1560,7 +2384,7 @@ Id Builder::createVariable(Decoration precision, StorageClass storageClass, Id t Id Builder::createUndefined(Id type) { Instruction* inst = new Instruction(getUniqueId(), type, OpUndef); - buildPoint->addInstruction(std::unique_ptr(inst)); + addInstruction(std::unique_ptr(inst)); return inst->getResultId(); } @@ -1575,7 +2399,7 @@ spv::MemoryAccessMask Builder::sanitizeMemoryAccessForStorageClass(spv::MemoryAc case spv::StorageClassPhysicalStorageBufferEXT: break; default: - memoryAccess = spv::MemoryAccessMask(memoryAccess & + memoryAccess = spv::MemoryAccessMask(memoryAccess & ~(spv::MemoryAccessMakePointerAvailableKHRMask | spv::MemoryAccessMakePointerVisibleKHRMask | spv::MemoryAccessNonPrivatePointerKHRMask)); @@ -1604,7 +2428,7 @@ void Builder::createStore(Id rValue, Id lValue, spv::MemoryAccessMask memoryAcce } } - buildPoint->addInstruction(std::unique_ptr(store)); + addInstruction(std::unique_ptr(store)); } // Comments in header @@ -1626,7 +2450,7 @@ Id Builder::createLoad(Id lValue, spv::Decoration precision, spv::MemoryAccessMa } } - buildPoint->addInstruction(std::unique_ptr(load)); + addInstruction(std::unique_ptr(load)); setPrecision(load->getResultId(), precision); return load->getResultId(); @@ -1644,7 +2468,7 @@ Id Builder::createAccessChain(StorageClass storageClass, Id base, const std::vec chain->addIdOperand(base); for (int i = 0; i < (int)offsets.size(); ++i) chain->addIdOperand(offsets[i]); - buildPoint->addInstruction(std::unique_ptr(chain)); + addInstruction(std::unique_ptr(chain)); return chain->getResultId(); } @@ -1655,12 +2479,29 @@ Id Builder::createArrayLength(Id base, unsigned int member) Instruction* length = new Instruction(getUniqueId(), intType, OpArrayLength); length->addIdOperand(base); length->addImmediateOperand(member); - buildPoint->addInstruction(std::unique_ptr(length)); + addInstruction(std::unique_ptr(length)); return length->getResultId(); } -Id Builder::createCooperativeMatrixLength(Id type) +Id Builder::createCooperativeMatrixLengthKHR(Id type) +{ + spv::Id intType = makeUintType(32); + + // Generate code for spec constants if in spec constant operation + // generation mode. + if (generatingOpCodeForSpecConst) { + return createSpecConstantOp(OpCooperativeMatrixLengthKHR, intType, std::vector(1, type), std::vector()); + } + + Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthKHR); + length->addIdOperand(type); + addInstruction(std::unique_ptr(length)); + + return length->getResultId(); +} + +Id Builder::createCooperativeMatrixLengthNV(Id type) { spv::Id intType = makeUintType(32); @@ -1672,7 +2513,7 @@ Id Builder::createCooperativeMatrixLength(Id type) Instruction* length = new Instruction(getUniqueId(), intType, OpCooperativeMatrixLengthNV); length->addIdOperand(type); - buildPoint->addInstruction(std::unique_ptr(length)); + addInstruction(std::unique_ptr(length)); return length->getResultId(); } @@ -1688,7 +2529,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, unsigned index) Instruction* extract = new Instruction(getUniqueId(), typeId, OpCompositeExtract); extract->addIdOperand(composite); extract->addImmediateOperand(index); - buildPoint->addInstruction(std::unique_ptr(extract)); + addInstruction(std::unique_ptr(extract)); return extract->getResultId(); } @@ -1704,7 +2545,7 @@ Id Builder::createCompositeExtract(Id composite, Id typeId, const std::vectoraddIdOperand(composite); for (int i = 0; i < (int)indexes.size(); ++i) extract->addImmediateOperand(indexes[i]); - buildPoint->addInstruction(std::unique_ptr(extract)); + addInstruction(std::unique_ptr(extract)); return extract->getResultId(); } @@ -1715,7 +2556,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, unsigned i insert->addIdOperand(object); insert->addIdOperand(composite); insert->addImmediateOperand(index); - buildPoint->addInstruction(std::unique_ptr(insert)); + addInstruction(std::unique_ptr(insert)); return insert->getResultId(); } @@ -1727,7 +2568,7 @@ Id Builder::createCompositeInsert(Id object, Id composite, Id typeId, const std: insert->addIdOperand(composite); for (int i = 0; i < (int)indexes.size(); ++i) insert->addImmediateOperand(indexes[i]); - buildPoint->addInstruction(std::unique_ptr(insert)); + addInstruction(std::unique_ptr(insert)); return insert->getResultId(); } @@ -1737,7 +2578,7 @@ Id Builder::createVectorExtractDynamic(Id vector, Id typeId, Id componentIndex) Instruction* extract = new Instruction(getUniqueId(), typeId, OpVectorExtractDynamic); extract->addIdOperand(vector); extract->addIdOperand(componentIndex); - buildPoint->addInstruction(std::unique_ptr(extract)); + addInstruction(std::unique_ptr(extract)); return extract->getResultId(); } @@ -1748,7 +2589,7 @@ Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id com insert->addIdOperand(vector); insert->addIdOperand(component); insert->addIdOperand(componentIndex); - buildPoint->addInstruction(std::unique_ptr(insert)); + addInstruction(std::unique_ptr(insert)); return insert->getResultId(); } @@ -1757,7 +2598,7 @@ Id Builder::createVectorInsertDynamic(Id vector, Id typeId, Id component, Id com void Builder::createNoResultOp(Op opCode) { Instruction* op = new Instruction(opCode); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } // An opcode that has one id operand, no result id, and no type @@ -1765,7 +2606,7 @@ void Builder::createNoResultOp(Op opCode, Id operand) { Instruction* op = new Instruction(opCode); op->addIdOperand(operand); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } // An opcode that has one or more operands, no result id, and no type @@ -1775,7 +2616,7 @@ void Builder::createNoResultOp(Op opCode, const std::vector& operands) for (auto it = operands.cbegin(); it != operands.cend(); ++it) { op->addIdOperand(*it); } - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } // An opcode that has multiple operands, no result id, and no type @@ -1788,7 +2629,7 @@ void Builder::createNoResultOp(Op opCode, const std::vector& operan else op->addImmediateOperand(it->word); } - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemanticsMask semantics) @@ -1797,7 +2638,7 @@ void Builder::createControlBarrier(Scope execution, Scope memory, MemorySemantic op->addIdOperand(makeUintConstant(execution)); op->addIdOperand(makeUintConstant(memory)); op->addIdOperand(makeUintConstant(semantics)); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemantics) @@ -1805,7 +2646,7 @@ void Builder::createMemoryBarrier(unsigned executionScope, unsigned memorySemant Instruction* op = new Instruction(OpMemoryBarrier); op->addIdOperand(makeUintConstant(executionScope)); op->addIdOperand(makeUintConstant(memorySemantics)); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); } // An opcode that has one operands, a result id, and a type @@ -1818,7 +2659,7 @@ Id Builder::createUnaryOp(Op opCode, Id typeId, Id operand) } Instruction* op = new Instruction(getUniqueId(), typeId, opCode); op->addIdOperand(operand); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1835,7 +2676,7 @@ Id Builder::createBinOp(Op opCode, Id typeId, Id left, Id right) Instruction* op = new Instruction(getUniqueId(), typeId, opCode); op->addIdOperand(left); op->addIdOperand(right); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1856,7 +2697,7 @@ Id Builder::createTriOp(Op opCode, Id typeId, Id op1, Id op2, Id op3) op->addIdOperand(op1); op->addIdOperand(op2); op->addIdOperand(op3); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1866,7 +2707,7 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& operands) Instruction* op = new Instruction(getUniqueId(), typeId, opCode); for (auto it = operands.cbegin(); it != operands.cend(); ++it) op->addIdOperand(*it); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1880,7 +2721,7 @@ Id Builder::createOp(Op opCode, Id typeId, const std::vector& opera else op->addImmediateOperand(it->word); } - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1897,6 +2738,14 @@ Id Builder::createSpecConstantOp(Op opCode, Id typeId, const std::vector& op module.mapInstruction(op); constantsTypesGlobals.push_back(std::unique_ptr(op)); + // OpSpecConstantOp's using 8 or 16 bit types require the associated capability + if (containsType(typeId, OpTypeInt, 8)) + addCapability(CapabilityInt8); + if (containsType(typeId, OpTypeInt, 16)) + addCapability(CapabilityInt16); + if (containsType(typeId, OpTypeFloat, 16)) + addCapability(CapabilityFloat16); + return op->getResultId(); } @@ -1906,7 +2755,7 @@ Id Builder::createFunctionCall(spv::Function* function, const std::vectoraddIdOperand(function->getId()); for (int a = 0; a < (int)args.size(); ++a) op->addIdOperand(args[a]); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -1928,7 +2777,7 @@ Id Builder::createRvalueSwizzle(Decoration precision, Id typeId, Id source, cons swizzle->addIdOperand(source); for (int i = 0; i < (int)channels.size(); ++i) swizzle->addImmediateOperand(channels[i]); - buildPoint->addInstruction(std::unique_ptr(swizzle)); + addInstruction(std::unique_ptr(swizzle)); return setPrecision(swizzle->getResultId(), precision); } @@ -1961,7 +2810,7 @@ Id Builder::createLvalueSwizzle(Id typeId, Id target, Id source, const std::vect // finish the instruction with these components selectors for (int i = 0; i < numTargetComponents; ++i) swizzle->addImmediateOperand(components[i]); - buildPoint->addInstruction(std::unique_ptr(swizzle)); + addInstruction(std::unique_ptr(swizzle)); return swizzle->getResultId(); } @@ -2006,7 +2855,7 @@ Id Builder::smearScalar(Decoration precision, Id scalar, Id vectorType) smear = new Instruction(getUniqueId(), vectorType, OpCompositeConstruct); for (int c = 0; c < numComponents; ++c) smear->addIdOperand(scalar); - buildPoint->addInstruction(std::unique_ptr(smear)); + addInstruction(std::unique_ptr(smear)); } return setPrecision(smear->getResultId(), precision); @@ -2021,7 +2870,7 @@ Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const for (int arg = 0; arg < (int)args.size(); ++arg) inst->addIdOperand(args[arg]); - buildPoint->addInstruction(std::unique_ptr(inst)); + addInstruction(std::unique_ptr(inst)); return inst->getResultId(); } @@ -2031,52 +2880,47 @@ Id Builder::createBuiltinCall(Id resultType, Id builtins, int entryPoint, const Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, bool fetch, bool proj, bool gather, bool noImplicitLod, const TextureParameters& parameters, ImageOperandsMask signExtensionMask) { - static const int maxTextureArgs = 10; - Id texArgs[maxTextureArgs] = {}; + std::vector texArgs; // // Set up the fixed arguments // - int numArgs = 0; bool explicitLod = false; - texArgs[numArgs++] = parameters.sampler; - texArgs[numArgs++] = parameters.coords; + texArgs.push_back(parameters.sampler); + texArgs.push_back(parameters.coords); if (parameters.Dref != NoResult) - texArgs[numArgs++] = parameters.Dref; + texArgs.push_back(parameters.Dref); if (parameters.component != NoResult) - texArgs[numArgs++] = parameters.component; + texArgs.push_back(parameters.component); -#ifndef GLSLANG_WEB if (parameters.granularity != NoResult) - texArgs[numArgs++] = parameters.granularity; + texArgs.push_back(parameters.granularity); if (parameters.coarse != NoResult) - texArgs[numArgs++] = parameters.coarse; -#endif + texArgs.push_back(parameters.coarse); // // Set up the optional arguments // - int optArgNum = numArgs; // track which operand, if it exists, is the mask of optional arguments - ++numArgs; // speculatively make room for the mask operand + size_t optArgNum = texArgs.size(); // the position of the mask for the optional arguments, if any. ImageOperandsMask mask = ImageOperandsMaskNone; // the mask operand if (parameters.bias) { mask = (ImageOperandsMask)(mask | ImageOperandsBiasMask); - texArgs[numArgs++] = parameters.bias; + texArgs.push_back(parameters.bias); } if (parameters.lod) { mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); - texArgs[numArgs++] = parameters.lod; + texArgs.push_back(parameters.lod); explicitLod = true; } else if (parameters.gradX) { mask = (ImageOperandsMask)(mask | ImageOperandsGradMask); - texArgs[numArgs++] = parameters.gradX; - texArgs[numArgs++] = parameters.gradY; + texArgs.push_back(parameters.gradX); + texArgs.push_back(parameters.gradY); explicitLod = true; } else if (noImplicitLod && ! fetch && ! gather) { // have to explicitly use lod of 0 if not allowed to have them be implicit, and // we would otherwise be about to issue an implicit instruction mask = (ImageOperandsMask)(mask | ImageOperandsLodMask); - texArgs[numArgs++] = makeFloatConstant(0.0); + texArgs.push_back(makeFloatConstant(0.0)); explicitLod = true; } if (parameters.offset) { @@ -2086,24 +2930,23 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, addCapability(CapabilityImageGatherExtended); mask = (ImageOperandsMask)(mask | ImageOperandsOffsetMask); } - texArgs[numArgs++] = parameters.offset; + texArgs.push_back(parameters.offset); } if (parameters.offsets) { addCapability(CapabilityImageGatherExtended); mask = (ImageOperandsMask)(mask | ImageOperandsConstOffsetsMask); - texArgs[numArgs++] = parameters.offsets; + texArgs.push_back(parameters.offsets); } -#ifndef GLSLANG_WEB if (parameters.sample) { mask = (ImageOperandsMask)(mask | ImageOperandsSampleMask); - texArgs[numArgs++] = parameters.sample; + texArgs.push_back(parameters.sample); } if (parameters.lodClamp) { // capability if this bit is used addCapability(CapabilityMinLod); mask = (ImageOperandsMask)(mask | ImageOperandsMinLodMask); - texArgs[numArgs++] = parameters.lodClamp; + texArgs.push_back(parameters.lodClamp); } if (parameters.nonprivate) { mask = mask | ImageOperandsNonPrivateTexelKHRMask; @@ -2111,12 +2954,10 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, if (parameters.volatil) { mask = mask | ImageOperandsVolatileTexelKHRMask; } -#endif mask = mask | signExtensionMask; - if (mask == ImageOperandsMaskNone) - --numArgs; // undo speculative reservation for the mask argument - else - texArgs[optArgNum] = mask; + // insert the operand for the mask, if any bits were set. + if (mask != ImageOperandsMaskNone) + texArgs.insert(texArgs.begin() + optArgNum, mask); // // Set up the instruction @@ -2127,7 +2968,6 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, opCode = OpImageSparseFetch; else opCode = OpImageFetch; -#ifndef GLSLANG_WEB } else if (parameters.granularity && parameters.coarse) { opCode = OpImageSampleFootprintNV; } else if (gather) { @@ -2141,7 +2981,6 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, opCode = OpImageSparseGather; else opCode = OpImageGather; -#endif } else if (explicitLod) { if (parameters.Dref) { if (proj) @@ -2220,14 +3059,14 @@ Id Builder::createTextureCall(Decoration precision, Id resultType, bool sparse, // Build the SPIR-V instruction Instruction* textureInst = new Instruction(getUniqueId(), resultType, opCode); - for (int op = 0; op < optArgNum; ++op) + for (size_t op = 0; op < optArgNum; ++op) textureInst->addIdOperand(texArgs[op]); - if (optArgNum < numArgs) + if (optArgNum < texArgs.size()) textureInst->addImmediateOperand(texArgs[optArgNum]); - for (int op = optArgNum + 1; op < numArgs; ++op) + for (size_t op = optArgNum + 1; op < texArgs.size(); ++op) textureInst->addIdOperand(texArgs[op]); setPrecision(textureInst->getResultId(), precision); - buildPoint->addInstruction(std::unique_ptr(textureInst)); + addInstruction(std::unique_ptr(textureInst)); Id resultId = textureInst->getResultId(); @@ -2307,7 +3146,7 @@ Id Builder::createTextureQueryCall(Op opCode, const TextureParameters& parameter query->addIdOperand(parameters.coords); if (parameters.lod) query->addIdOperand(parameters.lod); - buildPoint->addInstruction(std::unique_ptr(query)); + addInstruction(std::unique_ptr(query)); addCapability(CapabilityImageQuery); return query->getResultId(); @@ -2406,7 +3245,7 @@ Id Builder::createCompositeConstruct(Id typeId, const std::vector& constitue Instruction* op = new Instruction(getUniqueId(), typeId, OpCompositeConstruct); for (int c = 0; c < (int)constituents.size(); ++c) op->addIdOperand(constituents[c]); - buildPoint->addInstruction(std::unique_ptr(op)); + addInstruction(std::unique_ptr(op)); return op->getResultId(); } @@ -2504,12 +3343,7 @@ Id Builder::createMatrixConstructor(Decoration precision, const std::vector& int numRows = getTypeNumRows(resultTypeId); Instruction* instr = module.getInstruction(componentTypeId); -#ifdef GLSLANG_WEB - const unsigned bitCount = 32; - assert(bitCount == instr->getImmediateOperand(0)); -#else const unsigned bitCount = instr->getImmediateOperand(0); -#endif // Optimize matrix constructed from a bigger matrix if (isMatrix(sources[0]) && getNumColumns(sources[0]) >= numCols && getNumRows(sources[0]) >= numRows) { @@ -2629,7 +3463,7 @@ Builder::If::If(Id cond, unsigned int ctrl, Builder& gb) : builder(gb), condition(cond), control(ctrl), - elseBlock(0) + elseBlock(nullptr) { function = &builder.getBuildPoint()->getParent(); @@ -2707,7 +3541,7 @@ void Builder::makeSwitch(Id selector, unsigned int control, int numSegments, con switchInst->addIdOperand(segmentBlocks[valueIndexToSegment[i]]->getId()); segmentBlocks[valueIndexToSegment[i]]->addPredecessor(buildPoint); } - buildPoint->addInstruction(std::unique_ptr(switchInst)); + addInstruction(std::unique_ptr(switchInst)); // push the merge block switchMerges.push(mergeBlock); @@ -3226,7 +4060,7 @@ void Builder::createBranch(Block* block) { Instruction* branch = new Instruction(OpBranch); branch->addIdOperand(block->getId()); - buildPoint->addInstruction(std::unique_ptr(branch)); + addInstruction(std::unique_ptr(branch)); block->addPredecessor(buildPoint); } @@ -3235,7 +4069,7 @@ void Builder::createSelectionMerge(Block* mergeBlock, unsigned int control) Instruction* merge = new Instruction(OpSelectionMerge); merge->addIdOperand(mergeBlock->getId()); merge->addImmediateOperand(control); - buildPoint->addInstruction(std::unique_ptr(merge)); + addInstruction(std::unique_ptr(merge)); } void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned int control, @@ -3247,7 +4081,7 @@ void Builder::createLoopMerge(Block* mergeBlock, Block* continueBlock, unsigned merge->addImmediateOperand(control); for (int op = 0; op < (int)operands.size(); ++op) merge->addImmediateOperand(operands[op]); - buildPoint->addInstruction(std::unique_ptr(merge)); + addInstruction(std::unique_ptr(merge)); } void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* elseBlock) @@ -3256,7 +4090,7 @@ void Builder::createConditionalBranch(Id condition, Block* thenBlock, Block* els branch->addIdOperand(condition); branch->addIdOperand(thenBlock->getId()); branch->addIdOperand(elseBlock->getId()); - buildPoint->addInstruction(std::unique_ptr(branch)); + addInstruction(std::unique_ptr(branch)); thenBlock->addPredecessor(buildPoint); elseBlock->addPredecessor(buildPoint); } @@ -3271,10 +4105,10 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te const int opSourceWordCount = 4; const int nonNullBytesPerInstruction = 4 * (maxWordCount - opSourceWordCount) - 1; - if (source != SourceLanguageUnknown) { + if (sourceLang != SourceLanguageUnknown) { // OpSource Language Version File Source Instruction sourceInst(NoResult, NoType, OpSource); - sourceInst.addImmediateOperand(source); + sourceInst.addImmediateOperand(sourceLang); sourceInst.addImmediateOperand(sourceVersion); // File operand if (fileId != NoResult) { @@ -3307,7 +4141,8 @@ void Builder::dumpSourceInstructions(const spv::Id fileId, const std::string& te // Dump an OpSource[Continued] sequence for the source and every include file void Builder::dumpSourceInstructions(std::vector& out) const { - dumpSourceInstructions(sourceFileStringId, sourceText, out); + if (emitNonSemanticShaderDebugInfo) return; + dumpSourceInstructions(mainFileId, sourceText, out); for (auto iItr = includeFiles.begin(); iItr != includeFiles.end(); ++iItr) dumpSourceInstructions(iItr->first, *iItr->second, out); } @@ -3329,4 +4164,4 @@ void Builder::dumpModuleProcesses(std::vector& out) const } } -}; // end spv namespace +} // end spv namespace diff --git a/src/libraries/glslang/SPIRV/SpvBuilder.h b/src/libraries/glslang/SPIRV/SpvBuilder.h index c72d9b287..a65a98e33 100644 --- a/src/libraries/glslang/SPIRV/SpvBuilder.h +++ b/src/libraries/glslang/SPIRV/SpvBuilder.h @@ -50,6 +50,10 @@ #include "Logger.h" #include "spirv.hpp" #include "spvIR.h" +namespace spv { + #include "GLSL.ext.KHR.h" + #include "NonSemanticShaderDebugInfo100.h" +} #include #include @@ -82,7 +86,7 @@ public: void setSource(spv::SourceLanguage lang, int version) { - source = lang; + sourceLang = lang; sourceVersion = version; } spv::Id getStringId(const std::string& str) @@ -99,14 +103,54 @@ public: stringIds[file_c_str] = strId; return strId; } - void setSourceFile(const std::string& file) + + spv::Id getMainFileId() const { return mainFileId; } + + // Initialize the main source file name + void setDebugSourceFile(const std::string& file) { - sourceFileStringId = getStringId(file); + if (trackDebugInfo) { + dirtyLineTracker = true; + mainFileId = getStringId(file); + currentFileId = mainFileId; + } } + + // Set the debug source location tracker in the builder. + // The upcoming instructions in basic blocks will be associated to this location. + void setDebugSourceLocation(int line, const char* filename) + { + if (trackDebugInfo) { + dirtyLineTracker = true; + if (line != 0) { + // TODO: This is special handling of some AST nodes having (untracked) line 0. + // But they should have a valid line number. + currentLine = line; + if (filename) { + currentFileId = getStringId(filename); + } + } + } + } + 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 setEmitSpirvDebugInfo() + { + trackDebugInfo = true; + emitSpirvDebugInfo = true; + } + void setEmitNonSemanticShaderDebugInfo(bool emitSourceText) + { + trackDebugInfo = true; + emitNonSemanticShaderDebugInfo = true; + importNonSemanticShaderDebugInfoInstructions(); + + if (emitSourceText) { + emitNonSemanticShaderDebugSource = emitSourceText; + } + } void addExtension(const char* ext) { extensions.insert(ext); } void removeExtension(const char* ext) { @@ -147,19 +191,6 @@ public: 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(); @@ -170,7 +201,7 @@ public: 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& members, const char*); + Id makeStructType(const std::vector& members, const char* name, bool const compilerGenerated = true); Id makeStructResultType(Id type0, Id type1); Id makeVectorType(Id component, int size); Id makeMatrixType(Id component, int cols, int rows); @@ -180,13 +211,51 @@ public: 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); + Id makeCooperativeMatrixTypeKHR(Id component, Id scope, Id rows, Id cols, Id use); + Id makeCooperativeMatrixTypeNV(Id component, Id scope, Id rows, Id cols); + Id makeCooperativeMatrixTypeWithSameShape(Id component, Id otherType); Id makeGenericType(spv::Op opcode, std::vector& operands); + // SPIR-V NonSemantic Shader DebugInfo Instructions + struct DebugTypeLoc { + std::string name {}; + int line {0}; + int column {0}; + }; + std::unordered_map debugTypeLocs; + Id makeDebugInfoNone(); + Id makeBoolDebugType(int const size); + Id makeIntegerDebugType(int const width, bool const hasSign); + Id makeFloatDebugType(int const width); + Id makeSequentialDebugType(Id const baseType, Id const componentCount, NonSemanticShaderDebugInfo100Instructions const sequenceType); + Id makeArrayDebugType(Id const baseType, Id const componentCount); + Id makeVectorDebugType(Id const baseType, int const componentCount); + Id makeMatrixDebugType(Id const vectorType, int const vectorCount, bool columnMajor = true); + Id makeMemberDebugType(Id const memberType, DebugTypeLoc const& debugTypeLoc); + Id makeCompositeDebugType(std::vector const& memberTypes, char const*const name, + NonSemanticShaderDebugInfo100DebugCompositeType const tag, bool const isOpaqueType = false); + Id makePointerDebugType(StorageClass storageClass, Id const baseType); + Id makeDebugSource(const Id fileName); + Id makeDebugCompilationUnit(); + Id createDebugGlobalVariable(Id const type, char const*const name, Id const variable); + Id createDebugLocalVariable(Id type, char const*const name, size_t const argNumber = 0); + Id makeDebugExpression(); + Id makeDebugDeclare(Id const debugLocalVariable, Id const pointer); + Id makeDebugValue(Id const debugLocalVariable, Id const value); + Id makeDebugFunctionType(Id returnType, const std::vector& paramTypes); + Id makeDebugFunction(Function* function, Id nameId, Id funcTypeId); + Id makeDebugLexicalBlock(uint32_t line); + std::string unmangleFunctionName(std::string const& name) const; + void setupDebugFunctionEntry(Function* function, const char* name, int line, + const std::vector& paramTypes, + const std::vector& paramNames); + // accelerationStructureNV type Id makeAccelerationStructureType(); // rayQueryEXT type Id makeRayQueryType(); + // hitObjectNV type + Id makeHitObjectNVType(); // For querying about types. Id getTypeId(Id resultId) const { return module.getTypeId(resultId); } @@ -204,6 +273,7 @@ public: ImageFormat getImageTypeFormat(Id typeId) const { return (ImageFormat)module.getInstruction(typeId)->getImmediateOperand(6); } Id getResultingAccessChainType() const; + Id getIdOperand(Id resultId, int idx) { return module.getInstruction(resultId)->getIdOperand(idx); } bool isPointer(Id resultId) const { return isPointerType(getTypeId(resultId)); } bool isScalar(Id resultId) const { return isScalarType(getTypeId(resultId)); } @@ -228,11 +298,10 @@ public: 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 isCooperativeMatrixType(Id typeId)const + { + return getTypeClass(typeId) == OpTypeCooperativeMatrixKHR || getTypeClass(typeId) == OpTypeCooperativeMatrixNV; + } bool isAggregateType(Id typeId) const { return isArrayType(typeId) || isStructType(typeId) || isCooperativeMatrixType(typeId); } bool isImageType(Id typeId) const { return getTypeClass(typeId) == OpTypeImage; } @@ -318,6 +387,8 @@ public: Id makeFloat16Constant(float f16, bool specConstant = false); Id makeFpConstant(Id type, double d, bool specConstant = false); + Id importNonSemanticShaderDebugInfoInstructions(); + // Turn the array of constants into a proper spv constant of the requested type. Id makeCompositeConstant(Id type, const std::vector& comps, bool specConst = false); @@ -332,6 +403,7 @@ public: void addDecoration(Id, Decoration, const char*); void addDecoration(Id, Decoration, const std::vector& literals); void addDecoration(Id, Decoration, const std::vector& strings); + void addLinkageDecoration(Id id, const char* name, spv::LinkageType linkType); void addDecorationId(Id id, Decoration, Id idDecoration); void addDecorationId(Id id, Decoration, const std::vector& operandIds); void addMemberDecoration(Id, unsigned int member, Decoration, int num = -1); @@ -340,9 +412,19 @@ public: void addMemberDecoration(Id, unsigned int member, Decoration, const std::vector& strings); // At the end of what block do the next create*() instructions go? - void setBuildPoint(Block* bp) { buildPoint = bp; } + // Also reset current last DebugScope and current source line to unknown + void setBuildPoint(Block* bp) { + buildPoint = bp; + // TODO: Technically, change of build point should set line tracker dirty. But we'll have bad line info for + // branch instructions. Commenting this for now because at least this matches the old behavior. + dirtyScopeTracker = true; + } Block* getBuildPoint() const { return buildPoint; } + // Append an instruction to the end of the current build point. + // Optionally, additional debug info instructions may also be prepended. + void addInstruction(std::unique_ptr inst); + // Make the entry-point function. The returned pointer is only valid // for the lifetime of this builder. Function* makeEntryPoint(const char*); @@ -350,13 +432,23 @@ public: // 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& paramTypes, const std::vector>& precisions, Block **entry = 0); + Function* makeFunctionEntry(Decoration precision, Id returnType, const char* name, LinkageType linkType, + const std::vector& paramTypes, + const std::vector>& precisions, Block** entry = nullptr); // 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); + // Initialize state and generate instructions for new lexical scope + void enterLexicalBlock(uint32_t line); + + // Set state and generate instructions to exit current lexical scope + void leaveLexicalBlock(); + + // Prepare builder for generation of instructions for a function. + void enterFunction(Function const* function); + // Generate all the code needed to finish up a function. void leaveFunction(); @@ -364,9 +456,13 @@ public: // discard, terminate-invocation, terminateRayEXT, or ignoreIntersectionEXT void makeStatementTerminator(spv::Op opcode, const char *name); + // Create block terminator instruction for statements that have input operands + // such as OpEmitMeshTasksEXT + void makeStatementTerminator(spv::Op opcode, const std::vector& operands, const char* name); + // Create a global or function local or IO variable. - Id createVariable(Decoration precision, StorageClass, Id type, const char* name = nullptr, - Id initializer = NoResult); + Id createVariable(Decoration precision, StorageClass storageClass, Id type, const char* name = nullptr, + Id initializer = NoResult, bool const compilerGenerated = true); // Create an intermediate with an undefined value. Id createUndefined(Id type); @@ -386,8 +482,10 @@ public: // Create an OpArrayLength instruction Id createArrayLength(Id base, unsigned int member); + // Create an OpCooperativeMatrixLengthKHR instruction + Id createCooperativeMatrixLengthKHR(Id type); // Create an OpCooperativeMatrixLengthNV instruction - Id createCooperativeMatrixLength(Id type); + Id createCooperativeMatrixLengthNV(Id type); // Create an OpCompositeExtract instruction Id createCompositeExtract(Id composite, Id typeId, unsigned index); @@ -622,11 +720,6 @@ public: // 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 isNonUniform() const { return nonUniform; } bool anyCoherent() const { @@ -671,7 +764,6 @@ public: nonUniform |= other.nonUniform; return *this; } -#endif }; CoherentFlags coherentFlags; }; @@ -752,19 +844,17 @@ public: // Add capabilities, extensions, remove unneeded decorations, etc., // based on the resulting SPIR-V. - void postProcess(); + void postProcess(bool compileOnly); // 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&) const; @@ -801,13 +891,39 @@ public: const; unsigned int spvVersion; // the version of SPIR-V to emit in the header - SourceLanguage source; + SourceLanguage sourceLang; int sourceVersion; - spv::Id sourceFileStringId; + spv::Id nonSemanticShaderCompilationUnitId {0}; + spv::Id nonSemanticShaderDebugInfo {0}; + spv::Id debugInfoNone {0}; + spv::Id debugExpression {0}; // Debug expression with zero operations. std::string sourceText; - int currentLine; - const char* currentFile; - bool emitOpLines; + + // True if an new OpLine/OpDebugLine may need to be inserted. Either: + // 1. The current debug location changed + // 2. The current build point changed + bool dirtyLineTracker; + int currentLine = 0; + // OpString id of the current file name. Always 0 if debug info is off. + spv::Id currentFileId = 0; + // OpString id of the main file name. Always 0 if debug info is off. + spv::Id mainFileId = 0; + + // True if an new OpDebugScope may need to be inserted. Either: + // 1. A new lexical block is pushed + // 2. The current build point changed + bool dirtyScopeTracker; + std::stack currentDebugScopeId; + + // This flag toggles tracking of debug info while building the SPIR-V. + bool trackDebugInfo = false; + // This flag toggles emission of SPIR-V debug instructions, like OpLine and OpSource. + bool emitSpirvDebugInfo = false; + // This flag toggles emission of Non-Semantic Debug extension debug instructions. + bool emitNonSemanticShaderDebugInfo = false; + bool restoreNonSemanticShaderDebugInfo = false; + bool emitNonSemanticShaderDebugSource = false; + std::set extensions; std::vector sourceExtensions; std::vector moduleProcesses; @@ -841,6 +957,8 @@ public: std::unordered_map> groupedStructConstants; // map type opcodes to type instructions std::unordered_map> groupedTypes; + // map type opcodes to debug type instructions + std::unordered_map> groupedDebugTypes; // list of OpConstantNull instructions std::vector nullConstants; @@ -856,6 +974,12 @@ public: // map from include file name ids to their contents std::map includeFiles; + // map from core id to debug id + std::map debugId; + + // map from file name string id to DebugSource id + std::unordered_map debugSourceId; + // The stream for outputting warnings and errors. SpvBuildLogger* logger; }; // end Builder class diff --git a/src/libraries/glslang/SPIRV/SpvPostProcess.cpp b/src/libraries/glslang/SPIRV/SpvPostProcess.cpp index dd6dabce0..ebc69124e 100644 --- a/src/libraries/glslang/SPIRV/SpvPostProcess.cpp +++ b/src/libraries/glslang/SPIRV/SpvPostProcess.cpp @@ -52,11 +52,12 @@ namespace spv { #include "GLSL.ext.EXT.h" #include "GLSL.ext.AMD.h" #include "GLSL.ext.NV.h" + #include "GLSL.ext.ARM.h" + #include "GLSL.ext.QCOM.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. @@ -180,6 +181,7 @@ void Builder::postProcessType(const Instruction& inst, Id typeId) else if (width == 8) addCapability(CapabilityInt8); } + break; default: if (basicTypeOp == OpTypeInt) { if (width == 16) @@ -333,7 +335,6 @@ void Builder::postProcess(Instruction& inst) } } } -#endif // comment in header void Builder::postProcessCFG() @@ -394,7 +395,6 @@ void Builder::postProcessCFG() decorations.end()); } -#ifndef GLSLANG_WEB // comment in header void Builder::postProcessFeatures() { // Add per-instruction capabilities, extensions, etc., @@ -482,14 +482,15 @@ void Builder::postProcessFeatures() { } } } -#endif // comment in header -void Builder::postProcess() { - postProcessCFG(); -#ifndef GLSLANG_WEB - postProcessFeatures(); -#endif +void Builder::postProcess(bool compileOnly) +{ + // postProcessCFG needs an entrypoint to determine what is reachable, but if we are not creating an "executable" shader, we don't have an entrypoint + if (!compileOnly) + postProcessCFG(); + + postProcessFeatures(); } }; // end spv namespace diff --git a/src/libraries/glslang/SPIRV/SpvTools.cpp b/src/libraries/glslang/SPIRV/SpvTools.cpp index f78a79177..ff04f4f96 100644 --- a/src/libraries/glslang/SPIRV/SpvTools.cpp +++ b/src/libraries/glslang/SPIRV/SpvTools.cpp @@ -68,26 +68,8 @@ spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLog } case glslang::EShTargetVulkan_1_2: return spv_target_env::SPV_ENV_VULKAN_1_2; - case glslang::EShTargetUniversal: - switch (spvVersion.spv) { - case EShTargetSpv_1_0: - return spv_target_env::SPV_ENV_UNIVERSAL_1_0; - case EShTargetSpv_1_1: - return spv_target_env::SPV_ENV_UNIVERSAL_1_1; - case EShTargetSpv_1_2: - return spv_target_env::SPV_ENV_UNIVERSAL_1_2; - case EShTargetSpv_1_3: - return spv_target_env::SPV_ENV_UNIVERSAL_1_3; - case EShTargetSpv_1_4: - return spv_target_env::SPV_ENV_UNIVERSAL_1_4; - case EShTargetSpv_1_5: - return spv_target_env::SPV_ENV_UNIVERSAL_1_5; - case EShTargetSpv_1_6: - return spv_target_env::SPV_ENV_UNIVERSAL_1_6; - default: - logger->missingFunctionality("Target version for SPIRV-Tools validator"); - return spv_target_env::SPV_ENV_UNIVERSAL_1_6; - } + case glslang::EShTargetVulkan_1_3: + return spv_target_env::SPV_ENV_VULKAN_1_3; default: break; } @@ -230,6 +212,7 @@ void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector optimizer.RegisterPass(spvtools::CreateInterpolateFixupPass()); if (options->optimizeSize) { optimizer.RegisterPass(spvtools::CreateRedundancyEliminationPass()); + optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsSafePass()); } optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); optimizer.RegisterPass(spvtools::CreateCFGCleanupPass()); @@ -240,6 +223,56 @@ void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); } +bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector& spirv, + std::unordered_set* live_locs, + std::unordered_set* live_builtins, + spv::SpvBuildLogger*) +{ + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer(OptimizerMesssageConsumer); + + optimizer.RegisterPass(spvtools::CreateAnalyzeLiveInputPass(live_locs, live_builtins)); + + spvtools::OptimizerOptions spvOptOptions; + optimizer.SetTargetEnv(target_env); + spvOptOptions.set_run_validator(false); + return optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); +} + +void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector& spirv, + std::unordered_set* live_locs, + std::unordered_set* live_builtins, + spv::SpvBuildLogger*) +{ + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer(OptimizerMesssageConsumer); + + optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputStoresPass(live_locs, live_builtins)); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true)); + optimizer.RegisterPass(spvtools::CreateEliminateDeadOutputComponentsPass()); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass(false, true)); + + spvtools::OptimizerOptions spvOptOptions; + optimizer.SetTargetEnv(target_env); + spvOptOptions.set_run_validator(false); + optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); +} + +void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector& spirv, + spv::SpvBuildLogger*) +{ + spvtools::Optimizer optimizer(target_env); + optimizer.SetMessageConsumer(OptimizerMesssageConsumer); + + optimizer.RegisterPass(spvtools::CreateEliminateDeadInputComponentsPass()); + optimizer.RegisterPass(spvtools::CreateAggressiveDCEPass()); + + spvtools::OptimizerOptions spvOptOptions; + optimizer.SetTargetEnv(target_env); + spvOptOptions.set_run_validator(false); + optimizer.Run(spirv.data(), spirv.size(), &spirv, spvOptOptions); +} + // Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by // SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if // optimization is disabled. diff --git a/src/libraries/glslang/SPIRV/SpvTools.h b/src/libraries/glslang/SPIRV/SpvTools.h index d856c5236..3ef053d73 100644 --- a/src/libraries/glslang/SPIRV/SpvTools.h +++ b/src/libraries/glslang/SPIRV/SpvTools.h @@ -48,23 +48,16 @@ #endif #include "../glslang/MachineIndependent/localintermediate.h" +#include "GlslangToSpv.h" #include "Logger.h" namespace glslang { -struct SpvOptions { - SpvOptions() : generateDebugInfo(false), stripDebugInfo(false), disableOptimizer(true), - optimizeSize(false), disassemble(false), validate(false) { } - bool generateDebugInfo; - bool stripDebugInfo; - bool disableOptimizer; - bool optimizeSize; - bool disassemble; - bool validate; -}; - #if ENABLE_OPT +// Translate glslang's view of target versioning to what SPIRV-Tools uses. +spv_target_env MapToSpirvToolsEnv(const SpvVersion& spvVersion, spv::SpvBuildLogger* logger); + // Use the SPIRV-Tools disassembler to print SPIR-V using a SPV_ENV_UNIVERSAL_1_3 environment. void SpirvToolsDisassemble(std::ostream& out, const std::vector& spirv); @@ -80,6 +73,22 @@ void SpirvToolsValidate(const glslang::TIntermediate& intermediate, std::vector< void SpirvToolsTransform(const glslang::TIntermediate& intermediate, std::vector& spirv, spv::SpvBuildLogger*, const SpvOptions*); +// Apply the SPIRV-Tools EliminateDeadInputComponents pass to generated SPIR-V. Put result in |spirv|. +void SpirvToolsEliminateDeadInputComponents(spv_target_env target_env, std::vector& spirv, + spv::SpvBuildLogger*); + +// Apply the SPIRV-Tools AnalyzeDeadOutputStores pass to generated SPIR-V. Put result in |live_locs|. +// Return true if the result is valid. +bool SpirvToolsAnalyzeDeadOutputStores(spv_target_env target_env, std::vector& spirv, + std::unordered_set* live_locs, + std::unordered_set* live_builtins, spv::SpvBuildLogger*); + +// Apply the SPIRV-Tools EliminateDeadOutputStores and AggressiveDeadCodeElimination passes to generated SPIR-V using +// |live_locs|. Put result in |spirv|. +void SpirvToolsEliminateDeadOutputStores(spv_target_env target_env, std::vector& spirv, + std::unordered_set* live_locs, + std::unordered_set* live_builtins, spv::SpvBuildLogger*); + // Apply the SPIRV-Tools optimizer to strip debug info from SPIR-V. This is implicitly done by // SpirvToolsTransform if spvOptions->stripDebugInfo is set, but can be called separately if // optimization is disabled. diff --git a/src/libraries/glslang/SPIRV/disassemble.cpp b/src/libraries/glslang/SPIRV/disassemble.cpp index 73c988c5b..ab77610c4 100644 --- a/src/libraries/glslang/SPIRV/disassemble.cpp +++ b/src/libraries/glslang/SPIRV/disassemble.cpp @@ -43,6 +43,7 @@ #include #include #include +#include #include "disassemble.h" #include "doc.h" @@ -53,6 +54,9 @@ namespace spv { #include "GLSL.std.450.h" #include "GLSL.ext.AMD.h" #include "GLSL.ext.NV.h" + #include "GLSL.ext.ARM.h" + #include "NonSemanticShaderDebugInfo100.h" + #include "GLSL.ext.QCOM.h" } } const char* GlslStd450DebugNames[spv::GLSLstd450Count]; @@ -61,6 +65,7 @@ namespace spv { static const char* GLSLextAMDGetDebugNames(const char*, unsigned); static const char* GLSLextNVGetDebugNames(const char*, unsigned); +static const char* NonSemanticShaderDebugInfo100GetDebugNames(unsigned); static void Kill(std::ostream& out, const char* message) { @@ -75,6 +80,8 @@ enum ExtInstSet { GLSLextNVInst, OpenCLExtInst, NonSemanticDebugPrintfExtInst, + NonSemanticDebugBreakExtInst, + NonSemanticShaderDebugInfo100 }; // Container class for a single instance of a SPIR-V stream, with methods for disassembly. @@ -100,6 +107,7 @@ protected: void outputMask(OperandClass operandClass, unsigned mask); void disassembleImmediates(int numOperands); void disassembleIds(int numOperands); + std::pair decodeString(); int disassembleString(); void disassembleInstruction(Id resultId, Id typeId, Op opCode, int numOperands); @@ -290,31 +298,44 @@ void SpirvStream::disassembleIds(int numOperands) } } -// return the number of operands consumed by the string -int SpirvStream::disassembleString() +// decode string from words at current position (non-consuming) +std::pair SpirvStream::decodeString() { - int startWord = word; - - out << " \""; - - const char* wordString; + std::string res; + int wordPos = word; + char c; bool done = false; + do { - unsigned int content = stream[word]; - wordString = (const char*)&content; + unsigned int content = stream[wordPos]; for (int charCount = 0; charCount < 4; ++charCount) { - if (*wordString == 0) { + c = content & 0xff; + content >>= 8; + if (c == '\0') { done = true; break; } - out << *(wordString++); + res += c; } - ++word; - } while (! done); + ++wordPos; + } while(! done); + return std::make_pair(wordPos - word, res); +} + +// return the number of operands consumed by the string +int SpirvStream::disassembleString() +{ + out << " \""; + + std::pair decoderes = decodeString(); + + out << decoderes.second; out << "\""; - return word - startWord; + word += decoderes.first; + + return decoderes.first; } void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, int numOperands) @@ -331,7 +352,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, nextNestedControl = 0; } } else if (opCode == OpExtInstImport) { - idDescriptor[resultId] = (const char*)(&stream[word]); + idDescriptor[resultId] = decodeString().second; } else { if (resultId != 0 && idDescriptor[resultId].size() == 0) { @@ -340,7 +361,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, switch (stream[word]) { case 8: idDescriptor[resultId] = "int8_t"; break; case 16: idDescriptor[resultId] = "int16_t"; break; - default: assert(0); // fallthrough + default: assert(0); [[fallthrough]]; case 32: idDescriptor[resultId] = "int"; break; case 64: idDescriptor[resultId] = "int64_t"; break; } @@ -348,7 +369,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, case OpTypeFloat: switch (stream[word]) { case 16: idDescriptor[resultId] = "float16_t"; break; - default: assert(0); // fallthrough + default: assert(0); [[fallthrough]]; case 32: idDescriptor[resultId] = "float"; break; case 64: idDescriptor[resultId] = "float64_t"; break; } @@ -428,7 +449,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, --numOperands; // Get names for printing "(XXX)" for readability, *after* this id if (opCode == OpName) - idDescriptor[stream[word - 1]] = (const char*)(&stream[word]); + idDescriptor[stream[word - 1]] = decodeString().second; break; case OperandVariableIds: disassembleIds(numOperands); @@ -486,6 +507,10 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, extInstSet = OpenCLExtInst; } else if (strcmp("NonSemantic.DebugPrintf", name) == 0) { extInstSet = NonSemanticDebugPrintfExtInst; + } else if (strcmp("NonSemantic.DebugBreak", name) == 0) { + extInstSet = NonSemanticDebugBreakExtInst; + } else if (strcmp("NonSemantic.Shader.DebugInfo.100", name) == 0) { + extInstSet = NonSemanticShaderDebugInfo100; } 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 || @@ -494,7 +519,7 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, } 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_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; @@ -511,6 +536,10 @@ void SpirvStream::disassembleInstruction(Id resultId, Id /*typeId*/, Op opCode, out << "(" << GLSLextNVGetDebugNames(name, entrypoint) << ")"; } else if (extInstSet == NonSemanticDebugPrintfExtInst) { out << "(DebugPrintf)"; + } else if (extInstSet == NonSemanticDebugBreakExtInst) { + out << "(DebugBreak)"; + } else if (extInstSet == NonSemanticShaderDebugInfo100) { + out << "(" << NonSemanticShaderDebugInfo100GetDebugNames(entrypoint) << ")"; } } break; @@ -734,6 +763,59 @@ static const char* GLSLextNVGetDebugNames(const char* name, unsigned entrypoint) return "Bad"; } +static const char* NonSemanticShaderDebugInfo100GetDebugNames(unsigned entrypoint) +{ + switch (entrypoint) { + case NonSemanticShaderDebugInfo100DebugInfoNone: return "DebugInfoNone"; + case NonSemanticShaderDebugInfo100DebugCompilationUnit: return "DebugCompilationUnit"; + case NonSemanticShaderDebugInfo100DebugTypeBasic: return "DebugTypeBasic"; + case NonSemanticShaderDebugInfo100DebugTypePointer: return "DebugTypePointer"; + case NonSemanticShaderDebugInfo100DebugTypeQualifier: return "DebugTypeQualifier"; + case NonSemanticShaderDebugInfo100DebugTypeArray: return "DebugTypeArray"; + case NonSemanticShaderDebugInfo100DebugTypeVector: return "DebugTypeVector"; + case NonSemanticShaderDebugInfo100DebugTypedef: return "DebugTypedef"; + case NonSemanticShaderDebugInfo100DebugTypeFunction: return "DebugTypeFunction"; + case NonSemanticShaderDebugInfo100DebugTypeEnum: return "DebugTypeEnum"; + case NonSemanticShaderDebugInfo100DebugTypeComposite: return "DebugTypeComposite"; + case NonSemanticShaderDebugInfo100DebugTypeMember: return "DebugTypeMember"; + case NonSemanticShaderDebugInfo100DebugTypeInheritance: return "DebugTypeInheritance"; + case NonSemanticShaderDebugInfo100DebugTypePtrToMember: return "DebugTypePtrToMember"; + case NonSemanticShaderDebugInfo100DebugTypeTemplate: return "DebugTypeTemplate"; + case NonSemanticShaderDebugInfo100DebugTypeTemplateParameter: return "DebugTypeTemplateParameter"; + case NonSemanticShaderDebugInfo100DebugTypeTemplateTemplateParameter: return "DebugTypeTemplateTemplateParameter"; + case NonSemanticShaderDebugInfo100DebugTypeTemplateParameterPack: return "DebugTypeTemplateParameterPack"; + case NonSemanticShaderDebugInfo100DebugGlobalVariable: return "DebugGlobalVariable"; + case NonSemanticShaderDebugInfo100DebugFunctionDeclaration: return "DebugFunctionDeclaration"; + case NonSemanticShaderDebugInfo100DebugFunction: return "DebugFunction"; + case NonSemanticShaderDebugInfo100DebugLexicalBlock: return "DebugLexicalBlock"; + case NonSemanticShaderDebugInfo100DebugLexicalBlockDiscriminator: return "DebugLexicalBlockDiscriminator"; + case NonSemanticShaderDebugInfo100DebugScope: return "DebugScope"; + case NonSemanticShaderDebugInfo100DebugNoScope: return "DebugNoScope"; + case NonSemanticShaderDebugInfo100DebugInlinedAt: return "DebugInlinedAt"; + case NonSemanticShaderDebugInfo100DebugLocalVariable: return "DebugLocalVariable"; + case NonSemanticShaderDebugInfo100DebugInlinedVariable: return "DebugInlinedVariable"; + case NonSemanticShaderDebugInfo100DebugDeclare: return "DebugDeclare"; + case NonSemanticShaderDebugInfo100DebugValue: return "DebugValue"; + case NonSemanticShaderDebugInfo100DebugOperation: return "DebugOperation"; + case NonSemanticShaderDebugInfo100DebugExpression: return "DebugExpression"; + case NonSemanticShaderDebugInfo100DebugMacroDef: return "DebugMacroDef"; + case NonSemanticShaderDebugInfo100DebugMacroUndef: return "DebugMacroUndef"; + case NonSemanticShaderDebugInfo100DebugImportedEntity: return "DebugImportedEntity"; + case NonSemanticShaderDebugInfo100DebugSource: return "DebugSource"; + case NonSemanticShaderDebugInfo100DebugFunctionDefinition: return "DebugFunctionDefinition"; + case NonSemanticShaderDebugInfo100DebugSourceContinued: return "DebugSourceContinued"; + case NonSemanticShaderDebugInfo100DebugLine: return "DebugLine"; + case NonSemanticShaderDebugInfo100DebugNoLine: return "DebugNoLine"; + case NonSemanticShaderDebugInfo100DebugBuildIdentifier: return "DebugBuildIdentifier"; + case NonSemanticShaderDebugInfo100DebugStoragePath: return "DebugStoragePath"; + case NonSemanticShaderDebugInfo100DebugEntryPoint: return "DebugEntryPoint"; + case NonSemanticShaderDebugInfo100DebugTypeMatrix: return "DebugTypeMatrix"; + default: return "Bad"; + } + + return "Bad"; +} + void Disassemble(std::ostream& out, const std::vector& stream) { SpirvStream SpirvStream(out, stream); diff --git a/src/libraries/glslang/SPIRV/doc.cpp b/src/libraries/glslang/SPIRV/doc.cpp old mode 100644 new mode 100755 index 9a569e0d7..26e4b1018 --- a/src/libraries/glslang/SPIRV/doc.cpp +++ b/src/libraries/glslang/SPIRV/doc.cpp @@ -1,5 +1,6 @@ // // Copyright (C) 2014-2015 LunarG, Inc. +// Copyright (C) 2022-2024 Arm Limited. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. @@ -45,6 +46,7 @@ #include #include #include +#include namespace spv { extern "C" { @@ -53,6 +55,8 @@ namespace spv { #include "GLSL.ext.EXT.h" #include "GLSL.ext.AMD.h" #include "GLSL.ext.NV.h" + #include "GLSL.ext.ARM.h" + #include "GLSL.ext.QCOM.h" } } @@ -97,6 +101,8 @@ const char* ExecutionModelString(int model) case 6: return "Kernel"; case ExecutionModelTaskNV: return "TaskNV"; case ExecutionModelMeshNV: return "MeshNV"; + case ExecutionModelTaskEXT: return "TaskEXT"; + case ExecutionModelMeshEXT: return "MeshEXT"; default: return "Bad"; @@ -173,28 +179,33 @@ const char* ExecutionModeString(int mode) case 31: return "ContractionOff"; case 32: return "Bad"; - case ExecutionModeInitializer: return "Initializer"; - case ExecutionModeFinalizer: return "Finalizer"; - case ExecutionModeSubgroupSize: return "SubgroupSize"; - case ExecutionModeSubgroupsPerWorkgroup: return "SubgroupsPerWorkgroup"; - case ExecutionModeSubgroupsPerWorkgroupId: return "SubgroupsPerWorkgroupId"; - case ExecutionModeLocalSizeId: return "LocalSizeId"; - case ExecutionModeLocalSizeHintId: return "LocalSizeHintId"; + case ExecutionModeInitializer: return "Initializer"; + case ExecutionModeFinalizer: return "Finalizer"; + case ExecutionModeSubgroupSize: return "SubgroupSize"; + case ExecutionModeSubgroupsPerWorkgroup: return "SubgroupsPerWorkgroup"; + case ExecutionModeSubgroupsPerWorkgroupId: return "SubgroupsPerWorkgroupId"; + case ExecutionModeLocalSizeId: return "LocalSizeId"; + case ExecutionModeLocalSizeHintId: return "LocalSizeHintId"; - case ExecutionModePostDepthCoverage: return "PostDepthCoverage"; - case ExecutionModeDenormPreserve: return "DenormPreserve"; - case ExecutionModeDenormFlushToZero: return "DenormFlushToZero"; - case ExecutionModeSignedZeroInfNanPreserve: return "SignedZeroInfNanPreserve"; - case ExecutionModeRoundingModeRTE: return "RoundingModeRTE"; - case ExecutionModeRoundingModeRTZ: return "RoundingModeRTZ"; - case ExecutionModeStencilRefReplacingEXT: return "StencilRefReplacingEXT"; + case ExecutionModePostDepthCoverage: return "PostDepthCoverage"; + case ExecutionModeDenormPreserve: return "DenormPreserve"; + case ExecutionModeDenormFlushToZero: return "DenormFlushToZero"; + case ExecutionModeSignedZeroInfNanPreserve: return "SignedZeroInfNanPreserve"; + case ExecutionModeRoundingModeRTE: return "RoundingModeRTE"; + case ExecutionModeRoundingModeRTZ: return "RoundingModeRTZ"; + case ExecutionModeEarlyAndLateFragmentTestsAMD: return "EarlyAndLateFragmentTestsAMD"; + case ExecutionModeStencilRefUnchangedFrontAMD: return "StencilRefUnchangedFrontAMD"; + case ExecutionModeStencilRefLessFrontAMD: return "StencilRefLessFrontAMD"; + case ExecutionModeStencilRefGreaterBackAMD: return "StencilRefGreaterBackAMD"; + case ExecutionModeStencilRefReplacingEXT: return "StencilRefReplacingEXT"; case ExecutionModeSubgroupUniformControlFlowKHR: return "SubgroupUniformControlFlow"; + case ExecutionModeMaximallyReconvergesKHR: return "MaximallyReconverges"; - case ExecutionModeOutputLinesNV: return "OutputLinesNV"; - case ExecutionModeOutputPrimitivesNV: return "OutputPrimitivesNV"; - case ExecutionModeOutputTrianglesNV: return "OutputTrianglesNV"; - case ExecutionModeDerivativeGroupQuadsNV: return "DerivativeGroupQuadsNV"; - case ExecutionModeDerivativeGroupLinearNV: return "DerivativeGroupLinearNV"; + case ExecutionModeOutputLinesNV: return "OutputLinesNV"; + case ExecutionModeOutputPrimitivesNV: return "OutputPrimitivesNV"; + case ExecutionModeOutputTrianglesNV: return "OutputTrianglesNV"; + case ExecutionModeDerivativeGroupQuadsNV: return "DerivativeGroupQuadsNV"; + case ExecutionModeDerivativeGroupLinearNV: return "DerivativeGroupLinearNV"; case ExecutionModePixelInterlockOrderedEXT: return "PixelInterlockOrderedEXT"; case ExecutionModePixelInterlockUnorderedEXT: return "PixelInterlockUnorderedEXT"; @@ -208,6 +219,13 @@ const char* ExecutionModeString(int mode) case ExecutionModeNoGlobalOffsetINTEL: return "NoGlobalOffsetINTEL"; case ExecutionModeNumSIMDWorkitemsINTEL: return "NumSIMDWorkitemsINTEL"; + case ExecutionModeRequireFullQuadsKHR: return "RequireFullQuadsKHR"; + case ExecutionModeQuadDerivativesKHR: return "QuadDerivativesKHR"; + + case ExecutionModeNonCoherentColorAttachmentReadEXT: return "NonCoherentColorAttachmentReadEXT"; + case ExecutionModeNonCoherentDepthAttachmentReadEXT: return "NonCoherentDepthAttachmentReadEXT"; + case ExecutionModeNonCoherentStencilAttachmentReadEXT: return "NonCoherentStencilAttachmentReadEXT"; + case ExecutionModeCeiling: default: return "Bad"; } @@ -238,7 +256,9 @@ const char* StorageClassString(int StorageClass) case StorageClassIncomingCallableDataKHR: return "IncomingCallableDataKHR"; case StorageClassPhysicalStorageBufferEXT: return "PhysicalStorageBufferEXT"; - + case StorageClassTaskPayloadWorkgroupEXT: return "TaskPayloadWorkgroupEXT"; + case StorageClassHitObjectAttributeNV: return "HitObjectAttributeNV"; + case StorageClassTileImageEXT: return "TileImageEXT"; default: return "Bad"; } } @@ -297,7 +317,10 @@ const char* DecorationString(int decoration) case DecorationCeiling: default: return "Bad"; - case DecorationExplicitInterpAMD: return "ExplicitInterpAMD"; + case DecorationWeightTextureQCOM: return "DecorationWeightTextureQCOM"; + case DecorationBlockMatchTextureQCOM: return "DecorationBlockMatchTextureQCOM"; + case DecorationBlockMatchSamplerQCOM: return "DecorationBlockMatchSamplerQCOM"; + case DecorationExplicitInterpAMD: return "ExplicitInterpAMD"; case DecorationOverrideCoverageNV: return "OverrideCoverageNV"; case DecorationPassthroughNV: return "PassthroughNV"; case DecorationViewportRelativeNV: return "ViewportRelativeNV"; @@ -305,13 +328,16 @@ const char* DecorationString(int decoration) case DecorationPerPrimitiveNV: return "PerPrimitiveNV"; case DecorationPerViewNV: return "PerViewNV"; case DecorationPerTaskNV: return "PerTaskNV"; - case DecorationPerVertexNV: return "PerVertexNV"; + + case DecorationPerVertexKHR: return "PerVertexKHR"; case DecorationNonUniformEXT: return "DecorationNonUniformEXT"; case DecorationHlslCounterBufferGOOGLE: return "DecorationHlslCounterBufferGOOGLE"; case DecorationHlslSemanticGOOGLE: return "DecorationHlslSemanticGOOGLE"; case DecorationRestrictPointerEXT: return "DecorationRestrictPointerEXT"; case DecorationAliasedPointerEXT: return "DecorationAliasedPointerEXT"; + + case DecorationHitObjectShaderRecordBufferNV: return "DecorationHitObjectShaderRecordBufferNV"; } } @@ -392,6 +418,12 @@ const char* BuiltInString(int builtIn) case BuiltInObjectRayDirectionKHR: return "ObjectRayDirectionKHR"; case BuiltInRayTminKHR: return "RayTminKHR"; case BuiltInRayTmaxKHR: return "RayTmaxKHR"; + case BuiltInCullMaskKHR: return "CullMaskKHR"; + case BuiltInHitTriangleVertexPositionsKHR: return "HitTriangleVertexPositionsKHR"; + case BuiltInHitMicroTriangleVertexPositionsNV: return "HitMicroTriangleVertexPositionsNV"; + case BuiltInHitMicroTriangleVertexBarycentricsNV: return "HitMicroTriangleVertexBarycentricsNV"; + case BuiltInHitKindFrontFacingMicroTriangleNV: return "HitKindFrontFacingMicroTriangleNV"; + case BuiltInHitKindBackFacingMicroTriangleNV: return "HitKindBackFacingMicroTriangleNV"; case BuiltInInstanceCustomIndexKHR: return "InstanceCustomIndexKHR"; case BuiltInRayGeometryIndexKHR: return "RayGeometryIndexKHR"; case BuiltInObjectToWorldKHR: return "ObjectToWorldKHR"; @@ -406,8 +438,8 @@ const char* BuiltInString(int builtIn) case BuiltInViewportMaskPerViewNV: return "ViewportMaskPerViewNV"; // case BuiltInFragmentSizeNV: return "FragmentSizeNV"; // superseded by BuiltInFragSizeEXT // case BuiltInInvocationsPerPixelNV: return "InvocationsPerPixelNV"; // superseded by BuiltInFragInvocationCountEXT - case BuiltInBaryCoordNV: return "BaryCoordNV"; - case BuiltInBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; + case BuiltInBaryCoordKHR: return "BaryCoordKHR"; + case BuiltInBaryCoordNoPerspKHR: return "BaryCoordNoPerspKHR"; case BuiltInFragSizeEXT: return "FragSizeEXT"; case BuiltInFragInvocationCountEXT: return "FragInvocationCountEXT"; @@ -427,6 +459,15 @@ const char* BuiltInString(int builtIn) case BuiltInWarpIDNV: return "WarpIDNV"; case BuiltInSMIDNV: return "SMIDNV"; case BuiltInCurrentRayTimeNV: return "CurrentRayTimeNV"; + case BuiltInPrimitivePointIndicesEXT: return "PrimitivePointIndicesEXT"; + case BuiltInPrimitiveLineIndicesEXT: return "PrimitiveLineIndicesEXT"; + case BuiltInPrimitiveTriangleIndicesEXT: return "PrimitiveTriangleIndicesEXT"; + case BuiltInCullPrimitiveEXT: return "CullPrimitiveEXT"; + case BuiltInCoreCountARM: return "CoreCountARM"; + case BuiltInCoreIDARM: return "CoreIDARM"; + case BuiltInCoreMaxIDARM: return "CoreMaxIDARM"; + case BuiltInWarpIDARM: return "WarpIDARM"; + case BuiltInWarpMaxIDARM: return "BuiltInWarpMaxIDARM"; default: return "Bad"; } @@ -442,6 +483,7 @@ const char* DimensionString(int dim) case 4: return "Rect"; case 5: return "Buffer"; case 6: return "SubpassData"; + case DimTileImageDataEXT: return "TileImageDataEXT"; default: return "Bad"; } @@ -556,7 +598,7 @@ const char* ImageChannelOrderString(int format) case 17: return "sRGBA"; case 18: return "sBGRA"; - default: + default: return "Bad"; } } @@ -761,6 +803,21 @@ const char* MemoryAccessString(int mem) } } +const int CooperativeMatrixOperandsCeiling = 6; + +const char* CooperativeMatrixOperandsString(int op) +{ + switch (op) { + case CooperativeMatrixOperandsMatrixASignedComponentsKHRShift: return "ASignedComponentsKHR"; + case CooperativeMatrixOperandsMatrixBSignedComponentsKHRShift: return "BSignedComponentsKHR"; + case CooperativeMatrixOperandsMatrixCSignedComponentsKHRShift: return "CSignedComponentsKHR"; + case CooperativeMatrixOperandsMatrixResultSignedComponentsKHRShift: return "ResultSignedComponentsKHR"; + case CooperativeMatrixOperandsSaturatingAccumulationKHRShift: return "SaturatingAccumulationKHR"; + + default: return "Bad"; + } +} + const char* ScopeString(int mem) { switch (mem) { @@ -842,7 +899,7 @@ const char* CapabilityString(int info) case 22: return "Int16"; case 23: return "TessellationPointSize"; case 24: return "GeometryPointSize"; - case 25: return "ImageGatherExtended"; + case 25: return "ImageGatherExtended"; case 26: return "Bad"; case 27: return "StorageImageMultisample"; case 28: return "UniformBufferArrayDynamicIndexing"; @@ -887,6 +944,7 @@ const char* CapabilityString(int info) case CapabilitySubgroupBallotKHR: return "SubgroupBallotKHR"; case CapabilityDrawParameters: return "DrawParameters"; case CapabilitySubgroupVoteKHR: return "SubgroupVoteKHR"; + case CapabilityGroupNonUniformRotateKHR: return "CapabilityGroupNonUniformRotateKHR"; case CapabilityStorageUniformBufferBlock16: return "StorageUniformBufferBlock16"; case CapabilityStorageUniform16: return "StorageUniform16"; @@ -925,14 +983,20 @@ const char* CapabilityString(int info) case CapabilityRayTracingNV: return "RayTracingNV"; case CapabilityRayTracingMotionBlurNV: return "RayTracingMotionBlurNV"; case CapabilityRayTracingKHR: return "RayTracingKHR"; + case CapabilityRayCullMaskKHR: return "RayCullMaskKHR"; case CapabilityRayQueryKHR: return "RayQueryKHR"; case CapabilityRayTracingProvisionalKHR: return "RayTracingProvisionalKHR"; case CapabilityRayTraversalPrimitiveCullingKHR: return "RayTraversalPrimitiveCullingKHR"; + case CapabilityRayTracingPositionFetchKHR: return "RayTracingPositionFetchKHR"; + case CapabilityDisplacementMicromapNV: return "DisplacementMicromapNV"; + case CapabilityRayTracingDisplacementMicromapNV: return "CapabilityRayTracingDisplacementMicromapNV"; + case CapabilityRayQueryPositionFetchKHR: return "RayQueryPositionFetchKHR"; case CapabilityComputeDerivativeGroupQuadsNV: return "ComputeDerivativeGroupQuadsNV"; case CapabilityComputeDerivativeGroupLinearNV: return "ComputeDerivativeGroupLinearNV"; - case CapabilityFragmentBarycentricNV: return "FragmentBarycentricNV"; + case CapabilityFragmentBarycentricKHR: return "FragmentBarycentricKHR"; case CapabilityMeshShadingNV: return "MeshShadingNV"; case CapabilityImageFootprintNV: return "ImageFootprintNV"; + case CapabilityMeshShadingEXT: return "MeshShadingEXT"; // case CapabilityShadingRateNV: return "ShadingRateNV"; // superseded by FragmentDensityEXT case CapabilitySampleMaskOverrideCoverageNV: return "SampleMaskOverrideCoverageNV"; case CapabilityFragmentDensityEXT: return "FragmentDensityEXT"; @@ -960,20 +1024,29 @@ const char* CapabilityString(int info) case CapabilityVariablePointers: return "VariablePointers"; case CapabilityCooperativeMatrixNV: return "CooperativeMatrixNV"; + case CapabilityCooperativeMatrixKHR: return "CooperativeMatrixKHR"; case CapabilityShaderSMBuiltinsNV: return "ShaderSMBuiltinsNV"; case CapabilityFragmentShaderSampleInterlockEXT: return "CapabilityFragmentShaderSampleInterlockEXT"; case CapabilityFragmentShaderPixelInterlockEXT: return "CapabilityFragmentShaderPixelInterlockEXT"; case CapabilityFragmentShaderShadingRateInterlockEXT: return "CapabilityFragmentShaderShadingRateInterlockEXT"; + case CapabilityTileImageColorReadAccessEXT: return "TileImageColorReadAccessEXT"; + case CapabilityTileImageDepthReadAccessEXT: return "TileImageDepthReadAccessEXT"; + case CapabilityTileImageStencilReadAccessEXT: return "TileImageStencilReadAccessEXT"; + case CapabilityFragmentShadingRateKHR: return "FragmentShadingRateKHR"; case CapabilityDemoteToHelperInvocationEXT: return "DemoteToHelperInvocationEXT"; + case CapabilityAtomicFloat16VectorNV: return "AtomicFloat16VectorNV"; case CapabilityShaderClockKHR: return "ShaderClockKHR"; + case CapabilityQuadControlKHR: return "QuadControlKHR"; case CapabilityInt64ImageEXT: return "Int64ImageEXT"; case CapabilityIntegerFunctions2INTEL: return "CapabilityIntegerFunctions2INTEL"; + case CapabilityExpectAssumeKHR: return "ExpectAssumeKHR"; + case CapabilityAtomicFloat16AddEXT: return "AtomicFloat16AddEXT"; case CapabilityAtomicFloat32AddEXT: return "AtomicFloat32AddEXT"; case CapabilityAtomicFloat64AddEXT: return "AtomicFloat64AddEXT"; @@ -984,6 +1057,13 @@ const char* CapabilityString(int info) case CapabilityWorkgroupMemoryExplicitLayoutKHR: return "CapabilityWorkgroupMemoryExplicitLayoutKHR"; case CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR: return "CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR"; case CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR: return "CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR"; + case CapabilityCoreBuiltinsARM: return "CoreBuiltinsARM"; + + case CapabilityShaderInvocationReorderNV: return "ShaderInvocationReorderNV"; + + case CapabilityTextureSampleWeightedQCOM: return "TextureSampleWeightedQCOM"; + case CapabilityTextureBoxFilterQCOM: return "TextureBoxFilterQCOM"; + case CapabilityTextureBlockMatchQCOM: return "TextureBlockMatchQCOM"; default: return "Bad"; } @@ -1363,10 +1443,16 @@ const char* OpcodeString(int op) case 4430: return "OpSubgroupAllEqualKHR"; case 4432: return "OpSubgroupReadInvocationKHR"; + case OpGroupNonUniformQuadAllKHR: return "OpGroupNonUniformQuadAllKHR"; + case OpGroupNonUniformQuadAnyKHR: return "OpGroupNonUniformQuadAnyKHR"; + case OpAtomicFAddEXT: return "OpAtomicFAddEXT"; case OpAtomicFMinEXT: return "OpAtomicFMinEXT"; case OpAtomicFMaxEXT: return "OpAtomicFMaxEXT"; + case OpAssumeTrueKHR: return "OpAssumeTrueKHR"; + case OpExpectKHR: return "OpExpectKHR"; + case 5000: return "OpGroupIAddNonUniformAMD"; case 5001: return "OpGroupFAddNonUniformAMD"; case 5002: return "OpGroupFMinNonUniformAMD"; @@ -1400,6 +1486,10 @@ const char* OpcodeString(int op) case OpGroupNonUniformPartitionNV: return "OpGroupNonUniformPartitionNV"; case OpImageSampleFootprintNV: return "OpImageSampleFootprintNV"; case OpWritePackedPrimitiveIndices4x8NV: return "OpWritePackedPrimitiveIndices4x8NV"; + case OpEmitMeshTasksEXT: return "OpEmitMeshTasksEXT"; + case OpSetMeshOutputsEXT: return "OpSetMeshOutputsEXT"; + + case OpGroupNonUniformRotateKHR: return "OpGroupNonUniformRotateKHR"; case OpTypeRayQueryKHR: return "OpTypeRayQueryKHR"; case OpRayQueryInitializeKHR: return "OpRayQueryInitializeKHR"; @@ -1425,18 +1515,74 @@ const char* OpcodeString(int op) case OpRayQueryGetWorldRayOriginKHR: return "OpRayQueryGetWorldRayOriginKHR"; case OpRayQueryGetIntersectionObjectToWorldKHR: return "OpRayQueryGetIntersectionObjectToWorldKHR"; case OpRayQueryGetIntersectionWorldToObjectKHR: return "OpRayQueryGetIntersectionWorldToObjectKHR"; + case OpRayQueryGetIntersectionTriangleVertexPositionsKHR: return "OpRayQueryGetIntersectionTriangleVertexPositionsKHR"; case OpTypeCooperativeMatrixNV: return "OpTypeCooperativeMatrixNV"; case OpCooperativeMatrixLoadNV: return "OpCooperativeMatrixLoadNV"; case OpCooperativeMatrixStoreNV: return "OpCooperativeMatrixStoreNV"; case OpCooperativeMatrixMulAddNV: return "OpCooperativeMatrixMulAddNV"; case OpCooperativeMatrixLengthNV: return "OpCooperativeMatrixLengthNV"; + case OpTypeCooperativeMatrixKHR: return "OpTypeCooperativeMatrixKHR"; + case OpCooperativeMatrixLoadKHR: return "OpCooperativeMatrixLoadKHR"; + case OpCooperativeMatrixStoreKHR: return "OpCooperativeMatrixStoreKHR"; + case OpCooperativeMatrixMulAddKHR: return "OpCooperativeMatrixMulAddKHR"; + case OpCooperativeMatrixLengthKHR: return "OpCooperativeMatrixLengthKHR"; case OpDemoteToHelperInvocationEXT: return "OpDemoteToHelperInvocationEXT"; case OpIsHelperInvocationEXT: return "OpIsHelperInvocationEXT"; case OpBeginInvocationInterlockEXT: return "OpBeginInvocationInterlockEXT"; case OpEndInvocationInterlockEXT: return "OpEndInvocationInterlockEXT"; + case OpTypeHitObjectNV: return "OpTypeHitObjectNV"; + case OpHitObjectTraceRayNV: return "OpHitObjectTraceRayNV"; + case OpHitObjectTraceRayMotionNV: return "OpHitObjectTraceRayMotionNV"; + case OpHitObjectRecordHitNV: return "OpHitObjectRecordHitNV"; + case OpHitObjectRecordHitMotionNV: return "OpHitObjectRecordHitMotionNV"; + case OpHitObjectRecordHitWithIndexNV: return "OpHitObjectRecordHitWithIndexNV"; + case OpHitObjectRecordHitWithIndexMotionNV: return "OpHitObjectRecordHitWithIndexMotionNV"; + case OpHitObjectRecordMissNV: return "OpHitObjectRecordMissNV"; + case OpHitObjectRecordMissMotionNV: return "OpHitObjectRecordMissMotionNV"; + case OpHitObjectRecordEmptyNV: return "OpHitObjectRecordEmptyNV"; + case OpHitObjectExecuteShaderNV: return "OpHitObjectExecuteShaderNV"; + case OpReorderThreadWithHintNV: return "OpReorderThreadWithHintNV"; + case OpReorderThreadWithHitObjectNV: return "OpReorderThreadWithHitObjectNV"; + case OpHitObjectGetCurrentTimeNV: return "OpHitObjectGetCurrentTimeNV"; + case OpHitObjectGetAttributesNV: return "OpHitObjectGetAttributesNV"; + case OpHitObjectGetHitKindNV: return "OpHitObjectGetFrontFaceNV"; + case OpHitObjectGetPrimitiveIndexNV: return "OpHitObjectGetPrimitiveIndexNV"; + case OpHitObjectGetGeometryIndexNV: return "OpHitObjectGetGeometryIndexNV"; + case OpHitObjectGetInstanceIdNV: return "OpHitObjectGetInstanceIdNV"; + case OpHitObjectGetInstanceCustomIndexNV: return "OpHitObjectGetInstanceCustomIndexNV"; + case OpHitObjectGetObjectRayDirectionNV: return "OpHitObjectGetObjectRayDirectionNV"; + case OpHitObjectGetObjectRayOriginNV: return "OpHitObjectGetObjectRayOriginNV"; + case OpHitObjectGetWorldRayDirectionNV: return "OpHitObjectGetWorldRayDirectionNV"; + case OpHitObjectGetWorldRayOriginNV: return "OpHitObjectGetWorldRayOriginNV"; + case OpHitObjectGetWorldToObjectNV: return "OpHitObjectGetWorldToObjectNV"; + case OpHitObjectGetObjectToWorldNV: return "OpHitObjectGetObjectToWorldNV"; + case OpHitObjectGetRayTMaxNV: return "OpHitObjectGetRayTMaxNV"; + case OpHitObjectGetRayTMinNV: return "OpHitObjectGetRayTMinNV"; + case OpHitObjectIsEmptyNV: return "OpHitObjectIsEmptyNV"; + case OpHitObjectIsHitNV: return "OpHitObjectIsHitNV"; + case OpHitObjectIsMissNV: return "OpHitObjectIsMissNV"; + case OpHitObjectGetShaderBindingTableRecordIndexNV: return "OpHitObjectGetShaderBindingTableRecordIndexNV"; + case OpHitObjectGetShaderRecordBufferHandleNV: return "OpHitObjectGetShaderRecordBufferHandleNV"; + + case OpFetchMicroTriangleVertexBarycentricNV: return "OpFetchMicroTriangleVertexBarycentricNV"; + case OpFetchMicroTriangleVertexPositionNV: return "OpFetchMicroTriangleVertexPositionNV"; + + case OpColorAttachmentReadEXT: return "OpColorAttachmentReadEXT"; + case OpDepthAttachmentReadEXT: return "OpDepthAttachmentReadEXT"; + case OpStencilAttachmentReadEXT: return "OpStencilAttachmentReadEXT"; + + case OpImageSampleWeightedQCOM: return "OpImageSampleWeightedQCOM"; + case OpImageBoxFilterQCOM: return "OpImageBoxFilterQCOM"; + case OpImageBlockMatchSADQCOM: return "OpImageBlockMatchSADQCOM"; + case OpImageBlockMatchSSDQCOM: return "OpImageBlockMatchSSDQCOM"; + case OpImageBlockMatchWindowSSDQCOM: return "OpImageBlockMatchWindowSSDQCOM"; + case OpImageBlockMatchWindowSADQCOM: return "OpImageBlockMatchWindowSADQCOM"; + case OpImageBlockMatchGatherSSDQCOM: return "OpImageBlockMatchGatherSSDQCOM"; + case OpImageBlockMatchGatherSADQCOM: return "OpImageBlockMatchGatherSADQCOM"; + default: return "Bad"; } @@ -1456,1553 +1602,1875 @@ EnumParameters LoopControlParams[FunctionControlCeiling]; EnumParameters SelectionControlParams[SelectControlCeiling]; EnumParameters FunctionControlParams[FunctionControlCeiling]; EnumParameters MemoryAccessParams[MemoryAccessCeiling]; +EnumParameters CooperativeMatrixOperandsParams[CooperativeMatrixOperandsCeiling]; // Set up all the parameterizing descriptions of the opcodes, operands, etc. void Parameterize() { // only do this once. - static bool initialized = false; - if (initialized) - return; - initialized = true; - - // Exceptions to having a result and a resulting type . - // (Everything is initialized to have both). - - InstructionDesc[OpNop].setResultAndType(false, false); - InstructionDesc[OpSource].setResultAndType(false, false); - InstructionDesc[OpSourceContinued].setResultAndType(false, false); - InstructionDesc[OpSourceExtension].setResultAndType(false, false); - InstructionDesc[OpExtension].setResultAndType(false, false); - InstructionDesc[OpExtInstImport].setResultAndType(true, false); - InstructionDesc[OpCapability].setResultAndType(false, false); - InstructionDesc[OpMemoryModel].setResultAndType(false, false); - InstructionDesc[OpEntryPoint].setResultAndType(false, false); - InstructionDesc[OpExecutionMode].setResultAndType(false, false); - InstructionDesc[OpExecutionModeId].setResultAndType(false, false); - InstructionDesc[OpTypeVoid].setResultAndType(true, false); - InstructionDesc[OpTypeBool].setResultAndType(true, false); - InstructionDesc[OpTypeInt].setResultAndType(true, false); - InstructionDesc[OpTypeFloat].setResultAndType(true, false); - InstructionDesc[OpTypeVector].setResultAndType(true, false); - InstructionDesc[OpTypeMatrix].setResultAndType(true, false); - InstructionDesc[OpTypeImage].setResultAndType(true, false); - InstructionDesc[OpTypeSampler].setResultAndType(true, false); - InstructionDesc[OpTypeSampledImage].setResultAndType(true, false); - InstructionDesc[OpTypeArray].setResultAndType(true, false); - InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false); - InstructionDesc[OpTypeStruct].setResultAndType(true, false); - InstructionDesc[OpTypeOpaque].setResultAndType(true, false); - InstructionDesc[OpTypePointer].setResultAndType(true, false); - InstructionDesc[OpTypeForwardPointer].setResultAndType(false, false); - InstructionDesc[OpTypeFunction].setResultAndType(true, false); - InstructionDesc[OpTypeEvent].setResultAndType(true, false); - InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false); - InstructionDesc[OpTypeReserveId].setResultAndType(true, false); - InstructionDesc[OpTypeQueue].setResultAndType(true, false); - InstructionDesc[OpTypePipe].setResultAndType(true, false); - InstructionDesc[OpFunctionEnd].setResultAndType(false, false); - InstructionDesc[OpStore].setResultAndType(false, false); - InstructionDesc[OpImageWrite].setResultAndType(false, false); - InstructionDesc[OpDecorationGroup].setResultAndType(true, false); - InstructionDesc[OpDecorate].setResultAndType(false, false); - InstructionDesc[OpDecorateId].setResultAndType(false, false); - InstructionDesc[OpDecorateStringGOOGLE].setResultAndType(false, false); - InstructionDesc[OpMemberDecorate].setResultAndType(false, false); - InstructionDesc[OpMemberDecorateStringGOOGLE].setResultAndType(false, false); - InstructionDesc[OpGroupDecorate].setResultAndType(false, false); - InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false); - InstructionDesc[OpName].setResultAndType(false, false); - InstructionDesc[OpMemberName].setResultAndType(false, false); - InstructionDesc[OpString].setResultAndType(true, false); - InstructionDesc[OpLine].setResultAndType(false, false); - InstructionDesc[OpNoLine].setResultAndType(false, false); - InstructionDesc[OpCopyMemory].setResultAndType(false, false); - InstructionDesc[OpCopyMemorySized].setResultAndType(false, false); - InstructionDesc[OpEmitVertex].setResultAndType(false, false); - InstructionDesc[OpEndPrimitive].setResultAndType(false, false); - InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false); - InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false); - InstructionDesc[OpControlBarrier].setResultAndType(false, false); - InstructionDesc[OpMemoryBarrier].setResultAndType(false, false); - InstructionDesc[OpAtomicStore].setResultAndType(false, false); - InstructionDesc[OpLoopMerge].setResultAndType(false, false); - InstructionDesc[OpSelectionMerge].setResultAndType(false, false); - InstructionDesc[OpLabel].setResultAndType(true, false); - InstructionDesc[OpBranch].setResultAndType(false, false); - InstructionDesc[OpBranchConditional].setResultAndType(false, false); - InstructionDesc[OpSwitch].setResultAndType(false, false); - InstructionDesc[OpKill].setResultAndType(false, false); - InstructionDesc[OpTerminateInvocation].setResultAndType(false, false); - InstructionDesc[OpReturn].setResultAndType(false, false); - InstructionDesc[OpReturnValue].setResultAndType(false, false); - InstructionDesc[OpUnreachable].setResultAndType(false, false); - InstructionDesc[OpLifetimeStart].setResultAndType(false, false); - InstructionDesc[OpLifetimeStop].setResultAndType(false, false); - InstructionDesc[OpCommitReadPipe].setResultAndType(false, false); - InstructionDesc[OpCommitWritePipe].setResultAndType(false, false); - InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false); - InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false); - InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false); - InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false); - InstructionDesc[OpRetainEvent].setResultAndType(false, false); - InstructionDesc[OpReleaseEvent].setResultAndType(false, false); - InstructionDesc[OpGroupWaitEvents].setResultAndType(false, false); - InstructionDesc[OpAtomicFlagClear].setResultAndType(false, false); - InstructionDesc[OpModuleProcessed].setResultAndType(false, false); - InstructionDesc[OpTypeCooperativeMatrixNV].setResultAndType(true, false); - InstructionDesc[OpCooperativeMatrixStoreNV].setResultAndType(false, false); - InstructionDesc[OpBeginInvocationInterlockEXT].setResultAndType(false, false); - InstructionDesc[OpEndInvocationInterlockEXT].setResultAndType(false, false); - - // Specific additional context-dependent operands - - ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "'Number of <>'"); - - ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'"); - ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'"); - ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'"); - - ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'"); - ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'"); - ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'"); - - ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "'Vertex count'"); - ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandLiteralNumber, "'Vector type'"); - - DecorationOperands[DecorationStream].push(OperandLiteralNumber, "'Stream Number'"); - DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "'Location'"); - DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "'Component'"); - DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "'Index'"); - DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "'Binding Point'"); - DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "'Descriptor Set'"); - DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "'Byte Offset'"); - DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "'XFB Buffer Number'"); - DecorationOperands[DecorationXfbStride].push(OperandLiteralNumber, "'XFB Stride'"); - DecorationOperands[DecorationArrayStride].push(OperandLiteralNumber, "'Array Stride'"); - DecorationOperands[DecorationMatrixStride].push(OperandLiteralNumber, "'Matrix Stride'"); - DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <>"); - DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "'Floating-Point Rounding Mode'"); - DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "'Fast-Math Mode'"); - DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "'Name'"); - DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "'Linkage Type'"); - DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "'Function Parameter Attribute'"); - DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "'Specialization Constant ID'"); - DecorationOperands[DecorationInputAttachmentIndex].push(OperandLiteralNumber, "'Attachment Index'"); - DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "'Alignment'"); - - OperandClassParams[OperandSource].set(0, SourceString, 0); - OperandClassParams[OperandExecutionModel].set(0, ExecutionModelString, nullptr); - OperandClassParams[OperandAddressing].set(0, AddressingString, nullptr); - OperandClassParams[OperandMemory].set(0, MemoryString, nullptr); - OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams); - OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands); - OperandClassParams[OperandStorage].set(0, StorageClassString, nullptr); - OperandClassParams[OperandDimensionality].set(0, DimensionString, nullptr); - OperandClassParams[OperandSamplerAddressingMode].set(0, SamplerAddressingModeString, nullptr); - OperandClassParams[OperandSamplerFilterMode].set(0, SamplerFilterModeString, nullptr); - OperandClassParams[OperandSamplerImageFormat].set(0, ImageFormatString, nullptr); - OperandClassParams[OperandImageChannelOrder].set(0, ImageChannelOrderString, nullptr); - OperandClassParams[OperandImageChannelDataType].set(0, ImageChannelDataTypeString, nullptr); - OperandClassParams[OperandImageOperands].set(ImageOperandsCeiling, ImageOperandsString, ImageOperandsParams, true); - OperandClassParams[OperandFPFastMath].set(0, FPFastMathString, nullptr, true); - OperandClassParams[OperandFPRoundingMode].set(0, FPRoundingModeString, nullptr); - OperandClassParams[OperandLinkageType].set(0, LinkageTypeString, nullptr); - OperandClassParams[OperandFuncParamAttr].set(0, FuncParamAttrString, nullptr); - OperandClassParams[OperandAccessQualifier].set(0, AccessQualifierString, nullptr); - OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams); - OperandClassParams[OperandDecoration].setOperands(DecorationOperands); - OperandClassParams[OperandBuiltIn].set(0, BuiltInString, nullptr); - OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true); - OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true); - OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true); - OperandClassParams[OperandMemorySemantics].set(0, MemorySemanticsString, nullptr, true); - OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true); - OperandClassParams[OperandScope].set(0, ScopeString, nullptr); - OperandClassParams[OperandGroupOperation].set(0, GroupOperationString, nullptr); - OperandClassParams[OperandKernelEnqueueFlags].set(0, KernelEnqueueFlagsString, nullptr); - OperandClassParams[OperandKernelProfilingInfo].set(0, KernelProfilingInfoString, nullptr, true); - OperandClassParams[OperandCapability].set(0, CapabilityString, nullptr); - OperandClassParams[OperandOpcode].set(OpCodeMask + 1, OpcodeString, 0); - - // set name of operator, an initial set of style operands, and the description - - InstructionDesc[OpSource].operands.push(OperandSource, ""); - InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'"); - InstructionDesc[OpSource].operands.push(OperandId, "'File'", true); - InstructionDesc[OpSource].operands.push(OperandLiteralString, "'Source'", true); - - InstructionDesc[OpSourceContinued].operands.push(OperandLiteralString, "'Continued Source'"); - - InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'"); - - InstructionDesc[OpName].operands.push(OperandId, "'Target'"); - InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'"); - - InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'"); - InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'"); - InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'"); - - InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'"); - - InstructionDesc[OpLine].operands.push(OperandId, "'File'"); - InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'"); - InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'"); - - InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'"); - - InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'"); - - InstructionDesc[OpCapability].operands.push(OperandCapability, "'Capability'"); + static std::once_flag initialized; + std::call_once(initialized, [](){ + + // Exceptions to having a result and a resulting type . + // (Everything is initialized to have both). + + InstructionDesc[OpNop].setResultAndType(false, false); + InstructionDesc[OpSource].setResultAndType(false, false); + InstructionDesc[OpSourceContinued].setResultAndType(false, false); + InstructionDesc[OpSourceExtension].setResultAndType(false, false); + InstructionDesc[OpExtension].setResultAndType(false, false); + InstructionDesc[OpExtInstImport].setResultAndType(true, false); + InstructionDesc[OpCapability].setResultAndType(false, false); + InstructionDesc[OpMemoryModel].setResultAndType(false, false); + InstructionDesc[OpEntryPoint].setResultAndType(false, false); + InstructionDesc[OpExecutionMode].setResultAndType(false, false); + InstructionDesc[OpExecutionModeId].setResultAndType(false, false); + InstructionDesc[OpTypeVoid].setResultAndType(true, false); + InstructionDesc[OpTypeBool].setResultAndType(true, false); + InstructionDesc[OpTypeInt].setResultAndType(true, false); + InstructionDesc[OpTypeFloat].setResultAndType(true, false); + InstructionDesc[OpTypeVector].setResultAndType(true, false); + InstructionDesc[OpTypeMatrix].setResultAndType(true, false); + InstructionDesc[OpTypeImage].setResultAndType(true, false); + InstructionDesc[OpTypeSampler].setResultAndType(true, false); + InstructionDesc[OpTypeSampledImage].setResultAndType(true, false); + InstructionDesc[OpTypeArray].setResultAndType(true, false); + InstructionDesc[OpTypeRuntimeArray].setResultAndType(true, false); + InstructionDesc[OpTypeStruct].setResultAndType(true, false); + InstructionDesc[OpTypeOpaque].setResultAndType(true, false); + InstructionDesc[OpTypePointer].setResultAndType(true, false); + InstructionDesc[OpTypeForwardPointer].setResultAndType(false, false); + InstructionDesc[OpTypeFunction].setResultAndType(true, false); + InstructionDesc[OpTypeEvent].setResultAndType(true, false); + InstructionDesc[OpTypeDeviceEvent].setResultAndType(true, false); + InstructionDesc[OpTypeReserveId].setResultAndType(true, false); + InstructionDesc[OpTypeQueue].setResultAndType(true, false); + InstructionDesc[OpTypePipe].setResultAndType(true, false); + InstructionDesc[OpFunctionEnd].setResultAndType(false, false); + InstructionDesc[OpStore].setResultAndType(false, false); + InstructionDesc[OpImageWrite].setResultAndType(false, false); + InstructionDesc[OpDecorationGroup].setResultAndType(true, false); + InstructionDesc[OpDecorate].setResultAndType(false, false); + InstructionDesc[OpDecorateId].setResultAndType(false, false); + InstructionDesc[OpDecorateStringGOOGLE].setResultAndType(false, false); + InstructionDesc[OpMemberDecorate].setResultAndType(false, false); + InstructionDesc[OpMemberDecorateStringGOOGLE].setResultAndType(false, false); + InstructionDesc[OpGroupDecorate].setResultAndType(false, false); + InstructionDesc[OpGroupMemberDecorate].setResultAndType(false, false); + InstructionDesc[OpName].setResultAndType(false, false); + InstructionDesc[OpMemberName].setResultAndType(false, false); + InstructionDesc[OpString].setResultAndType(true, false); + InstructionDesc[OpLine].setResultAndType(false, false); + InstructionDesc[OpNoLine].setResultAndType(false, false); + InstructionDesc[OpCopyMemory].setResultAndType(false, false); + InstructionDesc[OpCopyMemorySized].setResultAndType(false, false); + InstructionDesc[OpEmitVertex].setResultAndType(false, false); + InstructionDesc[OpEndPrimitive].setResultAndType(false, false); + InstructionDesc[OpEmitStreamVertex].setResultAndType(false, false); + InstructionDesc[OpEndStreamPrimitive].setResultAndType(false, false); + InstructionDesc[OpControlBarrier].setResultAndType(false, false); + InstructionDesc[OpMemoryBarrier].setResultAndType(false, false); + InstructionDesc[OpAtomicStore].setResultAndType(false, false); + InstructionDesc[OpLoopMerge].setResultAndType(false, false); + InstructionDesc[OpSelectionMerge].setResultAndType(false, false); + InstructionDesc[OpLabel].setResultAndType(true, false); + InstructionDesc[OpBranch].setResultAndType(false, false); + InstructionDesc[OpBranchConditional].setResultAndType(false, false); + InstructionDesc[OpSwitch].setResultAndType(false, false); + InstructionDesc[OpKill].setResultAndType(false, false); + InstructionDesc[OpTerminateInvocation].setResultAndType(false, false); + InstructionDesc[OpReturn].setResultAndType(false, false); + InstructionDesc[OpReturnValue].setResultAndType(false, false); + InstructionDesc[OpUnreachable].setResultAndType(false, false); + InstructionDesc[OpLifetimeStart].setResultAndType(false, false); + InstructionDesc[OpLifetimeStop].setResultAndType(false, false); + InstructionDesc[OpCommitReadPipe].setResultAndType(false, false); + InstructionDesc[OpCommitWritePipe].setResultAndType(false, false); + InstructionDesc[OpGroupCommitWritePipe].setResultAndType(false, false); + InstructionDesc[OpGroupCommitReadPipe].setResultAndType(false, false); + InstructionDesc[OpCaptureEventProfilingInfo].setResultAndType(false, false); + InstructionDesc[OpSetUserEventStatus].setResultAndType(false, false); + InstructionDesc[OpRetainEvent].setResultAndType(false, false); + InstructionDesc[OpReleaseEvent].setResultAndType(false, false); + InstructionDesc[OpGroupWaitEvents].setResultAndType(false, false); + InstructionDesc[OpAtomicFlagClear].setResultAndType(false, false); + InstructionDesc[OpModuleProcessed].setResultAndType(false, false); + InstructionDesc[OpTypeCooperativeMatrixNV].setResultAndType(true, false); + InstructionDesc[OpCooperativeMatrixStoreNV].setResultAndType(false, false); + InstructionDesc[OpTypeCooperativeMatrixKHR].setResultAndType(true, false); + InstructionDesc[OpCooperativeMatrixStoreKHR].setResultAndType(false, false); + InstructionDesc[OpBeginInvocationInterlockEXT].setResultAndType(false, false); + InstructionDesc[OpEndInvocationInterlockEXT].setResultAndType(false, false); + InstructionDesc[OpAssumeTrueKHR].setResultAndType(false, false); + // Specific additional context-dependent operands + + ExecutionModeOperands[ExecutionModeInvocations].push(OperandLiteralNumber, "'Number of <>'"); + + ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'x size'"); + ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'y size'"); + ExecutionModeOperands[ExecutionModeLocalSize].push(OperandLiteralNumber, "'z size'"); + + ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'x size'"); + ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'y size'"); + ExecutionModeOperands[ExecutionModeLocalSizeHint].push(OperandLiteralNumber, "'z size'"); + + ExecutionModeOperands[ExecutionModeOutputVertices].push(OperandLiteralNumber, "'Vertex count'"); + ExecutionModeOperands[ExecutionModeVecTypeHint].push(OperandLiteralNumber, "'Vector type'"); + + DecorationOperands[DecorationStream].push(OperandLiteralNumber, "'Stream Number'"); + DecorationOperands[DecorationLocation].push(OperandLiteralNumber, "'Location'"); + DecorationOperands[DecorationComponent].push(OperandLiteralNumber, "'Component'"); + DecorationOperands[DecorationIndex].push(OperandLiteralNumber, "'Index'"); + DecorationOperands[DecorationBinding].push(OperandLiteralNumber, "'Binding Point'"); + DecorationOperands[DecorationDescriptorSet].push(OperandLiteralNumber, "'Descriptor Set'"); + DecorationOperands[DecorationOffset].push(OperandLiteralNumber, "'Byte Offset'"); + DecorationOperands[DecorationXfbBuffer].push(OperandLiteralNumber, "'XFB Buffer Number'"); + DecorationOperands[DecorationXfbStride].push(OperandLiteralNumber, "'XFB Stride'"); + DecorationOperands[DecorationArrayStride].push(OperandLiteralNumber, "'Array Stride'"); + DecorationOperands[DecorationMatrixStride].push(OperandLiteralNumber, "'Matrix Stride'"); + DecorationOperands[DecorationBuiltIn].push(OperandLiteralNumber, "See <>"); + DecorationOperands[DecorationFPRoundingMode].push(OperandFPRoundingMode, "'Floating-Point Rounding Mode'"); + DecorationOperands[DecorationFPFastMathMode].push(OperandFPFastMath, "'Fast-Math Mode'"); + DecorationOperands[DecorationLinkageAttributes].push(OperandLiteralString, "'Name'"); + DecorationOperands[DecorationLinkageAttributes].push(OperandLinkageType, "'Linkage Type'"); + DecorationOperands[DecorationFuncParamAttr].push(OperandFuncParamAttr, "'Function Parameter Attribute'"); + DecorationOperands[DecorationSpecId].push(OperandLiteralNumber, "'Specialization Constant ID'"); + DecorationOperands[DecorationInputAttachmentIndex].push(OperandLiteralNumber, "'Attachment Index'"); + DecorationOperands[DecorationAlignment].push(OperandLiteralNumber, "'Alignment'"); + + OperandClassParams[OperandSource].set(0, SourceString, nullptr); + OperandClassParams[OperandExecutionModel].set(0, ExecutionModelString, nullptr); + OperandClassParams[OperandAddressing].set(0, AddressingString, nullptr); + OperandClassParams[OperandMemory].set(0, MemoryString, nullptr); + OperandClassParams[OperandExecutionMode].set(ExecutionModeCeiling, ExecutionModeString, ExecutionModeParams); + OperandClassParams[OperandExecutionMode].setOperands(ExecutionModeOperands); + OperandClassParams[OperandStorage].set(0, StorageClassString, nullptr); + OperandClassParams[OperandDimensionality].set(0, DimensionString, nullptr); + OperandClassParams[OperandSamplerAddressingMode].set(0, SamplerAddressingModeString, nullptr); + OperandClassParams[OperandSamplerFilterMode].set(0, SamplerFilterModeString, nullptr); + OperandClassParams[OperandSamplerImageFormat].set(0, ImageFormatString, nullptr); + OperandClassParams[OperandImageChannelOrder].set(0, ImageChannelOrderString, nullptr); + OperandClassParams[OperandImageChannelDataType].set(0, ImageChannelDataTypeString, nullptr); + OperandClassParams[OperandImageOperands].set(ImageOperandsCeiling, ImageOperandsString, ImageOperandsParams, true); + OperandClassParams[OperandFPFastMath].set(0, FPFastMathString, nullptr, true); + OperandClassParams[OperandFPRoundingMode].set(0, FPRoundingModeString, nullptr); + OperandClassParams[OperandLinkageType].set(0, LinkageTypeString, nullptr); + OperandClassParams[OperandFuncParamAttr].set(0, FuncParamAttrString, nullptr); + OperandClassParams[OperandAccessQualifier].set(0, AccessQualifierString, nullptr); + OperandClassParams[OperandDecoration].set(DecorationCeiling, DecorationString, DecorationParams); + OperandClassParams[OperandDecoration].setOperands(DecorationOperands); + OperandClassParams[OperandBuiltIn].set(0, BuiltInString, nullptr); + OperandClassParams[OperandSelect].set(SelectControlCeiling, SelectControlString, SelectionControlParams, true); + OperandClassParams[OperandLoop].set(LoopControlCeiling, LoopControlString, LoopControlParams, true); + OperandClassParams[OperandFunction].set(FunctionControlCeiling, FunctionControlString, FunctionControlParams, true); + OperandClassParams[OperandMemorySemantics].set(0, MemorySemanticsString, nullptr, true); + OperandClassParams[OperandMemoryAccess].set(MemoryAccessCeiling, MemoryAccessString, MemoryAccessParams, true); + OperandClassParams[OperandScope].set(0, ScopeString, nullptr); + OperandClassParams[OperandGroupOperation].set(0, GroupOperationString, nullptr); + OperandClassParams[OperandKernelEnqueueFlags].set(0, KernelEnqueueFlagsString, nullptr); + OperandClassParams[OperandKernelProfilingInfo].set(0, KernelProfilingInfoString, nullptr, true); + OperandClassParams[OperandCapability].set(0, CapabilityString, nullptr); + OperandClassParams[OperandCooperativeMatrixOperands].set(CooperativeMatrixOperandsCeiling, CooperativeMatrixOperandsString, CooperativeMatrixOperandsParams, true); + OperandClassParams[OperandOpcode].set(OpCodeMask + 1, OpcodeString, nullptr); + + // set name of operator, an initial set of style operands, and the description + + InstructionDesc[OpSource].operands.push(OperandSource, ""); + InstructionDesc[OpSource].operands.push(OperandLiteralNumber, "'Version'"); + InstructionDesc[OpSource].operands.push(OperandId, "'File'", true); + InstructionDesc[OpSource].operands.push(OperandLiteralString, "'Source'", true); + + InstructionDesc[OpSourceContinued].operands.push(OperandLiteralString, "'Continued Source'"); + + InstructionDesc[OpSourceExtension].operands.push(OperandLiteralString, "'Extension'"); + + InstructionDesc[OpName].operands.push(OperandId, "'Target'"); + InstructionDesc[OpName].operands.push(OperandLiteralString, "'Name'"); + + InstructionDesc[OpMemberName].operands.push(OperandId, "'Type'"); + InstructionDesc[OpMemberName].operands.push(OperandLiteralNumber, "'Member'"); + InstructionDesc[OpMemberName].operands.push(OperandLiteralString, "'Name'"); + + InstructionDesc[OpString].operands.push(OperandLiteralString, "'String'"); + + InstructionDesc[OpLine].operands.push(OperandId, "'File'"); + InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Line'"); + InstructionDesc[OpLine].operands.push(OperandLiteralNumber, "'Column'"); + + InstructionDesc[OpExtension].operands.push(OperandLiteralString, "'Name'"); + + InstructionDesc[OpExtInstImport].operands.push(OperandLiteralString, "'Name'"); + + InstructionDesc[OpCapability].operands.push(OperandCapability, "'Capability'"); + + InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, ""); + InstructionDesc[OpMemoryModel].operands.push(OperandMemory, ""); + + InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, ""); + InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'"); + InstructionDesc[OpEntryPoint].operands.push(OperandLiteralString, "'Name'"); + InstructionDesc[OpEntryPoint].operands.push(OperandVariableIds, "'Interface'"); + + InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'"); + InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'"); + InstructionDesc[OpExecutionMode].operands.push(OperandOptionalLiteral, "See <>"); + + InstructionDesc[OpExecutionModeId].operands.push(OperandId, "'Entry Point'"); + InstructionDesc[OpExecutionModeId].operands.push(OperandExecutionMode, "'Mode'"); + InstructionDesc[OpExecutionModeId].operands.push(OperandVariableIds, "See <>"); + + InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'"); + InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'"); + + InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'"); + + InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component Type'"); + InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component Count'"); - InstructionDesc[OpMemoryModel].operands.push(OperandAddressing, ""); - InstructionDesc[OpMemoryModel].operands.push(OperandMemory, ""); - - InstructionDesc[OpEntryPoint].operands.push(OperandExecutionModel, ""); - InstructionDesc[OpEntryPoint].operands.push(OperandId, "'Entry Point'"); - InstructionDesc[OpEntryPoint].operands.push(OperandLiteralString, "'Name'"); - InstructionDesc[OpEntryPoint].operands.push(OperandVariableIds, "'Interface'"); - - InstructionDesc[OpExecutionMode].operands.push(OperandId, "'Entry Point'"); - InstructionDesc[OpExecutionMode].operands.push(OperandExecutionMode, "'Mode'"); - InstructionDesc[OpExecutionMode].operands.push(OperandOptionalLiteral, "See <>"); - - InstructionDesc[OpExecutionModeId].operands.push(OperandId, "'Entry Point'"); - InstructionDesc[OpExecutionModeId].operands.push(OperandExecutionMode, "'Mode'"); - InstructionDesc[OpExecutionModeId].operands.push(OperandVariableIds, "See <>"); - - InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Width'"); - InstructionDesc[OpTypeInt].operands.push(OperandLiteralNumber, "'Signedness'"); - - InstructionDesc[OpTypeFloat].operands.push(OperandLiteralNumber, "'Width'"); - - InstructionDesc[OpTypeVector].operands.push(OperandId, "'Component Type'"); - InstructionDesc[OpTypeVector].operands.push(OperandLiteralNumber, "'Component Count'"); + InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column Type'"); + InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column Count'"); - InstructionDesc[OpTypeMatrix].operands.push(OperandId, "'Column Type'"); - InstructionDesc[OpTypeMatrix].operands.push(OperandLiteralNumber, "'Column Count'"); + InstructionDesc[OpTypeImage].operands.push(OperandId, "'Sampled Type'"); + InstructionDesc[OpTypeImage].operands.push(OperandDimensionality, ""); + InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Depth'"); + InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Arrayed'"); + InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'MS'"); + InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Sampled'"); + InstructionDesc[OpTypeImage].operands.push(OperandSamplerImageFormat, ""); + InstructionDesc[OpTypeImage].operands.push(OperandAccessQualifier, "", true); - InstructionDesc[OpTypeImage].operands.push(OperandId, "'Sampled Type'"); - InstructionDesc[OpTypeImage].operands.push(OperandDimensionality, ""); - InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Depth'"); - InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Arrayed'"); - InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'MS'"); - InstructionDesc[OpTypeImage].operands.push(OperandLiteralNumber, "'Sampled'"); - InstructionDesc[OpTypeImage].operands.push(OperandSamplerImageFormat, ""); - InstructionDesc[OpTypeImage].operands.push(OperandAccessQualifier, "", true); + InstructionDesc[OpTypeSampledImage].operands.push(OperandId, "'Image Type'"); - InstructionDesc[OpTypeSampledImage].operands.push(OperandId, "'Image Type'"); + InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element Type'"); + InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'"); - InstructionDesc[OpTypeArray].operands.push(OperandId, "'Element Type'"); - InstructionDesc[OpTypeArray].operands.push(OperandId, "'Length'"); + InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element Type'"); - InstructionDesc[OpTypeRuntimeArray].operands.push(OperandId, "'Element Type'"); + InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n..."); - InstructionDesc[OpTypeStruct].operands.push(OperandVariableIds, "'Member 0 type', +\n'member 1 type', +\n..."); + InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type."); - InstructionDesc[OpTypeOpaque].operands.push(OperandLiteralString, "The name of the opaque type."); + InstructionDesc[OpTypePointer].operands.push(OperandStorage, ""); + InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'"); - InstructionDesc[OpTypePointer].operands.push(OperandStorage, ""); - InstructionDesc[OpTypePointer].operands.push(OperandId, "'Type'"); + InstructionDesc[OpTypeForwardPointer].operands.push(OperandId, "'Pointer Type'"); + InstructionDesc[OpTypeForwardPointer].operands.push(OperandStorage, ""); - InstructionDesc[OpTypeForwardPointer].operands.push(OperandId, "'Pointer Type'"); - InstructionDesc[OpTypeForwardPointer].operands.push(OperandStorage, ""); + InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'"); - InstructionDesc[OpTypePipe].operands.push(OperandAccessQualifier, "'Qualifier'"); + InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'"); + InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n..."); - InstructionDesc[OpTypeFunction].operands.push(OperandId, "'Return Type'"); - InstructionDesc[OpTypeFunction].operands.push(OperandVariableIds, "'Parameter 0 Type', +\n'Parameter 1 Type', +\n..."); + InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'"); - InstructionDesc[OpConstant].operands.push(OperandVariableLiterals, "'Value'"); + InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'"); - InstructionDesc[OpConstantComposite].operands.push(OperandVariableIds, "'Constituents'"); + InstructionDesc[OpConstantSampler].operands.push(OperandSamplerAddressingMode, ""); + InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'"); + InstructionDesc[OpConstantSampler].operands.push(OperandSamplerFilterMode, ""); - InstructionDesc[OpConstantSampler].operands.push(OperandSamplerAddressingMode, ""); - InstructionDesc[OpConstantSampler].operands.push(OperandLiteralNumber, "'Param'"); - InstructionDesc[OpConstantSampler].operands.push(OperandSamplerFilterMode, ""); + InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'"); - InstructionDesc[OpSpecConstant].operands.push(OperandVariableLiterals, "'Value'"); + InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'"); - InstructionDesc[OpSpecConstantComposite].operands.push(OperandVariableIds, "'Constituents'"); + InstructionDesc[OpSpecConstantOp].operands.push(OperandLiteralNumber, "'Opcode'"); + InstructionDesc[OpSpecConstantOp].operands.push(OperandVariableIds, "'Operands'"); - InstructionDesc[OpSpecConstantOp].operands.push(OperandLiteralNumber, "'Opcode'"); - InstructionDesc[OpSpecConstantOp].operands.push(OperandVariableIds, "'Operands'"); + InstructionDesc[OpVariable].operands.push(OperandStorage, ""); + InstructionDesc[OpVariable].operands.push(OperandId, "'Initializer'", true); - InstructionDesc[OpVariable].operands.push(OperandStorage, ""); - InstructionDesc[OpVariable].operands.push(OperandId, "'Initializer'", true); + InstructionDesc[OpFunction].operands.push(OperandFunction, ""); + InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'"); - InstructionDesc[OpFunction].operands.push(OperandFunction, ""); - InstructionDesc[OpFunction].operands.push(OperandId, "'Function Type'"); + InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'"); + InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n..."); - InstructionDesc[OpFunctionCall].operands.push(OperandId, "'Function'"); - InstructionDesc[OpFunctionCall].operands.push(OperandVariableIds, "'Argument 0', +\n'Argument 1', +\n..."); + InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'"); + InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'"); + InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n..."); - InstructionDesc[OpExtInst].operands.push(OperandId, "'Set'"); - InstructionDesc[OpExtInst].operands.push(OperandLiteralNumber, "'Instruction'"); - InstructionDesc[OpExtInst].operands.push(OperandVariableIds, "'Operand 1', +\n'Operand 2', +\n..."); + InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpLoad].operands.push(OperandMemoryAccess, "", true); + InstructionDesc[OpLoad].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpLoad].operands.push(OperandId, "", true); - InstructionDesc[OpLoad].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpLoad].operands.push(OperandMemoryAccess, "", true); - InstructionDesc[OpLoad].operands.push(OperandLiteralNumber, "", true); - InstructionDesc[OpLoad].operands.push(OperandId, "", true); + InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpStore].operands.push(OperandId, "'Object'"); + InstructionDesc[OpStore].operands.push(OperandMemoryAccess, "", true); + InstructionDesc[OpStore].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpStore].operands.push(OperandId, "", true); - InstructionDesc[OpStore].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpStore].operands.push(OperandId, "'Object'"); - InstructionDesc[OpStore].operands.push(OperandMemoryAccess, "", true); - InstructionDesc[OpStore].operands.push(OperandLiteralNumber, "", true); - InstructionDesc[OpStore].operands.push(OperandId, "", true); + InstructionDesc[OpPhi].operands.push(OperandVariableIds, "'Variable, Parent, ...'"); - InstructionDesc[OpPhi].operands.push(OperandVariableIds, "'Variable, Parent, ...'"); + InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'"); + InstructionDesc[OpDecorate].operands.push(OperandDecoration, ""); + InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <>."); - InstructionDesc[OpDecorate].operands.push(OperandId, "'Target'"); - InstructionDesc[OpDecorate].operands.push(OperandDecoration, ""); - InstructionDesc[OpDecorate].operands.push(OperandVariableLiterals, "See <>."); + InstructionDesc[OpDecorateId].operands.push(OperandId, "'Target'"); + InstructionDesc[OpDecorateId].operands.push(OperandDecoration, ""); + InstructionDesc[OpDecorateId].operands.push(OperandVariableIds, "See <>."); - InstructionDesc[OpDecorateId].operands.push(OperandId, "'Target'"); - InstructionDesc[OpDecorateId].operands.push(OperandDecoration, ""); - InstructionDesc[OpDecorateId].operands.push(OperandVariableIds, "See <>."); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandId, "'Target'"); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandDecoration, ""); + InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); - InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandId, "'Target'"); - InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandDecoration, ""); - InstructionDesc[OpDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure Type'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); + InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, ""); + InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <>."); - InstructionDesc[OpMemberDecorate].operands.push(OperandId, "'Structure Type'"); - InstructionDesc[OpMemberDecorate].operands.push(OperandLiteralNumber, "'Member'"); - InstructionDesc[OpMemberDecorate].operands.push(OperandDecoration, ""); - InstructionDesc[OpMemberDecorate].operands.push(OperandVariableLiterals, "See <>."); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandId, "'Structure Type'"); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralNumber, "'Member'"); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandDecoration, ""); + InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); - InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandId, "'Structure Type'"); - InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandLiteralNumber, "'Member'"); - InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandDecoration, ""); - InstructionDesc[OpMemberDecorateStringGOOGLE].operands.push(OperandVariableLiteralStrings, "'Literal Strings'"); + InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration Group'"); + InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Targets'"); - InstructionDesc[OpGroupDecorate].operands.push(OperandId, "'Decoration Group'"); - InstructionDesc[OpGroupDecorate].operands.push(OperandVariableIds, "'Targets'"); + InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration Group'"); + InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIdLiteral, "'Targets'"); - InstructionDesc[OpGroupMemberDecorate].operands.push(OperandId, "'Decoration Group'"); - InstructionDesc[OpGroupMemberDecorate].operands.push(OperandVariableIdLiteral, "'Targets'"); + InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'"); - InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpVectorExtractDynamic].operands.push(OperandId, "'Index'"); + InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'"); + InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'"); - InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Component'"); - InstructionDesc[OpVectorInsertDynamic].operands.push(OperandId, "'Index'"); + InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'"); + InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'"); + InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'"); - InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 1'"); - InstructionDesc[OpVectorShuffle].operands.push(OperandId, "'Vector 2'"); - InstructionDesc[OpVectorShuffle].operands.push(OperandVariableLiterals, "'Components'"); + InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'"); - InstructionDesc[OpCompositeConstruct].operands.push(OperandVariableIds, "'Constituents'"); + InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'"); + InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'"); - InstructionDesc[OpCompositeExtract].operands.push(OperandId, "'Composite'"); - InstructionDesc[OpCompositeExtract].operands.push(OperandVariableLiterals, "'Indexes'"); + InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'"); + InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'"); + InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'"); - InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Object'"); - InstructionDesc[OpCompositeInsert].operands.push(OperandId, "'Composite'"); - InstructionDesc[OpCompositeInsert].operands.push(OperandVariableLiterals, "'Indexes'"); + InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpCopyObject].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'"); + InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'"); + InstructionDesc[OpCopyMemory].operands.push(OperandMemoryAccess, "", true); - InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Target'"); - InstructionDesc[OpCopyMemory].operands.push(OperandId, "'Source'"); - InstructionDesc[OpCopyMemory].operands.push(OperandMemoryAccess, "", true); + InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'"); + InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'"); + InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'"); + InstructionDesc[OpCopyMemorySized].operands.push(OperandMemoryAccess, "", true); + + InstructionDesc[OpSampledImage].operands.push(OperandId, "'Image'"); + InstructionDesc[OpSampledImage].operands.push(OperandId, "'Sampler'"); + + InstructionDesc[OpImage].operands.push(OperandId, "'Sampled Image'"); + + InstructionDesc[OpImageRead].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageRead].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageRead].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageRead].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageWrite].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageWrite].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageWrite].operands.push(OperandId, "'Texel'"); + InstructionDesc[OpImageWrite].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageWrite].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageFetch].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageFetch].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageFetch].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageFetch].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageGather].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageGather].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageGather].operands.push(OperandId, "'Component'"); + InstructionDesc[OpImageGather].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageGather].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageDrefGather].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageDrefGather].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Target'"); - InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Source'"); - InstructionDesc[OpCopyMemorySized].operands.push(OperandId, "'Size'"); - InstructionDesc[OpCopyMemorySized].operands.push(OperandMemoryAccess, "", true); - - InstructionDesc[OpSampledImage].operands.push(OperandId, "'Image'"); - InstructionDesc[OpSampledImage].operands.push(OperandId, "'Sampler'"); - - InstructionDesc[OpImage].operands.push(OperandId, "'Sampled Image'"); - - InstructionDesc[OpImageRead].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageRead].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageRead].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageRead].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageWrite].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageWrite].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageWrite].operands.push(OperandId, "'Texel'"); - InstructionDesc[OpImageWrite].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageWrite].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleImplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleExplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageFetch].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageFetch].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageFetch].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageFetch].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageGather].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageGather].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageGather].operands.push(OperandId, "'Component'"); - InstructionDesc[OpImageGather].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageGather].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageDrefGather].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageDrefGather].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageDrefGather].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleImplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleExplicitLod].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleDrefImplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleDrefExplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleProjImplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleProjExplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleProjDrefImplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseSampleProjDrefExplicitLod].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseFetch].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseFetch].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageSparseFetch].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseFetch].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseFetch].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Component'"); + InstructionDesc[OpImageSparseGather].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseGather].operands.push(OperandId, "'Component'"); - InstructionDesc[OpImageSparseGather].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseGather].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'D~ref~'"); + InstructionDesc[OpImageSparseDrefGather].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseDrefGather].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseDrefGather].operands.push(OperandId, "'D~ref~'"); - InstructionDesc[OpImageSparseDrefGather].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseDrefGather].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSparseRead].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSparseRead].operands.push(OperandVariableIds, "", true); - InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageSparseRead].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSparseRead].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSparseRead].operands.push(OperandVariableIds, "", true); + InstructionDesc[OpImageSparseTexelsResident].operands.push(OperandId, "'Resident Code'"); - InstructionDesc[OpImageSparseTexelsResident].operands.push(OperandId, "'Resident Code'"); + InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Level of Detail'"); - InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQuerySizeLod].operands.push(OperandId, "'Level of Detail'"); + InstructionDesc[OpImageQuerySize].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQuerySize].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryLod].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageQueryLevels].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryLevels].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQuerySamples].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQuerySamples].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQueryFormat].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryFormat].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageQueryOrder].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageQueryOrder].operands.push(OperandId, "'Image'"); + InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'"); + InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpAccessChain].operands.push(OperandId, "'Base'"); - InstructionDesc[OpAccessChain].operands.push(OperandVariableIds, "'Indexes'"); + InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'"); + InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpInBoundsAccessChain].operands.push(OperandId, "'Base'"); - InstructionDesc[OpInBoundsAccessChain].operands.push(OperandVariableIds, "'Indexes'"); + InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Base'"); + InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Element'"); + InstructionDesc[OpPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Base'"); - InstructionDesc[OpPtrAccessChain].operands.push(OperandId, "'Element'"); - InstructionDesc[OpPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); + InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Base'"); + InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Element'"); + InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); - InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Base'"); - InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandId, "'Element'"); - InstructionDesc[OpInBoundsPtrAccessChain].operands.push(OperandVariableIds, "'Indexes'"); + InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpSNegate].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpFNegate].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpNot].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpNot].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpAny].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpAny].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpAll].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpAll].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'"); - InstructionDesc[OpConvertFToU].operands.push(OperandId, "'Float Value'"); + InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'"); - InstructionDesc[OpConvertFToS].operands.push(OperandId, "'Float Value'"); + InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'"); - InstructionDesc[OpConvertSToF].operands.push(OperandId, "'Signed Value'"); + InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned Value'"); - InstructionDesc[OpConvertUToF].operands.push(OperandId, "'Unsigned Value'"); + InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned Value'"); - InstructionDesc[OpUConvert].operands.push(OperandId, "'Unsigned Value'"); + InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'"); - InstructionDesc[OpSConvert].operands.push(OperandId, "'Signed Value'"); + InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'"); - InstructionDesc[OpFConvert].operands.push(OperandId, "'Float Value'"); + InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'"); - InstructionDesc[OpSatConvertSToU].operands.push(OperandId, "'Signed Value'"); + InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'"); - InstructionDesc[OpSatConvertUToS].operands.push(OperandId, "'Unsigned Value'"); + InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpConvertPtrToU].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer Value'"); - InstructionDesc[OpConvertUToPtr].operands.push(OperandId, "'Integer Value'"); + InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpPtrCastToGeneric].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpGenericCastToPtr].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'Storage'"); - InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpGenericCastToPtrExplicit].operands.push(OperandStorage, "'Storage'"); + InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpGenericPtrMemSemantics].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpBitcast].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpQuantizeToF16].operands.push(OperandId, "'Value'"); - InstructionDesc[OpQuantizeToF16].operands.push(OperandId, "'Value'"); + InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'"); - InstructionDesc[OpTranspose].operands.push(OperandId, "'Matrix'"); + InstructionDesc[OpCopyLogical].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpCopyLogical].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpIsNan].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsNan].operands.push(OperandId, "'x'"); + InstructionDesc[OpIsInf].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsInf].operands.push(OperandId, "'x'"); + InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsFinite].operands.push(OperandId, "'x'"); + InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'"); - InstructionDesc[OpIsNormal].operands.push(OperandId, "'x'"); + InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'"); - InstructionDesc[OpSignBitSet].operands.push(OperandId, "'x'"); + InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'"); + InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'"); - InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'x'"); - InstructionDesc[OpLessOrGreater].operands.push(OperandId, "'y'"); + InstructionDesc[OpOrdered].operands.push(OperandId, "'x'"); + InstructionDesc[OpOrdered].operands.push(OperandId, "'y'"); - InstructionDesc[OpOrdered].operands.push(OperandId, "'x'"); - InstructionDesc[OpOrdered].operands.push(OperandId, "'y'"); + InstructionDesc[OpUnordered].operands.push(OperandId, "'x'"); + InstructionDesc[OpUnordered].operands.push(OperandId, "'y'"); - InstructionDesc[OpUnordered].operands.push(OperandId, "'x'"); - InstructionDesc[OpUnordered].operands.push(OperandId, "'y'"); + InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'"); + InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'"); - InstructionDesc[OpArrayLength].operands.push(OperandId, "'Structure'"); - InstructionDesc[OpArrayLength].operands.push(OperandLiteralNumber, "'Array member'"); + InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpIAdd].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFAdd].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpISub].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpISub].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFSub].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpIMul].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFMul].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpUDiv].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSDiv].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFDiv].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpUMod].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSRem].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSMod].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFRem].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFMod].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'"); - InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpVectorTimesScalar].operands.push(OperandId, "'Scalar'"); + InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'"); + InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'"); - InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Matrix'"); - InstructionDesc[OpMatrixTimesScalar].operands.push(OperandId, "'Scalar'"); + InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'"); - InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpVectorTimesMatrix].operands.push(OperandId, "'Matrix'"); + InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'"); + InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'"); - InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Matrix'"); - InstructionDesc[OpMatrixTimesVector].operands.push(OperandId, "'Vector'"); + InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'"); + InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'"); - InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'LeftMatrix'"); - InstructionDesc[OpMatrixTimesMatrix].operands.push(OperandId, "'RightMatrix'"); + InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'"); + InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'"); - InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 1'"); - InstructionDesc[OpOuterProduct].operands.push(OperandId, "'Vector 2'"); + InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'"); + InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'"); - InstructionDesc[OpDot].operands.push(OperandId, "'Vector 1'"); - InstructionDesc[OpDot].operands.push(OperandId, "'Vector 2'"); + InstructionDesc[OpIAddCarry].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpIAddCarry].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpIAddCarry].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpIAddCarry].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpISubBorrow].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpISubBorrow].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpISubBorrow].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpISubBorrow].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpUMulExtended].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpUMulExtended].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpUMulExtended].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpUMulExtended].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSMulExtended].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSMulExtended].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSMulExtended].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSMulExtended].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Base'"); + InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Shift'"); - InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Base'"); - InstructionDesc[OpShiftRightLogical].operands.push(OperandId, "'Shift'"); + InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Base'"); + InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Shift'"); - InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Base'"); - InstructionDesc[OpShiftRightArithmetic].operands.push(OperandId, "'Shift'"); + InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Base'"); + InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Shift'"); - InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Base'"); - InstructionDesc[OpShiftLeftLogical].operands.push(OperandId, "'Shift'"); + InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpLogicalOr].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpLogicalAnd].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpLogicalEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpLogicalEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpLogicalEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpLogicalEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpLogicalNotEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpLogicalNotEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpLogicalNotEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpLogicalNotEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpLogicalNot].operands.push(OperandId, "'Operand'"); - InstructionDesc[OpLogicalNot].operands.push(OperandId, "'Operand'"); + InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpBitwiseOr].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpBitwiseXor].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpBitwiseAnd].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Base'"); + InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Insert'"); + InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Offset'"); + InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Count'"); - InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Base'"); - InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Insert'"); - InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Offset'"); - InstructionDesc[OpBitFieldInsert].operands.push(OperandId, "'Count'"); + InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Base'"); + InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Offset'"); + InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Count'"); - InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Base'"); - InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Offset'"); - InstructionDesc[OpBitFieldSExtract].operands.push(OperandId, "'Count'"); - - InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Base'"); - InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Offset'"); - InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Count'"); - - InstructionDesc[OpBitReverse].operands.push(OperandId, "'Base'"); + InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Base'"); + InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Offset'"); + InstructionDesc[OpBitFieldUExtract].operands.push(OperandId, "'Count'"); - InstructionDesc[OpBitCount].operands.push(OperandId, "'Base'"); + InstructionDesc[OpBitReverse].operands.push(OperandId, "'Base'"); - InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'"); - InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'"); - InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'"); + InstructionDesc[OpBitCount].operands.push(OperandId, "'Base'"); - InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSelect].operands.push(OperandId, "'Condition'"); + InstructionDesc[OpSelect].operands.push(OperandId, "'Object 1'"); + InstructionDesc[OpSelect].operands.push(OperandId, "'Object 2'"); - InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpIEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpINotEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdNotEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordNotEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpULessThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSLessThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdLessThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordLessThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpUGreaterThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSGreaterThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdGreaterThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordGreaterThan].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpULessThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSLessThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdLessThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordLessThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpUGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpSGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); - InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); + InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFOrdGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpDPdx].operands.push(OperandId, "'P'"); + InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 1'"); + InstructionDesc[OpFUnordGreaterThanEqual].operands.push(OperandId, "'Operand 2'"); - InstructionDesc[OpDPdy].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdx].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidth].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdy].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'"); + InstructionDesc[OpFwidth].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdxFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdyFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'"); + InstructionDesc[OpFwidthFine].operands.push(OperandId, "'P'"); - InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdxCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'"); + InstructionDesc[OpDPdyCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'"); + InstructionDesc[OpFwidthCoarse].operands.push(OperandId, "'P'"); - InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'"); + InstructionDesc[OpEmitStreamVertex].operands.push(OperandId, "'Stream'"); - InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Memory'"); - InstructionDesc[OpControlBarrier].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpEndStreamPrimitive].operands.push(OperandId, "'Stream'"); - InstructionDesc[OpMemoryBarrier].operands.push(OperandScope, "'Memory'"); - InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpControlBarrier].operands.push(OperandScope, "'Memory'"); + InstructionDesc[OpControlBarrier].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Image'"); - InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Sample'"); + InstructionDesc[OpMemoryBarrier].operands.push(OperandScope, "'Memory'"); + InstructionDesc[OpMemoryBarrier].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicLoad].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Image'"); + InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageTexelPointer].operands.push(OperandId, "'Sample'"); - InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicStore].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicLoad].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicLoad].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicLoad].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicExchange].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicStore].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicStore].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicStore].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Equal'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Unequal'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'"); + InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicExchange].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicExchange].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicExchange].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Equal'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Unequal'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Equal'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandMemorySemantics, "'Unequal'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicCompareExchange].operands.push(OperandId, "'Comparator'"); - InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicIIncrement].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Equal'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandMemorySemantics, "'Unequal'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicCompareExchangeWeak].operands.push(OperandId, "'Comparator'"); - InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicIDecrement].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicIIncrement].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicIIncrement].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicIIncrement].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicIAdd].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicIDecrement].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicIDecrement].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicIDecrement].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicFAddEXT].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicFAddEXT].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicIAdd].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicIAdd].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicIAdd].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicISub].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFAddEXT].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicUMin].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAssumeTrueKHR].operands.push(OperandId, "'Condition'"); - InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicUMax].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'"); + InstructionDesc[OpExpectKHR].operands.push(OperandId, "'Value'"); + InstructionDesc[OpExpectKHR].operands.push(OperandId, "'ExpectedValue'"); - InstructionDesc[OpAtomicSMin].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicSMin].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicSMin].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicSMin].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicISub].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicISub].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicISub].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicSMax].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicSMax].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicSMax].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicSMax].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicUMin].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicUMin].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicUMin].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicFMinEXT].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicFMinEXT].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicUMax].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicUMax].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicUMax].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Value'"); + InstructionDesc[OpAtomicSMin].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicSMin].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicSMin].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicSMin].operands.push(OperandId, "'Value'"); - InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicAnd].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicOr].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicXor].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'"); - InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandMemorySemantics, "'Semantics'"); - - InstructionDesc[OpAtomicFlagClear].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpAtomicFlagClear].operands.push(OperandScope, "'Scope'"); - InstructionDesc[OpAtomicFlagClear].operands.push(OperandMemorySemantics, "'Semantics'"); - - InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'"); - InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'"); - InstructionDesc[OpLoopMerge].operands.push(OperandLoop, ""); - InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, ""); - - InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'"); - InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, ""); - - InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'"); - - InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'"); - InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'"); - InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'"); - InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'"); - - InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'"); - InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'"); - InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'"); - - - InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpLifetimeStart].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "'Size'"); - - InstructionDesc[OpLifetimeStop].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "'Size'"); - - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Destination'"); - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Source'"); - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Num Elements'"); - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Stride'"); - InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Event'"); - - InstructionDesc[OpGroupWaitEvents].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Num Events'"); - InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Events List'"); - - InstructionDesc[OpGroupAll].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpGroupAny].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpGroupBroadcast].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'"); - InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'"); - - InstructionDesc[OpGroupIAdd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupFAdd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupUMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupSMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupSMin].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupFMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFMin].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupUMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupUMax].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupSMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupSMax].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupFMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFMax].operands.push(OperandId, "X"); - - InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Index'"); - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Index'"); - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); - InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); - InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'Reserve Id'"); - - InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); - InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); - InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Pipe'"); - InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); - InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Size'"); - InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); - - InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'"); - InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'"); - InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'"); - - InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Event'"); - InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Profiling Info'"); - InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Event'"); - InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Status'"); - - InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'Event'"); - - InstructionDesc[OpRetainEvent].operands.push(OperandId, "'Event'"); - - InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'Event'"); - - InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'"); - InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param'"); - InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Size'"); - InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Align'"); - - InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'"); - InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param'"); - InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Size'"); - InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Align'"); - - InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'"); - InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'"); - InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param'"); - InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Size'"); - InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Align'"); - - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'"); - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'"); - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param'"); - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Size'"); - InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Align'"); - - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Queue'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Flags'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'"); - InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'"); - - InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Queue'"); - InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'"); - InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'"); - InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'"); - - InstructionDesc[OpGroupNonUniformElect].operands.push(OperandScope, "'Execution'"); - - InstructionDesc[OpGroupNonUniformAll].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformAll].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformAny].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformAny].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "ID"); - - InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "Bit"); - - InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "'Id'"); - - InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "Mask"); - - InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "Offset"); - - InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "Offset"); - - InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "'ClusterSize'", true); + InstructionDesc[OpAtomicSMax].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicSMax].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicSMax].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicSMax].operands.push(OperandId, "'Value'"); - InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "'ClusterSize'", true); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFMinEXT].operands.push(OperandId, "'Value'"); - InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "'ClusterSize'", true); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicFMaxEXT].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicAnd].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicAnd].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicAnd].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicOr].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicOr].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicOr].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicXor].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicXor].operands.push(OperandMemorySemantics, "'Semantics'"); + InstructionDesc[OpAtomicXor].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFlagTestAndSet].operands.push(OperandMemorySemantics, "'Semantics'"); + + InstructionDesc[OpAtomicFlagClear].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpAtomicFlagClear].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpAtomicFlagClear].operands.push(OperandMemorySemantics, "'Semantics'"); + + InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Merge Block'"); + InstructionDesc[OpLoopMerge].operands.push(OperandId, "'Continue Target'"); + InstructionDesc[OpLoopMerge].operands.push(OperandLoop, ""); + InstructionDesc[OpLoopMerge].operands.push(OperandOptionalLiteral, ""); + + InstructionDesc[OpSelectionMerge].operands.push(OperandId, "'Merge Block'"); + InstructionDesc[OpSelectionMerge].operands.push(OperandSelect, ""); + + InstructionDesc[OpBranch].operands.push(OperandId, "'Target Label'"); + + InstructionDesc[OpBranchConditional].operands.push(OperandId, "'Condition'"); + InstructionDesc[OpBranchConditional].operands.push(OperandId, "'True Label'"); + InstructionDesc[OpBranchConditional].operands.push(OperandId, "'False Label'"); + InstructionDesc[OpBranchConditional].operands.push(OperandVariableLiterals, "'Branch weights'"); + + InstructionDesc[OpSwitch].operands.push(OperandId, "'Selector'"); + InstructionDesc[OpSwitch].operands.push(OperandId, "'Default'"); + InstructionDesc[OpSwitch].operands.push(OperandVariableLiteralId, "'Target'"); + + + InstructionDesc[OpReturnValue].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpLifetimeStart].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpLifetimeStart].operands.push(OperandLiteralNumber, "'Size'"); + + InstructionDesc[OpLifetimeStop].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpLifetimeStop].operands.push(OperandLiteralNumber, "'Size'"); + + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Destination'"); + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Source'"); + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Num Elements'"); + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Stride'"); + InstructionDesc[OpGroupAsyncCopy].operands.push(OperandId, "'Event'"); + + InstructionDesc[OpGroupWaitEvents].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Num Events'"); + InstructionDesc[OpGroupWaitEvents].operands.push(OperandId, "'Events List'"); + + InstructionDesc[OpGroupAll].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupAll].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpGroupAny].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupAny].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpGroupBroadcast].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'Value'"); + InstructionDesc[OpGroupBroadcast].operands.push(OperandId, "'LocalId'"); + + InstructionDesc[OpGroupIAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupIAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupIAdd].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupFAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFAdd].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupUMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMin].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupSMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMin].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMin].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupUMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMax].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupSMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMax].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMax].operands.push(OperandId, "X"); + + InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpReadPipe].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpReadPipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpWritePipe].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpWritePipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Index'"); + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpReservedReadPipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Index'"); + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpReservedWritePipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); + InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); + InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpIsValidReserveId].operands.push(OperandId, "'Reserve Id'"); + + InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGetNumPipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGetMaxPipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Num Packets'"); + InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGroupReserveReadPipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Num Packets'"); + InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGroupReserveWritePipePackets].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGroupCommitReadPipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Pipe'"); + InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Reserve Id'"); + InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Size'"); + InstructionDesc[OpGroupCommitWritePipe].operands.push(OperandId, "'Packet Alignment'"); + + InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkSize'"); + InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'LocalWorkSize'"); + InstructionDesc[OpBuildNDRange].operands.push(OperandId, "'GlobalWorkOffset'"); + + InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Event'"); + InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Profiling Info'"); + InstructionDesc[OpCaptureEventProfilingInfo].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Event'"); + InstructionDesc[OpSetUserEventStatus].operands.push(OperandId, "'Status'"); + + InstructionDesc[OpIsValidEvent].operands.push(OperandId, "'Event'"); + + InstructionDesc[OpRetainEvent].operands.push(OperandId, "'Event'"); + + InstructionDesc[OpReleaseEvent].operands.push(OperandId, "'Event'"); + + InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Invoke'"); + InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param'"); + InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Size'"); + InstructionDesc[OpGetKernelWorkGroupSize].operands.push(OperandId, "'Param Align'"); + + InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Invoke'"); + InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param'"); + InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Size'"); + InstructionDesc[OpGetKernelPreferredWorkGroupSizeMultiple].operands.push(OperandId, "'Param Align'"); + + InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'ND Range'"); + InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Invoke'"); + InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param'"); + InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Size'"); + InstructionDesc[OpGetKernelNDrangeSubGroupCount].operands.push(OperandId, "'Param Align'"); + + InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'ND Range'"); + InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Invoke'"); + InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param'"); + InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Size'"); + InstructionDesc[OpGetKernelNDrangeMaxSubGroupSize].operands.push(OperandId, "'Param Align'"); + + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Queue'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Flags'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'ND Range'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Num Events'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Wait Events'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Ret Event'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Invoke'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Size'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandId, "'Param Align'"); + InstructionDesc[OpEnqueueKernel].operands.push(OperandVariableIds, "'Local Size'"); + + InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Queue'"); + InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Num Events'"); + InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Wait Events'"); + InstructionDesc[OpEnqueueMarker].operands.push(OperandId, "'Ret Event'"); + + InstructionDesc[OpGroupNonUniformElect].operands.push(OperandScope, "'Execution'"); + + InstructionDesc[OpGroupNonUniformAll].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAll].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformAny].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAny].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformAllEqual].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBroadcast].operands.push(OperandId, "ID"); + + InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBroadcastFirst].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallot].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformInverseBallot].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBallotBitExtract].operands.push(OperandId, "Bit"); + + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBallotBitCount].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotFindLSB].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBallotFindMSB].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffle].operands.push(OperandId, "'Id'"); + + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleXor].operands.push(OperandId, "Mask"); + + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleUp].operands.push(OperandId, "Offset"); + + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformShuffleDown].operands.push(OperandId, "Offset"); + + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformIAdd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFAdd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformIMul].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMul].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformSMin].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformUMin].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMin].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "'ClusterSize'", true); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformSMax].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "'ClusterSize'", true); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformUMax].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "'ClusterSize'", true); - - InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "'Id'"); - - InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "X"); - InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "'Direction'"); - - InstructionDesc[OpSubgroupBallotKHR].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpSubgroupFirstInvocationKHR].operands.push(OperandId, "'Value'"); - - InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpSubgroupAllKHR].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpSubgroupAllKHR].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandId, "'Predicate'"); - - InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Value'"); - InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Index'"); - - InstructionDesc[OpModuleProcessed].operands.push(OperandLiteralString, "'process'"); - - InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandId, "'X'"); - - InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandId, "X"); - - InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); - InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); - InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandId, "X"); - - InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Image'"); - InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Coordinate'"); - - InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Image'"); - InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Fragment Index'"); - - InstructionDesc[OpGroupNonUniformPartitionNV].operands.push(OperandId, "X"); - - InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); - - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Acceleration Structure'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Flags'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Cull Mask'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'SBT Record Offset'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'SBT Record Stride'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Miss Index'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Origin'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'TMin'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Direction'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'TMax'"); - InstructionDesc[OpTraceNV].operands.push(OperandId, "'Payload'"); - InstructionDesc[OpTraceNV].setResultAndType(false, false); - - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Acceleration Structure'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Flags'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Cull Mask'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Offset'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Stride'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Miss Index'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Origin'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMin'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Direction'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMax'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Time'"); - InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Payload'"); - InstructionDesc[OpTraceRayMotionNV].setResultAndType(false, false); - - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Acceleration Structure'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Flags'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Cull Mask'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Offset'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Stride'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Miss Index'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Origin'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMin'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Direction'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMax'"); - InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Payload'"); - InstructionDesc[OpTraceRayKHR].setResultAndType(false, false); - - InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Parameter'"); - InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Kind'"); - - InstructionDesc[OpIgnoreIntersectionNV].setResultAndType(false, false); - - InstructionDesc[OpIgnoreIntersectionKHR].setResultAndType(false, false); - - InstructionDesc[OpTerminateRayNV].setResultAndType(false, false); - - InstructionDesc[OpTerminateRayKHR].setResultAndType(false, false); - - InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "SBT Record Index"); - InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "CallableData ID"); - InstructionDesc[OpExecuteCallableNV].setResultAndType(false, false); - - InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "SBT Record Index"); - InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "CallableData"); - InstructionDesc[OpExecuteCallableKHR].setResultAndType(false, false); - - InstructionDesc[OpConvertUToAccelerationStructureKHR].operands.push(OperandId, "Value"); - InstructionDesc[OpConvertUToAccelerationStructureKHR].setResultAndType(true, true); - - // Ray Query - InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); - InstructionDesc[OpTypeRayQueryKHR].setResultAndType(true, false); - - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'AccelerationS'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayFlags'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'CullMask'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Origin'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmin'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Direction'"); - InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmax'"); - InstructionDesc[OpRayQueryInitializeKHR].setResultAndType(false, false); - - InstructionDesc[OpRayQueryTerminateKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryTerminateKHR].setResultAndType(false, false); - - InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'THit'"); - InstructionDesc[OpRayQueryGenerateIntersectionKHR].setResultAndType(false, false); - - InstructionDesc[OpRayQueryConfirmIntersectionKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryConfirmIntersectionKHR].setResultAndType(false, false); - - InstructionDesc[OpRayQueryProceedKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryProceedKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionTypeKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetRayTMinKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetRayTMinKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetRayFlagsKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetRayFlagsKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionTKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].setResultAndType(true, true); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformFMax].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].setResultAndType(true, true); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseAnd].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].setResultAndType(true, true); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseOr].operands.push(OperandId, "'ClusterSize'", true); - InstructionDesc[OpRayQueryGetWorldRayOriginKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetWorldRayOriginKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].setResultAndType(true, true); - - InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'RayQuery'"); - InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'Committed'"); - InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].setResultAndType(true, true); - - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Sampled Image'"); - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Coordinate'"); - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Granularity'"); - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Coarse'"); - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandImageOperands, "", true); - InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandVariableIds, "", true); - - InstructionDesc[OpWritePackedPrimitiveIndices4x8NV].operands.push(OperandId, "'Index Offset'"); - InstructionDesc[OpWritePackedPrimitiveIndices4x8NV].operands.push(OperandId, "'Packed Indices'"); - - InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Component Type'"); - InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Scope'"); - InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Rows'"); - InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Columns'"); - - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Stride'"); - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Column Major'"); - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandMemoryAccess, "'Memory Access'"); - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandLiteralNumber, "", true); - InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "", true); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformBitwiseXor].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalAnd].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalOr].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformLogicalXor].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformQuadBroadcast].operands.push(OperandId, "'Id'"); + + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "X"); + InstructionDesc[OpGroupNonUniformQuadSwap].operands.push(OperandId, "'Direction'"); + + InstructionDesc[OpSubgroupBallotKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupFirstInvocationKHR].operands.push(OperandId, "'Value'"); + + InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAnyKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupAllKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAllKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpSubgroupAllEqualKHR].operands.push(OperandId, "'Predicate'"); + + InstructionDesc[OpGroupNonUniformRotateKHR].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupNonUniformRotateKHR].operands.push(OperandId, "'X'"); + InstructionDesc[OpGroupNonUniformRotateKHR].operands.push(OperandId, "'Delta'"); + InstructionDesc[OpGroupNonUniformRotateKHR].operands.push(OperandId, "'ClusterSize'", true); + + InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Value'"); + InstructionDesc[OpSubgroupReadInvocationKHR].operands.push(OperandId, "'Index'"); + + InstructionDesc[OpModuleProcessed].operands.push(OperandLiteralString, "'process'"); + + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupIAddNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFAddNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMinNonUniformAMD].operands.push(OperandId, "'X'"); + + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMinNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMinNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupUMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupSMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandScope, "'Execution'"); + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandGroupOperation, "'Operation'"); + InstructionDesc[OpGroupFMaxNonUniformAMD].operands.push(OperandId, "X"); + + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentMaskFetchAMD].operands.push(OperandId, "'Coordinate'"); + + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Image'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpFragmentFetchAMD].operands.push(OperandId, "'Fragment Index'"); + + InstructionDesc[OpGroupNonUniformPartitionNV].operands.push(OperandId, "X"); + + InstructionDesc[OpGroupNonUniformQuadAllKHR].operands.push(OperandId, "'Predicate'"); + InstructionDesc[OpGroupNonUniformQuadAnyKHR].operands.push(OperandId, "'Predicate'"); + InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); + + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Flags'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Cull Mask'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Origin'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Ray Direction'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpTraceNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpTraceNV].setResultAndType(false, false); + + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Flags'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Cull Mask'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Origin'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Ray Direction'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Time'"); + InstructionDesc[OpTraceRayMotionNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpTraceRayMotionNV].setResultAndType(false, false); + + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Flags'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Cull Mask'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Origin'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Ray Direction'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpTraceRayKHR].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpTraceRayKHR].setResultAndType(false, false); + + InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Parameter'"); + InstructionDesc[OpReportIntersectionKHR].operands.push(OperandId, "'Hit Kind'"); + + InstructionDesc[OpIgnoreIntersectionNV].setResultAndType(false, false); + + InstructionDesc[OpIgnoreIntersectionKHR].setResultAndType(false, false); + + InstructionDesc[OpTerminateRayNV].setResultAndType(false, false); + + InstructionDesc[OpTerminateRayKHR].setResultAndType(false, false); + + InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "SBT Record Index"); + InstructionDesc[OpExecuteCallableNV].operands.push(OperandId, "CallableData ID"); + InstructionDesc[OpExecuteCallableNV].setResultAndType(false, false); + + InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "SBT Record Index"); + InstructionDesc[OpExecuteCallableKHR].operands.push(OperandId, "CallableData"); + InstructionDesc[OpExecuteCallableKHR].setResultAndType(false, false); + + InstructionDesc[OpConvertUToAccelerationStructureKHR].operands.push(OperandId, "Value"); + InstructionDesc[OpConvertUToAccelerationStructureKHR].setResultAndType(true, true); + + // Ray Query + InstructionDesc[OpTypeAccelerationStructureKHR].setResultAndType(true, false); + InstructionDesc[OpTypeRayQueryKHR].setResultAndType(true, false); + + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'AccelerationS'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'RayFlags'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'CullMask'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmin'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpRayQueryInitializeKHR].operands.push(OperandId, "'Tmax'"); + InstructionDesc[OpRayQueryInitializeKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryTerminateKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryTerminateKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGenerateIntersectionKHR].operands.push(OperandId, "'THit'"); + InstructionDesc[OpRayQueryGenerateIntersectionKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryConfirmIntersectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryConfirmIntersectionKHR].setResultAndType(false, false); + + InstructionDesc[OpRayQueryProceedKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryProceedKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionTypeKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetRayTMinKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetRayTMinKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetRayFlagsKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetRayFlagsKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionTKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionTKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceCustomIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceIdKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionGeometryIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionPrimitiveIndexKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionBarycentricsKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionFrontFaceKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionCandidateAABBOpaqueKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayDirectionKHR].setResultAndType(true, true); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Pointer'"); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Object'"); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Stride'"); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Column Major'"); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandMemoryAccess, "'Memory Access'"); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandLiteralNumber, "", true); - InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "", true); + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectRayOriginKHR].setResultAndType(true, true); - InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'A'"); - InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'B'"); - InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'C'"); - - InstructionDesc[OpCooperativeMatrixLengthNV].operands.push(OperandId, "'Type'"); - - InstructionDesc[OpDemoteToHelperInvocationEXT].setResultAndType(false, false); - - InstructionDesc[OpReadClockKHR].operands.push(OperandScope, "'Scope'"); + InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetWorldRayDirectionKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetWorldRayOriginKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetWorldRayOriginKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionObjectToWorldKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionWorldToObjectKHR].setResultAndType(true, true); + + InstructionDesc[OpRayQueryGetIntersectionTriangleVertexPositionsKHR].operands.push(OperandId, "'RayQuery'"); + InstructionDesc[OpRayQueryGetIntersectionTriangleVertexPositionsKHR].operands.push(OperandId, "'Committed'"); + InstructionDesc[OpRayQueryGetIntersectionTriangleVertexPositionsKHR].setResultAndType(true, true); + + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Sampled Image'"); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Coordinate'"); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Granularity'"); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandId, "'Coarse'"); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleFootprintNV].operands.push(OperandVariableIds, "", true); + + InstructionDesc[OpWritePackedPrimitiveIndices4x8NV].operands.push(OperandId, "'Index Offset'"); + InstructionDesc[OpWritePackedPrimitiveIndices4x8NV].operands.push(OperandId, "'Packed Indices'"); + + InstructionDesc[OpEmitMeshTasksEXT].operands.push(OperandId, "'groupCountX'"); + InstructionDesc[OpEmitMeshTasksEXT].operands.push(OperandId, "'groupCountY'"); + InstructionDesc[OpEmitMeshTasksEXT].operands.push(OperandId, "'groupCountZ'"); + InstructionDesc[OpEmitMeshTasksEXT].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpEmitMeshTasksEXT].setResultAndType(false, false); + + InstructionDesc[OpSetMeshOutputsEXT].operands.push(OperandId, "'vertexCount'"); + InstructionDesc[OpSetMeshOutputsEXT].operands.push(OperandId, "'primitiveCount'"); + InstructionDesc[OpSetMeshOutputsEXT].setResultAndType(false, false); + + + InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Component Type'"); + InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Scope'"); + InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Rows'"); + InstructionDesc[OpTypeCooperativeMatrixNV].operands.push(OperandId, "'Columns'"); + + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Stride'"); + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "'Column Major'"); + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandMemoryAccess, "'Memory Access'"); + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpCooperativeMatrixLoadNV].operands.push(OperandId, "", true); + + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Object'"); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Stride'"); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "'Column Major'"); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandMemoryAccess, "'Memory Access'"); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpCooperativeMatrixStoreNV].operands.push(OperandId, "", true); + + InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'A'"); + InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'B'"); + InstructionDesc[OpCooperativeMatrixMulAddNV].operands.push(OperandId, "'C'"); + + InstructionDesc[OpCooperativeMatrixLengthNV].operands.push(OperandId, "'Type'"); + + InstructionDesc[OpTypeCooperativeMatrixKHR].operands.push(OperandId, "'Component Type'"); + InstructionDesc[OpTypeCooperativeMatrixKHR].operands.push(OperandId, "'Scope'"); + InstructionDesc[OpTypeCooperativeMatrixKHR].operands.push(OperandId, "'Rows'"); + InstructionDesc[OpTypeCooperativeMatrixKHR].operands.push(OperandId, "'Columns'"); + InstructionDesc[OpTypeCooperativeMatrixKHR].operands.push(OperandId, "'Use'"); + + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandId, "'Memory Layout'"); + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandId, "'Stride'"); + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandMemoryAccess, "'Memory Access'"); + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpCooperativeMatrixLoadKHR].operands.push(OperandId, "", true); + + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandId, "'Pointer'"); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandId, "'Object'"); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandId, "'Memory Layout'"); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandId, "'Stride'"); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandMemoryAccess, "'Memory Access'"); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandLiteralNumber, "", true); + InstructionDesc[OpCooperativeMatrixStoreKHR].operands.push(OperandId, "", true); + + InstructionDesc[OpCooperativeMatrixMulAddKHR].operands.push(OperandId, "'A'"); + InstructionDesc[OpCooperativeMatrixMulAddKHR].operands.push(OperandId, "'B'"); + InstructionDesc[OpCooperativeMatrixMulAddKHR].operands.push(OperandId, "'C'"); + InstructionDesc[OpCooperativeMatrixMulAddKHR].operands.push(OperandCooperativeMatrixOperands, "'Cooperative Matrix Operands'", true); + + InstructionDesc[OpCooperativeMatrixLengthKHR].operands.push(OperandId, "'Type'"); + + InstructionDesc[OpDemoteToHelperInvocationEXT].setResultAndType(false, false); + + InstructionDesc[OpReadClockKHR].operands.push(OperandScope, "'Scope'"); + + InstructionDesc[OpTypeHitObjectNV].setResultAndType(true, false); + + InstructionDesc[OpHitObjectGetShaderRecordBufferHandleNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetShaderRecordBufferHandleNV].setResultAndType(true, true); + + InstructionDesc[OpReorderThreadWithHintNV].operands.push(OperandId, "'Hint'"); + InstructionDesc[OpReorderThreadWithHintNV].operands.push(OperandId, "'Bits'"); + InstructionDesc[OpReorderThreadWithHintNV].setResultAndType(false, false); + + InstructionDesc[OpReorderThreadWithHitObjectNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpReorderThreadWithHitObjectNV].operands.push(OperandId, "'Hint'"); + InstructionDesc[OpReorderThreadWithHitObjectNV].operands.push(OperandId, "'Bits'"); + InstructionDesc[OpReorderThreadWithHitObjectNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectGetCurrentTimeNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetCurrentTimeNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetHitKindNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetHitKindNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetPrimitiveIndexNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetPrimitiveIndexNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetGeometryIndexNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetGeometryIndexNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetInstanceIdNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetInstanceIdNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetInstanceCustomIndexNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetInstanceCustomIndexNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetObjectRayDirectionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetObjectRayDirectionNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetObjectRayOriginNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetObjectRayOriginNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetWorldRayDirectionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetWorldRayDirectionNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetWorldRayOriginNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetWorldRayOriginNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetWorldToObjectNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetWorldToObjectNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetObjectToWorldNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetObjectToWorldNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetRayTMaxNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetRayTMaxNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetRayTMinNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetRayTMinNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetShaderBindingTableRecordIndexNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetShaderBindingTableRecordIndexNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectIsEmptyNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectIsEmptyNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectIsHitNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectIsHitNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectIsMissNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectIsMissNV].setResultAndType(true, true); + + InstructionDesc[OpHitObjectGetAttributesNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectGetAttributesNV].operands.push(OperandId, "'HitObjectAttribute'"); + InstructionDesc[OpHitObjectGetAttributesNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectExecuteShaderNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectExecuteShaderNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpHitObjectExecuteShaderNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'InstanceId'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'PrimitiveId'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'GeometryIndex'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'HitKind'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordHitNV].operands.push(OperandId, "'HitObject Attribute'"); + InstructionDesc[OpHitObjectRecordHitNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'InstanceId'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'PrimitiveId'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'GeometryIndex'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'HitKind'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'Current Time'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].operands.push(OperandId, "'HitObject Attribute'"); + InstructionDesc[OpHitObjectRecordHitMotionNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'InstanceId'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'PrimitiveId'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'GeometryIndex'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'HitKind'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'SBT Record Index'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].operands.push(OperandId, "'HitObject Attribute'"); + InstructionDesc[OpHitObjectRecordHitWithIndexNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'InstanceId'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'PrimitiveId'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'GeometryIndex'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'HitKind'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'SBT Record Index'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'Current Time'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].operands.push(OperandId, "'HitObject Attribute'"); + InstructionDesc[OpHitObjectRecordHitWithIndexMotionNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'SBT Index'"); + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordMissNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordMissNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'SBT Index'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].operands.push(OperandId, "'Current Time'"); + InstructionDesc[OpHitObjectRecordMissMotionNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectRecordEmptyNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectRecordEmptyNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'RayFlags'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Cullmask'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectTraceRayNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpHitObjectTraceRayNV].setResultAndType(false, false); + + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'HitObject'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'RayFlags'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Cullmask'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'SBT Record Offset'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'SBT Record Stride'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Miss Index'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Origin'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'TMin'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Direction'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'TMax'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Time'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].operands.push(OperandId, "'Payload'"); + InstructionDesc[OpHitObjectTraceRayMotionNV].setResultAndType(false, false); + + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].operands.push(OperandId, "'Instance ID'"); + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].operands.push(OperandId, "'Geometry Index'"); + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].operands.push(OperandId, "'Primitive Index'"); + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].operands.push(OperandId, "'Barycentrics'"); + InstructionDesc[OpFetchMicroTriangleVertexBarycentricNV].setResultAndType(true, true); + + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].operands.push(OperandId, "'Acceleration Structure'"); + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].operands.push(OperandId, "'Instance ID'"); + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].operands.push(OperandId, "'Geometry Index'"); + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].operands.push(OperandId, "'Primitive Index'"); + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].operands.push(OperandId, "'Barycentrics'"); + InstructionDesc[OpFetchMicroTriangleVertexPositionNV].setResultAndType(true, true); + + InstructionDesc[OpColorAttachmentReadEXT].operands.push(OperandId, "'Attachment'"); + InstructionDesc[OpColorAttachmentReadEXT].operands.push(OperandId, "'Sample'", true); + InstructionDesc[OpStencilAttachmentReadEXT].operands.push(OperandId, "'Sample'", true); + InstructionDesc[OpDepthAttachmentReadEXT].operands.push(OperandId, "'Sample'", true); + + InstructionDesc[OpImageSampleWeightedQCOM].operands.push(OperandId, "'source texture'"); + InstructionDesc[OpImageSampleWeightedQCOM].operands.push(OperandId, "'texture coordinates'"); + InstructionDesc[OpImageSampleWeightedQCOM].operands.push(OperandId, "'weights texture'"); + InstructionDesc[OpImageSampleWeightedQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageSampleWeightedQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBoxFilterQCOM].operands.push(OperandId, "'source texture'"); + InstructionDesc[OpImageBoxFilterQCOM].operands.push(OperandId, "'texture coordinates'"); + InstructionDesc[OpImageBoxFilterQCOM].operands.push(OperandId, "'box size'"); + InstructionDesc[OpImageBoxFilterQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBoxFilterQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchSADQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchSADQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchSSDQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchSSDQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchWindowSSDQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchWindowSADQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchGatherSSDQCOM].setResultAndType(true, true); + + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'target texture'"); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'target coordinates'"); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'reference texture'"); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'reference coordinates'"); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandId, "'block size'"); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].operands.push(OperandImageOperands, "", true); + InstructionDesc[OpImageBlockMatchGatherSADQCOM].setResultAndType(true, true); + }); } }; // end spv namespace diff --git a/src/libraries/glslang/SPIRV/doc.h b/src/libraries/glslang/SPIRV/doc.h index 2a0b28c6b..521529913 100644 --- a/src/libraries/glslang/SPIRV/doc.h +++ b/src/libraries/glslang/SPIRV/doc.h @@ -156,6 +156,7 @@ enum OperandClass { OperandKernelEnqueueFlags, OperandKernelProfilingInfo, OperandCapability, + OperandCooperativeMatrixOperands, OperandOpcode, @@ -190,15 +191,15 @@ protected: // Parameterize an enumerant class EnumParameters { public: - EnumParameters() : desc(0) { } + EnumParameters() : desc(nullptr) { } 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) { } + EnumDefinition() : + ceiling(0), bitmask(false), getName(nullptr), enumParams(nullptr), operandParams(nullptr) { } void set(int ceil, const char* (*name)(int), EnumParameters* ep, bool mask = false) { ceiling = ceil; @@ -239,8 +240,8 @@ public: OperandParameters operands; protected: - int typePresent : 1; - int resultPresent : 1; + bool typePresent : 1; + bool resultPresent : 1; }; // The set of objects that hold all the instruction/operand diff --git a/src/libraries/glslang/SPIRV/hex_float.h b/src/libraries/glslang/SPIRV/hex_float.h index 8be8e9f7e..785e8af11 100644 --- a/src/libraries/glslang/SPIRV/hex_float.h +++ b/src/libraries/glslang/SPIRV/hex_float.h @@ -23,19 +23,6 @@ #include #include -#if defined(_MSC_VER) && _MSC_VER < 1800 -namespace std { -bool isnan(double f) -{ - return ::_isnan(f) != 0; -} -bool isinf(double f) -{ - return ::_finite(f) == 0; -} -} -#endif - #include "bitutils.h" namespace spvutils { diff --git a/src/libraries/glslang/SPIRV/spirv.hpp b/src/libraries/glslang/SPIRV/spirv.hpp index c1abd2640..6eceabe67 100644 --- a/src/libraries/glslang/SPIRV/spirv.hpp +++ b/src/libraries/glslang/SPIRV/spirv.hpp @@ -1,2314 +1,2815 @@ -// Copyright (c) 2014-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. - -// This header is automatically generated by the same tool that creates -// the Binary Section of the SPIR-V specification. - -// Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python, C#, D -// -// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] -// - C# will use enum classes in the Specification class located in the "Spv" namespace, -// e.g.: Spv.Specification.SourceLanguage.GLSL -// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL -// -// Some tokens act like mask values, which can be OR'd together, -// while others are mutually exclusive. The mask-like ones have -// "Mask" in their name, and a parallel enum that has the shift -// amount (1 << x) for each corresponding enumerant. - -#ifndef spirv_HPP -#define spirv_HPP - -namespace spv { - -typedef unsigned int Id; - -#define SPV_VERSION 0x10500 -#define SPV_REVISION 4 - -static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010500; -static const unsigned int Revision = 4; -static const unsigned int OpCodeMask = 0xffff; -static const unsigned int WordCountShift = 16; - -enum SourceLanguage { - SourceLanguageUnknown = 0, - SourceLanguageESSL = 1, - SourceLanguageGLSL = 2, - SourceLanguageOpenCL_C = 3, - SourceLanguageOpenCL_CPP = 4, - SourceLanguageHLSL = 5, - SourceLanguageMax = 0x7fffffff, -}; - -enum ExecutionModel { - ExecutionModelVertex = 0, - ExecutionModelTessellationControl = 1, - ExecutionModelTessellationEvaluation = 2, - ExecutionModelGeometry = 3, - ExecutionModelFragment = 4, - ExecutionModelGLCompute = 5, - ExecutionModelKernel = 6, - ExecutionModelTaskNV = 5267, - ExecutionModelMeshNV = 5268, - ExecutionModelRayGenerationKHR = 5313, - ExecutionModelRayGenerationNV = 5313, - ExecutionModelIntersectionKHR = 5314, - ExecutionModelIntersectionNV = 5314, - ExecutionModelAnyHitKHR = 5315, - ExecutionModelAnyHitNV = 5315, - ExecutionModelClosestHitKHR = 5316, - ExecutionModelClosestHitNV = 5316, - ExecutionModelMissKHR = 5317, - ExecutionModelMissNV = 5317, - ExecutionModelCallableKHR = 5318, - ExecutionModelCallableNV = 5318, - ExecutionModelMax = 0x7fffffff, -}; - -enum AddressingModel { - AddressingModelLogical = 0, - AddressingModelPhysical32 = 1, - AddressingModelPhysical64 = 2, - AddressingModelPhysicalStorageBuffer64 = 5348, - AddressingModelPhysicalStorageBuffer64EXT = 5348, - AddressingModelMax = 0x7fffffff, -}; - -enum MemoryModel { - MemoryModelSimple = 0, - MemoryModelGLSL450 = 1, - MemoryModelOpenCL = 2, - MemoryModelVulkan = 3, - MemoryModelVulkanKHR = 3, - MemoryModelMax = 0x7fffffff, -}; - -enum ExecutionMode { - ExecutionModeInvocations = 0, - ExecutionModeSpacingEqual = 1, - ExecutionModeSpacingFractionalEven = 2, - ExecutionModeSpacingFractionalOdd = 3, - ExecutionModeVertexOrderCw = 4, - ExecutionModeVertexOrderCcw = 5, - ExecutionModePixelCenterInteger = 6, - ExecutionModeOriginUpperLeft = 7, - ExecutionModeOriginLowerLeft = 8, - ExecutionModeEarlyFragmentTests = 9, - ExecutionModePointMode = 10, - ExecutionModeXfb = 11, - ExecutionModeDepthReplacing = 12, - ExecutionModeDepthGreater = 14, - ExecutionModeDepthLess = 15, - ExecutionModeDepthUnchanged = 16, - ExecutionModeLocalSize = 17, - ExecutionModeLocalSizeHint = 18, - ExecutionModeInputPoints = 19, - ExecutionModeInputLines = 20, - ExecutionModeInputLinesAdjacency = 21, - ExecutionModeTriangles = 22, - ExecutionModeInputTrianglesAdjacency = 23, - ExecutionModeQuads = 24, - ExecutionModeIsolines = 25, - ExecutionModeOutputVertices = 26, - ExecutionModeOutputPoints = 27, - ExecutionModeOutputLineStrip = 28, - ExecutionModeOutputTriangleStrip = 29, - ExecutionModeVecTypeHint = 30, - ExecutionModeContractionOff = 31, - ExecutionModeInitializer = 33, - ExecutionModeFinalizer = 34, - ExecutionModeSubgroupSize = 35, - ExecutionModeSubgroupsPerWorkgroup = 36, - ExecutionModeSubgroupsPerWorkgroupId = 37, - ExecutionModeLocalSizeId = 38, - ExecutionModeLocalSizeHintId = 39, - ExecutionModeSubgroupUniformControlFlowKHR = 4421, - ExecutionModePostDepthCoverage = 4446, - ExecutionModeDenormPreserve = 4459, - ExecutionModeDenormFlushToZero = 4460, - ExecutionModeSignedZeroInfNanPreserve = 4461, - ExecutionModeRoundingModeRTE = 4462, - ExecutionModeRoundingModeRTZ = 4463, - ExecutionModeStencilRefReplacingEXT = 5027, - ExecutionModeOutputLinesNV = 5269, - ExecutionModeOutputPrimitivesNV = 5270, - ExecutionModeDerivativeGroupQuadsNV = 5289, - ExecutionModeDerivativeGroupLinearNV = 5290, - ExecutionModeOutputTrianglesNV = 5298, - ExecutionModePixelInterlockOrderedEXT = 5366, - ExecutionModePixelInterlockUnorderedEXT = 5367, - ExecutionModeSampleInterlockOrderedEXT = 5368, - ExecutionModeSampleInterlockUnorderedEXT = 5369, - ExecutionModeShadingRateInterlockOrderedEXT = 5370, - ExecutionModeShadingRateInterlockUnorderedEXT = 5371, - ExecutionModeSharedLocalMemorySizeINTEL = 5618, - ExecutionModeRoundingModeRTPINTEL = 5620, - ExecutionModeRoundingModeRTNINTEL = 5621, - ExecutionModeFloatingPointModeALTINTEL = 5622, - ExecutionModeFloatingPointModeIEEEINTEL = 5623, - ExecutionModeMaxWorkgroupSizeINTEL = 5893, - ExecutionModeMaxWorkDimINTEL = 5894, - ExecutionModeNoGlobalOffsetINTEL = 5895, - ExecutionModeNumSIMDWorkitemsINTEL = 5896, - ExecutionModeSchedulerTargetFmaxMhzINTEL = 5903, - ExecutionModeMax = 0x7fffffff, -}; - -enum StorageClass { - StorageClassUniformConstant = 0, - StorageClassInput = 1, - StorageClassUniform = 2, - StorageClassOutput = 3, - StorageClassWorkgroup = 4, - StorageClassCrossWorkgroup = 5, - StorageClassPrivate = 6, - StorageClassFunction = 7, - StorageClassGeneric = 8, - StorageClassPushConstant = 9, - StorageClassAtomicCounter = 10, - StorageClassImage = 11, - StorageClassStorageBuffer = 12, - StorageClassCallableDataKHR = 5328, - StorageClassCallableDataNV = 5328, - StorageClassIncomingCallableDataKHR = 5329, - StorageClassIncomingCallableDataNV = 5329, - StorageClassRayPayloadKHR = 5338, - StorageClassRayPayloadNV = 5338, - StorageClassHitAttributeKHR = 5339, - StorageClassHitAttributeNV = 5339, - StorageClassIncomingRayPayloadKHR = 5342, - StorageClassIncomingRayPayloadNV = 5342, - StorageClassShaderRecordBufferKHR = 5343, - StorageClassShaderRecordBufferNV = 5343, - StorageClassPhysicalStorageBuffer = 5349, - StorageClassPhysicalStorageBufferEXT = 5349, - StorageClassCodeSectionINTEL = 5605, - StorageClassDeviceOnlyINTEL = 5936, - StorageClassHostOnlyINTEL = 5937, - StorageClassMax = 0x7fffffff, -}; - -enum Dim { - Dim1D = 0, - Dim2D = 1, - Dim3D = 2, - DimCube = 3, - DimRect = 4, - DimBuffer = 5, - DimSubpassData = 6, - DimMax = 0x7fffffff, -}; - -enum SamplerAddressingMode { - SamplerAddressingModeNone = 0, - SamplerAddressingModeClampToEdge = 1, - SamplerAddressingModeClamp = 2, - SamplerAddressingModeRepeat = 3, - SamplerAddressingModeRepeatMirrored = 4, - SamplerAddressingModeMax = 0x7fffffff, -}; - -enum SamplerFilterMode { - SamplerFilterModeNearest = 0, - SamplerFilterModeLinear = 1, - SamplerFilterModeMax = 0x7fffffff, -}; - -enum ImageFormat { - ImageFormatUnknown = 0, - ImageFormatRgba32f = 1, - ImageFormatRgba16f = 2, - ImageFormatR32f = 3, - ImageFormatRgba8 = 4, - ImageFormatRgba8Snorm = 5, - ImageFormatRg32f = 6, - ImageFormatRg16f = 7, - ImageFormatR11fG11fB10f = 8, - ImageFormatR16f = 9, - ImageFormatRgba16 = 10, - ImageFormatRgb10A2 = 11, - ImageFormatRg16 = 12, - ImageFormatRg8 = 13, - ImageFormatR16 = 14, - ImageFormatR8 = 15, - ImageFormatRgba16Snorm = 16, - ImageFormatRg16Snorm = 17, - ImageFormatRg8Snorm = 18, - ImageFormatR16Snorm = 19, - ImageFormatR8Snorm = 20, - ImageFormatRgba32i = 21, - ImageFormatRgba16i = 22, - ImageFormatRgba8i = 23, - ImageFormatR32i = 24, - ImageFormatRg32i = 25, - ImageFormatRg16i = 26, - ImageFormatRg8i = 27, - ImageFormatR16i = 28, - ImageFormatR8i = 29, - ImageFormatRgba32ui = 30, - ImageFormatRgba16ui = 31, - ImageFormatRgba8ui = 32, - ImageFormatR32ui = 33, - ImageFormatRgb10a2ui = 34, - ImageFormatRg32ui = 35, - ImageFormatRg16ui = 36, - ImageFormatRg8ui = 37, - ImageFormatR16ui = 38, - ImageFormatR8ui = 39, - ImageFormatR64ui = 40, - ImageFormatR64i = 41, - ImageFormatMax = 0x7fffffff, -}; - -enum ImageChannelOrder { - ImageChannelOrderR = 0, - ImageChannelOrderA = 1, - ImageChannelOrderRG = 2, - ImageChannelOrderRA = 3, - ImageChannelOrderRGB = 4, - ImageChannelOrderRGBA = 5, - ImageChannelOrderBGRA = 6, - ImageChannelOrderARGB = 7, - ImageChannelOrderIntensity = 8, - ImageChannelOrderLuminance = 9, - ImageChannelOrderRx = 10, - ImageChannelOrderRGx = 11, - ImageChannelOrderRGBx = 12, - ImageChannelOrderDepth = 13, - ImageChannelOrderDepthStencil = 14, - ImageChannelOrdersRGB = 15, - ImageChannelOrdersRGBx = 16, - ImageChannelOrdersRGBA = 17, - ImageChannelOrdersBGRA = 18, - ImageChannelOrderABGR = 19, - ImageChannelOrderMax = 0x7fffffff, -}; - -enum ImageChannelDataType { - ImageChannelDataTypeSnormInt8 = 0, - ImageChannelDataTypeSnormInt16 = 1, - ImageChannelDataTypeUnormInt8 = 2, - ImageChannelDataTypeUnormInt16 = 3, - ImageChannelDataTypeUnormShort565 = 4, - ImageChannelDataTypeUnormShort555 = 5, - ImageChannelDataTypeUnormInt101010 = 6, - ImageChannelDataTypeSignedInt8 = 7, - ImageChannelDataTypeSignedInt16 = 8, - ImageChannelDataTypeSignedInt32 = 9, - ImageChannelDataTypeUnsignedInt8 = 10, - ImageChannelDataTypeUnsignedInt16 = 11, - ImageChannelDataTypeUnsignedInt32 = 12, - ImageChannelDataTypeHalfFloat = 13, - ImageChannelDataTypeFloat = 14, - ImageChannelDataTypeUnormInt24 = 15, - ImageChannelDataTypeUnormInt101010_2 = 16, - ImageChannelDataTypeMax = 0x7fffffff, -}; - -enum ImageOperandsShift { - ImageOperandsBiasShift = 0, - ImageOperandsLodShift = 1, - ImageOperandsGradShift = 2, - ImageOperandsConstOffsetShift = 3, - ImageOperandsOffsetShift = 4, - ImageOperandsConstOffsetsShift = 5, - ImageOperandsSampleShift = 6, - ImageOperandsMinLodShift = 7, - ImageOperandsMakeTexelAvailableShift = 8, - ImageOperandsMakeTexelAvailableKHRShift = 8, - ImageOperandsMakeTexelVisibleShift = 9, - ImageOperandsMakeTexelVisibleKHRShift = 9, - ImageOperandsNonPrivateTexelShift = 10, - ImageOperandsNonPrivateTexelKHRShift = 10, - ImageOperandsVolatileTexelShift = 11, - ImageOperandsVolatileTexelKHRShift = 11, - ImageOperandsSignExtendShift = 12, - ImageOperandsZeroExtendShift = 13, - ImageOperandsMax = 0x7fffffff, -}; - -enum ImageOperandsMask { - ImageOperandsMaskNone = 0, - ImageOperandsBiasMask = 0x00000001, - ImageOperandsLodMask = 0x00000002, - ImageOperandsGradMask = 0x00000004, - ImageOperandsConstOffsetMask = 0x00000008, - ImageOperandsOffsetMask = 0x00000010, - ImageOperandsConstOffsetsMask = 0x00000020, - ImageOperandsSampleMask = 0x00000040, - ImageOperandsMinLodMask = 0x00000080, - ImageOperandsMakeTexelAvailableMask = 0x00000100, - ImageOperandsMakeTexelAvailableKHRMask = 0x00000100, - ImageOperandsMakeTexelVisibleMask = 0x00000200, - ImageOperandsMakeTexelVisibleKHRMask = 0x00000200, - ImageOperandsNonPrivateTexelMask = 0x00000400, - ImageOperandsNonPrivateTexelKHRMask = 0x00000400, - ImageOperandsVolatileTexelMask = 0x00000800, - ImageOperandsVolatileTexelKHRMask = 0x00000800, - ImageOperandsSignExtendMask = 0x00001000, - ImageOperandsZeroExtendMask = 0x00002000, -}; - -enum FPFastMathModeShift { - FPFastMathModeNotNaNShift = 0, - FPFastMathModeNotInfShift = 1, - FPFastMathModeNSZShift = 2, - FPFastMathModeAllowRecipShift = 3, - FPFastMathModeFastShift = 4, - FPFastMathModeAllowContractFastINTELShift = 16, - FPFastMathModeAllowReassocINTELShift = 17, - FPFastMathModeMax = 0x7fffffff, -}; - -enum FPFastMathModeMask { - FPFastMathModeMaskNone = 0, - FPFastMathModeNotNaNMask = 0x00000001, - FPFastMathModeNotInfMask = 0x00000002, - FPFastMathModeNSZMask = 0x00000004, - FPFastMathModeAllowRecipMask = 0x00000008, - FPFastMathModeFastMask = 0x00000010, - FPFastMathModeAllowContractFastINTELMask = 0x00010000, - FPFastMathModeAllowReassocINTELMask = 0x00020000, -}; - -enum FPRoundingMode { - FPRoundingModeRTE = 0, - FPRoundingModeRTZ = 1, - FPRoundingModeRTP = 2, - FPRoundingModeRTN = 3, - FPRoundingModeMax = 0x7fffffff, -}; - -enum LinkageType { - LinkageTypeExport = 0, - LinkageTypeImport = 1, - LinkageTypeLinkOnceODR = 2, - LinkageTypeMax = 0x7fffffff, -}; - -enum AccessQualifier { - AccessQualifierReadOnly = 0, - AccessQualifierWriteOnly = 1, - AccessQualifierReadWrite = 2, - AccessQualifierMax = 0x7fffffff, -}; - -enum FunctionParameterAttribute { - FunctionParameterAttributeZext = 0, - FunctionParameterAttributeSext = 1, - FunctionParameterAttributeByVal = 2, - FunctionParameterAttributeSret = 3, - FunctionParameterAttributeNoAlias = 4, - FunctionParameterAttributeNoCapture = 5, - FunctionParameterAttributeNoWrite = 6, - FunctionParameterAttributeNoReadWrite = 7, - FunctionParameterAttributeMax = 0x7fffffff, -}; - -enum Decoration { - DecorationRelaxedPrecision = 0, - DecorationSpecId = 1, - DecorationBlock = 2, - DecorationBufferBlock = 3, - DecorationRowMajor = 4, - DecorationColMajor = 5, - DecorationArrayStride = 6, - DecorationMatrixStride = 7, - DecorationGLSLShared = 8, - DecorationGLSLPacked = 9, - DecorationCPacked = 10, - DecorationBuiltIn = 11, - DecorationNoPerspective = 13, - DecorationFlat = 14, - DecorationPatch = 15, - DecorationCentroid = 16, - DecorationSample = 17, - DecorationInvariant = 18, - DecorationRestrict = 19, - DecorationAliased = 20, - DecorationVolatile = 21, - DecorationConstant = 22, - DecorationCoherent = 23, - DecorationNonWritable = 24, - DecorationNonReadable = 25, - DecorationUniform = 26, - DecorationUniformId = 27, - DecorationSaturatedConversion = 28, - DecorationStream = 29, - DecorationLocation = 30, - DecorationComponent = 31, - DecorationIndex = 32, - DecorationBinding = 33, - DecorationDescriptorSet = 34, - DecorationOffset = 35, - DecorationXfbBuffer = 36, - DecorationXfbStride = 37, - DecorationFuncParamAttr = 38, - DecorationFPRoundingMode = 39, - DecorationFPFastMathMode = 40, - DecorationLinkageAttributes = 41, - DecorationNoContraction = 42, - DecorationInputAttachmentIndex = 43, - DecorationAlignment = 44, - DecorationMaxByteOffset = 45, - DecorationAlignmentId = 46, - DecorationMaxByteOffsetId = 47, - DecorationNoSignedWrap = 4469, - DecorationNoUnsignedWrap = 4470, - DecorationExplicitInterpAMD = 4999, - DecorationOverrideCoverageNV = 5248, - DecorationPassthroughNV = 5250, - DecorationViewportRelativeNV = 5252, - DecorationSecondaryViewportRelativeNV = 5256, - DecorationPerPrimitiveNV = 5271, - DecorationPerViewNV = 5272, - DecorationPerTaskNV = 5273, - DecorationPerVertexNV = 5285, - DecorationNonUniform = 5300, - DecorationNonUniformEXT = 5300, - DecorationRestrictPointer = 5355, - DecorationRestrictPointerEXT = 5355, - DecorationAliasedPointer = 5356, - DecorationAliasedPointerEXT = 5356, - DecorationSIMTCallINTEL = 5599, - DecorationReferencedIndirectlyINTEL = 5602, - DecorationClobberINTEL = 5607, - DecorationSideEffectsINTEL = 5608, - DecorationVectorComputeVariableINTEL = 5624, - DecorationFuncParamIOKindINTEL = 5625, - DecorationVectorComputeFunctionINTEL = 5626, - DecorationStackCallINTEL = 5627, - DecorationGlobalVariableOffsetINTEL = 5628, - DecorationCounterBuffer = 5634, - DecorationHlslCounterBufferGOOGLE = 5634, - DecorationHlslSemanticGOOGLE = 5635, - DecorationUserSemantic = 5635, - DecorationUserTypeGOOGLE = 5636, - DecorationFunctionRoundingModeINTEL = 5822, - DecorationFunctionDenormModeINTEL = 5823, - DecorationRegisterINTEL = 5825, - DecorationMemoryINTEL = 5826, - DecorationNumbanksINTEL = 5827, - DecorationBankwidthINTEL = 5828, - DecorationMaxPrivateCopiesINTEL = 5829, - DecorationSinglepumpINTEL = 5830, - DecorationDoublepumpINTEL = 5831, - DecorationMaxReplicatesINTEL = 5832, - DecorationSimpleDualPortINTEL = 5833, - DecorationMergeINTEL = 5834, - DecorationBankBitsINTEL = 5835, - DecorationForcePow2DepthINTEL = 5836, - DecorationBurstCoalesceINTEL = 5899, - DecorationCacheSizeINTEL = 5900, - DecorationDontStaticallyCoalesceINTEL = 5901, - DecorationPrefetchINTEL = 5902, - DecorationStallEnableINTEL = 5905, - DecorationFuseLoopsInFunctionINTEL = 5907, - DecorationBufferLocationINTEL = 5921, - DecorationIOPipeStorageINTEL = 5944, - DecorationFunctionFloatingPointModeINTEL = 6080, - DecorationSingleElementVectorINTEL = 6085, - DecorationVectorComputeCallableFunctionINTEL = 6087, - DecorationMax = 0x7fffffff, -}; - -enum BuiltIn { - BuiltInPosition = 0, - BuiltInPointSize = 1, - BuiltInClipDistance = 3, - BuiltInCullDistance = 4, - BuiltInVertexId = 5, - BuiltInInstanceId = 6, - BuiltInPrimitiveId = 7, - BuiltInInvocationId = 8, - BuiltInLayer = 9, - BuiltInViewportIndex = 10, - BuiltInTessLevelOuter = 11, - BuiltInTessLevelInner = 12, - BuiltInTessCoord = 13, - BuiltInPatchVertices = 14, - BuiltInFragCoord = 15, - BuiltInPointCoord = 16, - BuiltInFrontFacing = 17, - BuiltInSampleId = 18, - BuiltInSamplePosition = 19, - BuiltInSampleMask = 20, - BuiltInFragDepth = 22, - BuiltInHelperInvocation = 23, - BuiltInNumWorkgroups = 24, - BuiltInWorkgroupSize = 25, - BuiltInWorkgroupId = 26, - BuiltInLocalInvocationId = 27, - BuiltInGlobalInvocationId = 28, - BuiltInLocalInvocationIndex = 29, - BuiltInWorkDim = 30, - BuiltInGlobalSize = 31, - BuiltInEnqueuedWorkgroupSize = 32, - BuiltInGlobalOffset = 33, - BuiltInGlobalLinearId = 34, - BuiltInSubgroupSize = 36, - BuiltInSubgroupMaxSize = 37, - BuiltInNumSubgroups = 38, - BuiltInNumEnqueuedSubgroups = 39, - BuiltInSubgroupId = 40, - BuiltInSubgroupLocalInvocationId = 41, - BuiltInVertexIndex = 42, - BuiltInInstanceIndex = 43, - BuiltInSubgroupEqMask = 4416, - BuiltInSubgroupEqMaskKHR = 4416, - BuiltInSubgroupGeMask = 4417, - BuiltInSubgroupGeMaskKHR = 4417, - BuiltInSubgroupGtMask = 4418, - BuiltInSubgroupGtMaskKHR = 4418, - BuiltInSubgroupLeMask = 4419, - BuiltInSubgroupLeMaskKHR = 4419, - BuiltInSubgroupLtMask = 4420, - BuiltInSubgroupLtMaskKHR = 4420, - BuiltInBaseVertex = 4424, - BuiltInBaseInstance = 4425, - BuiltInDrawIndex = 4426, - BuiltInPrimitiveShadingRateKHR = 4432, - BuiltInDeviceIndex = 4438, - BuiltInViewIndex = 4440, - BuiltInShadingRateKHR = 4444, - BuiltInBaryCoordNoPerspAMD = 4992, - BuiltInBaryCoordNoPerspCentroidAMD = 4993, - BuiltInBaryCoordNoPerspSampleAMD = 4994, - BuiltInBaryCoordSmoothAMD = 4995, - BuiltInBaryCoordSmoothCentroidAMD = 4996, - BuiltInBaryCoordSmoothSampleAMD = 4997, - BuiltInBaryCoordPullModelAMD = 4998, - BuiltInFragStencilRefEXT = 5014, - BuiltInViewportMaskNV = 5253, - BuiltInSecondaryPositionNV = 5257, - BuiltInSecondaryViewportMaskNV = 5258, - BuiltInPositionPerViewNV = 5261, - BuiltInViewportMaskPerViewNV = 5262, - BuiltInFullyCoveredEXT = 5264, - BuiltInTaskCountNV = 5274, - BuiltInPrimitiveCountNV = 5275, - BuiltInPrimitiveIndicesNV = 5276, - BuiltInClipDistancePerViewNV = 5277, - BuiltInCullDistancePerViewNV = 5278, - BuiltInLayerPerViewNV = 5279, - BuiltInMeshViewCountNV = 5280, - BuiltInMeshViewIndicesNV = 5281, - BuiltInBaryCoordNV = 5286, - BuiltInBaryCoordNoPerspNV = 5287, - BuiltInFragSizeEXT = 5292, - BuiltInFragmentSizeNV = 5292, - BuiltInFragInvocationCountEXT = 5293, - BuiltInInvocationsPerPixelNV = 5293, - BuiltInLaunchIdKHR = 5319, - BuiltInLaunchIdNV = 5319, - BuiltInLaunchSizeKHR = 5320, - BuiltInLaunchSizeNV = 5320, - BuiltInWorldRayOriginKHR = 5321, - BuiltInWorldRayOriginNV = 5321, - BuiltInWorldRayDirectionKHR = 5322, - BuiltInWorldRayDirectionNV = 5322, - BuiltInObjectRayOriginKHR = 5323, - BuiltInObjectRayOriginNV = 5323, - BuiltInObjectRayDirectionKHR = 5324, - BuiltInObjectRayDirectionNV = 5324, - BuiltInRayTminKHR = 5325, - BuiltInRayTminNV = 5325, - BuiltInRayTmaxKHR = 5326, - BuiltInRayTmaxNV = 5326, - BuiltInInstanceCustomIndexKHR = 5327, - BuiltInInstanceCustomIndexNV = 5327, - BuiltInObjectToWorldKHR = 5330, - BuiltInObjectToWorldNV = 5330, - BuiltInWorldToObjectKHR = 5331, - BuiltInWorldToObjectNV = 5331, - BuiltInHitTNV = 5332, - BuiltInHitKindKHR = 5333, - BuiltInHitKindNV = 5333, - BuiltInCurrentRayTimeNV = 5334, - BuiltInIncomingRayFlagsKHR = 5351, - BuiltInIncomingRayFlagsNV = 5351, - BuiltInRayGeometryIndexKHR = 5352, - BuiltInWarpsPerSMNV = 5374, - BuiltInSMCountNV = 5375, - BuiltInWarpIDNV = 5376, - BuiltInSMIDNV = 5377, - BuiltInMax = 0x7fffffff, -}; - -enum SelectionControlShift { - SelectionControlFlattenShift = 0, - SelectionControlDontFlattenShift = 1, - SelectionControlMax = 0x7fffffff, -}; - -enum SelectionControlMask { - SelectionControlMaskNone = 0, - SelectionControlFlattenMask = 0x00000001, - SelectionControlDontFlattenMask = 0x00000002, -}; - -enum LoopControlShift { - LoopControlUnrollShift = 0, - LoopControlDontUnrollShift = 1, - LoopControlDependencyInfiniteShift = 2, - LoopControlDependencyLengthShift = 3, - LoopControlMinIterationsShift = 4, - LoopControlMaxIterationsShift = 5, - LoopControlIterationMultipleShift = 6, - LoopControlPeelCountShift = 7, - LoopControlPartialCountShift = 8, - LoopControlInitiationIntervalINTELShift = 16, - LoopControlMaxConcurrencyINTELShift = 17, - LoopControlDependencyArrayINTELShift = 18, - LoopControlPipelineEnableINTELShift = 19, - LoopControlLoopCoalesceINTELShift = 20, - LoopControlMaxInterleavingINTELShift = 21, - LoopControlSpeculatedIterationsINTELShift = 22, - LoopControlNoFusionINTELShift = 23, - LoopControlMax = 0x7fffffff, -}; - -enum LoopControlMask { - LoopControlMaskNone = 0, - LoopControlUnrollMask = 0x00000001, - LoopControlDontUnrollMask = 0x00000002, - LoopControlDependencyInfiniteMask = 0x00000004, - LoopControlDependencyLengthMask = 0x00000008, - LoopControlMinIterationsMask = 0x00000010, - LoopControlMaxIterationsMask = 0x00000020, - LoopControlIterationMultipleMask = 0x00000040, - LoopControlPeelCountMask = 0x00000080, - LoopControlPartialCountMask = 0x00000100, - LoopControlInitiationIntervalINTELMask = 0x00010000, - LoopControlMaxConcurrencyINTELMask = 0x00020000, - LoopControlDependencyArrayINTELMask = 0x00040000, - LoopControlPipelineEnableINTELMask = 0x00080000, - LoopControlLoopCoalesceINTELMask = 0x00100000, - LoopControlMaxInterleavingINTELMask = 0x00200000, - LoopControlSpeculatedIterationsINTELMask = 0x00400000, - LoopControlNoFusionINTELMask = 0x00800000, -}; - -enum FunctionControlShift { - FunctionControlInlineShift = 0, - FunctionControlDontInlineShift = 1, - FunctionControlPureShift = 2, - FunctionControlConstShift = 3, - FunctionControlMax = 0x7fffffff, -}; - -enum FunctionControlMask { - FunctionControlMaskNone = 0, - FunctionControlInlineMask = 0x00000001, - FunctionControlDontInlineMask = 0x00000002, - FunctionControlPureMask = 0x00000004, - FunctionControlConstMask = 0x00000008, -}; - -enum MemorySemanticsShift { - MemorySemanticsAcquireShift = 1, - MemorySemanticsReleaseShift = 2, - MemorySemanticsAcquireReleaseShift = 3, - MemorySemanticsSequentiallyConsistentShift = 4, - MemorySemanticsUniformMemoryShift = 6, - MemorySemanticsSubgroupMemoryShift = 7, - MemorySemanticsWorkgroupMemoryShift = 8, - MemorySemanticsCrossWorkgroupMemoryShift = 9, - MemorySemanticsAtomicCounterMemoryShift = 10, - MemorySemanticsImageMemoryShift = 11, - MemorySemanticsOutputMemoryShift = 12, - MemorySemanticsOutputMemoryKHRShift = 12, - MemorySemanticsMakeAvailableShift = 13, - MemorySemanticsMakeAvailableKHRShift = 13, - MemorySemanticsMakeVisibleShift = 14, - MemorySemanticsMakeVisibleKHRShift = 14, - MemorySemanticsVolatileShift = 15, - MemorySemanticsMax = 0x7fffffff, -}; - -enum MemorySemanticsMask { - MemorySemanticsMaskNone = 0, - MemorySemanticsAcquireMask = 0x00000002, - MemorySemanticsReleaseMask = 0x00000004, - MemorySemanticsAcquireReleaseMask = 0x00000008, - MemorySemanticsSequentiallyConsistentMask = 0x00000010, - MemorySemanticsUniformMemoryMask = 0x00000040, - MemorySemanticsSubgroupMemoryMask = 0x00000080, - MemorySemanticsWorkgroupMemoryMask = 0x00000100, - MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, - MemorySemanticsAtomicCounterMemoryMask = 0x00000400, - MemorySemanticsImageMemoryMask = 0x00000800, - MemorySemanticsOutputMemoryMask = 0x00001000, - MemorySemanticsOutputMemoryKHRMask = 0x00001000, - MemorySemanticsMakeAvailableMask = 0x00002000, - MemorySemanticsMakeAvailableKHRMask = 0x00002000, - MemorySemanticsMakeVisibleMask = 0x00004000, - MemorySemanticsMakeVisibleKHRMask = 0x00004000, - MemorySemanticsVolatileMask = 0x00008000, -}; - -enum MemoryAccessShift { - MemoryAccessVolatileShift = 0, - MemoryAccessAlignedShift = 1, - MemoryAccessNontemporalShift = 2, - MemoryAccessMakePointerAvailableShift = 3, - MemoryAccessMakePointerAvailableKHRShift = 3, - MemoryAccessMakePointerVisibleShift = 4, - MemoryAccessMakePointerVisibleKHRShift = 4, - MemoryAccessNonPrivatePointerShift = 5, - MemoryAccessNonPrivatePointerKHRShift = 5, - MemoryAccessMax = 0x7fffffff, -}; - -enum MemoryAccessMask { - MemoryAccessMaskNone = 0, - MemoryAccessVolatileMask = 0x00000001, - MemoryAccessAlignedMask = 0x00000002, - MemoryAccessNontemporalMask = 0x00000004, - MemoryAccessMakePointerAvailableMask = 0x00000008, - MemoryAccessMakePointerAvailableKHRMask = 0x00000008, - MemoryAccessMakePointerVisibleMask = 0x00000010, - MemoryAccessMakePointerVisibleKHRMask = 0x00000010, - MemoryAccessNonPrivatePointerMask = 0x00000020, - MemoryAccessNonPrivatePointerKHRMask = 0x00000020, -}; - -enum Scope { - ScopeCrossDevice = 0, - ScopeDevice = 1, - ScopeWorkgroup = 2, - ScopeSubgroup = 3, - ScopeInvocation = 4, - ScopeQueueFamily = 5, - ScopeQueueFamilyKHR = 5, - ScopeShaderCallKHR = 6, - ScopeMax = 0x7fffffff, -}; - -enum GroupOperation { - GroupOperationReduce = 0, - GroupOperationInclusiveScan = 1, - GroupOperationExclusiveScan = 2, - GroupOperationClusteredReduce = 3, - GroupOperationPartitionedReduceNV = 6, - GroupOperationPartitionedInclusiveScanNV = 7, - GroupOperationPartitionedExclusiveScanNV = 8, - GroupOperationMax = 0x7fffffff, -}; - -enum KernelEnqueueFlags { - KernelEnqueueFlagsNoWait = 0, - KernelEnqueueFlagsWaitKernel = 1, - KernelEnqueueFlagsWaitWorkGroup = 2, - KernelEnqueueFlagsMax = 0x7fffffff, -}; - -enum KernelProfilingInfoShift { - KernelProfilingInfoCmdExecTimeShift = 0, - KernelProfilingInfoMax = 0x7fffffff, -}; - -enum KernelProfilingInfoMask { - KernelProfilingInfoMaskNone = 0, - KernelProfilingInfoCmdExecTimeMask = 0x00000001, -}; - -enum Capability { - CapabilityMatrix = 0, - CapabilityShader = 1, - CapabilityGeometry = 2, - CapabilityTessellation = 3, - CapabilityAddresses = 4, - CapabilityLinkage = 5, - CapabilityKernel = 6, - CapabilityVector16 = 7, - CapabilityFloat16Buffer = 8, - CapabilityFloat16 = 9, - CapabilityFloat64 = 10, - CapabilityInt64 = 11, - CapabilityInt64Atomics = 12, - CapabilityImageBasic = 13, - CapabilityImageReadWrite = 14, - CapabilityImageMipmap = 15, - CapabilityPipes = 17, - CapabilityGroups = 18, - CapabilityDeviceEnqueue = 19, - CapabilityLiteralSampler = 20, - CapabilityAtomicStorage = 21, - CapabilityInt16 = 22, - CapabilityTessellationPointSize = 23, - CapabilityGeometryPointSize = 24, - CapabilityImageGatherExtended = 25, - CapabilityStorageImageMultisample = 27, - CapabilityUniformBufferArrayDynamicIndexing = 28, - CapabilitySampledImageArrayDynamicIndexing = 29, - CapabilityStorageBufferArrayDynamicIndexing = 30, - CapabilityStorageImageArrayDynamicIndexing = 31, - CapabilityClipDistance = 32, - CapabilityCullDistance = 33, - CapabilityImageCubeArray = 34, - CapabilitySampleRateShading = 35, - CapabilityImageRect = 36, - CapabilitySampledRect = 37, - CapabilityGenericPointer = 38, - CapabilityInt8 = 39, - CapabilityInputAttachment = 40, - CapabilitySparseResidency = 41, - CapabilityMinLod = 42, - CapabilitySampled1D = 43, - CapabilityImage1D = 44, - CapabilitySampledCubeArray = 45, - CapabilitySampledBuffer = 46, - CapabilityImageBuffer = 47, - CapabilityImageMSArray = 48, - CapabilityStorageImageExtendedFormats = 49, - CapabilityImageQuery = 50, - CapabilityDerivativeControl = 51, - CapabilityInterpolationFunction = 52, - CapabilityTransformFeedback = 53, - CapabilityGeometryStreams = 54, - CapabilityStorageImageReadWithoutFormat = 55, - CapabilityStorageImageWriteWithoutFormat = 56, - CapabilityMultiViewport = 57, - CapabilitySubgroupDispatch = 58, - CapabilityNamedBarrier = 59, - CapabilityPipeStorage = 60, - CapabilityGroupNonUniform = 61, - CapabilityGroupNonUniformVote = 62, - CapabilityGroupNonUniformArithmetic = 63, - CapabilityGroupNonUniformBallot = 64, - CapabilityGroupNonUniformShuffle = 65, - CapabilityGroupNonUniformShuffleRelative = 66, - CapabilityGroupNonUniformClustered = 67, - CapabilityGroupNonUniformQuad = 68, - CapabilityShaderLayer = 69, - CapabilityShaderViewportIndex = 70, - CapabilityFragmentShadingRateKHR = 4422, - CapabilitySubgroupBallotKHR = 4423, - CapabilityDrawParameters = 4427, - CapabilityWorkgroupMemoryExplicitLayoutKHR = 4428, - CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, - CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, - CapabilitySubgroupVoteKHR = 4431, - CapabilityStorageBuffer16BitAccess = 4433, - CapabilityStorageUniformBufferBlock16 = 4433, - CapabilityStorageUniform16 = 4434, - CapabilityUniformAndStorageBuffer16BitAccess = 4434, - CapabilityStoragePushConstant16 = 4435, - CapabilityStorageInputOutput16 = 4436, - CapabilityDeviceGroup = 4437, - CapabilityMultiView = 4439, - CapabilityVariablePointersStorageBuffer = 4441, - CapabilityVariablePointers = 4442, - CapabilityAtomicStorageOps = 4445, - CapabilitySampleMaskPostDepthCoverage = 4447, - CapabilityStorageBuffer8BitAccess = 4448, - CapabilityUniformAndStorageBuffer8BitAccess = 4449, - CapabilityStoragePushConstant8 = 4450, - CapabilityDenormPreserve = 4464, - CapabilityDenormFlushToZero = 4465, - CapabilitySignedZeroInfNanPreserve = 4466, - CapabilityRoundingModeRTE = 4467, - CapabilityRoundingModeRTZ = 4468, - CapabilityRayQueryProvisionalKHR = 4471, - CapabilityRayQueryKHR = 4472, - CapabilityRayTraversalPrimitiveCullingKHR = 4478, - CapabilityRayTracingKHR = 4479, - CapabilityFloat16ImageAMD = 5008, - CapabilityImageGatherBiasLodAMD = 5009, - CapabilityFragmentMaskAMD = 5010, - CapabilityStencilExportEXT = 5013, - CapabilityImageReadWriteLodAMD = 5015, - CapabilityInt64ImageEXT = 5016, - CapabilityShaderClockKHR = 5055, - CapabilitySampleMaskOverrideCoverageNV = 5249, - CapabilityGeometryShaderPassthroughNV = 5251, - CapabilityShaderViewportIndexLayerEXT = 5254, - CapabilityShaderViewportIndexLayerNV = 5254, - CapabilityShaderViewportMaskNV = 5255, - CapabilityShaderStereoViewNV = 5259, - CapabilityPerViewAttributesNV = 5260, - CapabilityFragmentFullyCoveredEXT = 5265, - CapabilityMeshShadingNV = 5266, - CapabilityImageFootprintNV = 5282, - CapabilityFragmentBarycentricNV = 5284, - CapabilityComputeDerivativeGroupQuadsNV = 5288, - CapabilityFragmentDensityEXT = 5291, - CapabilityShadingRateNV = 5291, - CapabilityGroupNonUniformPartitionedNV = 5297, - CapabilityShaderNonUniform = 5301, - CapabilityShaderNonUniformEXT = 5301, - CapabilityRuntimeDescriptorArray = 5302, - CapabilityRuntimeDescriptorArrayEXT = 5302, - CapabilityInputAttachmentArrayDynamicIndexing = 5303, - CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, - CapabilityUniformTexelBufferArrayDynamicIndexing = 5304, - CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, - CapabilityStorageTexelBufferArrayDynamicIndexing = 5305, - CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, - CapabilityUniformBufferArrayNonUniformIndexing = 5306, - CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, - CapabilitySampledImageArrayNonUniformIndexing = 5307, - CapabilitySampledImageArrayNonUniformIndexingEXT = 5307, - CapabilityStorageBufferArrayNonUniformIndexing = 5308, - CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, - CapabilityStorageImageArrayNonUniformIndexing = 5309, - CapabilityStorageImageArrayNonUniformIndexingEXT = 5309, - CapabilityInputAttachmentArrayNonUniformIndexing = 5310, - CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, - CapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, - CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, - CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, - CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, - CapabilityRayTracingNV = 5340, - CapabilityRayTracingMotionBlurNV = 5341, - CapabilityVulkanMemoryModel = 5345, - CapabilityVulkanMemoryModelKHR = 5345, - CapabilityVulkanMemoryModelDeviceScope = 5346, - CapabilityVulkanMemoryModelDeviceScopeKHR = 5346, - CapabilityPhysicalStorageBufferAddresses = 5347, - CapabilityPhysicalStorageBufferAddressesEXT = 5347, - CapabilityComputeDerivativeGroupLinearNV = 5350, - CapabilityRayTracingProvisionalKHR = 5353, - CapabilityCooperativeMatrixNV = 5357, - CapabilityFragmentShaderSampleInterlockEXT = 5363, - CapabilityFragmentShaderShadingRateInterlockEXT = 5372, - CapabilityShaderSMBuiltinsNV = 5373, - CapabilityFragmentShaderPixelInterlockEXT = 5378, - CapabilityDemoteToHelperInvocation = 5379, - CapabilityDemoteToHelperInvocationEXT = 5379, - CapabilitySubgroupShuffleINTEL = 5568, - CapabilitySubgroupBufferBlockIOINTEL = 5569, - CapabilitySubgroupImageBlockIOINTEL = 5570, - CapabilitySubgroupImageMediaBlockIOINTEL = 5579, - CapabilityRoundToInfinityINTEL = 5582, - CapabilityFloatingPointModeINTEL = 5583, - CapabilityIntegerFunctions2INTEL = 5584, - CapabilityFunctionPointersINTEL = 5603, - CapabilityIndirectReferencesINTEL = 5604, - CapabilityAsmINTEL = 5606, - CapabilityAtomicFloat32MinMaxEXT = 5612, - CapabilityAtomicFloat64MinMaxEXT = 5613, - CapabilityAtomicFloat16MinMaxEXT = 5616, - CapabilityVectorComputeINTEL = 5617, - CapabilityVectorAnyINTEL = 5619, - CapabilityExpectAssumeKHR = 5629, - CapabilitySubgroupAvcMotionEstimationINTEL = 5696, - CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, - CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, - CapabilityVariableLengthArrayINTEL = 5817, - CapabilityFunctionFloatControlINTEL = 5821, - CapabilityFPGAMemoryAttributesINTEL = 5824, - CapabilityFPFastMathModeINTEL = 5837, - CapabilityArbitraryPrecisionIntegersINTEL = 5844, - CapabilityUnstructuredLoopControlsINTEL = 5886, - CapabilityFPGALoopControlsINTEL = 5888, - CapabilityKernelAttributesINTEL = 5892, - CapabilityFPGAKernelAttributesINTEL = 5897, - CapabilityFPGAMemoryAccessesINTEL = 5898, - CapabilityFPGAClusterAttributesINTEL = 5904, - CapabilityLoopFuseINTEL = 5906, - CapabilityFPGABufferLocationINTEL = 5920, - CapabilityUSMStorageClassesINTEL = 5935, - CapabilityIOPipesINTEL = 5943, - CapabilityBlockingPipesINTEL = 5945, - CapabilityFPGARegINTEL = 5948, - CapabilityAtomicFloat32AddEXT = 6033, - CapabilityAtomicFloat64AddEXT = 6034, - CapabilityLongConstantCompositeINTEL = 6089, - CapabilityAtomicFloat16AddEXT = 6095, - CapabilityMax = 0x7fffffff, -}; - -enum RayFlagsShift { - RayFlagsOpaqueKHRShift = 0, - RayFlagsNoOpaqueKHRShift = 1, - RayFlagsTerminateOnFirstHitKHRShift = 2, - RayFlagsSkipClosestHitShaderKHRShift = 3, - RayFlagsCullBackFacingTrianglesKHRShift = 4, - RayFlagsCullFrontFacingTrianglesKHRShift = 5, - RayFlagsCullOpaqueKHRShift = 6, - RayFlagsCullNoOpaqueKHRShift = 7, - RayFlagsSkipTrianglesKHRShift = 8, - RayFlagsSkipAABBsKHRShift = 9, - RayFlagsMax = 0x7fffffff, -}; - -enum RayFlagsMask { - RayFlagsMaskNone = 0, - RayFlagsOpaqueKHRMask = 0x00000001, - RayFlagsNoOpaqueKHRMask = 0x00000002, - RayFlagsTerminateOnFirstHitKHRMask = 0x00000004, - RayFlagsSkipClosestHitShaderKHRMask = 0x00000008, - RayFlagsCullBackFacingTrianglesKHRMask = 0x00000010, - RayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020, - RayFlagsCullOpaqueKHRMask = 0x00000040, - RayFlagsCullNoOpaqueKHRMask = 0x00000080, - RayFlagsSkipTrianglesKHRMask = 0x00000100, - RayFlagsSkipAABBsKHRMask = 0x00000200, -}; - -enum RayQueryIntersection { - RayQueryIntersectionRayQueryCandidateIntersectionKHR = 0, - RayQueryIntersectionRayQueryCommittedIntersectionKHR = 1, - RayQueryIntersectionMax = 0x7fffffff, -}; - -enum RayQueryCommittedIntersectionType { - RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0, - RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1, - RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2, - RayQueryCommittedIntersectionTypeMax = 0x7fffffff, -}; - -enum RayQueryCandidateIntersectionType { - RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0, - RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1, - RayQueryCandidateIntersectionTypeMax = 0x7fffffff, -}; - -enum FragmentShadingRateShift { - FragmentShadingRateVertical2PixelsShift = 0, - FragmentShadingRateVertical4PixelsShift = 1, - FragmentShadingRateHorizontal2PixelsShift = 2, - FragmentShadingRateHorizontal4PixelsShift = 3, - FragmentShadingRateMax = 0x7fffffff, -}; - -enum FragmentShadingRateMask { - FragmentShadingRateMaskNone = 0, - FragmentShadingRateVertical2PixelsMask = 0x00000001, - FragmentShadingRateVertical4PixelsMask = 0x00000002, - FragmentShadingRateHorizontal2PixelsMask = 0x00000004, - FragmentShadingRateHorizontal4PixelsMask = 0x00000008, -}; - -enum FPDenormMode { - FPDenormModePreserve = 0, - FPDenormModeFlushToZero = 1, - FPDenormModeMax = 0x7fffffff, -}; - -enum FPOperationMode { - FPOperationModeIEEE = 0, - FPOperationModeALT = 1, - FPOperationModeMax = 0x7fffffff, -}; - -enum Op { - OpNop = 0, - OpUndef = 1, - OpSourceContinued = 2, - OpSource = 3, - OpSourceExtension = 4, - OpName = 5, - OpMemberName = 6, - OpString = 7, - OpLine = 8, - OpExtension = 10, - OpExtInstImport = 11, - OpExtInst = 12, - OpMemoryModel = 14, - OpEntryPoint = 15, - OpExecutionMode = 16, - OpCapability = 17, - OpTypeVoid = 19, - OpTypeBool = 20, - OpTypeInt = 21, - OpTypeFloat = 22, - OpTypeVector = 23, - OpTypeMatrix = 24, - OpTypeImage = 25, - OpTypeSampler = 26, - OpTypeSampledImage = 27, - OpTypeArray = 28, - OpTypeRuntimeArray = 29, - OpTypeStruct = 30, - OpTypeOpaque = 31, - OpTypePointer = 32, - OpTypeFunction = 33, - OpTypeEvent = 34, - OpTypeDeviceEvent = 35, - OpTypeReserveId = 36, - OpTypeQueue = 37, - OpTypePipe = 38, - OpTypeForwardPointer = 39, - OpConstantTrue = 41, - OpConstantFalse = 42, - OpConstant = 43, - OpConstantComposite = 44, - OpConstantSampler = 45, - OpConstantNull = 46, - OpSpecConstantTrue = 48, - OpSpecConstantFalse = 49, - OpSpecConstant = 50, - OpSpecConstantComposite = 51, - OpSpecConstantOp = 52, - OpFunction = 54, - OpFunctionParameter = 55, - OpFunctionEnd = 56, - OpFunctionCall = 57, - OpVariable = 59, - OpImageTexelPointer = 60, - OpLoad = 61, - OpStore = 62, - OpCopyMemory = 63, - OpCopyMemorySized = 64, - OpAccessChain = 65, - OpInBoundsAccessChain = 66, - OpPtrAccessChain = 67, - OpArrayLength = 68, - OpGenericPtrMemSemantics = 69, - OpInBoundsPtrAccessChain = 70, - OpDecorate = 71, - OpMemberDecorate = 72, - OpDecorationGroup = 73, - OpGroupDecorate = 74, - OpGroupMemberDecorate = 75, - OpVectorExtractDynamic = 77, - OpVectorInsertDynamic = 78, - OpVectorShuffle = 79, - OpCompositeConstruct = 80, - OpCompositeExtract = 81, - OpCompositeInsert = 82, - OpCopyObject = 83, - OpTranspose = 84, - OpSampledImage = 86, - OpImageSampleImplicitLod = 87, - OpImageSampleExplicitLod = 88, - OpImageSampleDrefImplicitLod = 89, - OpImageSampleDrefExplicitLod = 90, - OpImageSampleProjImplicitLod = 91, - OpImageSampleProjExplicitLod = 92, - OpImageSampleProjDrefImplicitLod = 93, - OpImageSampleProjDrefExplicitLod = 94, - OpImageFetch = 95, - OpImageGather = 96, - OpImageDrefGather = 97, - OpImageRead = 98, - OpImageWrite = 99, - OpImage = 100, - OpImageQueryFormat = 101, - OpImageQueryOrder = 102, - OpImageQuerySizeLod = 103, - OpImageQuerySize = 104, - OpImageQueryLod = 105, - OpImageQueryLevels = 106, - OpImageQuerySamples = 107, - OpConvertFToU = 109, - OpConvertFToS = 110, - OpConvertSToF = 111, - OpConvertUToF = 112, - OpUConvert = 113, - OpSConvert = 114, - OpFConvert = 115, - OpQuantizeToF16 = 116, - OpConvertPtrToU = 117, - OpSatConvertSToU = 118, - OpSatConvertUToS = 119, - OpConvertUToPtr = 120, - OpPtrCastToGeneric = 121, - OpGenericCastToPtr = 122, - OpGenericCastToPtrExplicit = 123, - OpBitcast = 124, - OpSNegate = 126, - OpFNegate = 127, - OpIAdd = 128, - OpFAdd = 129, - OpISub = 130, - OpFSub = 131, - OpIMul = 132, - OpFMul = 133, - OpUDiv = 134, - OpSDiv = 135, - OpFDiv = 136, - OpUMod = 137, - OpSRem = 138, - OpSMod = 139, - OpFRem = 140, - OpFMod = 141, - OpVectorTimesScalar = 142, - OpMatrixTimesScalar = 143, - OpVectorTimesMatrix = 144, - OpMatrixTimesVector = 145, - OpMatrixTimesMatrix = 146, - OpOuterProduct = 147, - OpDot = 148, - OpIAddCarry = 149, - OpISubBorrow = 150, - OpUMulExtended = 151, - OpSMulExtended = 152, - OpAny = 154, - OpAll = 155, - OpIsNan = 156, - OpIsInf = 157, - OpIsFinite = 158, - OpIsNormal = 159, - OpSignBitSet = 160, - OpLessOrGreater = 161, - OpOrdered = 162, - OpUnordered = 163, - OpLogicalEqual = 164, - OpLogicalNotEqual = 165, - OpLogicalOr = 166, - OpLogicalAnd = 167, - OpLogicalNot = 168, - OpSelect = 169, - OpIEqual = 170, - OpINotEqual = 171, - OpUGreaterThan = 172, - OpSGreaterThan = 173, - OpUGreaterThanEqual = 174, - OpSGreaterThanEqual = 175, - OpULessThan = 176, - OpSLessThan = 177, - OpULessThanEqual = 178, - OpSLessThanEqual = 179, - OpFOrdEqual = 180, - OpFUnordEqual = 181, - OpFOrdNotEqual = 182, - OpFUnordNotEqual = 183, - OpFOrdLessThan = 184, - OpFUnordLessThan = 185, - OpFOrdGreaterThan = 186, - OpFUnordGreaterThan = 187, - OpFOrdLessThanEqual = 188, - OpFUnordLessThanEqual = 189, - OpFOrdGreaterThanEqual = 190, - OpFUnordGreaterThanEqual = 191, - OpShiftRightLogical = 194, - OpShiftRightArithmetic = 195, - OpShiftLeftLogical = 196, - OpBitwiseOr = 197, - OpBitwiseXor = 198, - OpBitwiseAnd = 199, - OpNot = 200, - OpBitFieldInsert = 201, - OpBitFieldSExtract = 202, - OpBitFieldUExtract = 203, - OpBitReverse = 204, - OpBitCount = 205, - OpDPdx = 207, - OpDPdy = 208, - OpFwidth = 209, - OpDPdxFine = 210, - OpDPdyFine = 211, - OpFwidthFine = 212, - OpDPdxCoarse = 213, - OpDPdyCoarse = 214, - OpFwidthCoarse = 215, - OpEmitVertex = 218, - OpEndPrimitive = 219, - OpEmitStreamVertex = 220, - OpEndStreamPrimitive = 221, - OpControlBarrier = 224, - OpMemoryBarrier = 225, - OpAtomicLoad = 227, - OpAtomicStore = 228, - OpAtomicExchange = 229, - OpAtomicCompareExchange = 230, - OpAtomicCompareExchangeWeak = 231, - OpAtomicIIncrement = 232, - OpAtomicIDecrement = 233, - OpAtomicIAdd = 234, - OpAtomicISub = 235, - OpAtomicSMin = 236, - OpAtomicUMin = 237, - OpAtomicSMax = 238, - OpAtomicUMax = 239, - OpAtomicAnd = 240, - OpAtomicOr = 241, - OpAtomicXor = 242, - OpPhi = 245, - OpLoopMerge = 246, - OpSelectionMerge = 247, - OpLabel = 248, - OpBranch = 249, - OpBranchConditional = 250, - OpSwitch = 251, - OpKill = 252, - OpReturn = 253, - OpReturnValue = 254, - OpUnreachable = 255, - OpLifetimeStart = 256, - OpLifetimeStop = 257, - OpGroupAsyncCopy = 259, - OpGroupWaitEvents = 260, - OpGroupAll = 261, - OpGroupAny = 262, - OpGroupBroadcast = 263, - OpGroupIAdd = 264, - OpGroupFAdd = 265, - OpGroupFMin = 266, - OpGroupUMin = 267, - OpGroupSMin = 268, - OpGroupFMax = 269, - OpGroupUMax = 270, - OpGroupSMax = 271, - OpReadPipe = 274, - OpWritePipe = 275, - OpReservedReadPipe = 276, - OpReservedWritePipe = 277, - OpReserveReadPipePackets = 278, - OpReserveWritePipePackets = 279, - OpCommitReadPipe = 280, - OpCommitWritePipe = 281, - OpIsValidReserveId = 282, - OpGetNumPipePackets = 283, - OpGetMaxPipePackets = 284, - OpGroupReserveReadPipePackets = 285, - OpGroupReserveWritePipePackets = 286, - OpGroupCommitReadPipe = 287, - OpGroupCommitWritePipe = 288, - OpEnqueueMarker = 291, - OpEnqueueKernel = 292, - OpGetKernelNDrangeSubGroupCount = 293, - OpGetKernelNDrangeMaxSubGroupSize = 294, - OpGetKernelWorkGroupSize = 295, - OpGetKernelPreferredWorkGroupSizeMultiple = 296, - OpRetainEvent = 297, - OpReleaseEvent = 298, - OpCreateUserEvent = 299, - OpIsValidEvent = 300, - OpSetUserEventStatus = 301, - OpCaptureEventProfilingInfo = 302, - OpGetDefaultQueue = 303, - OpBuildNDRange = 304, - OpImageSparseSampleImplicitLod = 305, - OpImageSparseSampleExplicitLod = 306, - OpImageSparseSampleDrefImplicitLod = 307, - OpImageSparseSampleDrefExplicitLod = 308, - OpImageSparseSampleProjImplicitLod = 309, - OpImageSparseSampleProjExplicitLod = 310, - OpImageSparseSampleProjDrefImplicitLod = 311, - OpImageSparseSampleProjDrefExplicitLod = 312, - OpImageSparseFetch = 313, - OpImageSparseGather = 314, - OpImageSparseDrefGather = 315, - OpImageSparseTexelsResident = 316, - OpNoLine = 317, - OpAtomicFlagTestAndSet = 318, - OpAtomicFlagClear = 319, - OpImageSparseRead = 320, - OpSizeOf = 321, - OpTypePipeStorage = 322, - OpConstantPipeStorage = 323, - OpCreatePipeFromPipeStorage = 324, - OpGetKernelLocalSizeForSubgroupCount = 325, - OpGetKernelMaxNumSubgroups = 326, - OpTypeNamedBarrier = 327, - OpNamedBarrierInitialize = 328, - OpMemoryNamedBarrier = 329, - OpModuleProcessed = 330, - OpExecutionModeId = 331, - OpDecorateId = 332, - OpGroupNonUniformElect = 333, - OpGroupNonUniformAll = 334, - OpGroupNonUniformAny = 335, - OpGroupNonUniformAllEqual = 336, - OpGroupNonUniformBroadcast = 337, - OpGroupNonUniformBroadcastFirst = 338, - OpGroupNonUniformBallot = 339, - OpGroupNonUniformInverseBallot = 340, - OpGroupNonUniformBallotBitExtract = 341, - OpGroupNonUniformBallotBitCount = 342, - OpGroupNonUniformBallotFindLSB = 343, - OpGroupNonUniformBallotFindMSB = 344, - OpGroupNonUniformShuffle = 345, - OpGroupNonUniformShuffleXor = 346, - OpGroupNonUniformShuffleUp = 347, - OpGroupNonUniformShuffleDown = 348, - OpGroupNonUniformIAdd = 349, - OpGroupNonUniformFAdd = 350, - OpGroupNonUniformIMul = 351, - OpGroupNonUniformFMul = 352, - OpGroupNonUniformSMin = 353, - OpGroupNonUniformUMin = 354, - OpGroupNonUniformFMin = 355, - OpGroupNonUniformSMax = 356, - OpGroupNonUniformUMax = 357, - OpGroupNonUniformFMax = 358, - OpGroupNonUniformBitwiseAnd = 359, - OpGroupNonUniformBitwiseOr = 360, - OpGroupNonUniformBitwiseXor = 361, - OpGroupNonUniformLogicalAnd = 362, - OpGroupNonUniformLogicalOr = 363, - OpGroupNonUniformLogicalXor = 364, - OpGroupNonUniformQuadBroadcast = 365, - OpGroupNonUniformQuadSwap = 366, - OpCopyLogical = 400, - OpPtrEqual = 401, - OpPtrNotEqual = 402, - OpPtrDiff = 403, - OpTerminateInvocation = 4416, - OpSubgroupBallotKHR = 4421, - OpSubgroupFirstInvocationKHR = 4422, - OpSubgroupAllKHR = 4428, - OpSubgroupAnyKHR = 4429, - OpSubgroupAllEqualKHR = 4430, - OpSubgroupReadInvocationKHR = 4432, - OpTraceRayKHR = 4445, - OpExecuteCallableKHR = 4446, - OpConvertUToAccelerationStructureKHR = 4447, - OpIgnoreIntersectionKHR = 4448, - OpTerminateRayKHR = 4449, - OpTypeRayQueryKHR = 4472, - OpRayQueryInitializeKHR = 4473, - OpRayQueryTerminateKHR = 4474, - OpRayQueryGenerateIntersectionKHR = 4475, - OpRayQueryConfirmIntersectionKHR = 4476, - OpRayQueryProceedKHR = 4477, - OpRayQueryGetIntersectionTypeKHR = 4479, - OpGroupIAddNonUniformAMD = 5000, - OpGroupFAddNonUniformAMD = 5001, - OpGroupFMinNonUniformAMD = 5002, - OpGroupUMinNonUniformAMD = 5003, - OpGroupSMinNonUniformAMD = 5004, - OpGroupFMaxNonUniformAMD = 5005, - OpGroupUMaxNonUniformAMD = 5006, - OpGroupSMaxNonUniformAMD = 5007, - OpFragmentMaskFetchAMD = 5011, - OpFragmentFetchAMD = 5012, - OpReadClockKHR = 5056, - OpImageSampleFootprintNV = 5283, - OpGroupNonUniformPartitionNV = 5296, - OpWritePackedPrimitiveIndices4x8NV = 5299, - OpReportIntersectionKHR = 5334, - OpReportIntersectionNV = 5334, - OpIgnoreIntersectionNV = 5335, - OpTerminateRayNV = 5336, - OpTraceNV = 5337, - OpTraceMotionNV = 5338, - OpTraceRayMotionNV = 5339, - OpTypeAccelerationStructureKHR = 5341, - OpTypeAccelerationStructureNV = 5341, - OpExecuteCallableNV = 5344, - OpTypeCooperativeMatrixNV = 5358, - OpCooperativeMatrixLoadNV = 5359, - OpCooperativeMatrixStoreNV = 5360, - OpCooperativeMatrixMulAddNV = 5361, - OpCooperativeMatrixLengthNV = 5362, - OpBeginInvocationInterlockEXT = 5364, - OpEndInvocationInterlockEXT = 5365, - OpDemoteToHelperInvocationEXT = 5380, - OpIsHelperInvocationEXT = 5381, - OpSubgroupShuffleINTEL = 5571, - OpSubgroupShuffleDownINTEL = 5572, - OpSubgroupShuffleUpINTEL = 5573, - OpSubgroupShuffleXorINTEL = 5574, - OpSubgroupBlockReadINTEL = 5575, - OpSubgroupBlockWriteINTEL = 5576, - OpSubgroupImageBlockReadINTEL = 5577, - OpSubgroupImageBlockWriteINTEL = 5578, - OpSubgroupImageMediaBlockReadINTEL = 5580, - OpSubgroupImageMediaBlockWriteINTEL = 5581, - OpUCountLeadingZerosINTEL = 5585, - OpUCountTrailingZerosINTEL = 5586, - OpAbsISubINTEL = 5587, - OpAbsUSubINTEL = 5588, - OpIAddSatINTEL = 5589, - OpUAddSatINTEL = 5590, - OpIAverageINTEL = 5591, - OpUAverageINTEL = 5592, - OpIAverageRoundedINTEL = 5593, - OpUAverageRoundedINTEL = 5594, - OpISubSatINTEL = 5595, - OpUSubSatINTEL = 5596, - OpIMul32x16INTEL = 5597, - OpUMul32x16INTEL = 5598, - OpConstFunctionPointerINTEL = 5600, - OpFunctionPointerCallINTEL = 5601, - OpAsmTargetINTEL = 5609, - OpAsmINTEL = 5610, - OpAsmCallINTEL = 5611, - OpAtomicFMinEXT = 5614, - OpAtomicFMaxEXT = 5615, - OpAssumeTrueKHR = 5630, - OpExpectKHR = 5631, - OpDecorateString = 5632, - OpDecorateStringGOOGLE = 5632, - OpMemberDecorateString = 5633, - OpMemberDecorateStringGOOGLE = 5633, - OpVmeImageINTEL = 5699, - OpTypeVmeImageINTEL = 5700, - OpTypeAvcImePayloadINTEL = 5701, - OpTypeAvcRefPayloadINTEL = 5702, - OpTypeAvcSicPayloadINTEL = 5703, - OpTypeAvcMcePayloadINTEL = 5704, - OpTypeAvcMceResultINTEL = 5705, - OpTypeAvcImeResultINTEL = 5706, - OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, - OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, - OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, - OpTypeAvcImeDualReferenceStreaminINTEL = 5710, - OpTypeAvcRefResultINTEL = 5711, - OpTypeAvcSicResultINTEL = 5712, - OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, - OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, - OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, - OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, - OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, - OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, - OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, - OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, - OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, - OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, - OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, - OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, - OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, - OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, - OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, - OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, - OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, - OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, - OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, - OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, - OpSubgroupAvcMceConvertToImeResultINTEL = 5733, - OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, - OpSubgroupAvcMceConvertToRefResultINTEL = 5735, - OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, - OpSubgroupAvcMceConvertToSicResultINTEL = 5737, - OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, - OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, - OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, - OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, - OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, - OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, - OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, - OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, - OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, - OpSubgroupAvcImeInitializeINTEL = 5747, - OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, - OpSubgroupAvcImeSetDualReferenceINTEL = 5749, - OpSubgroupAvcImeRefWindowSizeINTEL = 5750, - OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, - OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, - OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, - OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, - OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, - OpSubgroupAvcImeSetWeightedSadINTEL = 5756, - OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, - OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, - OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, - OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, - OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, - OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, - OpSubgroupAvcImeConvertToMceResultINTEL = 5765, - OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, - OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, - OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, - OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, - OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, - OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, - OpSubgroupAvcImeGetBorderReachedINTEL = 5776, - OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, - OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, - OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, - OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, - OpSubgroupAvcFmeInitializeINTEL = 5781, - OpSubgroupAvcBmeInitializeINTEL = 5782, - OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, - OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, - OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, - OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, - OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, - OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, - OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, - OpSubgroupAvcRefConvertToMceResultINTEL = 5790, - OpSubgroupAvcSicInitializeINTEL = 5791, - OpSubgroupAvcSicConfigureSkcINTEL = 5792, - OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, - OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, - OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, - OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, - OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, - OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, - OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, - OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, - OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, - OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, - OpSubgroupAvcSicEvaluateIpeINTEL = 5803, - OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, - OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, - OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, - OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, - OpSubgroupAvcSicConvertToMceResultINTEL = 5808, - OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, - OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, - OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, - OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, - OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, - OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, - OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, - OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, - OpVariableLengthArrayINTEL = 5818, - OpSaveMemoryINTEL = 5819, - OpRestoreMemoryINTEL = 5820, - OpLoopControlINTEL = 5887, - OpPtrCastToCrossWorkgroupINTEL = 5934, - OpCrossWorkgroupCastToPtrINTEL = 5938, - OpReadPipeBlockingINTEL = 5946, - OpWritePipeBlockingINTEL = 5947, - OpFPGARegINTEL = 5949, - OpRayQueryGetRayTMinKHR = 6016, - OpRayQueryGetRayFlagsKHR = 6017, - OpRayQueryGetIntersectionTKHR = 6018, - OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, - OpRayQueryGetIntersectionInstanceIdKHR = 6020, - OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, - OpRayQueryGetIntersectionGeometryIndexKHR = 6022, - OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, - OpRayQueryGetIntersectionBarycentricsKHR = 6024, - OpRayQueryGetIntersectionFrontFaceKHR = 6025, - OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, - OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, - OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, - OpRayQueryGetWorldRayDirectionKHR = 6029, - OpRayQueryGetWorldRayOriginKHR = 6030, - OpRayQueryGetIntersectionObjectToWorldKHR = 6031, - OpRayQueryGetIntersectionWorldToObjectKHR = 6032, - OpAtomicFAddEXT = 6035, - OpTypeBufferSurfaceINTEL = 6086, - OpTypeStructContinuedINTEL = 6090, - OpConstantCompositeContinuedINTEL = 6091, - OpSpecConstantCompositeContinuedINTEL = 6092, - OpMax = 0x7fffffff, -}; - -#ifdef SPV_ENABLE_UTILITY_CODE -inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { - *hasResult = *hasResultType = false; - switch (opcode) { - default: /* unknown opcode */ break; - case OpNop: *hasResult = false; *hasResultType = false; break; - case OpUndef: *hasResult = true; *hasResultType = true; break; - case OpSourceContinued: *hasResult = false; *hasResultType = false; break; - case OpSource: *hasResult = false; *hasResultType = false; break; - case OpSourceExtension: *hasResult = false; *hasResultType = false; break; - case OpName: *hasResult = false; *hasResultType = false; break; - case OpMemberName: *hasResult = false; *hasResultType = false; break; - case OpString: *hasResult = true; *hasResultType = false; break; - case OpLine: *hasResult = false; *hasResultType = false; break; - case OpExtension: *hasResult = false; *hasResultType = false; break; - case OpExtInstImport: *hasResult = true; *hasResultType = false; break; - case OpExtInst: *hasResult = true; *hasResultType = true; break; - case OpMemoryModel: *hasResult = false; *hasResultType = false; break; - case OpEntryPoint: *hasResult = false; *hasResultType = false; break; - case OpExecutionMode: *hasResult = false; *hasResultType = false; break; - case OpCapability: *hasResult = false; *hasResultType = false; break; - case OpTypeVoid: *hasResult = true; *hasResultType = false; break; - case OpTypeBool: *hasResult = true; *hasResultType = false; break; - case OpTypeInt: *hasResult = true; *hasResultType = false; break; - case OpTypeFloat: *hasResult = true; *hasResultType = false; break; - case OpTypeVector: *hasResult = true; *hasResultType = false; break; - case OpTypeMatrix: *hasResult = true; *hasResultType = false; break; - case OpTypeImage: *hasResult = true; *hasResultType = false; break; - case OpTypeSampler: *hasResult = true; *hasResultType = false; break; - case OpTypeSampledImage: *hasResult = true; *hasResultType = false; break; - case OpTypeArray: *hasResult = true; *hasResultType = false; break; - case OpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; - case OpTypeStruct: *hasResult = true; *hasResultType = false; break; - case OpTypeOpaque: *hasResult = true; *hasResultType = false; break; - case OpTypePointer: *hasResult = true; *hasResultType = false; break; - case OpTypeFunction: *hasResult = true; *hasResultType = false; break; - case OpTypeEvent: *hasResult = true; *hasResultType = false; break; - case OpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; - case OpTypeReserveId: *hasResult = true; *hasResultType = false; break; - case OpTypeQueue: *hasResult = true; *hasResultType = false; break; - case OpTypePipe: *hasResult = true; *hasResultType = false; break; - case OpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; - case OpConstantTrue: *hasResult = true; *hasResultType = true; break; - case OpConstantFalse: *hasResult = true; *hasResultType = true; break; - case OpConstant: *hasResult = true; *hasResultType = true; break; - case OpConstantComposite: *hasResult = true; *hasResultType = true; break; - case OpConstantSampler: *hasResult = true; *hasResultType = true; break; - case OpConstantNull: *hasResult = true; *hasResultType = true; break; - case OpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; - case OpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; - case OpSpecConstant: *hasResult = true; *hasResultType = true; break; - case OpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; - case OpSpecConstantOp: *hasResult = true; *hasResultType = true; break; - case OpFunction: *hasResult = true; *hasResultType = true; break; - case OpFunctionParameter: *hasResult = true; *hasResultType = true; break; - case OpFunctionEnd: *hasResult = false; *hasResultType = false; break; - case OpFunctionCall: *hasResult = true; *hasResultType = true; break; - case OpVariable: *hasResult = true; *hasResultType = true; break; - case OpImageTexelPointer: *hasResult = true; *hasResultType = true; break; - case OpLoad: *hasResult = true; *hasResultType = true; break; - case OpStore: *hasResult = false; *hasResultType = false; break; - case OpCopyMemory: *hasResult = false; *hasResultType = false; break; - case OpCopyMemorySized: *hasResult = false; *hasResultType = false; break; - case OpAccessChain: *hasResult = true; *hasResultType = true; break; - case OpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; - case OpPtrAccessChain: *hasResult = true; *hasResultType = true; break; - case OpArrayLength: *hasResult = true; *hasResultType = true; break; - case OpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; - case OpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; - case OpDecorate: *hasResult = false; *hasResultType = false; break; - case OpMemberDecorate: *hasResult = false; *hasResultType = false; break; - case OpDecorationGroup: *hasResult = true; *hasResultType = false; break; - case OpGroupDecorate: *hasResult = false; *hasResultType = false; break; - case OpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; - case OpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; - case OpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; - case OpVectorShuffle: *hasResult = true; *hasResultType = true; break; - case OpCompositeConstruct: *hasResult = true; *hasResultType = true; break; - case OpCompositeExtract: *hasResult = true; *hasResultType = true; break; - case OpCompositeInsert: *hasResult = true; *hasResultType = true; break; - case OpCopyObject: *hasResult = true; *hasResultType = true; break; - case OpTranspose: *hasResult = true; *hasResultType = true; break; - case OpSampledImage: *hasResult = true; *hasResultType = true; break; - case OpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageFetch: *hasResult = true; *hasResultType = true; break; - case OpImageGather: *hasResult = true; *hasResultType = true; break; - case OpImageDrefGather: *hasResult = true; *hasResultType = true; break; - case OpImageRead: *hasResult = true; *hasResultType = true; break; - case OpImageWrite: *hasResult = false; *hasResultType = false; break; - case OpImage: *hasResult = true; *hasResultType = true; break; - case OpImageQueryFormat: *hasResult = true; *hasResultType = true; break; - case OpImageQueryOrder: *hasResult = true; *hasResultType = true; break; - case OpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; - case OpImageQuerySize: *hasResult = true; *hasResultType = true; break; - case OpImageQueryLod: *hasResult = true; *hasResultType = true; break; - case OpImageQueryLevels: *hasResult = true; *hasResultType = true; break; - case OpImageQuerySamples: *hasResult = true; *hasResultType = true; break; - case OpConvertFToU: *hasResult = true; *hasResultType = true; break; - case OpConvertFToS: *hasResult = true; *hasResultType = true; break; - case OpConvertSToF: *hasResult = true; *hasResultType = true; break; - case OpConvertUToF: *hasResult = true; *hasResultType = true; break; - case OpUConvert: *hasResult = true; *hasResultType = true; break; - case OpSConvert: *hasResult = true; *hasResultType = true; break; - case OpFConvert: *hasResult = true; *hasResultType = true; break; - case OpQuantizeToF16: *hasResult = true; *hasResultType = true; break; - case OpConvertPtrToU: *hasResult = true; *hasResultType = true; break; - case OpSatConvertSToU: *hasResult = true; *hasResultType = true; break; - case OpSatConvertUToS: *hasResult = true; *hasResultType = true; break; - case OpConvertUToPtr: *hasResult = true; *hasResultType = true; break; - case OpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; - case OpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; - case OpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; - case OpBitcast: *hasResult = true; *hasResultType = true; break; - case OpSNegate: *hasResult = true; *hasResultType = true; break; - case OpFNegate: *hasResult = true; *hasResultType = true; break; - case OpIAdd: *hasResult = true; *hasResultType = true; break; - case OpFAdd: *hasResult = true; *hasResultType = true; break; - case OpISub: *hasResult = true; *hasResultType = true; break; - case OpFSub: *hasResult = true; *hasResultType = true; break; - case OpIMul: *hasResult = true; *hasResultType = true; break; - case OpFMul: *hasResult = true; *hasResultType = true; break; - case OpUDiv: *hasResult = true; *hasResultType = true; break; - case OpSDiv: *hasResult = true; *hasResultType = true; break; - case OpFDiv: *hasResult = true; *hasResultType = true; break; - case OpUMod: *hasResult = true; *hasResultType = true; break; - case OpSRem: *hasResult = true; *hasResultType = true; break; - case OpSMod: *hasResult = true; *hasResultType = true; break; - case OpFRem: *hasResult = true; *hasResultType = true; break; - case OpFMod: *hasResult = true; *hasResultType = true; break; - case OpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; - case OpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; - case OpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; - case OpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; - case OpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; - case OpOuterProduct: *hasResult = true; *hasResultType = true; break; - case OpDot: *hasResult = true; *hasResultType = true; break; - case OpIAddCarry: *hasResult = true; *hasResultType = true; break; - case OpISubBorrow: *hasResult = true; *hasResultType = true; break; - case OpUMulExtended: *hasResult = true; *hasResultType = true; break; - case OpSMulExtended: *hasResult = true; *hasResultType = true; break; - case OpAny: *hasResult = true; *hasResultType = true; break; - case OpAll: *hasResult = true; *hasResultType = true; break; - case OpIsNan: *hasResult = true; *hasResultType = true; break; - case OpIsInf: *hasResult = true; *hasResultType = true; break; - case OpIsFinite: *hasResult = true; *hasResultType = true; break; - case OpIsNormal: *hasResult = true; *hasResultType = true; break; - case OpSignBitSet: *hasResult = true; *hasResultType = true; break; - case OpLessOrGreater: *hasResult = true; *hasResultType = true; break; - case OpOrdered: *hasResult = true; *hasResultType = true; break; - case OpUnordered: *hasResult = true; *hasResultType = true; break; - case OpLogicalEqual: *hasResult = true; *hasResultType = true; break; - case OpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; - case OpLogicalOr: *hasResult = true; *hasResultType = true; break; - case OpLogicalAnd: *hasResult = true; *hasResultType = true; break; - case OpLogicalNot: *hasResult = true; *hasResultType = true; break; - case OpSelect: *hasResult = true; *hasResultType = true; break; - case OpIEqual: *hasResult = true; *hasResultType = true; break; - case OpINotEqual: *hasResult = true; *hasResultType = true; break; - case OpUGreaterThan: *hasResult = true; *hasResultType = true; break; - case OpSGreaterThan: *hasResult = true; *hasResultType = true; break; - case OpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case OpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case OpULessThan: *hasResult = true; *hasResultType = true; break; - case OpSLessThan: *hasResult = true; *hasResultType = true; break; - case OpULessThanEqual: *hasResult = true; *hasResultType = true; break; - case OpSLessThanEqual: *hasResult = true; *hasResultType = true; break; - case OpFOrdEqual: *hasResult = true; *hasResultType = true; break; - case OpFUnordEqual: *hasResult = true; *hasResultType = true; break; - case OpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; - case OpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; - case OpFOrdLessThan: *hasResult = true; *hasResultType = true; break; - case OpFUnordLessThan: *hasResult = true; *hasResultType = true; break; - case OpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; - case OpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; - case OpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; - case OpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; - case OpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case OpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case OpShiftRightLogical: *hasResult = true; *hasResultType = true; break; - case OpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; - case OpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; - case OpBitwiseOr: *hasResult = true; *hasResultType = true; break; - case OpBitwiseXor: *hasResult = true; *hasResultType = true; break; - case OpBitwiseAnd: *hasResult = true; *hasResultType = true; break; - case OpNot: *hasResult = true; *hasResultType = true; break; - case OpBitFieldInsert: *hasResult = true; *hasResultType = true; break; - case OpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; - case OpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; - case OpBitReverse: *hasResult = true; *hasResultType = true; break; - case OpBitCount: *hasResult = true; *hasResultType = true; break; - case OpDPdx: *hasResult = true; *hasResultType = true; break; - case OpDPdy: *hasResult = true; *hasResultType = true; break; - case OpFwidth: *hasResult = true; *hasResultType = true; break; - case OpDPdxFine: *hasResult = true; *hasResultType = true; break; - case OpDPdyFine: *hasResult = true; *hasResultType = true; break; - case OpFwidthFine: *hasResult = true; *hasResultType = true; break; - case OpDPdxCoarse: *hasResult = true; *hasResultType = true; break; - case OpDPdyCoarse: *hasResult = true; *hasResultType = true; break; - case OpFwidthCoarse: *hasResult = true; *hasResultType = true; break; - case OpEmitVertex: *hasResult = false; *hasResultType = false; break; - case OpEndPrimitive: *hasResult = false; *hasResultType = false; break; - case OpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; - case OpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; - case OpControlBarrier: *hasResult = false; *hasResultType = false; break; - case OpMemoryBarrier: *hasResult = false; *hasResultType = false; break; - case OpAtomicLoad: *hasResult = true; *hasResultType = true; break; - case OpAtomicStore: *hasResult = false; *hasResultType = false; break; - case OpAtomicExchange: *hasResult = true; *hasResultType = true; break; - case OpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; - case OpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; - case OpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; - case OpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; - case OpAtomicIAdd: *hasResult = true; *hasResultType = true; break; - case OpAtomicISub: *hasResult = true; *hasResultType = true; break; - case OpAtomicSMin: *hasResult = true; *hasResultType = true; break; - case OpAtomicUMin: *hasResult = true; *hasResultType = true; break; - case OpAtomicSMax: *hasResult = true; *hasResultType = true; break; - case OpAtomicUMax: *hasResult = true; *hasResultType = true; break; - case OpAtomicAnd: *hasResult = true; *hasResultType = true; break; - case OpAtomicOr: *hasResult = true; *hasResultType = true; break; - case OpAtomicXor: *hasResult = true; *hasResultType = true; break; - case OpPhi: *hasResult = true; *hasResultType = true; break; - case OpLoopMerge: *hasResult = false; *hasResultType = false; break; - case OpSelectionMerge: *hasResult = false; *hasResultType = false; break; - case OpLabel: *hasResult = true; *hasResultType = false; break; - case OpBranch: *hasResult = false; *hasResultType = false; break; - case OpBranchConditional: *hasResult = false; *hasResultType = false; break; - case OpSwitch: *hasResult = false; *hasResultType = false; break; - case OpKill: *hasResult = false; *hasResultType = false; break; - case OpReturn: *hasResult = false; *hasResultType = false; break; - case OpReturnValue: *hasResult = false; *hasResultType = false; break; - case OpUnreachable: *hasResult = false; *hasResultType = false; break; - case OpLifetimeStart: *hasResult = false; *hasResultType = false; break; - case OpLifetimeStop: *hasResult = false; *hasResultType = false; break; - case OpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; - case OpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; - case OpGroupAll: *hasResult = true; *hasResultType = true; break; - case OpGroupAny: *hasResult = true; *hasResultType = true; break; - case OpGroupBroadcast: *hasResult = true; *hasResultType = true; break; - case OpGroupIAdd: *hasResult = true; *hasResultType = true; break; - case OpGroupFAdd: *hasResult = true; *hasResultType = true; break; - case OpGroupFMin: *hasResult = true; *hasResultType = true; break; - case OpGroupUMin: *hasResult = true; *hasResultType = true; break; - case OpGroupSMin: *hasResult = true; *hasResultType = true; break; - case OpGroupFMax: *hasResult = true; *hasResultType = true; break; - case OpGroupUMax: *hasResult = true; *hasResultType = true; break; - case OpGroupSMax: *hasResult = true; *hasResultType = true; break; - case OpReadPipe: *hasResult = true; *hasResultType = true; break; - case OpWritePipe: *hasResult = true; *hasResultType = true; break; - case OpReservedReadPipe: *hasResult = true; *hasResultType = true; break; - case OpReservedWritePipe: *hasResult = true; *hasResultType = true; break; - case OpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; - case OpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; - case OpCommitReadPipe: *hasResult = false; *hasResultType = false; break; - case OpCommitWritePipe: *hasResult = false; *hasResultType = false; break; - case OpIsValidReserveId: *hasResult = true; *hasResultType = true; break; - case OpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; - case OpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; - case OpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; - case OpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; - case OpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; - case OpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; - case OpEnqueueMarker: *hasResult = true; *hasResultType = true; break; - case OpEnqueueKernel: *hasResult = true; *hasResultType = true; break; - case OpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; - case OpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; - case OpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; - case OpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; - case OpRetainEvent: *hasResult = false; *hasResultType = false; break; - case OpReleaseEvent: *hasResult = false; *hasResultType = false; break; - case OpCreateUserEvent: *hasResult = true; *hasResultType = true; break; - case OpIsValidEvent: *hasResult = true; *hasResultType = true; break; - case OpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; - case OpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; - case OpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; - case OpBuildNDRange: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case OpImageSparseFetch: *hasResult = true; *hasResultType = true; break; - case OpImageSparseGather: *hasResult = true; *hasResultType = true; break; - case OpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; - case OpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; - case OpNoLine: *hasResult = false; *hasResultType = false; break; - case OpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; - case OpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; - case OpImageSparseRead: *hasResult = true; *hasResultType = true; break; - case OpSizeOf: *hasResult = true; *hasResultType = true; break; - case OpTypePipeStorage: *hasResult = true; *hasResultType = false; break; - case OpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; - case OpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; - case OpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; - case OpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; - case OpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; - case OpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; - case OpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; - case OpModuleProcessed: *hasResult = false; *hasResultType = false; break; - case OpExecutionModeId: *hasResult = false; *hasResultType = false; break; - case OpDecorateId: *hasResult = false; *hasResultType = false; break; - case OpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; - case OpCopyLogical: *hasResult = true; *hasResultType = true; break; - case OpPtrEqual: *hasResult = true; *hasResultType = true; break; - case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; - case OpPtrDiff: *hasResult = true; *hasResultType = true; break; - case OpTerminateInvocation: *hasResult = false; *hasResultType = false; break; - case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; - case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; - case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; - case OpTraceRayKHR: *hasResult = false; *hasResultType = false; break; - case OpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; - case OpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break; - case OpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case OpTerminateRayKHR: *hasResult = false; *hasResultType = false; break; - case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; - case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; - case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; - case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case OpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case OpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break; - case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case OpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; - case OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; - case OpReadClockKHR: *hasResult = true; *hasResultType = true; break; - case OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; - case OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; - case OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; - case OpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; - case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; - case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; - case OpTraceNV: *hasResult = false; *hasResultType = false; break; - case OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; - case OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; - case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; - case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; - case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; - case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; - case OpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; - case OpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; - case OpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; - case OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; - case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; - case OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; - case OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; - case OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case OpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case OpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case OpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; - case OpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; - case OpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; - case OpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; - case OpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; - case OpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; - case OpIAverageINTEL: *hasResult = true; *hasResultType = true; break; - case OpUAverageINTEL: *hasResult = true; *hasResultType = true; break; - case OpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; - case OpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; - case OpISubSatINTEL: *hasResult = true; *hasResultType = true; break; - case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; - case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case OpConstFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; - case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; - case OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; - case OpAsmINTEL: *hasResult = true; *hasResultType = true; break; - case OpAsmCallINTEL: *hasResult = true; *hasResultType = true; break; - case OpAtomicFMinEXT: *hasResult = true; *hasResultType = true; break; - case OpAtomicFMaxEXT: *hasResult = true; *hasResultType = true; break; - case OpAssumeTrueKHR: *hasResult = false; *hasResultType = false; break; - case OpExpectKHR: *hasResult = true; *hasResultType = true; break; - case OpDecorateString: *hasResult = false; *hasResultType = false; break; - case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; - case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; - case OpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; - case OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; - case OpVariableLengthArrayINTEL: *hasResult = true; *hasResultType = true; break; - case OpSaveMemoryINTEL: *hasResult = true; *hasResultType = true; break; - case OpRestoreMemoryINTEL: *hasResult = false; *hasResultType = false; break; - case OpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; - case OpPtrCastToCrossWorkgroupINTEL: *hasResult = true; *hasResultType = true; break; - case OpCrossWorkgroupCastToPtrINTEL: *hasResult = true; *hasResultType = true; break; - case OpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; - case OpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; - case OpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; - case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; - case OpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; - case OpTypeBufferSurfaceINTEL: *hasResult = true; *hasResultType = false; break; - case OpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break; - case OpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; - case OpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; - } -} -#endif /* SPV_ENABLE_UTILITY_CODE */ - -// Overload operator| for mask bit combining - -inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } -inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); } -inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); } -inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); } -inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); } -inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } -inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } -inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } -inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); } -inline FragmentShadingRateMask operator|(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) | unsigned(b)); } - -} // end namespace spv - -#endif // #ifndef spirv_HPP +// Copyright (c) 2014-2024 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. + +// This header is automatically generated by the same tool that creates +// the Binary Section of the SPIR-V specification. + +// Enumeration tokens for SPIR-V, in various styles: +// C, C++, C++11, JSON, Lua, Python, C#, D, Beef +// +// - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL +// - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL +// - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL +// - Lua will use tables, e.g.: spv.SourceLanguage.GLSL +// - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] +// - C# will use enum classes in the Specification class located in the "Spv" namespace, +// e.g.: Spv.Specification.SourceLanguage.GLSL +// - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL +// - Beef will use enum classes in the Specification class located in the "Spv" namespace, +// e.g.: Spv.Specification.SourceLanguage.GLSL +// +// Some tokens act like mask values, which can be OR'd together, +// while others are mutually exclusive. The mask-like ones have +// "Mask" in their name, and a parallel enum that has the shift +// amount (1 << x) for each corresponding enumerant. + +#ifndef spirv_HPP +#define spirv_HPP + +namespace spv { + +typedef unsigned int Id; + +#define SPV_VERSION 0x10600 +#define SPV_REVISION 1 + +static const unsigned int MagicNumber = 0x07230203; +static const unsigned int Version = 0x00010600; +static const unsigned int Revision = 1; +static const unsigned int OpCodeMask = 0xffff; +static const unsigned int WordCountShift = 16; + +enum SourceLanguage { + SourceLanguageUnknown = 0, + SourceLanguageESSL = 1, + SourceLanguageGLSL = 2, + SourceLanguageOpenCL_C = 3, + SourceLanguageOpenCL_CPP = 4, + SourceLanguageHLSL = 5, + SourceLanguageCPP_for_OpenCL = 6, + SourceLanguageSYCL = 7, + SourceLanguageMax = 0x7fffffff, +}; + +enum ExecutionModel { + ExecutionModelVertex = 0, + ExecutionModelTessellationControl = 1, + ExecutionModelTessellationEvaluation = 2, + ExecutionModelGeometry = 3, + ExecutionModelFragment = 4, + ExecutionModelGLCompute = 5, + ExecutionModelKernel = 6, + ExecutionModelTaskNV = 5267, + ExecutionModelMeshNV = 5268, + ExecutionModelRayGenerationKHR = 5313, + ExecutionModelRayGenerationNV = 5313, + ExecutionModelIntersectionKHR = 5314, + ExecutionModelIntersectionNV = 5314, + ExecutionModelAnyHitKHR = 5315, + ExecutionModelAnyHitNV = 5315, + ExecutionModelClosestHitKHR = 5316, + ExecutionModelClosestHitNV = 5316, + ExecutionModelMissKHR = 5317, + ExecutionModelMissNV = 5317, + ExecutionModelCallableKHR = 5318, + ExecutionModelCallableNV = 5318, + ExecutionModelTaskEXT = 5364, + ExecutionModelMeshEXT = 5365, + ExecutionModelMax = 0x7fffffff, +}; + +enum AddressingModel { + AddressingModelLogical = 0, + AddressingModelPhysical32 = 1, + AddressingModelPhysical64 = 2, + AddressingModelPhysicalStorageBuffer64 = 5348, + AddressingModelPhysicalStorageBuffer64EXT = 5348, + AddressingModelMax = 0x7fffffff, +}; + +enum MemoryModel { + MemoryModelSimple = 0, + MemoryModelGLSL450 = 1, + MemoryModelOpenCL = 2, + MemoryModelVulkan = 3, + MemoryModelVulkanKHR = 3, + MemoryModelMax = 0x7fffffff, +}; + +enum ExecutionMode { + ExecutionModeInvocations = 0, + ExecutionModeSpacingEqual = 1, + ExecutionModeSpacingFractionalEven = 2, + ExecutionModeSpacingFractionalOdd = 3, + ExecutionModeVertexOrderCw = 4, + ExecutionModeVertexOrderCcw = 5, + ExecutionModePixelCenterInteger = 6, + ExecutionModeOriginUpperLeft = 7, + ExecutionModeOriginLowerLeft = 8, + ExecutionModeEarlyFragmentTests = 9, + ExecutionModePointMode = 10, + ExecutionModeXfb = 11, + ExecutionModeDepthReplacing = 12, + ExecutionModeDepthGreater = 14, + ExecutionModeDepthLess = 15, + ExecutionModeDepthUnchanged = 16, + ExecutionModeLocalSize = 17, + ExecutionModeLocalSizeHint = 18, + ExecutionModeInputPoints = 19, + ExecutionModeInputLines = 20, + ExecutionModeInputLinesAdjacency = 21, + ExecutionModeTriangles = 22, + ExecutionModeInputTrianglesAdjacency = 23, + ExecutionModeQuads = 24, + ExecutionModeIsolines = 25, + ExecutionModeOutputVertices = 26, + ExecutionModeOutputPoints = 27, + ExecutionModeOutputLineStrip = 28, + ExecutionModeOutputTriangleStrip = 29, + ExecutionModeVecTypeHint = 30, + ExecutionModeContractionOff = 31, + ExecutionModeInitializer = 33, + ExecutionModeFinalizer = 34, + ExecutionModeSubgroupSize = 35, + ExecutionModeSubgroupsPerWorkgroup = 36, + ExecutionModeSubgroupsPerWorkgroupId = 37, + ExecutionModeLocalSizeId = 38, + ExecutionModeLocalSizeHintId = 39, + ExecutionModeNonCoherentColorAttachmentReadEXT = 4169, + ExecutionModeNonCoherentDepthAttachmentReadEXT = 4170, + ExecutionModeNonCoherentStencilAttachmentReadEXT = 4171, + ExecutionModeSubgroupUniformControlFlowKHR = 4421, + ExecutionModePostDepthCoverage = 4446, + ExecutionModeDenormPreserve = 4459, + ExecutionModeDenormFlushToZero = 4460, + ExecutionModeSignedZeroInfNanPreserve = 4461, + ExecutionModeRoundingModeRTE = 4462, + ExecutionModeRoundingModeRTZ = 4463, + ExecutionModeEarlyAndLateFragmentTestsAMD = 5017, + ExecutionModeStencilRefReplacingEXT = 5027, + ExecutionModeStencilRefUnchangedFrontAMD = 5079, + ExecutionModeStencilRefGreaterFrontAMD = 5080, + ExecutionModeStencilRefLessFrontAMD = 5081, + ExecutionModeStencilRefUnchangedBackAMD = 5082, + ExecutionModeStencilRefGreaterBackAMD = 5083, + ExecutionModeStencilRefLessBackAMD = 5084, + ExecutionModeQuadDerivativesKHR = 5088, + ExecutionModeRequireFullQuadsKHR = 5089, + ExecutionModeOutputLinesEXT = 5269, + ExecutionModeOutputLinesNV = 5269, + ExecutionModeOutputPrimitivesEXT = 5270, + ExecutionModeOutputPrimitivesNV = 5270, + ExecutionModeDerivativeGroupQuadsNV = 5289, + ExecutionModeDerivativeGroupLinearNV = 5290, + ExecutionModeOutputTrianglesEXT = 5298, + ExecutionModeOutputTrianglesNV = 5298, + ExecutionModePixelInterlockOrderedEXT = 5366, + ExecutionModePixelInterlockUnorderedEXT = 5367, + ExecutionModeSampleInterlockOrderedEXT = 5368, + ExecutionModeSampleInterlockUnorderedEXT = 5369, + ExecutionModeShadingRateInterlockOrderedEXT = 5370, + ExecutionModeShadingRateInterlockUnorderedEXT = 5371, + ExecutionModeSharedLocalMemorySizeINTEL = 5618, + ExecutionModeRoundingModeRTPINTEL = 5620, + ExecutionModeRoundingModeRTNINTEL = 5621, + ExecutionModeFloatingPointModeALTINTEL = 5622, + ExecutionModeFloatingPointModeIEEEINTEL = 5623, + ExecutionModeMaxWorkgroupSizeINTEL = 5893, + ExecutionModeMaxWorkDimINTEL = 5894, + ExecutionModeNoGlobalOffsetINTEL = 5895, + ExecutionModeNumSIMDWorkitemsINTEL = 5896, + ExecutionModeSchedulerTargetFmaxMhzINTEL = 5903, + ExecutionModeMaximallyReconvergesKHR = 6023, + ExecutionModeStreamingInterfaceINTEL = 6154, + ExecutionModeNamedBarrierCountINTEL = 6417, + ExecutionModeMax = 0x7fffffff, +}; + +enum StorageClass { + StorageClassUniformConstant = 0, + StorageClassInput = 1, + StorageClassUniform = 2, + StorageClassOutput = 3, + StorageClassWorkgroup = 4, + StorageClassCrossWorkgroup = 5, + StorageClassPrivate = 6, + StorageClassFunction = 7, + StorageClassGeneric = 8, + StorageClassPushConstant = 9, + StorageClassAtomicCounter = 10, + StorageClassImage = 11, + StorageClassStorageBuffer = 12, + StorageClassTileImageEXT = 4172, + StorageClassCallableDataKHR = 5328, + StorageClassCallableDataNV = 5328, + StorageClassIncomingCallableDataKHR = 5329, + StorageClassIncomingCallableDataNV = 5329, + StorageClassRayPayloadKHR = 5338, + StorageClassRayPayloadNV = 5338, + StorageClassHitAttributeKHR = 5339, + StorageClassHitAttributeNV = 5339, + StorageClassIncomingRayPayloadKHR = 5342, + StorageClassIncomingRayPayloadNV = 5342, + StorageClassShaderRecordBufferKHR = 5343, + StorageClassShaderRecordBufferNV = 5343, + StorageClassPhysicalStorageBuffer = 5349, + StorageClassPhysicalStorageBufferEXT = 5349, + StorageClassHitObjectAttributeNV = 5385, + StorageClassTaskPayloadWorkgroupEXT = 5402, + StorageClassCodeSectionINTEL = 5605, + StorageClassDeviceOnlyINTEL = 5936, + StorageClassHostOnlyINTEL = 5937, + StorageClassMax = 0x7fffffff, +}; + +enum Dim { + Dim1D = 0, + Dim2D = 1, + Dim3D = 2, + DimCube = 3, + DimRect = 4, + DimBuffer = 5, + DimSubpassData = 6, + DimTileImageDataEXT = 4173, + DimMax = 0x7fffffff, +}; + +enum SamplerAddressingMode { + SamplerAddressingModeNone = 0, + SamplerAddressingModeClampToEdge = 1, + SamplerAddressingModeClamp = 2, + SamplerAddressingModeRepeat = 3, + SamplerAddressingModeRepeatMirrored = 4, + SamplerAddressingModeMax = 0x7fffffff, +}; + +enum SamplerFilterMode { + SamplerFilterModeNearest = 0, + SamplerFilterModeLinear = 1, + SamplerFilterModeMax = 0x7fffffff, +}; + +enum ImageFormat { + ImageFormatUnknown = 0, + ImageFormatRgba32f = 1, + ImageFormatRgba16f = 2, + ImageFormatR32f = 3, + ImageFormatRgba8 = 4, + ImageFormatRgba8Snorm = 5, + ImageFormatRg32f = 6, + ImageFormatRg16f = 7, + ImageFormatR11fG11fB10f = 8, + ImageFormatR16f = 9, + ImageFormatRgba16 = 10, + ImageFormatRgb10A2 = 11, + ImageFormatRg16 = 12, + ImageFormatRg8 = 13, + ImageFormatR16 = 14, + ImageFormatR8 = 15, + ImageFormatRgba16Snorm = 16, + ImageFormatRg16Snorm = 17, + ImageFormatRg8Snorm = 18, + ImageFormatR16Snorm = 19, + ImageFormatR8Snorm = 20, + ImageFormatRgba32i = 21, + ImageFormatRgba16i = 22, + ImageFormatRgba8i = 23, + ImageFormatR32i = 24, + ImageFormatRg32i = 25, + ImageFormatRg16i = 26, + ImageFormatRg8i = 27, + ImageFormatR16i = 28, + ImageFormatR8i = 29, + ImageFormatRgba32ui = 30, + ImageFormatRgba16ui = 31, + ImageFormatRgba8ui = 32, + ImageFormatR32ui = 33, + ImageFormatRgb10a2ui = 34, + ImageFormatRg32ui = 35, + ImageFormatRg16ui = 36, + ImageFormatRg8ui = 37, + ImageFormatR16ui = 38, + ImageFormatR8ui = 39, + ImageFormatR64ui = 40, + ImageFormatR64i = 41, + ImageFormatMax = 0x7fffffff, +}; + +enum ImageChannelOrder { + ImageChannelOrderR = 0, + ImageChannelOrderA = 1, + ImageChannelOrderRG = 2, + ImageChannelOrderRA = 3, + ImageChannelOrderRGB = 4, + ImageChannelOrderRGBA = 5, + ImageChannelOrderBGRA = 6, + ImageChannelOrderARGB = 7, + ImageChannelOrderIntensity = 8, + ImageChannelOrderLuminance = 9, + ImageChannelOrderRx = 10, + ImageChannelOrderRGx = 11, + ImageChannelOrderRGBx = 12, + ImageChannelOrderDepth = 13, + ImageChannelOrderDepthStencil = 14, + ImageChannelOrdersRGB = 15, + ImageChannelOrdersRGBx = 16, + ImageChannelOrdersRGBA = 17, + ImageChannelOrdersBGRA = 18, + ImageChannelOrderABGR = 19, + ImageChannelOrderMax = 0x7fffffff, +}; + +enum ImageChannelDataType { + ImageChannelDataTypeSnormInt8 = 0, + ImageChannelDataTypeSnormInt16 = 1, + ImageChannelDataTypeUnormInt8 = 2, + ImageChannelDataTypeUnormInt16 = 3, + ImageChannelDataTypeUnormShort565 = 4, + ImageChannelDataTypeUnormShort555 = 5, + ImageChannelDataTypeUnormInt101010 = 6, + ImageChannelDataTypeSignedInt8 = 7, + ImageChannelDataTypeSignedInt16 = 8, + ImageChannelDataTypeSignedInt32 = 9, + ImageChannelDataTypeUnsignedInt8 = 10, + ImageChannelDataTypeUnsignedInt16 = 11, + ImageChannelDataTypeUnsignedInt32 = 12, + ImageChannelDataTypeHalfFloat = 13, + ImageChannelDataTypeFloat = 14, + ImageChannelDataTypeUnormInt24 = 15, + ImageChannelDataTypeUnormInt101010_2 = 16, + ImageChannelDataTypeMax = 0x7fffffff, +}; + +enum ImageOperandsShift { + ImageOperandsBiasShift = 0, + ImageOperandsLodShift = 1, + ImageOperandsGradShift = 2, + ImageOperandsConstOffsetShift = 3, + ImageOperandsOffsetShift = 4, + ImageOperandsConstOffsetsShift = 5, + ImageOperandsSampleShift = 6, + ImageOperandsMinLodShift = 7, + ImageOperandsMakeTexelAvailableShift = 8, + ImageOperandsMakeTexelAvailableKHRShift = 8, + ImageOperandsMakeTexelVisibleShift = 9, + ImageOperandsMakeTexelVisibleKHRShift = 9, + ImageOperandsNonPrivateTexelShift = 10, + ImageOperandsNonPrivateTexelKHRShift = 10, + ImageOperandsVolatileTexelShift = 11, + ImageOperandsVolatileTexelKHRShift = 11, + ImageOperandsSignExtendShift = 12, + ImageOperandsZeroExtendShift = 13, + ImageOperandsNontemporalShift = 14, + ImageOperandsOffsetsShift = 16, + ImageOperandsMax = 0x7fffffff, +}; + +enum ImageOperandsMask { + ImageOperandsMaskNone = 0, + ImageOperandsBiasMask = 0x00000001, + ImageOperandsLodMask = 0x00000002, + ImageOperandsGradMask = 0x00000004, + ImageOperandsConstOffsetMask = 0x00000008, + ImageOperandsOffsetMask = 0x00000010, + ImageOperandsConstOffsetsMask = 0x00000020, + ImageOperandsSampleMask = 0x00000040, + ImageOperandsMinLodMask = 0x00000080, + ImageOperandsMakeTexelAvailableMask = 0x00000100, + ImageOperandsMakeTexelAvailableKHRMask = 0x00000100, + ImageOperandsMakeTexelVisibleMask = 0x00000200, + ImageOperandsMakeTexelVisibleKHRMask = 0x00000200, + ImageOperandsNonPrivateTexelMask = 0x00000400, + ImageOperandsNonPrivateTexelKHRMask = 0x00000400, + ImageOperandsVolatileTexelMask = 0x00000800, + ImageOperandsVolatileTexelKHRMask = 0x00000800, + ImageOperandsSignExtendMask = 0x00001000, + ImageOperandsZeroExtendMask = 0x00002000, + ImageOperandsNontemporalMask = 0x00004000, + ImageOperandsOffsetsMask = 0x00010000, +}; + +enum FPFastMathModeShift { + FPFastMathModeNotNaNShift = 0, + FPFastMathModeNotInfShift = 1, + FPFastMathModeNSZShift = 2, + FPFastMathModeAllowRecipShift = 3, + FPFastMathModeFastShift = 4, + FPFastMathModeAllowContractFastINTELShift = 16, + FPFastMathModeAllowReassocINTELShift = 17, + FPFastMathModeMax = 0x7fffffff, +}; + +enum FPFastMathModeMask { + FPFastMathModeMaskNone = 0, + FPFastMathModeNotNaNMask = 0x00000001, + FPFastMathModeNotInfMask = 0x00000002, + FPFastMathModeNSZMask = 0x00000004, + FPFastMathModeAllowRecipMask = 0x00000008, + FPFastMathModeFastMask = 0x00000010, + FPFastMathModeAllowContractFastINTELMask = 0x00010000, + FPFastMathModeAllowReassocINTELMask = 0x00020000, +}; + +enum FPRoundingMode { + FPRoundingModeRTE = 0, + FPRoundingModeRTZ = 1, + FPRoundingModeRTP = 2, + FPRoundingModeRTN = 3, + FPRoundingModeMax = 0x7fffffff, +}; + +enum LinkageType { + LinkageTypeExport = 0, + LinkageTypeImport = 1, + LinkageTypeLinkOnceODR = 2, + LinkageTypeMax = 0x7fffffff, +}; + +enum AccessQualifier { + AccessQualifierReadOnly = 0, + AccessQualifierWriteOnly = 1, + AccessQualifierReadWrite = 2, + AccessQualifierMax = 0x7fffffff, +}; + +enum FunctionParameterAttribute { + FunctionParameterAttributeZext = 0, + FunctionParameterAttributeSext = 1, + FunctionParameterAttributeByVal = 2, + FunctionParameterAttributeSret = 3, + FunctionParameterAttributeNoAlias = 4, + FunctionParameterAttributeNoCapture = 5, + FunctionParameterAttributeNoWrite = 6, + FunctionParameterAttributeNoReadWrite = 7, + FunctionParameterAttributeRuntimeAlignedINTEL = 5940, + FunctionParameterAttributeMax = 0x7fffffff, +}; + +enum Decoration { + DecorationRelaxedPrecision = 0, + DecorationSpecId = 1, + DecorationBlock = 2, + DecorationBufferBlock = 3, + DecorationRowMajor = 4, + DecorationColMajor = 5, + DecorationArrayStride = 6, + DecorationMatrixStride = 7, + DecorationGLSLShared = 8, + DecorationGLSLPacked = 9, + DecorationCPacked = 10, + DecorationBuiltIn = 11, + DecorationNoPerspective = 13, + DecorationFlat = 14, + DecorationPatch = 15, + DecorationCentroid = 16, + DecorationSample = 17, + DecorationInvariant = 18, + DecorationRestrict = 19, + DecorationAliased = 20, + DecorationVolatile = 21, + DecorationConstant = 22, + DecorationCoherent = 23, + DecorationNonWritable = 24, + DecorationNonReadable = 25, + DecorationUniform = 26, + DecorationUniformId = 27, + DecorationSaturatedConversion = 28, + DecorationStream = 29, + DecorationLocation = 30, + DecorationComponent = 31, + DecorationIndex = 32, + DecorationBinding = 33, + DecorationDescriptorSet = 34, + DecorationOffset = 35, + DecorationXfbBuffer = 36, + DecorationXfbStride = 37, + DecorationFuncParamAttr = 38, + DecorationFPRoundingMode = 39, + DecorationFPFastMathMode = 40, + DecorationLinkageAttributes = 41, + DecorationNoContraction = 42, + DecorationInputAttachmentIndex = 43, + DecorationAlignment = 44, + DecorationMaxByteOffset = 45, + DecorationAlignmentId = 46, + DecorationMaxByteOffsetId = 47, + DecorationNoSignedWrap = 4469, + DecorationNoUnsignedWrap = 4470, + DecorationWeightTextureQCOM = 4487, + DecorationBlockMatchTextureQCOM = 4488, + DecorationBlockMatchSamplerQCOM = 4499, + DecorationExplicitInterpAMD = 4999, + DecorationOverrideCoverageNV = 5248, + DecorationPassthroughNV = 5250, + DecorationViewportRelativeNV = 5252, + DecorationSecondaryViewportRelativeNV = 5256, + DecorationPerPrimitiveEXT = 5271, + DecorationPerPrimitiveNV = 5271, + DecorationPerViewNV = 5272, + DecorationPerTaskNV = 5273, + DecorationPerVertexKHR = 5285, + DecorationPerVertexNV = 5285, + DecorationNonUniform = 5300, + DecorationNonUniformEXT = 5300, + DecorationRestrictPointer = 5355, + DecorationRestrictPointerEXT = 5355, + DecorationAliasedPointer = 5356, + DecorationAliasedPointerEXT = 5356, + DecorationHitObjectShaderRecordBufferNV = 5386, + DecorationBindlessSamplerNV = 5398, + DecorationBindlessImageNV = 5399, + DecorationBoundSamplerNV = 5400, + DecorationBoundImageNV = 5401, + DecorationSIMTCallINTEL = 5599, + DecorationReferencedIndirectlyINTEL = 5602, + DecorationClobberINTEL = 5607, + DecorationSideEffectsINTEL = 5608, + DecorationVectorComputeVariableINTEL = 5624, + DecorationFuncParamIOKindINTEL = 5625, + DecorationVectorComputeFunctionINTEL = 5626, + DecorationStackCallINTEL = 5627, + DecorationGlobalVariableOffsetINTEL = 5628, + DecorationCounterBuffer = 5634, + DecorationHlslCounterBufferGOOGLE = 5634, + DecorationHlslSemanticGOOGLE = 5635, + DecorationUserSemantic = 5635, + DecorationUserTypeGOOGLE = 5636, + DecorationFunctionRoundingModeINTEL = 5822, + DecorationFunctionDenormModeINTEL = 5823, + DecorationRegisterINTEL = 5825, + DecorationMemoryINTEL = 5826, + DecorationNumbanksINTEL = 5827, + DecorationBankwidthINTEL = 5828, + DecorationMaxPrivateCopiesINTEL = 5829, + DecorationSinglepumpINTEL = 5830, + DecorationDoublepumpINTEL = 5831, + DecorationMaxReplicatesINTEL = 5832, + DecorationSimpleDualPortINTEL = 5833, + DecorationMergeINTEL = 5834, + DecorationBankBitsINTEL = 5835, + DecorationForcePow2DepthINTEL = 5836, + DecorationBurstCoalesceINTEL = 5899, + DecorationCacheSizeINTEL = 5900, + DecorationDontStaticallyCoalesceINTEL = 5901, + DecorationPrefetchINTEL = 5902, + DecorationStallEnableINTEL = 5905, + DecorationFuseLoopsInFunctionINTEL = 5907, + DecorationMathOpDSPModeINTEL = 5909, + DecorationAliasScopeINTEL = 5914, + DecorationNoAliasINTEL = 5915, + DecorationInitiationIntervalINTEL = 5917, + DecorationMaxConcurrencyINTEL = 5918, + DecorationPipelineEnableINTEL = 5919, + DecorationBufferLocationINTEL = 5921, + DecorationIOPipeStorageINTEL = 5944, + DecorationFunctionFloatingPointModeINTEL = 6080, + DecorationSingleElementVectorINTEL = 6085, + DecorationVectorComputeCallableFunctionINTEL = 6087, + DecorationMediaBlockIOINTEL = 6140, + DecorationConduitKernelArgumentINTEL = 6175, + DecorationRegisterMapKernelArgumentINTEL = 6176, + DecorationMMHostInterfaceAddressWidthINTEL = 6177, + DecorationMMHostInterfaceDataWidthINTEL = 6178, + DecorationMMHostInterfaceLatencyINTEL = 6179, + DecorationMMHostInterfaceReadWriteModeINTEL = 6180, + DecorationMMHostInterfaceMaxBurstINTEL = 6181, + DecorationMMHostInterfaceWaitRequestINTEL = 6182, + DecorationStableKernelArgumentINTEL = 6183, + DecorationMax = 0x7fffffff, +}; + +enum BuiltIn { + BuiltInPosition = 0, + BuiltInPointSize = 1, + BuiltInClipDistance = 3, + BuiltInCullDistance = 4, + BuiltInVertexId = 5, + BuiltInInstanceId = 6, + BuiltInPrimitiveId = 7, + BuiltInInvocationId = 8, + BuiltInLayer = 9, + BuiltInViewportIndex = 10, + BuiltInTessLevelOuter = 11, + BuiltInTessLevelInner = 12, + BuiltInTessCoord = 13, + BuiltInPatchVertices = 14, + BuiltInFragCoord = 15, + BuiltInPointCoord = 16, + BuiltInFrontFacing = 17, + BuiltInSampleId = 18, + BuiltInSamplePosition = 19, + BuiltInSampleMask = 20, + BuiltInFragDepth = 22, + BuiltInHelperInvocation = 23, + BuiltInNumWorkgroups = 24, + BuiltInWorkgroupSize = 25, + BuiltInWorkgroupId = 26, + BuiltInLocalInvocationId = 27, + BuiltInGlobalInvocationId = 28, + BuiltInLocalInvocationIndex = 29, + BuiltInWorkDim = 30, + BuiltInGlobalSize = 31, + BuiltInEnqueuedWorkgroupSize = 32, + BuiltInGlobalOffset = 33, + BuiltInGlobalLinearId = 34, + BuiltInSubgroupSize = 36, + BuiltInSubgroupMaxSize = 37, + BuiltInNumSubgroups = 38, + BuiltInNumEnqueuedSubgroups = 39, + BuiltInSubgroupId = 40, + BuiltInSubgroupLocalInvocationId = 41, + BuiltInVertexIndex = 42, + BuiltInInstanceIndex = 43, + BuiltInCoreIDARM = 4160, + BuiltInCoreCountARM = 4161, + BuiltInCoreMaxIDARM = 4162, + BuiltInWarpIDARM = 4163, + BuiltInWarpMaxIDARM = 4164, + BuiltInSubgroupEqMask = 4416, + BuiltInSubgroupEqMaskKHR = 4416, + BuiltInSubgroupGeMask = 4417, + BuiltInSubgroupGeMaskKHR = 4417, + BuiltInSubgroupGtMask = 4418, + BuiltInSubgroupGtMaskKHR = 4418, + BuiltInSubgroupLeMask = 4419, + BuiltInSubgroupLeMaskKHR = 4419, + BuiltInSubgroupLtMask = 4420, + BuiltInSubgroupLtMaskKHR = 4420, + BuiltInBaseVertex = 4424, + BuiltInBaseInstance = 4425, + BuiltInDrawIndex = 4426, + BuiltInPrimitiveShadingRateKHR = 4432, + BuiltInDeviceIndex = 4438, + BuiltInViewIndex = 4440, + BuiltInShadingRateKHR = 4444, + BuiltInBaryCoordNoPerspAMD = 4992, + BuiltInBaryCoordNoPerspCentroidAMD = 4993, + BuiltInBaryCoordNoPerspSampleAMD = 4994, + BuiltInBaryCoordSmoothAMD = 4995, + BuiltInBaryCoordSmoothCentroidAMD = 4996, + BuiltInBaryCoordSmoothSampleAMD = 4997, + BuiltInBaryCoordPullModelAMD = 4998, + BuiltInFragStencilRefEXT = 5014, + BuiltInViewportMaskNV = 5253, + BuiltInSecondaryPositionNV = 5257, + BuiltInSecondaryViewportMaskNV = 5258, + BuiltInPositionPerViewNV = 5261, + BuiltInViewportMaskPerViewNV = 5262, + BuiltInFullyCoveredEXT = 5264, + BuiltInTaskCountNV = 5274, + BuiltInPrimitiveCountNV = 5275, + BuiltInPrimitiveIndicesNV = 5276, + BuiltInClipDistancePerViewNV = 5277, + BuiltInCullDistancePerViewNV = 5278, + BuiltInLayerPerViewNV = 5279, + BuiltInMeshViewCountNV = 5280, + BuiltInMeshViewIndicesNV = 5281, + BuiltInBaryCoordKHR = 5286, + BuiltInBaryCoordNV = 5286, + BuiltInBaryCoordNoPerspKHR = 5287, + BuiltInBaryCoordNoPerspNV = 5287, + BuiltInFragSizeEXT = 5292, + BuiltInFragmentSizeNV = 5292, + BuiltInFragInvocationCountEXT = 5293, + BuiltInInvocationsPerPixelNV = 5293, + BuiltInPrimitivePointIndicesEXT = 5294, + BuiltInPrimitiveLineIndicesEXT = 5295, + BuiltInPrimitiveTriangleIndicesEXT = 5296, + BuiltInCullPrimitiveEXT = 5299, + BuiltInLaunchIdKHR = 5319, + BuiltInLaunchIdNV = 5319, + BuiltInLaunchSizeKHR = 5320, + BuiltInLaunchSizeNV = 5320, + BuiltInWorldRayOriginKHR = 5321, + BuiltInWorldRayOriginNV = 5321, + BuiltInWorldRayDirectionKHR = 5322, + BuiltInWorldRayDirectionNV = 5322, + BuiltInObjectRayOriginKHR = 5323, + BuiltInObjectRayOriginNV = 5323, + BuiltInObjectRayDirectionKHR = 5324, + BuiltInObjectRayDirectionNV = 5324, + BuiltInRayTminKHR = 5325, + BuiltInRayTminNV = 5325, + BuiltInRayTmaxKHR = 5326, + BuiltInRayTmaxNV = 5326, + BuiltInInstanceCustomIndexKHR = 5327, + BuiltInInstanceCustomIndexNV = 5327, + BuiltInObjectToWorldKHR = 5330, + BuiltInObjectToWorldNV = 5330, + BuiltInWorldToObjectKHR = 5331, + BuiltInWorldToObjectNV = 5331, + BuiltInHitTNV = 5332, + BuiltInHitKindKHR = 5333, + BuiltInHitKindNV = 5333, + BuiltInCurrentRayTimeNV = 5334, + BuiltInHitTriangleVertexPositionsKHR = 5335, + BuiltInHitMicroTriangleVertexPositionsNV = 5337, + BuiltInHitMicroTriangleVertexBarycentricsNV = 5344, + BuiltInIncomingRayFlagsKHR = 5351, + BuiltInIncomingRayFlagsNV = 5351, + BuiltInRayGeometryIndexKHR = 5352, + BuiltInWarpsPerSMNV = 5374, + BuiltInSMCountNV = 5375, + BuiltInWarpIDNV = 5376, + BuiltInSMIDNV = 5377, + BuiltInHitKindFrontFacingMicroTriangleNV = 5405, + BuiltInHitKindBackFacingMicroTriangleNV = 5406, + BuiltInCullMaskKHR = 6021, + BuiltInMax = 0x7fffffff, +}; + +enum SelectionControlShift { + SelectionControlFlattenShift = 0, + SelectionControlDontFlattenShift = 1, + SelectionControlMax = 0x7fffffff, +}; + +enum SelectionControlMask { + SelectionControlMaskNone = 0, + SelectionControlFlattenMask = 0x00000001, + SelectionControlDontFlattenMask = 0x00000002, +}; + +enum LoopControlShift { + LoopControlUnrollShift = 0, + LoopControlDontUnrollShift = 1, + LoopControlDependencyInfiniteShift = 2, + LoopControlDependencyLengthShift = 3, + LoopControlMinIterationsShift = 4, + LoopControlMaxIterationsShift = 5, + LoopControlIterationMultipleShift = 6, + LoopControlPeelCountShift = 7, + LoopControlPartialCountShift = 8, + LoopControlInitiationIntervalINTELShift = 16, + LoopControlMaxConcurrencyINTELShift = 17, + LoopControlDependencyArrayINTELShift = 18, + LoopControlPipelineEnableINTELShift = 19, + LoopControlLoopCoalesceINTELShift = 20, + LoopControlMaxInterleavingINTELShift = 21, + LoopControlSpeculatedIterationsINTELShift = 22, + LoopControlNoFusionINTELShift = 23, + LoopControlLoopCountINTELShift = 24, + LoopControlMaxReinvocationDelayINTELShift = 25, + LoopControlMax = 0x7fffffff, +}; + +enum LoopControlMask { + LoopControlMaskNone = 0, + LoopControlUnrollMask = 0x00000001, + LoopControlDontUnrollMask = 0x00000002, + LoopControlDependencyInfiniteMask = 0x00000004, + LoopControlDependencyLengthMask = 0x00000008, + LoopControlMinIterationsMask = 0x00000010, + LoopControlMaxIterationsMask = 0x00000020, + LoopControlIterationMultipleMask = 0x00000040, + LoopControlPeelCountMask = 0x00000080, + LoopControlPartialCountMask = 0x00000100, + LoopControlInitiationIntervalINTELMask = 0x00010000, + LoopControlMaxConcurrencyINTELMask = 0x00020000, + LoopControlDependencyArrayINTELMask = 0x00040000, + LoopControlPipelineEnableINTELMask = 0x00080000, + LoopControlLoopCoalesceINTELMask = 0x00100000, + LoopControlMaxInterleavingINTELMask = 0x00200000, + LoopControlSpeculatedIterationsINTELMask = 0x00400000, + LoopControlNoFusionINTELMask = 0x00800000, + LoopControlLoopCountINTELMask = 0x01000000, + LoopControlMaxReinvocationDelayINTELMask = 0x02000000, +}; + +enum FunctionControlShift { + FunctionControlInlineShift = 0, + FunctionControlDontInlineShift = 1, + FunctionControlPureShift = 2, + FunctionControlConstShift = 3, + FunctionControlOptNoneINTELShift = 16, + FunctionControlMax = 0x7fffffff, +}; + +enum FunctionControlMask { + FunctionControlMaskNone = 0, + FunctionControlInlineMask = 0x00000001, + FunctionControlDontInlineMask = 0x00000002, + FunctionControlPureMask = 0x00000004, + FunctionControlConstMask = 0x00000008, + FunctionControlOptNoneINTELMask = 0x00010000, +}; + +enum MemorySemanticsShift { + MemorySemanticsAcquireShift = 1, + MemorySemanticsReleaseShift = 2, + MemorySemanticsAcquireReleaseShift = 3, + MemorySemanticsSequentiallyConsistentShift = 4, + MemorySemanticsUniformMemoryShift = 6, + MemorySemanticsSubgroupMemoryShift = 7, + MemorySemanticsWorkgroupMemoryShift = 8, + MemorySemanticsCrossWorkgroupMemoryShift = 9, + MemorySemanticsAtomicCounterMemoryShift = 10, + MemorySemanticsImageMemoryShift = 11, + MemorySemanticsOutputMemoryShift = 12, + MemorySemanticsOutputMemoryKHRShift = 12, + MemorySemanticsMakeAvailableShift = 13, + MemorySemanticsMakeAvailableKHRShift = 13, + MemorySemanticsMakeVisibleShift = 14, + MemorySemanticsMakeVisibleKHRShift = 14, + MemorySemanticsVolatileShift = 15, + MemorySemanticsMax = 0x7fffffff, +}; + +enum MemorySemanticsMask { + MemorySemanticsMaskNone = 0, + MemorySemanticsAcquireMask = 0x00000002, + MemorySemanticsReleaseMask = 0x00000004, + MemorySemanticsAcquireReleaseMask = 0x00000008, + MemorySemanticsSequentiallyConsistentMask = 0x00000010, + MemorySemanticsUniformMemoryMask = 0x00000040, + MemorySemanticsSubgroupMemoryMask = 0x00000080, + MemorySemanticsWorkgroupMemoryMask = 0x00000100, + MemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, + MemorySemanticsAtomicCounterMemoryMask = 0x00000400, + MemorySemanticsImageMemoryMask = 0x00000800, + MemorySemanticsOutputMemoryMask = 0x00001000, + MemorySemanticsOutputMemoryKHRMask = 0x00001000, + MemorySemanticsMakeAvailableMask = 0x00002000, + MemorySemanticsMakeAvailableKHRMask = 0x00002000, + MemorySemanticsMakeVisibleMask = 0x00004000, + MemorySemanticsMakeVisibleKHRMask = 0x00004000, + MemorySemanticsVolatileMask = 0x00008000, +}; + +enum MemoryAccessShift { + MemoryAccessVolatileShift = 0, + MemoryAccessAlignedShift = 1, + MemoryAccessNontemporalShift = 2, + MemoryAccessMakePointerAvailableShift = 3, + MemoryAccessMakePointerAvailableKHRShift = 3, + MemoryAccessMakePointerVisibleShift = 4, + MemoryAccessMakePointerVisibleKHRShift = 4, + MemoryAccessNonPrivatePointerShift = 5, + MemoryAccessNonPrivatePointerKHRShift = 5, + MemoryAccessAliasScopeINTELMaskShift = 16, + MemoryAccessNoAliasINTELMaskShift = 17, + MemoryAccessMax = 0x7fffffff, +}; + +enum MemoryAccessMask { + MemoryAccessMaskNone = 0, + MemoryAccessVolatileMask = 0x00000001, + MemoryAccessAlignedMask = 0x00000002, + MemoryAccessNontemporalMask = 0x00000004, + MemoryAccessMakePointerAvailableMask = 0x00000008, + MemoryAccessMakePointerAvailableKHRMask = 0x00000008, + MemoryAccessMakePointerVisibleMask = 0x00000010, + MemoryAccessMakePointerVisibleKHRMask = 0x00000010, + MemoryAccessNonPrivatePointerMask = 0x00000020, + MemoryAccessNonPrivatePointerKHRMask = 0x00000020, + MemoryAccessAliasScopeINTELMaskMask = 0x00010000, + MemoryAccessNoAliasINTELMaskMask = 0x00020000, +}; + +enum Scope { + ScopeCrossDevice = 0, + ScopeDevice = 1, + ScopeWorkgroup = 2, + ScopeSubgroup = 3, + ScopeInvocation = 4, + ScopeQueueFamily = 5, + ScopeQueueFamilyKHR = 5, + ScopeShaderCallKHR = 6, + ScopeMax = 0x7fffffff, +}; + +enum GroupOperation { + GroupOperationReduce = 0, + GroupOperationInclusiveScan = 1, + GroupOperationExclusiveScan = 2, + GroupOperationClusteredReduce = 3, + GroupOperationPartitionedReduceNV = 6, + GroupOperationPartitionedInclusiveScanNV = 7, + GroupOperationPartitionedExclusiveScanNV = 8, + GroupOperationMax = 0x7fffffff, +}; + +enum KernelEnqueueFlags { + KernelEnqueueFlagsNoWait = 0, + KernelEnqueueFlagsWaitKernel = 1, + KernelEnqueueFlagsWaitWorkGroup = 2, + KernelEnqueueFlagsMax = 0x7fffffff, +}; + +enum KernelProfilingInfoShift { + KernelProfilingInfoCmdExecTimeShift = 0, + KernelProfilingInfoMax = 0x7fffffff, +}; + +enum KernelProfilingInfoMask { + KernelProfilingInfoMaskNone = 0, + KernelProfilingInfoCmdExecTimeMask = 0x00000001, +}; + +enum Capability { + CapabilityMatrix = 0, + CapabilityShader = 1, + CapabilityGeometry = 2, + CapabilityTessellation = 3, + CapabilityAddresses = 4, + CapabilityLinkage = 5, + CapabilityKernel = 6, + CapabilityVector16 = 7, + CapabilityFloat16Buffer = 8, + CapabilityFloat16 = 9, + CapabilityFloat64 = 10, + CapabilityInt64 = 11, + CapabilityInt64Atomics = 12, + CapabilityImageBasic = 13, + CapabilityImageReadWrite = 14, + CapabilityImageMipmap = 15, + CapabilityPipes = 17, + CapabilityGroups = 18, + CapabilityDeviceEnqueue = 19, + CapabilityLiteralSampler = 20, + CapabilityAtomicStorage = 21, + CapabilityInt16 = 22, + CapabilityTessellationPointSize = 23, + CapabilityGeometryPointSize = 24, + CapabilityImageGatherExtended = 25, + CapabilityStorageImageMultisample = 27, + CapabilityUniformBufferArrayDynamicIndexing = 28, + CapabilitySampledImageArrayDynamicIndexing = 29, + CapabilityStorageBufferArrayDynamicIndexing = 30, + CapabilityStorageImageArrayDynamicIndexing = 31, + CapabilityClipDistance = 32, + CapabilityCullDistance = 33, + CapabilityImageCubeArray = 34, + CapabilitySampleRateShading = 35, + CapabilityImageRect = 36, + CapabilitySampledRect = 37, + CapabilityGenericPointer = 38, + CapabilityInt8 = 39, + CapabilityInputAttachment = 40, + CapabilitySparseResidency = 41, + CapabilityMinLod = 42, + CapabilitySampled1D = 43, + CapabilityImage1D = 44, + CapabilitySampledCubeArray = 45, + CapabilitySampledBuffer = 46, + CapabilityImageBuffer = 47, + CapabilityImageMSArray = 48, + CapabilityStorageImageExtendedFormats = 49, + CapabilityImageQuery = 50, + CapabilityDerivativeControl = 51, + CapabilityInterpolationFunction = 52, + CapabilityTransformFeedback = 53, + CapabilityGeometryStreams = 54, + CapabilityStorageImageReadWithoutFormat = 55, + CapabilityStorageImageWriteWithoutFormat = 56, + CapabilityMultiViewport = 57, + CapabilitySubgroupDispatch = 58, + CapabilityNamedBarrier = 59, + CapabilityPipeStorage = 60, + CapabilityGroupNonUniform = 61, + CapabilityGroupNonUniformVote = 62, + CapabilityGroupNonUniformArithmetic = 63, + CapabilityGroupNonUniformBallot = 64, + CapabilityGroupNonUniformShuffle = 65, + CapabilityGroupNonUniformShuffleRelative = 66, + CapabilityGroupNonUniformClustered = 67, + CapabilityGroupNonUniformQuad = 68, + CapabilityShaderLayer = 69, + CapabilityShaderViewportIndex = 70, + CapabilityUniformDecoration = 71, + CapabilityCoreBuiltinsARM = 4165, + CapabilityTileImageColorReadAccessEXT = 4166, + CapabilityTileImageDepthReadAccessEXT = 4167, + CapabilityTileImageStencilReadAccessEXT = 4168, + CapabilityFragmentShadingRateKHR = 4422, + CapabilitySubgroupBallotKHR = 4423, + CapabilityDrawParameters = 4427, + CapabilityWorkgroupMemoryExplicitLayoutKHR = 4428, + CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, + CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, + CapabilitySubgroupVoteKHR = 4431, + CapabilityStorageBuffer16BitAccess = 4433, + CapabilityStorageUniformBufferBlock16 = 4433, + CapabilityStorageUniform16 = 4434, + CapabilityUniformAndStorageBuffer16BitAccess = 4434, + CapabilityStoragePushConstant16 = 4435, + CapabilityStorageInputOutput16 = 4436, + CapabilityDeviceGroup = 4437, + CapabilityMultiView = 4439, + CapabilityVariablePointersStorageBuffer = 4441, + CapabilityVariablePointers = 4442, + CapabilityAtomicStorageOps = 4445, + CapabilitySampleMaskPostDepthCoverage = 4447, + CapabilityStorageBuffer8BitAccess = 4448, + CapabilityUniformAndStorageBuffer8BitAccess = 4449, + CapabilityStoragePushConstant8 = 4450, + CapabilityDenormPreserve = 4464, + CapabilityDenormFlushToZero = 4465, + CapabilitySignedZeroInfNanPreserve = 4466, + CapabilityRoundingModeRTE = 4467, + CapabilityRoundingModeRTZ = 4468, + CapabilityRayQueryProvisionalKHR = 4471, + CapabilityRayQueryKHR = 4472, + CapabilityRayTraversalPrimitiveCullingKHR = 4478, + CapabilityRayTracingKHR = 4479, + CapabilityTextureSampleWeightedQCOM = 4484, + CapabilityTextureBoxFilterQCOM = 4485, + CapabilityTextureBlockMatchQCOM = 4486, + CapabilityTextureBlockMatch2QCOM = 4498, + CapabilityFloat16ImageAMD = 5008, + CapabilityImageGatherBiasLodAMD = 5009, + CapabilityFragmentMaskAMD = 5010, + CapabilityStencilExportEXT = 5013, + CapabilityImageReadWriteLodAMD = 5015, + CapabilityInt64ImageEXT = 5016, + CapabilityShaderClockKHR = 5055, + CapabilityQuadControlKHR = 5087, + CapabilitySampleMaskOverrideCoverageNV = 5249, + CapabilityGeometryShaderPassthroughNV = 5251, + CapabilityShaderViewportIndexLayerEXT = 5254, + CapabilityShaderViewportIndexLayerNV = 5254, + CapabilityShaderViewportMaskNV = 5255, + CapabilityShaderStereoViewNV = 5259, + CapabilityPerViewAttributesNV = 5260, + CapabilityFragmentFullyCoveredEXT = 5265, + CapabilityMeshShadingNV = 5266, + CapabilityImageFootprintNV = 5282, + CapabilityMeshShadingEXT = 5283, + CapabilityFragmentBarycentricKHR = 5284, + CapabilityFragmentBarycentricNV = 5284, + CapabilityComputeDerivativeGroupQuadsNV = 5288, + CapabilityFragmentDensityEXT = 5291, + CapabilityShadingRateNV = 5291, + CapabilityGroupNonUniformPartitionedNV = 5297, + CapabilityShaderNonUniform = 5301, + CapabilityShaderNonUniformEXT = 5301, + CapabilityRuntimeDescriptorArray = 5302, + CapabilityRuntimeDescriptorArrayEXT = 5302, + CapabilityInputAttachmentArrayDynamicIndexing = 5303, + CapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, + CapabilityUniformTexelBufferArrayDynamicIndexing = 5304, + CapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, + CapabilityStorageTexelBufferArrayDynamicIndexing = 5305, + CapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, + CapabilityUniformBufferArrayNonUniformIndexing = 5306, + CapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, + CapabilitySampledImageArrayNonUniformIndexing = 5307, + CapabilitySampledImageArrayNonUniformIndexingEXT = 5307, + CapabilityStorageBufferArrayNonUniformIndexing = 5308, + CapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, + CapabilityStorageImageArrayNonUniformIndexing = 5309, + CapabilityStorageImageArrayNonUniformIndexingEXT = 5309, + CapabilityInputAttachmentArrayNonUniformIndexing = 5310, + CapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, + CapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, + CapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, + CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, + CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, + CapabilityRayTracingPositionFetchKHR = 5336, + CapabilityRayTracingNV = 5340, + CapabilityRayTracingMotionBlurNV = 5341, + CapabilityVulkanMemoryModel = 5345, + CapabilityVulkanMemoryModelKHR = 5345, + CapabilityVulkanMemoryModelDeviceScope = 5346, + CapabilityVulkanMemoryModelDeviceScopeKHR = 5346, + CapabilityPhysicalStorageBufferAddresses = 5347, + CapabilityPhysicalStorageBufferAddressesEXT = 5347, + CapabilityComputeDerivativeGroupLinearNV = 5350, + CapabilityRayTracingProvisionalKHR = 5353, + CapabilityCooperativeMatrixNV = 5357, + CapabilityFragmentShaderSampleInterlockEXT = 5363, + CapabilityFragmentShaderShadingRateInterlockEXT = 5372, + CapabilityShaderSMBuiltinsNV = 5373, + CapabilityFragmentShaderPixelInterlockEXT = 5378, + CapabilityDemoteToHelperInvocation = 5379, + CapabilityDemoteToHelperInvocationEXT = 5379, + CapabilityDisplacementMicromapNV = 5380, + CapabilityRayTracingOpacityMicromapEXT = 5381, + CapabilityShaderInvocationReorderNV = 5383, + CapabilityBindlessTextureNV = 5390, + CapabilityRayQueryPositionFetchKHR = 5391, + CapabilityAtomicFloat16VectorNV = 5404, + CapabilityRayTracingDisplacementMicromapNV = 5409, + CapabilitySubgroupShuffleINTEL = 5568, + CapabilitySubgroupBufferBlockIOINTEL = 5569, + CapabilitySubgroupImageBlockIOINTEL = 5570, + CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityRoundToInfinityINTEL = 5582, + CapabilityFloatingPointModeINTEL = 5583, + CapabilityIntegerFunctions2INTEL = 5584, + CapabilityFunctionPointersINTEL = 5603, + CapabilityIndirectReferencesINTEL = 5604, + CapabilityAsmINTEL = 5606, + CapabilityAtomicFloat32MinMaxEXT = 5612, + CapabilityAtomicFloat64MinMaxEXT = 5613, + CapabilityAtomicFloat16MinMaxEXT = 5616, + CapabilityVectorComputeINTEL = 5617, + CapabilityVectorAnyINTEL = 5619, + CapabilityExpectAssumeKHR = 5629, + CapabilitySubgroupAvcMotionEstimationINTEL = 5696, + CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, + CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, + CapabilityVariableLengthArrayINTEL = 5817, + CapabilityFunctionFloatControlINTEL = 5821, + CapabilityFPGAMemoryAttributesINTEL = 5824, + CapabilityFPFastMathModeINTEL = 5837, + CapabilityArbitraryPrecisionIntegersINTEL = 5844, + CapabilityArbitraryPrecisionFloatingPointINTEL = 5845, + CapabilityUnstructuredLoopControlsINTEL = 5886, + CapabilityFPGALoopControlsINTEL = 5888, + CapabilityKernelAttributesINTEL = 5892, + CapabilityFPGAKernelAttributesINTEL = 5897, + CapabilityFPGAMemoryAccessesINTEL = 5898, + CapabilityFPGAClusterAttributesINTEL = 5904, + CapabilityLoopFuseINTEL = 5906, + CapabilityFPGADSPControlINTEL = 5908, + CapabilityMemoryAccessAliasingINTEL = 5910, + CapabilityFPGAInvocationPipeliningAttributesINTEL = 5916, + CapabilityFPGABufferLocationINTEL = 5920, + CapabilityArbitraryPrecisionFixedPointINTEL = 5922, + CapabilityUSMStorageClassesINTEL = 5935, + CapabilityRuntimeAlignedAttributeINTEL = 5939, + CapabilityIOPipesINTEL = 5943, + CapabilityBlockingPipesINTEL = 5945, + CapabilityFPGARegINTEL = 5948, + CapabilityDotProductInputAll = 6016, + CapabilityDotProductInputAllKHR = 6016, + CapabilityDotProductInput4x8Bit = 6017, + CapabilityDotProductInput4x8BitKHR = 6017, + CapabilityDotProductInput4x8BitPacked = 6018, + CapabilityDotProductInput4x8BitPackedKHR = 6018, + CapabilityDotProduct = 6019, + CapabilityDotProductKHR = 6019, + CapabilityRayCullMaskKHR = 6020, + CapabilityCooperativeMatrixKHR = 6022, + CapabilityBitInstructions = 6025, + CapabilityGroupNonUniformRotateKHR = 6026, + CapabilityAtomicFloat32AddEXT = 6033, + CapabilityAtomicFloat64AddEXT = 6034, + CapabilityLongConstantCompositeINTEL = 6089, + CapabilityOptNoneINTEL = 6094, + CapabilityAtomicFloat16AddEXT = 6095, + CapabilityDebugInfoModuleINTEL = 6114, + CapabilitySplitBarrierINTEL = 6141, + CapabilityFPGAArgumentInterfacesINTEL = 6174, + CapabilityGroupUniformArithmeticKHR = 6400, + CapabilityMax = 0x7fffffff, +}; + +enum RayFlagsShift { + RayFlagsOpaqueKHRShift = 0, + RayFlagsNoOpaqueKHRShift = 1, + RayFlagsTerminateOnFirstHitKHRShift = 2, + RayFlagsSkipClosestHitShaderKHRShift = 3, + RayFlagsCullBackFacingTrianglesKHRShift = 4, + RayFlagsCullFrontFacingTrianglesKHRShift = 5, + RayFlagsCullOpaqueKHRShift = 6, + RayFlagsCullNoOpaqueKHRShift = 7, + RayFlagsSkipTrianglesKHRShift = 8, + RayFlagsSkipAABBsKHRShift = 9, + RayFlagsForceOpacityMicromap2StateEXTShift = 10, + RayFlagsMax = 0x7fffffff, +}; + +enum RayFlagsMask { + RayFlagsMaskNone = 0, + RayFlagsOpaqueKHRMask = 0x00000001, + RayFlagsNoOpaqueKHRMask = 0x00000002, + RayFlagsTerminateOnFirstHitKHRMask = 0x00000004, + RayFlagsSkipClosestHitShaderKHRMask = 0x00000008, + RayFlagsCullBackFacingTrianglesKHRMask = 0x00000010, + RayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020, + RayFlagsCullOpaqueKHRMask = 0x00000040, + RayFlagsCullNoOpaqueKHRMask = 0x00000080, + RayFlagsSkipTrianglesKHRMask = 0x00000100, + RayFlagsSkipAABBsKHRMask = 0x00000200, + RayFlagsForceOpacityMicromap2StateEXTMask = 0x00000400, +}; + +enum RayQueryIntersection { + RayQueryIntersectionRayQueryCandidateIntersectionKHR = 0, + RayQueryIntersectionRayQueryCommittedIntersectionKHR = 1, + RayQueryIntersectionMax = 0x7fffffff, +}; + +enum RayQueryCommittedIntersectionType { + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0, + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1, + RayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2, + RayQueryCommittedIntersectionTypeMax = 0x7fffffff, +}; + +enum RayQueryCandidateIntersectionType { + RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0, + RayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1, + RayQueryCandidateIntersectionTypeMax = 0x7fffffff, +}; + +enum FragmentShadingRateShift { + FragmentShadingRateVertical2PixelsShift = 0, + FragmentShadingRateVertical4PixelsShift = 1, + FragmentShadingRateHorizontal2PixelsShift = 2, + FragmentShadingRateHorizontal4PixelsShift = 3, + FragmentShadingRateMax = 0x7fffffff, +}; + +enum FragmentShadingRateMask { + FragmentShadingRateMaskNone = 0, + FragmentShadingRateVertical2PixelsMask = 0x00000001, + FragmentShadingRateVertical4PixelsMask = 0x00000002, + FragmentShadingRateHorizontal2PixelsMask = 0x00000004, + FragmentShadingRateHorizontal4PixelsMask = 0x00000008, +}; + +enum FPDenormMode { + FPDenormModePreserve = 0, + FPDenormModeFlushToZero = 1, + FPDenormModeMax = 0x7fffffff, +}; + +enum FPOperationMode { + FPOperationModeIEEE = 0, + FPOperationModeALT = 1, + FPOperationModeMax = 0x7fffffff, +}; + +enum QuantizationModes { + QuantizationModesTRN = 0, + QuantizationModesTRN_ZERO = 1, + QuantizationModesRND = 2, + QuantizationModesRND_ZERO = 3, + QuantizationModesRND_INF = 4, + QuantizationModesRND_MIN_INF = 5, + QuantizationModesRND_CONV = 6, + QuantizationModesRND_CONV_ODD = 7, + QuantizationModesMax = 0x7fffffff, +}; + +enum OverflowModes { + OverflowModesWRAP = 0, + OverflowModesSAT = 1, + OverflowModesSAT_ZERO = 2, + OverflowModesSAT_SYM = 3, + OverflowModesMax = 0x7fffffff, +}; + +enum PackedVectorFormat { + PackedVectorFormatPackedVectorFormat4x8Bit = 0, + PackedVectorFormatPackedVectorFormat4x8BitKHR = 0, + PackedVectorFormatMax = 0x7fffffff, +}; + +enum CooperativeMatrixOperandsShift { + CooperativeMatrixOperandsMatrixASignedComponentsKHRShift = 0, + CooperativeMatrixOperandsMatrixBSignedComponentsKHRShift = 1, + CooperativeMatrixOperandsMatrixCSignedComponentsKHRShift = 2, + CooperativeMatrixOperandsMatrixResultSignedComponentsKHRShift = 3, + CooperativeMatrixOperandsSaturatingAccumulationKHRShift = 4, + CooperativeMatrixOperandsMax = 0x7fffffff, +}; + +enum CooperativeMatrixOperandsMask { + CooperativeMatrixOperandsMaskNone = 0, + CooperativeMatrixOperandsMatrixASignedComponentsKHRMask = 0x00000001, + CooperativeMatrixOperandsMatrixBSignedComponentsKHRMask = 0x00000002, + CooperativeMatrixOperandsMatrixCSignedComponentsKHRMask = 0x00000004, + CooperativeMatrixOperandsMatrixResultSignedComponentsKHRMask = 0x00000008, + CooperativeMatrixOperandsSaturatingAccumulationKHRMask = 0x00000010, +}; + +enum CooperativeMatrixLayout { + CooperativeMatrixLayoutRowMajorKHR = 0, + CooperativeMatrixLayoutColumnMajorKHR = 1, + CooperativeMatrixLayoutMax = 0x7fffffff, +}; + +enum CooperativeMatrixUse { + CooperativeMatrixUseMatrixAKHR = 0, + CooperativeMatrixUseMatrixBKHR = 1, + CooperativeMatrixUseMatrixAccumulatorKHR = 2, + CooperativeMatrixUseMax = 0x7fffffff, +}; + +enum Op { + OpNop = 0, + OpUndef = 1, + OpSourceContinued = 2, + OpSource = 3, + OpSourceExtension = 4, + OpName = 5, + OpMemberName = 6, + OpString = 7, + OpLine = 8, + OpExtension = 10, + OpExtInstImport = 11, + OpExtInst = 12, + OpMemoryModel = 14, + OpEntryPoint = 15, + OpExecutionMode = 16, + OpCapability = 17, + OpTypeVoid = 19, + OpTypeBool = 20, + OpTypeInt = 21, + OpTypeFloat = 22, + OpTypeVector = 23, + OpTypeMatrix = 24, + OpTypeImage = 25, + OpTypeSampler = 26, + OpTypeSampledImage = 27, + OpTypeArray = 28, + OpTypeRuntimeArray = 29, + OpTypeStruct = 30, + OpTypeOpaque = 31, + OpTypePointer = 32, + OpTypeFunction = 33, + OpTypeEvent = 34, + OpTypeDeviceEvent = 35, + OpTypeReserveId = 36, + OpTypeQueue = 37, + OpTypePipe = 38, + OpTypeForwardPointer = 39, + OpConstantTrue = 41, + OpConstantFalse = 42, + OpConstant = 43, + OpConstantComposite = 44, + OpConstantSampler = 45, + OpConstantNull = 46, + OpSpecConstantTrue = 48, + OpSpecConstantFalse = 49, + OpSpecConstant = 50, + OpSpecConstantComposite = 51, + OpSpecConstantOp = 52, + OpFunction = 54, + OpFunctionParameter = 55, + OpFunctionEnd = 56, + OpFunctionCall = 57, + OpVariable = 59, + OpImageTexelPointer = 60, + OpLoad = 61, + OpStore = 62, + OpCopyMemory = 63, + OpCopyMemorySized = 64, + OpAccessChain = 65, + OpInBoundsAccessChain = 66, + OpPtrAccessChain = 67, + OpArrayLength = 68, + OpGenericPtrMemSemantics = 69, + OpInBoundsPtrAccessChain = 70, + OpDecorate = 71, + OpMemberDecorate = 72, + OpDecorationGroup = 73, + OpGroupDecorate = 74, + OpGroupMemberDecorate = 75, + OpVectorExtractDynamic = 77, + OpVectorInsertDynamic = 78, + OpVectorShuffle = 79, + OpCompositeConstruct = 80, + OpCompositeExtract = 81, + OpCompositeInsert = 82, + OpCopyObject = 83, + OpTranspose = 84, + OpSampledImage = 86, + OpImageSampleImplicitLod = 87, + OpImageSampleExplicitLod = 88, + OpImageSampleDrefImplicitLod = 89, + OpImageSampleDrefExplicitLod = 90, + OpImageSampleProjImplicitLod = 91, + OpImageSampleProjExplicitLod = 92, + OpImageSampleProjDrefImplicitLod = 93, + OpImageSampleProjDrefExplicitLod = 94, + OpImageFetch = 95, + OpImageGather = 96, + OpImageDrefGather = 97, + OpImageRead = 98, + OpImageWrite = 99, + OpImage = 100, + OpImageQueryFormat = 101, + OpImageQueryOrder = 102, + OpImageQuerySizeLod = 103, + OpImageQuerySize = 104, + OpImageQueryLod = 105, + OpImageQueryLevels = 106, + OpImageQuerySamples = 107, + OpConvertFToU = 109, + OpConvertFToS = 110, + OpConvertSToF = 111, + OpConvertUToF = 112, + OpUConvert = 113, + OpSConvert = 114, + OpFConvert = 115, + OpQuantizeToF16 = 116, + OpConvertPtrToU = 117, + OpSatConvertSToU = 118, + OpSatConvertUToS = 119, + OpConvertUToPtr = 120, + OpPtrCastToGeneric = 121, + OpGenericCastToPtr = 122, + OpGenericCastToPtrExplicit = 123, + OpBitcast = 124, + OpSNegate = 126, + OpFNegate = 127, + OpIAdd = 128, + OpFAdd = 129, + OpISub = 130, + OpFSub = 131, + OpIMul = 132, + OpFMul = 133, + OpUDiv = 134, + OpSDiv = 135, + OpFDiv = 136, + OpUMod = 137, + OpSRem = 138, + OpSMod = 139, + OpFRem = 140, + OpFMod = 141, + OpVectorTimesScalar = 142, + OpMatrixTimesScalar = 143, + OpVectorTimesMatrix = 144, + OpMatrixTimesVector = 145, + OpMatrixTimesMatrix = 146, + OpOuterProduct = 147, + OpDot = 148, + OpIAddCarry = 149, + OpISubBorrow = 150, + OpUMulExtended = 151, + OpSMulExtended = 152, + OpAny = 154, + OpAll = 155, + OpIsNan = 156, + OpIsInf = 157, + OpIsFinite = 158, + OpIsNormal = 159, + OpSignBitSet = 160, + OpLessOrGreater = 161, + OpOrdered = 162, + OpUnordered = 163, + OpLogicalEqual = 164, + OpLogicalNotEqual = 165, + OpLogicalOr = 166, + OpLogicalAnd = 167, + OpLogicalNot = 168, + OpSelect = 169, + OpIEqual = 170, + OpINotEqual = 171, + OpUGreaterThan = 172, + OpSGreaterThan = 173, + OpUGreaterThanEqual = 174, + OpSGreaterThanEqual = 175, + OpULessThan = 176, + OpSLessThan = 177, + OpULessThanEqual = 178, + OpSLessThanEqual = 179, + OpFOrdEqual = 180, + OpFUnordEqual = 181, + OpFOrdNotEqual = 182, + OpFUnordNotEqual = 183, + OpFOrdLessThan = 184, + OpFUnordLessThan = 185, + OpFOrdGreaterThan = 186, + OpFUnordGreaterThan = 187, + OpFOrdLessThanEqual = 188, + OpFUnordLessThanEqual = 189, + OpFOrdGreaterThanEqual = 190, + OpFUnordGreaterThanEqual = 191, + OpShiftRightLogical = 194, + OpShiftRightArithmetic = 195, + OpShiftLeftLogical = 196, + OpBitwiseOr = 197, + OpBitwiseXor = 198, + OpBitwiseAnd = 199, + OpNot = 200, + OpBitFieldInsert = 201, + OpBitFieldSExtract = 202, + OpBitFieldUExtract = 203, + OpBitReverse = 204, + OpBitCount = 205, + OpDPdx = 207, + OpDPdy = 208, + OpFwidth = 209, + OpDPdxFine = 210, + OpDPdyFine = 211, + OpFwidthFine = 212, + OpDPdxCoarse = 213, + OpDPdyCoarse = 214, + OpFwidthCoarse = 215, + OpEmitVertex = 218, + OpEndPrimitive = 219, + OpEmitStreamVertex = 220, + OpEndStreamPrimitive = 221, + OpControlBarrier = 224, + OpMemoryBarrier = 225, + OpAtomicLoad = 227, + OpAtomicStore = 228, + OpAtomicExchange = 229, + OpAtomicCompareExchange = 230, + OpAtomicCompareExchangeWeak = 231, + OpAtomicIIncrement = 232, + OpAtomicIDecrement = 233, + OpAtomicIAdd = 234, + OpAtomicISub = 235, + OpAtomicSMin = 236, + OpAtomicUMin = 237, + OpAtomicSMax = 238, + OpAtomicUMax = 239, + OpAtomicAnd = 240, + OpAtomicOr = 241, + OpAtomicXor = 242, + OpPhi = 245, + OpLoopMerge = 246, + OpSelectionMerge = 247, + OpLabel = 248, + OpBranch = 249, + OpBranchConditional = 250, + OpSwitch = 251, + OpKill = 252, + OpReturn = 253, + OpReturnValue = 254, + OpUnreachable = 255, + OpLifetimeStart = 256, + OpLifetimeStop = 257, + OpGroupAsyncCopy = 259, + OpGroupWaitEvents = 260, + OpGroupAll = 261, + OpGroupAny = 262, + OpGroupBroadcast = 263, + OpGroupIAdd = 264, + OpGroupFAdd = 265, + OpGroupFMin = 266, + OpGroupUMin = 267, + OpGroupSMin = 268, + OpGroupFMax = 269, + OpGroupUMax = 270, + OpGroupSMax = 271, + OpReadPipe = 274, + OpWritePipe = 275, + OpReservedReadPipe = 276, + OpReservedWritePipe = 277, + OpReserveReadPipePackets = 278, + OpReserveWritePipePackets = 279, + OpCommitReadPipe = 280, + OpCommitWritePipe = 281, + OpIsValidReserveId = 282, + OpGetNumPipePackets = 283, + OpGetMaxPipePackets = 284, + OpGroupReserveReadPipePackets = 285, + OpGroupReserveWritePipePackets = 286, + OpGroupCommitReadPipe = 287, + OpGroupCommitWritePipe = 288, + OpEnqueueMarker = 291, + OpEnqueueKernel = 292, + OpGetKernelNDrangeSubGroupCount = 293, + OpGetKernelNDrangeMaxSubGroupSize = 294, + OpGetKernelWorkGroupSize = 295, + OpGetKernelPreferredWorkGroupSizeMultiple = 296, + OpRetainEvent = 297, + OpReleaseEvent = 298, + OpCreateUserEvent = 299, + OpIsValidEvent = 300, + OpSetUserEventStatus = 301, + OpCaptureEventProfilingInfo = 302, + OpGetDefaultQueue = 303, + OpBuildNDRange = 304, + OpImageSparseSampleImplicitLod = 305, + OpImageSparseSampleExplicitLod = 306, + OpImageSparseSampleDrefImplicitLod = 307, + OpImageSparseSampleDrefExplicitLod = 308, + OpImageSparseSampleProjImplicitLod = 309, + OpImageSparseSampleProjExplicitLod = 310, + OpImageSparseSampleProjDrefImplicitLod = 311, + OpImageSparseSampleProjDrefExplicitLod = 312, + OpImageSparseFetch = 313, + OpImageSparseGather = 314, + OpImageSparseDrefGather = 315, + OpImageSparseTexelsResident = 316, + OpNoLine = 317, + OpAtomicFlagTestAndSet = 318, + OpAtomicFlagClear = 319, + OpImageSparseRead = 320, + OpSizeOf = 321, + OpTypePipeStorage = 322, + OpConstantPipeStorage = 323, + OpCreatePipeFromPipeStorage = 324, + OpGetKernelLocalSizeForSubgroupCount = 325, + OpGetKernelMaxNumSubgroups = 326, + OpTypeNamedBarrier = 327, + OpNamedBarrierInitialize = 328, + OpMemoryNamedBarrier = 329, + OpModuleProcessed = 330, + OpExecutionModeId = 331, + OpDecorateId = 332, + OpGroupNonUniformElect = 333, + OpGroupNonUniformAll = 334, + OpGroupNonUniformAny = 335, + OpGroupNonUniformAllEqual = 336, + OpGroupNonUniformBroadcast = 337, + OpGroupNonUniformBroadcastFirst = 338, + OpGroupNonUniformBallot = 339, + OpGroupNonUniformInverseBallot = 340, + OpGroupNonUniformBallotBitExtract = 341, + OpGroupNonUniformBallotBitCount = 342, + OpGroupNonUniformBallotFindLSB = 343, + OpGroupNonUniformBallotFindMSB = 344, + OpGroupNonUniformShuffle = 345, + OpGroupNonUniformShuffleXor = 346, + OpGroupNonUniformShuffleUp = 347, + OpGroupNonUniformShuffleDown = 348, + OpGroupNonUniformIAdd = 349, + OpGroupNonUniformFAdd = 350, + OpGroupNonUniformIMul = 351, + OpGroupNonUniformFMul = 352, + OpGroupNonUniformSMin = 353, + OpGroupNonUniformUMin = 354, + OpGroupNonUniformFMin = 355, + OpGroupNonUniformSMax = 356, + OpGroupNonUniformUMax = 357, + OpGroupNonUniformFMax = 358, + OpGroupNonUniformBitwiseAnd = 359, + OpGroupNonUniformBitwiseOr = 360, + OpGroupNonUniformBitwiseXor = 361, + OpGroupNonUniformLogicalAnd = 362, + OpGroupNonUniformLogicalOr = 363, + OpGroupNonUniformLogicalXor = 364, + OpGroupNonUniformQuadBroadcast = 365, + OpGroupNonUniformQuadSwap = 366, + OpCopyLogical = 400, + OpPtrEqual = 401, + OpPtrNotEqual = 402, + OpPtrDiff = 403, + OpColorAttachmentReadEXT = 4160, + OpDepthAttachmentReadEXT = 4161, + OpStencilAttachmentReadEXT = 4162, + OpTerminateInvocation = 4416, + OpSubgroupBallotKHR = 4421, + OpSubgroupFirstInvocationKHR = 4422, + OpSubgroupAllKHR = 4428, + OpSubgroupAnyKHR = 4429, + OpSubgroupAllEqualKHR = 4430, + OpGroupNonUniformRotateKHR = 4431, + OpSubgroupReadInvocationKHR = 4432, + OpTraceRayKHR = 4445, + OpExecuteCallableKHR = 4446, + OpConvertUToAccelerationStructureKHR = 4447, + OpIgnoreIntersectionKHR = 4448, + OpTerminateRayKHR = 4449, + OpSDot = 4450, + OpSDotKHR = 4450, + OpUDot = 4451, + OpUDotKHR = 4451, + OpSUDot = 4452, + OpSUDotKHR = 4452, + OpSDotAccSat = 4453, + OpSDotAccSatKHR = 4453, + OpUDotAccSat = 4454, + OpUDotAccSatKHR = 4454, + OpSUDotAccSat = 4455, + OpSUDotAccSatKHR = 4455, + OpTypeCooperativeMatrixKHR = 4456, + OpCooperativeMatrixLoadKHR = 4457, + OpCooperativeMatrixStoreKHR = 4458, + OpCooperativeMatrixMulAddKHR = 4459, + OpCooperativeMatrixLengthKHR = 4460, + OpTypeRayQueryKHR = 4472, + OpRayQueryInitializeKHR = 4473, + OpRayQueryTerminateKHR = 4474, + OpRayQueryGenerateIntersectionKHR = 4475, + OpRayQueryConfirmIntersectionKHR = 4476, + OpRayQueryProceedKHR = 4477, + OpRayQueryGetIntersectionTypeKHR = 4479, + OpImageSampleWeightedQCOM = 4480, + OpImageBoxFilterQCOM = 4481, + OpImageBlockMatchSSDQCOM = 4482, + OpImageBlockMatchSADQCOM = 4483, + OpImageBlockMatchWindowSSDQCOM = 4500, + OpImageBlockMatchWindowSADQCOM = 4501, + OpImageBlockMatchGatherSSDQCOM = 4502, + OpImageBlockMatchGatherSADQCOM = 4503, + OpGroupIAddNonUniformAMD = 5000, + OpGroupFAddNonUniformAMD = 5001, + OpGroupFMinNonUniformAMD = 5002, + OpGroupUMinNonUniformAMD = 5003, + OpGroupSMinNonUniformAMD = 5004, + OpGroupFMaxNonUniformAMD = 5005, + OpGroupUMaxNonUniformAMD = 5006, + OpGroupSMaxNonUniformAMD = 5007, + OpFragmentMaskFetchAMD = 5011, + OpFragmentFetchAMD = 5012, + OpReadClockKHR = 5056, + OpGroupNonUniformQuadAllKHR = 5110, + OpGroupNonUniformQuadAnyKHR = 5111, + OpHitObjectRecordHitMotionNV = 5249, + OpHitObjectRecordHitWithIndexMotionNV = 5250, + OpHitObjectRecordMissMotionNV = 5251, + OpHitObjectGetWorldToObjectNV = 5252, + OpHitObjectGetObjectToWorldNV = 5253, + OpHitObjectGetObjectRayDirectionNV = 5254, + OpHitObjectGetObjectRayOriginNV = 5255, + OpHitObjectTraceRayMotionNV = 5256, + OpHitObjectGetShaderRecordBufferHandleNV = 5257, + OpHitObjectGetShaderBindingTableRecordIndexNV = 5258, + OpHitObjectRecordEmptyNV = 5259, + OpHitObjectTraceRayNV = 5260, + OpHitObjectRecordHitNV = 5261, + OpHitObjectRecordHitWithIndexNV = 5262, + OpHitObjectRecordMissNV = 5263, + OpHitObjectExecuteShaderNV = 5264, + OpHitObjectGetCurrentTimeNV = 5265, + OpHitObjectGetAttributesNV = 5266, + OpHitObjectGetHitKindNV = 5267, + OpHitObjectGetPrimitiveIndexNV = 5268, + OpHitObjectGetGeometryIndexNV = 5269, + OpHitObjectGetInstanceIdNV = 5270, + OpHitObjectGetInstanceCustomIndexNV = 5271, + OpHitObjectGetWorldRayDirectionNV = 5272, + OpHitObjectGetWorldRayOriginNV = 5273, + OpHitObjectGetRayTMaxNV = 5274, + OpHitObjectGetRayTMinNV = 5275, + OpHitObjectIsEmptyNV = 5276, + OpHitObjectIsHitNV = 5277, + OpHitObjectIsMissNV = 5278, + OpReorderThreadWithHitObjectNV = 5279, + OpReorderThreadWithHintNV = 5280, + OpTypeHitObjectNV = 5281, + OpImageSampleFootprintNV = 5283, + OpEmitMeshTasksEXT = 5294, + OpSetMeshOutputsEXT = 5295, + OpGroupNonUniformPartitionNV = 5296, + OpWritePackedPrimitiveIndices4x8NV = 5299, + OpFetchMicroTriangleVertexPositionNV = 5300, + OpFetchMicroTriangleVertexBarycentricNV = 5301, + OpReportIntersectionKHR = 5334, + OpReportIntersectionNV = 5334, + OpIgnoreIntersectionNV = 5335, + OpTerminateRayNV = 5336, + OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, + OpRayQueryGetIntersectionTriangleVertexPositionsKHR = 5340, + OpTypeAccelerationStructureKHR = 5341, + OpTypeAccelerationStructureNV = 5341, + OpExecuteCallableNV = 5344, + OpTypeCooperativeMatrixNV = 5358, + OpCooperativeMatrixLoadNV = 5359, + OpCooperativeMatrixStoreNV = 5360, + OpCooperativeMatrixMulAddNV = 5361, + OpCooperativeMatrixLengthNV = 5362, + OpBeginInvocationInterlockEXT = 5364, + OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocation = 5380, + OpDemoteToHelperInvocationEXT = 5380, + OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, + OpSubgroupShuffleINTEL = 5571, + OpSubgroupShuffleDownINTEL = 5572, + OpSubgroupShuffleUpINTEL = 5573, + OpSubgroupShuffleXorINTEL = 5574, + OpSubgroupBlockReadINTEL = 5575, + OpSubgroupBlockWriteINTEL = 5576, + OpSubgroupImageBlockReadINTEL = 5577, + OpSubgroupImageBlockWriteINTEL = 5578, + OpSubgroupImageMediaBlockReadINTEL = 5580, + OpSubgroupImageMediaBlockWriteINTEL = 5581, + OpUCountLeadingZerosINTEL = 5585, + OpUCountTrailingZerosINTEL = 5586, + OpAbsISubINTEL = 5587, + OpAbsUSubINTEL = 5588, + OpIAddSatINTEL = 5589, + OpUAddSatINTEL = 5590, + OpIAverageINTEL = 5591, + OpUAverageINTEL = 5592, + OpIAverageRoundedINTEL = 5593, + OpUAverageRoundedINTEL = 5594, + OpISubSatINTEL = 5595, + OpUSubSatINTEL = 5596, + OpIMul32x16INTEL = 5597, + OpUMul32x16INTEL = 5598, + OpConstantFunctionPointerINTEL = 5600, + OpFunctionPointerCallINTEL = 5601, + OpAsmTargetINTEL = 5609, + OpAsmINTEL = 5610, + OpAsmCallINTEL = 5611, + OpAtomicFMinEXT = 5614, + OpAtomicFMaxEXT = 5615, + OpAssumeTrueKHR = 5630, + OpExpectKHR = 5631, + OpDecorateString = 5632, + OpDecorateStringGOOGLE = 5632, + OpMemberDecorateString = 5633, + OpMemberDecorateStringGOOGLE = 5633, + OpVmeImageINTEL = 5699, + OpTypeVmeImageINTEL = 5700, + OpTypeAvcImePayloadINTEL = 5701, + OpTypeAvcRefPayloadINTEL = 5702, + OpTypeAvcSicPayloadINTEL = 5703, + OpTypeAvcMcePayloadINTEL = 5704, + OpTypeAvcMceResultINTEL = 5705, + OpTypeAvcImeResultINTEL = 5706, + OpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, + OpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, + OpTypeAvcImeSingleReferenceStreaminINTEL = 5709, + OpTypeAvcImeDualReferenceStreaminINTEL = 5710, + OpTypeAvcRefResultINTEL = 5711, + OpTypeAvcSicResultINTEL = 5712, + OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, + OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, + OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, + OpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, + OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, + OpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, + OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, + OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, + OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, + OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, + OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, + OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, + OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, + OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, + OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, + OpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, + OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, + OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, + OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, + OpSubgroupAvcMceConvertToImePayloadINTEL = 5732, + OpSubgroupAvcMceConvertToImeResultINTEL = 5733, + OpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, + OpSubgroupAvcMceConvertToRefResultINTEL = 5735, + OpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, + OpSubgroupAvcMceConvertToSicResultINTEL = 5737, + OpSubgroupAvcMceGetMotionVectorsINTEL = 5738, + OpSubgroupAvcMceGetInterDistortionsINTEL = 5739, + OpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, + OpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, + OpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, + OpSubgroupAvcMceGetInterDirectionsINTEL = 5743, + OpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, + OpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, + OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, + OpSubgroupAvcImeInitializeINTEL = 5747, + OpSubgroupAvcImeSetSingleReferenceINTEL = 5748, + OpSubgroupAvcImeSetDualReferenceINTEL = 5749, + OpSubgroupAvcImeRefWindowSizeINTEL = 5750, + OpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, + OpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, + OpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, + OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, + OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, + OpSubgroupAvcImeSetWeightedSadINTEL = 5756, + OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, + OpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, + OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, + OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, + OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, + OpSubgroupAvcImeConvertToMceResultINTEL = 5765, + OpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, + OpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, + OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, + OpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, + OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, + OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, + OpSubgroupAvcImeGetBorderReachedINTEL = 5776, + OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, + OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, + OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, + OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, + OpSubgroupAvcFmeInitializeINTEL = 5781, + OpSubgroupAvcBmeInitializeINTEL = 5782, + OpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, + OpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, + OpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, + OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, + OpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, + OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, + OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, + OpSubgroupAvcRefConvertToMceResultINTEL = 5790, + OpSubgroupAvcSicInitializeINTEL = 5791, + OpSubgroupAvcSicConfigureSkcINTEL = 5792, + OpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, + OpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, + OpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, + OpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, + OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, + OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, + OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, + OpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, + OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, + OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, + OpSubgroupAvcSicEvaluateIpeINTEL = 5803, + OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, + OpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, + OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, + OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, + OpSubgroupAvcSicConvertToMceResultINTEL = 5808, + OpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, + OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, + OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, + OpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, + OpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, + OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, + OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, + OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, + OpArbitraryFloatSinCosPiINTEL = 5840, + OpArbitraryFloatCastINTEL = 5841, + OpArbitraryFloatCastFromIntINTEL = 5842, + OpArbitraryFloatCastToIntINTEL = 5843, + OpArbitraryFloatAddINTEL = 5846, + OpArbitraryFloatSubINTEL = 5847, + OpArbitraryFloatMulINTEL = 5848, + OpArbitraryFloatDivINTEL = 5849, + OpArbitraryFloatGTINTEL = 5850, + OpArbitraryFloatGEINTEL = 5851, + OpArbitraryFloatLTINTEL = 5852, + OpArbitraryFloatLEINTEL = 5853, + OpArbitraryFloatEQINTEL = 5854, + OpArbitraryFloatRecipINTEL = 5855, + OpArbitraryFloatRSqrtINTEL = 5856, + OpArbitraryFloatCbrtINTEL = 5857, + OpArbitraryFloatHypotINTEL = 5858, + OpArbitraryFloatSqrtINTEL = 5859, + OpArbitraryFloatLogINTEL = 5860, + OpArbitraryFloatLog2INTEL = 5861, + OpArbitraryFloatLog10INTEL = 5862, + OpArbitraryFloatLog1pINTEL = 5863, + OpArbitraryFloatExpINTEL = 5864, + OpArbitraryFloatExp2INTEL = 5865, + OpArbitraryFloatExp10INTEL = 5866, + OpArbitraryFloatExpm1INTEL = 5867, + OpArbitraryFloatSinINTEL = 5868, + OpArbitraryFloatCosINTEL = 5869, + OpArbitraryFloatSinCosINTEL = 5870, + OpArbitraryFloatSinPiINTEL = 5871, + OpArbitraryFloatCosPiINTEL = 5872, + OpArbitraryFloatASinINTEL = 5873, + OpArbitraryFloatASinPiINTEL = 5874, + OpArbitraryFloatACosINTEL = 5875, + OpArbitraryFloatACosPiINTEL = 5876, + OpArbitraryFloatATanINTEL = 5877, + OpArbitraryFloatATanPiINTEL = 5878, + OpArbitraryFloatATan2INTEL = 5879, + OpArbitraryFloatPowINTEL = 5880, + OpArbitraryFloatPowRINTEL = 5881, + OpArbitraryFloatPowNINTEL = 5882, + OpLoopControlINTEL = 5887, + OpAliasDomainDeclINTEL = 5911, + OpAliasScopeDeclINTEL = 5912, + OpAliasScopeListDeclINTEL = 5913, + OpFixedSqrtINTEL = 5923, + OpFixedRecipINTEL = 5924, + OpFixedRsqrtINTEL = 5925, + OpFixedSinINTEL = 5926, + OpFixedCosINTEL = 5927, + OpFixedSinCosINTEL = 5928, + OpFixedSinPiINTEL = 5929, + OpFixedCosPiINTEL = 5930, + OpFixedSinCosPiINTEL = 5931, + OpFixedLogINTEL = 5932, + OpFixedExpINTEL = 5933, + OpPtrCastToCrossWorkgroupINTEL = 5934, + OpCrossWorkgroupCastToPtrINTEL = 5938, + OpReadPipeBlockingINTEL = 5946, + OpWritePipeBlockingINTEL = 5947, + OpFPGARegINTEL = 5949, + OpRayQueryGetRayTMinKHR = 6016, + OpRayQueryGetRayFlagsKHR = 6017, + OpRayQueryGetIntersectionTKHR = 6018, + OpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, + OpRayQueryGetIntersectionInstanceIdKHR = 6020, + OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, + OpRayQueryGetIntersectionGeometryIndexKHR = 6022, + OpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, + OpRayQueryGetIntersectionBarycentricsKHR = 6024, + OpRayQueryGetIntersectionFrontFaceKHR = 6025, + OpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, + OpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, + OpRayQueryGetIntersectionObjectRayOriginKHR = 6028, + OpRayQueryGetWorldRayDirectionKHR = 6029, + OpRayQueryGetWorldRayOriginKHR = 6030, + OpRayQueryGetIntersectionObjectToWorldKHR = 6031, + OpRayQueryGetIntersectionWorldToObjectKHR = 6032, + OpAtomicFAddEXT = 6035, + OpTypeBufferSurfaceINTEL = 6086, + OpTypeStructContinuedINTEL = 6090, + OpConstantCompositeContinuedINTEL = 6091, + OpSpecConstantCompositeContinuedINTEL = 6092, + OpControlBarrierArriveINTEL = 6142, + OpControlBarrierWaitINTEL = 6143, + OpGroupIMulKHR = 6401, + OpGroupFMulKHR = 6402, + OpGroupBitwiseAndKHR = 6403, + OpGroupBitwiseOrKHR = 6404, + OpGroupBitwiseXorKHR = 6405, + OpGroupLogicalAndKHR = 6406, + OpGroupLogicalOrKHR = 6407, + OpGroupLogicalXorKHR = 6408, + OpMax = 0x7fffffff, +}; + +#ifdef SPV_ENABLE_UTILITY_CODE +#ifndef __cplusplus +#include +#endif +inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { + *hasResult = *hasResultType = false; + switch (opcode) { + default: /* unknown opcode */ break; + case OpNop: *hasResult = false; *hasResultType = false; break; + case OpUndef: *hasResult = true; *hasResultType = true; break; + case OpSourceContinued: *hasResult = false; *hasResultType = false; break; + case OpSource: *hasResult = false; *hasResultType = false; break; + case OpSourceExtension: *hasResult = false; *hasResultType = false; break; + case OpName: *hasResult = false; *hasResultType = false; break; + case OpMemberName: *hasResult = false; *hasResultType = false; break; + case OpString: *hasResult = true; *hasResultType = false; break; + case OpLine: *hasResult = false; *hasResultType = false; break; + case OpExtension: *hasResult = false; *hasResultType = false; break; + case OpExtInstImport: *hasResult = true; *hasResultType = false; break; + case OpExtInst: *hasResult = true; *hasResultType = true; break; + case OpMemoryModel: *hasResult = false; *hasResultType = false; break; + case OpEntryPoint: *hasResult = false; *hasResultType = false; break; + case OpExecutionMode: *hasResult = false; *hasResultType = false; break; + case OpCapability: *hasResult = false; *hasResultType = false; break; + case OpTypeVoid: *hasResult = true; *hasResultType = false; break; + case OpTypeBool: *hasResult = true; *hasResultType = false; break; + case OpTypeInt: *hasResult = true; *hasResultType = false; break; + case OpTypeFloat: *hasResult = true; *hasResultType = false; break; + case OpTypeVector: *hasResult = true; *hasResultType = false; break; + case OpTypeMatrix: *hasResult = true; *hasResultType = false; break; + case OpTypeImage: *hasResult = true; *hasResultType = false; break; + case OpTypeSampler: *hasResult = true; *hasResultType = false; break; + case OpTypeSampledImage: *hasResult = true; *hasResultType = false; break; + case OpTypeArray: *hasResult = true; *hasResultType = false; break; + case OpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; + case OpTypeStruct: *hasResult = true; *hasResultType = false; break; + case OpTypeOpaque: *hasResult = true; *hasResultType = false; break; + case OpTypePointer: *hasResult = true; *hasResultType = false; break; + case OpTypeFunction: *hasResult = true; *hasResultType = false; break; + case OpTypeEvent: *hasResult = true; *hasResultType = false; break; + case OpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; + case OpTypeReserveId: *hasResult = true; *hasResultType = false; break; + case OpTypeQueue: *hasResult = true; *hasResultType = false; break; + case OpTypePipe: *hasResult = true; *hasResultType = false; break; + case OpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; + case OpConstantTrue: *hasResult = true; *hasResultType = true; break; + case OpConstantFalse: *hasResult = true; *hasResultType = true; break; + case OpConstant: *hasResult = true; *hasResultType = true; break; + case OpConstantComposite: *hasResult = true; *hasResultType = true; break; + case OpConstantSampler: *hasResult = true; *hasResultType = true; break; + case OpConstantNull: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; + case OpSpecConstant: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; + case OpSpecConstantOp: *hasResult = true; *hasResultType = true; break; + case OpFunction: *hasResult = true; *hasResultType = true; break; + case OpFunctionParameter: *hasResult = true; *hasResultType = true; break; + case OpFunctionEnd: *hasResult = false; *hasResultType = false; break; + case OpFunctionCall: *hasResult = true; *hasResultType = true; break; + case OpVariable: *hasResult = true; *hasResultType = true; break; + case OpImageTexelPointer: *hasResult = true; *hasResultType = true; break; + case OpLoad: *hasResult = true; *hasResultType = true; break; + case OpStore: *hasResult = false; *hasResultType = false; break; + case OpCopyMemory: *hasResult = false; *hasResultType = false; break; + case OpCopyMemorySized: *hasResult = false; *hasResultType = false; break; + case OpAccessChain: *hasResult = true; *hasResultType = true; break; + case OpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; + case OpPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case OpArrayLength: *hasResult = true; *hasResultType = true; break; + case OpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; + case OpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; + case OpDecorate: *hasResult = false; *hasResultType = false; break; + case OpMemberDecorate: *hasResult = false; *hasResultType = false; break; + case OpDecorationGroup: *hasResult = true; *hasResultType = false; break; + case OpGroupDecorate: *hasResult = false; *hasResultType = false; break; + case OpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; + case OpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; + case OpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; + case OpVectorShuffle: *hasResult = true; *hasResultType = true; break; + case OpCompositeConstruct: *hasResult = true; *hasResultType = true; break; + case OpCompositeExtract: *hasResult = true; *hasResultType = true; break; + case OpCompositeInsert: *hasResult = true; *hasResultType = true; break; + case OpCopyObject: *hasResult = true; *hasResultType = true; break; + case OpTranspose: *hasResult = true; *hasResultType = true; break; + case OpSampledImage: *hasResult = true; *hasResultType = true; break; + case OpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageFetch: *hasResult = true; *hasResultType = true; break; + case OpImageGather: *hasResult = true; *hasResultType = true; break; + case OpImageDrefGather: *hasResult = true; *hasResultType = true; break; + case OpImageRead: *hasResult = true; *hasResultType = true; break; + case OpImageWrite: *hasResult = false; *hasResultType = false; break; + case OpImage: *hasResult = true; *hasResultType = true; break; + case OpImageQueryFormat: *hasResult = true; *hasResultType = true; break; + case OpImageQueryOrder: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySize: *hasResult = true; *hasResultType = true; break; + case OpImageQueryLod: *hasResult = true; *hasResultType = true; break; + case OpImageQueryLevels: *hasResult = true; *hasResultType = true; break; + case OpImageQuerySamples: *hasResult = true; *hasResultType = true; break; + case OpConvertFToU: *hasResult = true; *hasResultType = true; break; + case OpConvertFToS: *hasResult = true; *hasResultType = true; break; + case OpConvertSToF: *hasResult = true; *hasResultType = true; break; + case OpConvertUToF: *hasResult = true; *hasResultType = true; break; + case OpUConvert: *hasResult = true; *hasResultType = true; break; + case OpSConvert: *hasResult = true; *hasResultType = true; break; + case OpFConvert: *hasResult = true; *hasResultType = true; break; + case OpQuantizeToF16: *hasResult = true; *hasResultType = true; break; + case OpConvertPtrToU: *hasResult = true; *hasResultType = true; break; + case OpSatConvertSToU: *hasResult = true; *hasResultType = true; break; + case OpSatConvertUToS: *hasResult = true; *hasResultType = true; break; + case OpConvertUToPtr: *hasResult = true; *hasResultType = true; break; + case OpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; + case OpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; + case OpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; + case OpBitcast: *hasResult = true; *hasResultType = true; break; + case OpSNegate: *hasResult = true; *hasResultType = true; break; + case OpFNegate: *hasResult = true; *hasResultType = true; break; + case OpIAdd: *hasResult = true; *hasResultType = true; break; + case OpFAdd: *hasResult = true; *hasResultType = true; break; + case OpISub: *hasResult = true; *hasResultType = true; break; + case OpFSub: *hasResult = true; *hasResultType = true; break; + case OpIMul: *hasResult = true; *hasResultType = true; break; + case OpFMul: *hasResult = true; *hasResultType = true; break; + case OpUDiv: *hasResult = true; *hasResultType = true; break; + case OpSDiv: *hasResult = true; *hasResultType = true; break; + case OpFDiv: *hasResult = true; *hasResultType = true; break; + case OpUMod: *hasResult = true; *hasResultType = true; break; + case OpSRem: *hasResult = true; *hasResultType = true; break; + case OpSMod: *hasResult = true; *hasResultType = true; break; + case OpFRem: *hasResult = true; *hasResultType = true; break; + case OpFMod: *hasResult = true; *hasResultType = true; break; + case OpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; + case OpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; + case OpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; + case OpOuterProduct: *hasResult = true; *hasResultType = true; break; + case OpDot: *hasResult = true; *hasResultType = true; break; + case OpIAddCarry: *hasResult = true; *hasResultType = true; break; + case OpISubBorrow: *hasResult = true; *hasResultType = true; break; + case OpUMulExtended: *hasResult = true; *hasResultType = true; break; + case OpSMulExtended: *hasResult = true; *hasResultType = true; break; + case OpAny: *hasResult = true; *hasResultType = true; break; + case OpAll: *hasResult = true; *hasResultType = true; break; + case OpIsNan: *hasResult = true; *hasResultType = true; break; + case OpIsInf: *hasResult = true; *hasResultType = true; break; + case OpIsFinite: *hasResult = true; *hasResultType = true; break; + case OpIsNormal: *hasResult = true; *hasResultType = true; break; + case OpSignBitSet: *hasResult = true; *hasResultType = true; break; + case OpLessOrGreater: *hasResult = true; *hasResultType = true; break; + case OpOrdered: *hasResult = true; *hasResultType = true; break; + case OpUnordered: *hasResult = true; *hasResultType = true; break; + case OpLogicalEqual: *hasResult = true; *hasResultType = true; break; + case OpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; + case OpLogicalOr: *hasResult = true; *hasResultType = true; break; + case OpLogicalAnd: *hasResult = true; *hasResultType = true; break; + case OpLogicalNot: *hasResult = true; *hasResultType = true; break; + case OpSelect: *hasResult = true; *hasResultType = true; break; + case OpIEqual: *hasResult = true; *hasResultType = true; break; + case OpINotEqual: *hasResult = true; *hasResultType = true; break; + case OpUGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpSGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpULessThan: *hasResult = true; *hasResultType = true; break; + case OpSLessThan: *hasResult = true; *hasResultType = true; break; + case OpULessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpSLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdLessThan: *hasResult = true; *hasResultType = true; break; + case OpFUnordLessThan: *hasResult = true; *hasResultType = true; break; + case OpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; + case OpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; + case OpShiftRightLogical: *hasResult = true; *hasResultType = true; break; + case OpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; + case OpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; + case OpBitwiseOr: *hasResult = true; *hasResultType = true; break; + case OpBitwiseXor: *hasResult = true; *hasResultType = true; break; + case OpBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case OpNot: *hasResult = true; *hasResultType = true; break; + case OpBitFieldInsert: *hasResult = true; *hasResultType = true; break; + case OpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; + case OpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; + case OpBitReverse: *hasResult = true; *hasResultType = true; break; + case OpBitCount: *hasResult = true; *hasResultType = true; break; + case OpDPdx: *hasResult = true; *hasResultType = true; break; + case OpDPdy: *hasResult = true; *hasResultType = true; break; + case OpFwidth: *hasResult = true; *hasResultType = true; break; + case OpDPdxFine: *hasResult = true; *hasResultType = true; break; + case OpDPdyFine: *hasResult = true; *hasResultType = true; break; + case OpFwidthFine: *hasResult = true; *hasResultType = true; break; + case OpDPdxCoarse: *hasResult = true; *hasResultType = true; break; + case OpDPdyCoarse: *hasResult = true; *hasResultType = true; break; + case OpFwidthCoarse: *hasResult = true; *hasResultType = true; break; + case OpEmitVertex: *hasResult = false; *hasResultType = false; break; + case OpEndPrimitive: *hasResult = false; *hasResultType = false; break; + case OpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; + case OpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; + case OpControlBarrier: *hasResult = false; *hasResultType = false; break; + case OpMemoryBarrier: *hasResult = false; *hasResultType = false; break; + case OpAtomicLoad: *hasResult = true; *hasResultType = true; break; + case OpAtomicStore: *hasResult = false; *hasResultType = false; break; + case OpAtomicExchange: *hasResult = true; *hasResultType = true; break; + case OpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; + case OpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; + case OpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; + case OpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; + case OpAtomicIAdd: *hasResult = true; *hasResultType = true; break; + case OpAtomicISub: *hasResult = true; *hasResultType = true; break; + case OpAtomicSMin: *hasResult = true; *hasResultType = true; break; + case OpAtomicUMin: *hasResult = true; *hasResultType = true; break; + case OpAtomicSMax: *hasResult = true; *hasResultType = true; break; + case OpAtomicUMax: *hasResult = true; *hasResultType = true; break; + case OpAtomicAnd: *hasResult = true; *hasResultType = true; break; + case OpAtomicOr: *hasResult = true; *hasResultType = true; break; + case OpAtomicXor: *hasResult = true; *hasResultType = true; break; + case OpPhi: *hasResult = true; *hasResultType = true; break; + case OpLoopMerge: *hasResult = false; *hasResultType = false; break; + case OpSelectionMerge: *hasResult = false; *hasResultType = false; break; + case OpLabel: *hasResult = true; *hasResultType = false; break; + case OpBranch: *hasResult = false; *hasResultType = false; break; + case OpBranchConditional: *hasResult = false; *hasResultType = false; break; + case OpSwitch: *hasResult = false; *hasResultType = false; break; + case OpKill: *hasResult = false; *hasResultType = false; break; + case OpReturn: *hasResult = false; *hasResultType = false; break; + case OpReturnValue: *hasResult = false; *hasResultType = false; break; + case OpUnreachable: *hasResult = false; *hasResultType = false; break; + case OpLifetimeStart: *hasResult = false; *hasResultType = false; break; + case OpLifetimeStop: *hasResult = false; *hasResultType = false; break; + case OpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; + case OpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; + case OpGroupAll: *hasResult = true; *hasResultType = true; break; + case OpGroupAny: *hasResult = true; *hasResultType = true; break; + case OpGroupBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupIAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupFAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupFMin: *hasResult = true; *hasResultType = true; break; + case OpGroupUMin: *hasResult = true; *hasResultType = true; break; + case OpGroupSMin: *hasResult = true; *hasResultType = true; break; + case OpGroupFMax: *hasResult = true; *hasResultType = true; break; + case OpGroupUMax: *hasResult = true; *hasResultType = true; break; + case OpGroupSMax: *hasResult = true; *hasResultType = true; break; + case OpReadPipe: *hasResult = true; *hasResultType = true; break; + case OpWritePipe: *hasResult = true; *hasResultType = true; break; + case OpReservedReadPipe: *hasResult = true; *hasResultType = true; break; + case OpReservedWritePipe: *hasResult = true; *hasResultType = true; break; + case OpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case OpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case OpCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case OpCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case OpIsValidReserveId: *hasResult = true; *hasResultType = true; break; + case OpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; + case OpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; + case OpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; + case OpEnqueueMarker: *hasResult = true; *hasResultType = true; break; + case OpEnqueueKernel: *hasResult = true; *hasResultType = true; break; + case OpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; + case OpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; + case OpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; + case OpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; + case OpRetainEvent: *hasResult = false; *hasResultType = false; break; + case OpReleaseEvent: *hasResult = false; *hasResultType = false; break; + case OpCreateUserEvent: *hasResult = true; *hasResultType = true; break; + case OpIsValidEvent: *hasResult = true; *hasResultType = true; break; + case OpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; + case OpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; + case OpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; + case OpBuildNDRange: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; + case OpImageSparseFetch: *hasResult = true; *hasResultType = true; break; + case OpImageSparseGather: *hasResult = true; *hasResultType = true; break; + case OpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; + case OpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; + case OpNoLine: *hasResult = false; *hasResultType = false; break; + case OpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; + case OpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; + case OpImageSparseRead: *hasResult = true; *hasResultType = true; break; + case OpSizeOf: *hasResult = true; *hasResultType = true; break; + case OpTypePipeStorage: *hasResult = true; *hasResultType = false; break; + case OpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; + case OpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; + case OpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; + case OpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; + case OpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; + case OpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; + case OpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; + case OpModuleProcessed: *hasResult = false; *hasResultType = false; break; + case OpExecutionModeId: *hasResult = false; *hasResultType = false; break; + case OpDecorateId: *hasResult = false; *hasResultType = false; break; + case OpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; + case OpCopyLogical: *hasResult = true; *hasResultType = true; break; + case OpPtrEqual: *hasResult = true; *hasResultType = true; break; + case OpPtrNotEqual: *hasResult = true; *hasResultType = true; break; + case OpPtrDiff: *hasResult = true; *hasResultType = true; break; + case OpColorAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; + case OpDepthAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; + case OpStencilAttachmentReadEXT: *hasResult = true; *hasResultType = true; break; + case OpTerminateInvocation: *hasResult = false; *hasResultType = false; break; + case OpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformRotateKHR: *hasResult = true; *hasResultType = true; break; + case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; + case OpTraceRayKHR: *hasResult = false; *hasResultType = false; break; + case OpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; + case OpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break; + case OpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpTerminateRayKHR: *hasResult = false; *hasResultType = false; break; + case OpSDot: *hasResult = true; *hasResultType = true; break; + case OpUDot: *hasResult = true; *hasResultType = true; break; + case OpSUDot: *hasResult = true; *hasResultType = true; break; + case OpSDotAccSat: *hasResult = true; *hasResultType = true; break; + case OpUDotAccSat: *hasResult = true; *hasResultType = true; break; + case OpSUDotAccSat: *hasResult = true; *hasResultType = true; break; + case OpTypeCooperativeMatrixKHR: *hasResult = true; *hasResultType = false; break; + case OpCooperativeMatrixLoadKHR: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixStoreKHR: *hasResult = false; *hasResultType = false; break; + case OpCooperativeMatrixMulAddKHR: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixLengthKHR: *hasResult = true; *hasResultType = true; break; + case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; + case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break; + case OpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break; + case OpImageSampleWeightedQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBoxFilterQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchSSDQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchSADQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchWindowSSDQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchWindowSADQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchGatherSSDQCOM: *hasResult = true; *hasResultType = true; break; + case OpImageBlockMatchGatherSADQCOM: *hasResult = true; *hasResultType = true; break; + case OpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; + case OpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; + case OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; + case OpReadClockKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadAllKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformQuadAnyKHR: *hasResult = true; *hasResultType = true; break; + case OpHitObjectRecordHitMotionNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectRecordHitWithIndexMotionNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectRecordMissMotionNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectGetWorldToObjectNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetObjectToWorldNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetObjectRayDirectionNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetObjectRayOriginNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectGetShaderRecordBufferHandleNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetShaderBindingTableRecordIndexNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectRecordEmptyNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectTraceRayNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectRecordHitNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectRecordHitWithIndexNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectRecordMissNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectExecuteShaderNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectGetCurrentTimeNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetAttributesNV: *hasResult = false; *hasResultType = false; break; + case OpHitObjectGetHitKindNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetPrimitiveIndexNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetGeometryIndexNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetInstanceIdNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetInstanceCustomIndexNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetWorldRayDirectionNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetWorldRayOriginNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetRayTMaxNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectGetRayTMinNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectIsEmptyNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectIsHitNV: *hasResult = true; *hasResultType = true; break; + case OpHitObjectIsMissNV: *hasResult = true; *hasResultType = true; break; + case OpReorderThreadWithHitObjectNV: *hasResult = false; *hasResultType = false; break; + case OpReorderThreadWithHintNV: *hasResult = false; *hasResultType = false; break; + case OpTypeHitObjectNV: *hasResult = true; *hasResultType = false; break; + case OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case OpEmitMeshTasksEXT: *hasResult = false; *hasResultType = false; break; + case OpSetMeshOutputsEXT: *hasResult = false; *hasResultType = false; break; + case OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; + case OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; + case OpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; + case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; + case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; + case OpTraceNV: *hasResult = false; *hasResultType = false; break; + case OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; + case OpRayQueryGetIntersectionTriangleVertexPositionsKHR: *hasResult = true; *hasResultType = true; break; + case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; + case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; + case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; + case OpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; + case OpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; + case OpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; + case OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; + case OpDemoteToHelperInvocation: *hasResult = false; *hasResultType = false; break; + case OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case OpConvertUToImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSamplerNV: *hasResult = true; *hasResultType = true; break; + case OpConvertImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSamplerToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSampledImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSampledImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpSamplerImageAddressingModeNV: *hasResult = false; *hasResultType = false; break; + case OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; + case OpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; + case OpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageINTEL: *hasResult = true; *hasResultType = true; break; + case OpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; + case OpISubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; + case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; + case OpConstantFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMinEXT: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMaxEXT: *hasResult = true; *hasResultType = true; break; + case OpAssumeTrueKHR: *hasResult = false; *hasResultType = false; break; + case OpExpectKHR: *hasResult = true; *hasResultType = true; break; + case OpDecorateString: *hasResult = false; *hasResultType = false; break; + case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; + case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; + case OpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; + case OpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; + case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + case OpVariableLengthArrayINTEL: *hasResult = true; *hasResultType = true; break; + case OpSaveMemoryINTEL: *hasResult = true; *hasResultType = true; break; + case OpRestoreMemoryINTEL: *hasResult = false; *hasResultType = false; break; + case OpArbitraryFloatSinCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastFromIntINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastToIntINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatAddINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSubINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatMulINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatDivINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatGTINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatGEINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLTINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLEINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatEQINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatRecipINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatRSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCbrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatHypotINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLogINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog10INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog1pINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExpINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExp2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExp10INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExpm1INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatASinINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatASinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatACosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatACosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATanINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATanPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATan2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowRINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowNINTEL: *hasResult = true; *hasResultType = true; break; + case OpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; + case OpAliasDomainDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpAliasScopeDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpAliasScopeListDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpFixedSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedRecipINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedRsqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedLogINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedExpINTEL: *hasResult = true; *hasResultType = true; break; + case OpPtrCastToCrossWorkgroupINTEL: *hasResult = true; *hasResultType = true; break; + case OpCrossWorkgroupCastToPtrINTEL: *hasResult = true; *hasResultType = true; break; + case OpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case OpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; + case OpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; + case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; + case OpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; + case OpTypeBufferSurfaceINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpControlBarrierArriveINTEL: *hasResult = false; *hasResultType = false; break; + case OpControlBarrierWaitINTEL: *hasResult = false; *hasResultType = false; break; + case OpGroupIMulKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupFMulKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseAndKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseOrKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseXorKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalAndKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalOrKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalXorKHR: *hasResult = true; *hasResultType = true; break; + } +} +#endif /* SPV_ENABLE_UTILITY_CODE */ + +// Overload bitwise operators for mask bit combining + +inline ImageOperandsMask operator|(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) | unsigned(b)); } +inline ImageOperandsMask operator&(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) & unsigned(b)); } +inline ImageOperandsMask operator^(ImageOperandsMask a, ImageOperandsMask b) { return ImageOperandsMask(unsigned(a) ^ unsigned(b)); } +inline ImageOperandsMask operator~(ImageOperandsMask a) { return ImageOperandsMask(~unsigned(a)); } +inline FPFastMathModeMask operator|(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) | unsigned(b)); } +inline FPFastMathModeMask operator&(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) & unsigned(b)); } +inline FPFastMathModeMask operator^(FPFastMathModeMask a, FPFastMathModeMask b) { return FPFastMathModeMask(unsigned(a) ^ unsigned(b)); } +inline FPFastMathModeMask operator~(FPFastMathModeMask a) { return FPFastMathModeMask(~unsigned(a)); } +inline SelectionControlMask operator|(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) | unsigned(b)); } +inline SelectionControlMask operator&(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) & unsigned(b)); } +inline SelectionControlMask operator^(SelectionControlMask a, SelectionControlMask b) { return SelectionControlMask(unsigned(a) ^ unsigned(b)); } +inline SelectionControlMask operator~(SelectionControlMask a) { return SelectionControlMask(~unsigned(a)); } +inline LoopControlMask operator|(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) | unsigned(b)); } +inline LoopControlMask operator&(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) & unsigned(b)); } +inline LoopControlMask operator^(LoopControlMask a, LoopControlMask b) { return LoopControlMask(unsigned(a) ^ unsigned(b)); } +inline LoopControlMask operator~(LoopControlMask a) { return LoopControlMask(~unsigned(a)); } +inline FunctionControlMask operator|(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) | unsigned(b)); } +inline FunctionControlMask operator&(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) & unsigned(b)); } +inline FunctionControlMask operator^(FunctionControlMask a, FunctionControlMask b) { return FunctionControlMask(unsigned(a) ^ unsigned(b)); } +inline FunctionControlMask operator~(FunctionControlMask a) { return FunctionControlMask(~unsigned(a)); } +inline MemorySemanticsMask operator|(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) | unsigned(b)); } +inline MemorySemanticsMask operator&(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) & unsigned(b)); } +inline MemorySemanticsMask operator^(MemorySemanticsMask a, MemorySemanticsMask b) { return MemorySemanticsMask(unsigned(a) ^ unsigned(b)); } +inline MemorySemanticsMask operator~(MemorySemanticsMask a) { return MemorySemanticsMask(~unsigned(a)); } +inline MemoryAccessMask operator|(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) | unsigned(b)); } +inline MemoryAccessMask operator&(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) & unsigned(b)); } +inline MemoryAccessMask operator^(MemoryAccessMask a, MemoryAccessMask b) { return MemoryAccessMask(unsigned(a) ^ unsigned(b)); } +inline MemoryAccessMask operator~(MemoryAccessMask a) { return MemoryAccessMask(~unsigned(a)); } +inline KernelProfilingInfoMask operator|(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) | unsigned(b)); } +inline KernelProfilingInfoMask operator&(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) & unsigned(b)); } +inline KernelProfilingInfoMask operator^(KernelProfilingInfoMask a, KernelProfilingInfoMask b) { return KernelProfilingInfoMask(unsigned(a) ^ unsigned(b)); } +inline KernelProfilingInfoMask operator~(KernelProfilingInfoMask a) { return KernelProfilingInfoMask(~unsigned(a)); } +inline RayFlagsMask operator|(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) | unsigned(b)); } +inline RayFlagsMask operator&(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) & unsigned(b)); } +inline RayFlagsMask operator^(RayFlagsMask a, RayFlagsMask b) { return RayFlagsMask(unsigned(a) ^ unsigned(b)); } +inline RayFlagsMask operator~(RayFlagsMask a) { return RayFlagsMask(~unsigned(a)); } +inline FragmentShadingRateMask operator|(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) | unsigned(b)); } +inline FragmentShadingRateMask operator&(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) & unsigned(b)); } +inline FragmentShadingRateMask operator^(FragmentShadingRateMask a, FragmentShadingRateMask b) { return FragmentShadingRateMask(unsigned(a) ^ unsigned(b)); } +inline FragmentShadingRateMask operator~(FragmentShadingRateMask a) { return FragmentShadingRateMask(~unsigned(a)); } +inline CooperativeMatrixOperandsMask operator|(CooperativeMatrixOperandsMask a, CooperativeMatrixOperandsMask b) { return CooperativeMatrixOperandsMask(unsigned(a) | unsigned(b)); } +inline CooperativeMatrixOperandsMask operator&(CooperativeMatrixOperandsMask a, CooperativeMatrixOperandsMask b) { return CooperativeMatrixOperandsMask(unsigned(a) & unsigned(b)); } +inline CooperativeMatrixOperandsMask operator^(CooperativeMatrixOperandsMask a, CooperativeMatrixOperandsMask b) { return CooperativeMatrixOperandsMask(unsigned(a) ^ unsigned(b)); } +inline CooperativeMatrixOperandsMask operator~(CooperativeMatrixOperandsMask a) { return CooperativeMatrixOperandsMask(~unsigned(a)); } + +} // end namespace spv + +#endif // #ifndef spirv_HPP + diff --git a/src/libraries/glslang/SPIRV/spvIR.h b/src/libraries/glslang/SPIRV/spvIR.h index 486e80d00..6f3124f8d 100644 --- a/src/libraries/glslang/SPIRV/spvIR.h +++ b/src/libraries/glslang/SPIRV/spvIR.h @@ -56,6 +56,7 @@ #include #include #include +#include namespace spv { @@ -97,6 +98,8 @@ public: explicit Instruction(Op opCode) : resultId(NoResult), typeId(NoType), opCode(opCode), block(nullptr) { } virtual ~Instruction() {} void addIdOperand(Id id) { + // ids can't be 0 + assert(id); operands.push_back(id); idOperand.push_back(true); } @@ -111,27 +114,23 @@ public: void addStringOperand(const char* str) { - unsigned int word; - char* wordString = (char*)&word; - char* wordPtr = wordString; - int charCount = 0; + unsigned int word = 0; + unsigned int shiftAmount = 0; char c; + do { c = *(str++); - *(wordPtr++) = c; - ++charCount; - if (charCount == 4) { + word |= ((unsigned int)c) << shiftAmount; + shiftAmount += 8; + if (shiftAmount == 32) { addImmediateOperand(word); - wordPtr = wordString; - charCount = 0; + word = 0; + shiftAmount = 0; } } while (c != 0); // deal with partial last word - if (charCount > 0) { - // pad with 0s - for (; charCount < 4; ++charCount) - *(wordPtr++) = 0; + if (shiftAmount > 0) { addImmediateOperand(word); } } @@ -192,6 +191,12 @@ protected: // SPIR-V IR block. // +struct DebugSourceLocation { + int line; + int column; + spv::Id fileId; +}; + class Block { public: Block(Id id, Function& parent); @@ -202,6 +207,28 @@ public: Id getId() { return instructions.front()->getResultId(); } Function& getParent() const { return parent; } + // Returns true if the source location is actually updated. + // Note we still need the builder to insert the line marker instruction. This is just a tracker. + bool updateDebugSourceLocation(int line, int column, spv::Id fileId) { + if (currentSourceLoc && currentSourceLoc->line == line && currentSourceLoc->column == column && + currentSourceLoc->fileId == fileId) { + return false; + } + + currentSourceLoc = DebugSourceLocation{line, column, fileId}; + return true; + } + // Returns true if the scope is actually updated. + // Note we still need the builder to insert the debug scope instruction. This is just a tracker. + bool updateDebugScope(spv::Id scopeId) { + assert(scopeId); + if (currentDebugScope && *currentDebugScope == scopeId) { + return false; + } + + currentDebugScope = scopeId; + return true; + } void addInstruction(std::unique_ptr inst); void addPredecessor(Block* pred) { predecessors.push_back(pred); pred->successors.push_back(this);} void addLocalVariable(std::unique_ptr inst) { localVariables.push_back(std::move(inst)); } @@ -294,6 +321,12 @@ protected: std::vector > localVariables; Function& parent; + // Track source location of the last source location marker instruction. + std::optional currentSourceLoc; + + // Track scope of the last debug scope instruction. + std::optional currentDebugScope; + // 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). @@ -325,7 +358,7 @@ void inReadableOrder(Block* root, std::function& getBlocks() const { return blocks; } void addLocalVariable(std::unique_ptr inst); Id getReturnType() const { return functionInstruction.getTypeId(); } + Id getFuncId() const { return functionInstruction.getResultId(); } + Id getFuncTypeId() const { return functionInstruction.getIdOperand(1); } void setReturnPrecision(Decoration precision) { if (precision == DecorationRelaxedPrecision) @@ -361,6 +396,14 @@ public: Decoration getReturnPrecision() const { return reducedPrecisionReturn ? DecorationRelaxedPrecision : NoPrecision; } + void setDebugLineInfo(Id fileName, int line, int column) { + lineInstruction = std::unique_ptr{new Instruction(OpLine)}; + lineInstruction->addIdOperand(fileName); + lineInstruction->addImmediateOperand(line); + lineInstruction->addImmediateOperand(column); + } + bool hasDebugLineInfo() const { return lineInstruction != nullptr; } + void setImplicitThis() { implicitThis = true; } bool hasImplicitThis() const { return implicitThis; } @@ -377,6 +420,11 @@ public: void dump(std::vector& out) const { + // OpLine + if (lineInstruction != nullptr) { + lineInstruction->dump(out); + } + // OpFunction functionInstruction.dump(out); @@ -390,17 +438,23 @@ public: end.dump(out); } + LinkageType getLinkType() const { return linkType; } + const char* getExportName() const { return exportName.c_str(); } + protected: Function(const Function&); Function& operator=(Function&); Module& parent; + std::unique_ptr lineInstruction; Instruction functionInstruction; std::vector parameterInstructions; std::vector blocks; bool implicitThis; // true if this is a member function expecting to be passed a 'this' as the first argument bool reducedPrecisionReturn; std::set reducedPrecisionParams; // list of parameter indexes that need a relaxed precision arg + LinkageType linkType; + std::string exportName; }; // @@ -460,9 +514,11 @@ protected: // 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), - reducedPrecisionReturn(false) +__inline Function::Function(Id id, Id resultType, Id functionType, Id firstParamId, LinkageType linkage, const std::string& name, Module& parent) + : parent(parent), lineInstruction(nullptr), + functionInstruction(id, resultType, OpFunction), implicitThis(false), + reducedPrecisionReturn(false), + linkType(linkage) { // OpFunction functionInstruction.addImmediateOperand(FunctionControlMaskNone); @@ -478,6 +534,11 @@ __inline Function::Function(Id id, Id resultType, Id functionType, Id firstParam parent.mapInstruction(param); parameterInstructions.push_back(param); } + + // If importing/exporting, save the function name (without the mangled parameters) for the linkage decoration + if (linkType != LinkageTypeMax) { + exportName = name.substr(0, name.find_first_of('(')); + } } __inline void Function::addLocalVariable(std::unique_ptr inst) diff --git a/src/libraries/glslang/OGLCompilersDLL/InitializeDll.h b/src/libraries/glslang/glslang/ExtensionHeaders/GL_EXT_shader_realtime_clock.glsl similarity index 79% rename from src/libraries/glslang/OGLCompilersDLL/InitializeDll.h rename to src/libraries/glslang/glslang/ExtensionHeaders/GL_EXT_shader_realtime_clock.glsl index 661cee4d2..7cf545d94 100644 --- a/src/libraries/glslang/OGLCompilersDLL/InitializeDll.h +++ b/src/libraries/glslang/glslang/ExtensionHeaders/GL_EXT_shader_realtime_clock.glsl @@ -1,5 +1,9 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2013-2016 LunarG, Inc. +// Copyright (C) 2016-2020 Google, Inc. +// Modifications Copyright(C) 2021 Advanced Micro Devices, Inc.All rights reserved. +// // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -31,19 +35,4 @@ // 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 diff --git a/src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp b/src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp index b3c7226df..1ef244962 100644 --- a/src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp +++ b/src/libraries/glslang/glslang/GenericCodeGen/CodeGen.cpp @@ -41,10 +41,9 @@ // class TGenericCompiler : public TCompiler { public: - TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { } + TGenericCompiler(EShLanguage l) : TCompiler(l, infoSink) {} virtual bool compile(TIntermNode* root, int version = 0, EProfile profile = ENoProfile); TInfoSink infoSink; - int debugOptions; }; // @@ -52,10 +51,7 @@ public: // compile object used by higher level code. It returns // a subclass of TCompiler. // -TCompiler* ConstructCompiler(EShLanguage language, int debugOptions) -{ - return new TGenericCompiler(language, debugOptions); -} +TCompiler* ConstructCompiler(EShLanguage language, int) { return new TGenericCompiler(language); } // // Delete the compiler made by ConstructCompiler diff --git a/src/libraries/glslang/glslang/GenericCodeGen/Link.cpp b/src/libraries/glslang/glslang/GenericCodeGen/Link.cpp index c38db0f69..5df39b814 100644 --- a/src/libraries/glslang/glslang/GenericCodeGen/Link.cpp +++ b/src/libraries/glslang/glslang/GenericCodeGen/Link.cpp @@ -44,11 +44,10 @@ // class TGenericLinker : public TLinker { public: - TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { } + TGenericLinker(EShExecutable e) : TLinker(e, infoSink) {} bool link(TCompilerList&, TUniformMap*) { return true; } void getAttributeBindings(ShBindingTable const **) const { } TInfoSink infoSink; - int debugOptions; }; // @@ -60,10 +59,7 @@ public: virtual int getLocation(const char*) { return 0; } }; -TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions) -{ - return new TGenericLinker(executable, debugOptions); -} +TShHandleBase* ConstructLinker(EShExecutable executable, int) { return new TGenericLinker(executable); } void DeleteLinker(TShHandleBase* linker) { @@ -82,7 +78,7 @@ void DeleteUniformMap(TUniformMap* map) TShHandleBase* ConstructBindings() { - return 0; + return nullptr; } void DeleteBindingList(TShHandleBase* bindingList) diff --git a/src/libraries/glslang/glslang/Include/BaseTypes.h b/src/libraries/glslang/glslang/Include/BaseTypes.h old mode 100644 new mode 100755 index c8203c223..64bffa892 --- a/src/libraries/glslang/glslang/Include/BaseTypes.h +++ b/src/libraries/glslang/glslang/Include/BaseTypes.h @@ -65,10 +65,10 @@ enum TBasicType { EbtAccStruct, EbtReference, EbtRayQuery, -#ifndef GLSLANG_WEB + EbtHitObjectNV, + EbtCoopmat, // SPIR-V type defined by spirv_type EbtSpirvType, -#endif // HLSL types that live only temporarily. EbtString, @@ -95,15 +95,16 @@ enum TStorageQualifier { EvqUniform, // read only, shared with app EvqBuffer, // read/write, shared with app EvqShared, // compute shader's read/write 'shared' qualifier -#ifndef GLSLANG_WEB EvqSpirvStorageClass, // spirv_storage_class -#endif EvqPayload, EvqPayloadIn, EvqHitAttr, EvqCallableData, EvqCallableDataIn, + EvqHitObjectAttrNV, + + EvqtaskPayloadSharedEXT, // parameters EvqIn, // also, for 'in' in the grammar before we know if it's a pipeline input or an 'in' parameter @@ -128,6 +129,9 @@ enum TStorageQualifier { // built-ins written by fragment shader EvqFragColor, EvqFragDepth, + EvqFragStencil, + + EvqTileImageEXT, // end of list EvqLast @@ -263,6 +267,7 @@ enum TBuiltInVariable { EbvObjectRayDirection, EbvRayTmin, EbvRayTmax, + EbvCullMask, EbvHitT, EbvHitKind, EbvObjectToWorld, @@ -274,6 +279,8 @@ enum TBuiltInVariable { // barycentrics EbvBaryCoordNV, EbvBaryCoordNoPerspNV, + EbvBaryCoordEXT, + EbvBaryCoordNoPerspEXT, // mesh shaders EbvTaskCountNV, EbvPrimitiveCountNV, @@ -284,6 +291,17 @@ enum TBuiltInVariable { EbvMeshViewCountNV, EbvMeshViewIndicesNV, + EbvMicroTrianglePositionNV, + EbvMicroTriangleBaryNV, + EbvHitKindFrontFacingMicroTriangleNV, + EbvHitKindBackFacingMicroTriangleNV, + + //GL_EXT_mesh_shader + EbvPrimitivePointIndicesEXT, + EbvPrimitiveLineIndicesEXT, + EbvPrimitiveTriangleIndicesEXT, + EbvCullPrimitiveEXT, + // sm builtins EbvWarpsPerSM, EbvSMCount, @@ -305,6 +323,15 @@ enum TBuiltInVariable { EbvByteAddressBuffer, EbvRWByteAddressBuffer, + // ARM specific core builtins + EbvCoreCountARM, + EbvCoreIDARM, + EbvCoreMaxIDARM, + EbvWarpIDARM, + EbvWarpMaxIDARM, + + EbvPositionFetch, + EbvLast }; @@ -317,10 +344,6 @@ enum TPrecisionQualifier { EpqHigh }; -#ifdef GLSLANG_WEB -__inline const char* GetStorageQualifierString(TStorageQualifier q) { return ""; } -__inline const char* GetPrecisionQualifierString(TPrecisionQualifier p) { return ""; } -#else // These will show up in error messages __inline const char* GetStorageQualifierString(TStorageQualifier q) { @@ -329,9 +352,7 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q) case EvqGlobal: return "global"; break; case EvqConst: return "const"; break; case EvqConstReadOnly: return "const (read only)"; break; -#ifndef GLSLANG_WEB case EvqSpirvStorageClass: return "spirv_storage_class"; break; -#endif case EvqVaryingIn: return "in"; break; case EvqVaryingOut: return "out"; break; case EvqUniform: return "uniform"; break; @@ -350,11 +371,14 @@ __inline const char* GetStorageQualifierString(TStorageQualifier q) case EvqPointCoord: return "gl_PointCoord"; break; case EvqFragColor: return "fragColor"; break; case EvqFragDepth: return "gl_FragDepth"; break; + case EvqFragStencil: return "gl_FragStencilRefARB"; break; case EvqPayload: return "rayPayloadNV"; break; case EvqPayloadIn: return "rayPayloadInNV"; break; case EvqHitAttr: return "hitAttributeNV"; break; case EvqCallableData: return "callableDataNV"; break; case EvqCallableDataIn: return "callableDataInNV"; break; + case EvqtaskPayloadSharedEXT: return "taskPayloadSharedEXT"; break; + case EvqHitObjectAttrNV:return "hitObjectAttributeNV"; break; default: return "unknown qualifier"; } } @@ -478,8 +502,10 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvWorldToObject: return "WorldToObjectNV"; case EbvCurrentRayTimeNV: return "CurrentRayTimeNV"; - case EbvBaryCoordNV: return "BaryCoordNV"; - case EbvBaryCoordNoPerspNV: return "BaryCoordNoPerspNV"; + case EbvBaryCoordEXT: + case EbvBaryCoordNV: return "BaryCoordKHR"; + case EbvBaryCoordNoPerspEXT: + case EbvBaryCoordNoPerspNV: return "BaryCoordNoPerspKHR"; case EbvTaskCountNV: return "TaskCountNV"; case EbvPrimitiveCountNV: return "PrimitiveCountNV"; @@ -489,6 +515,11 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvLayerPerViewNV: return "LayerPerViewNV"; case EbvMeshViewCountNV: return "MeshViewCountNV"; case EbvMeshViewIndicesNV: return "MeshViewIndicesNV"; + // GL_EXT_mesh_shader + case EbvPrimitivePointIndicesEXT: return "PrimitivePointIndicesEXT"; + case EbvPrimitiveLineIndicesEXT: return "PrimitiveLineIndicesEXT"; + case EbvPrimitiveTriangleIndicesEXT: return "PrimitiveTriangleIndicesEXT"; + case EbvCullPrimitiveEXT: return "CullPrimitiveEXT"; case EbvWarpsPerSM: return "WarpsPerSMNV"; case EbvSMCount: return "SMCountNV"; @@ -498,6 +529,9 @@ __inline const char* GetBuiltInVariableString(TBuiltInVariable v) case EbvShadingRateKHR: return "ShadingRateKHR"; case EbvPrimitiveShadingRateKHR: return "PrimitiveShadingRateKHR"; + case EbvHitKindFrontFacingMicroTriangleNV: return "HitKindFrontFacingMicroTriangleNV"; + case EbvHitKindBackFacingMicroTriangleNV: return "HitKindBackFacingMicroTriangleNV"; + default: return "unknown built-in variable"; } } @@ -512,7 +546,6 @@ __inline const char* GetPrecisionQualifierString(TPrecisionQualifier p) default: return "unknown precision qualifier"; } } -#endif __inline bool isTypeSignedInt(TBasicType type) { diff --git a/src/libraries/glslang/glslang/Include/Common.h b/src/libraries/glslang/glslang/Include/Common.h index 9042a1aa2..d1bd13b57 100644 --- a/src/libraries/glslang/glslang/Include/Common.h +++ b/src/libraries/glslang/glslang/Include/Common.h @@ -44,6 +44,7 @@ #else #include #endif +#include #include #include #include @@ -54,7 +55,7 @@ #include #include -#if defined(__ANDROID__) || (defined(_MSC_VER) && _MSC_VER < 1700) +#if defined(__ANDROID__) #include namespace std { template @@ -66,7 +67,7 @@ std::string to_string(const T& val) { } #endif -#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) || MINGW_HAS_SECURE_API +#if defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API #include #ifndef snprintf #define snprintf sprintf_s @@ -82,22 +83,6 @@ std::string to_string(const T& val) { #define UINT_PTR uintptr_t #endif -#if defined(_MSC_VER) && _MSC_VER < 1800 - #include - inline long long int strtoll (const char* str, char** endptr, int base) - { - return _strtoi64(str, endptr, base); - } - inline unsigned long long int strtoull (const char* str, char** endptr, int base) - { - return _strtoui64(str, endptr, base); - } - inline long long int atoll (const char* str) - { - return strtoll(str, NULL, 10); - } -#endif - #if defined(_MSC_VER) #define strdup _strdup #endif @@ -174,6 +159,11 @@ template inline T* NewPoolObject(T, int instances) return new(GetThreadPoolAllocator().allocate(instances * sizeof(T))) T[instances]; } +inline bool StartsWith(TString const &str, const char *prefix) +{ + return str.compare(0, strlen(prefix), prefix) == 0; +} + // // Pool allocator versions of vectors, lists, and maps // @@ -218,7 +208,7 @@ template T Max(const T a, const T b) { return a > b ? a : b; } // // Create a TString object from an integer. // -#if defined _MSC_VER || MINGW_HAS_SECURE_API +#if defined(_MSC_VER) || (defined(MINGW_HAS_SECURE_API) && MINGW_HAS_SECURE_API) inline const TString String(const int i, const int base = 10) { char text[16]; // 32 bit ints are at most 10 digits in base 10 @@ -307,34 +297,6 @@ template int IntLog2(T n) return result; } -inline bool IsInfinity(double x) { -#ifdef _MSC_VER - switch (_fpclass(x)) { - case _FPCLASS_NINF: - case _FPCLASS_PINF: - return true; - default: - return false; - } -#else - return std::isinf(x); -#endif -} - -inline bool IsNan(double x) { -#ifdef _MSC_VER - switch (_fpclass(x)) { - case _FPCLASS_SNAN: - case _FPCLASS_QNAN: - return true; - default: - return false; - } -#else - return std::isnan(x); -#endif -} - } // end namespace glslang #endif // _COMMON_INCLUDED_ diff --git a/src/libraries/glslang/glslang/Include/ConstantUnion.h b/src/libraries/glslang/glslang/Include/ConstantUnion.h index c4ffb8577..da4737b65 100644 --- a/src/libraries/glslang/glslang/Include/ConstantUnion.h +++ b/src/libraries/glslang/glslang/Include/ConstantUnion.h @@ -234,7 +234,6 @@ public: break; -#ifndef GLSLANG_WEB case EbtInt16: if (constant.i16Const == i16Const) return true; @@ -265,7 +264,6 @@ public: return true; break; -#endif default: assert(false && "Default missing"); } @@ -347,7 +345,6 @@ public: return true; return false; -#ifndef GLSLANG_WEB case EbtInt8: if (i8Const > constant.i8Const) return true; @@ -378,7 +375,6 @@ public: return true; return false; -#endif default: assert(false && "Default missing"); return false; @@ -389,7 +385,6 @@ public: { assert(type == constant.type); switch (type) { -#ifndef GLSLANG_WEB case EbtInt8: if (i8Const < constant.i8Const) return true; @@ -419,7 +414,6 @@ public: return true; return false; -#endif case EbtDouble: if (dConst < constant.dConst) return true; @@ -449,14 +443,12 @@ public: case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; case EbtUint: returnValue.setUConst(uConst + constant.uConst); break; case EbtDouble: returnValue.setDConst(dConst + constant.dConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const + constant.i8Const); break; case EbtInt16: returnValue.setI16Const(i16Const + constant.i16Const); break; case EbtInt64: returnValue.setI64Const(i64Const + constant.i64Const); break; case EbtUint8: returnValue.setU8Const(u8Const + constant.u8Const); break; case EbtUint16: returnValue.setU16Const(u16Const + constant.u16Const); break; case EbtUint64: returnValue.setU64Const(u64Const + constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -471,14 +463,12 @@ public: case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; case EbtUint: returnValue.setUConst(uConst - constant.uConst); break; case EbtDouble: returnValue.setDConst(dConst - constant.dConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const - constant.i8Const); break; case EbtInt16: returnValue.setI16Const(i16Const - constant.i16Const); break; case EbtInt64: returnValue.setI64Const(i64Const - constant.i64Const); break; case EbtUint8: returnValue.setU8Const(u8Const - constant.u8Const); break; case EbtUint16: returnValue.setU16Const(u16Const - constant.u16Const); break; case EbtUint64: returnValue.setU64Const(u64Const - constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -493,14 +483,12 @@ public: case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; case EbtUint: returnValue.setUConst(uConst * constant.uConst); break; case EbtDouble: returnValue.setDConst(dConst * constant.dConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const * constant.i8Const); break; case EbtInt16: returnValue.setI16Const(i16Const * constant.i16Const); break; case EbtInt64: returnValue.setI64Const(i64Const * constant.i64Const); break; case EbtUint8: returnValue.setU8Const(u8Const * constant.u8Const); break; case EbtUint16: returnValue.setU16Const(u16Const * constant.u16Const); break; case EbtUint64: returnValue.setU64Const(u64Const * constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -514,14 +502,12 @@ public: switch (type) { case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; case EbtUint: returnValue.setUConst(uConst % constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const % constant.i8Const); break; - case EbtInt16: returnValue.setI8Const(i8Const % constant.i16Const); break; + case EbtInt16: returnValue.setI16Const(i16Const % constant.i16Const); break; case EbtInt64: returnValue.setI64Const(i64Const % constant.i64Const); break; case EbtUint8: returnValue.setU8Const(u8Const % constant.u8Const); break; case EbtUint16: returnValue.setU16Const(u16Const % constant.u16Const); break; case EbtUint64: returnValue.setU64Const(u64Const % constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -532,7 +518,6 @@ public: { TConstUnion returnValue; switch (type) { -#ifndef GLSLANG_WEB case EbtInt8: switch (constant.type) { case EbtInt8: returnValue.setI8Const(i8Const >> constant.i8Const); break; @@ -585,19 +570,16 @@ public: default: assert(false && "Default missing"); } break; -#endif case EbtInt: switch (constant.type) { case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; case EbtUint: returnValue.setIConst(iConst >> constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setIConst(iConst >> constant.i8Const); break; case EbtUint8: returnValue.setIConst(iConst >> constant.u8Const); break; case EbtInt16: returnValue.setIConst(iConst >> constant.i16Const); break; case EbtUint16: returnValue.setIConst(iConst >> constant.u16Const); break; case EbtInt64: returnValue.setIConst(iConst >> constant.i64Const); break; case EbtUint64: returnValue.setIConst(iConst >> constant.u64Const); break; -#endif default: assert(false && "Default missing"); } break; @@ -605,18 +587,15 @@ public: switch (constant.type) { case EbtInt: returnValue.setUConst(uConst >> constant.iConst); break; case EbtUint: returnValue.setUConst(uConst >> constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setUConst(uConst >> constant.i8Const); break; case EbtUint8: returnValue.setUConst(uConst >> constant.u8Const); break; case EbtInt16: returnValue.setUConst(uConst >> constant.i16Const); break; case EbtUint16: returnValue.setUConst(uConst >> constant.u16Const); break; case EbtInt64: returnValue.setUConst(uConst >> constant.i64Const); break; case EbtUint64: returnValue.setUConst(uConst >> constant.u64Const); break; -#endif default: assert(false && "Default missing"); } break; -#ifndef GLSLANG_WEB case EbtInt64: switch (constant.type) { case EbtInt8: returnValue.setI64Const(i64Const >> constant.i8Const); break; @@ -643,7 +622,6 @@ public: default: assert(false && "Default missing"); } break; -#endif default: assert(false && "Default missing"); } @@ -654,7 +632,6 @@ public: { TConstUnion returnValue; switch (type) { -#ifndef GLSLANG_WEB case EbtInt8: switch (constant.type) { case EbtInt8: returnValue.setI8Const(i8Const << constant.i8Const); break; @@ -733,19 +710,16 @@ public: default: assert(false && "Default missing"); } break; -#endif case EbtInt: switch (constant.type) { case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; case EbtUint: returnValue.setIConst(iConst << constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setIConst(iConst << constant.i8Const); break; case EbtUint8: returnValue.setIConst(iConst << constant.u8Const); break; case EbtInt16: returnValue.setIConst(iConst << constant.i16Const); break; case EbtUint16: returnValue.setIConst(iConst << constant.u16Const); break; case EbtInt64: returnValue.setIConst(iConst << constant.i64Const); break; case EbtUint64: returnValue.setIConst(iConst << constant.u64Const); break; -#endif default: assert(false && "Default missing"); } break; @@ -753,14 +727,12 @@ public: switch (constant.type) { case EbtInt: returnValue.setUConst(uConst << constant.iConst); break; case EbtUint: returnValue.setUConst(uConst << constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setUConst(uConst << constant.i8Const); break; case EbtUint8: returnValue.setUConst(uConst << constant.u8Const); break; case EbtInt16: returnValue.setUConst(uConst << constant.i16Const); break; case EbtUint16: returnValue.setUConst(uConst << constant.u16Const); break; case EbtInt64: returnValue.setUConst(uConst << constant.i64Const); break; case EbtUint64: returnValue.setUConst(uConst << constant.u64Const); break; -#endif default: assert(false && "Default missing"); } break; @@ -777,14 +749,12 @@ public: switch (type) { case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; case EbtUint: returnValue.setUConst(uConst & constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const & constant.i8Const); break; case EbtUint8: returnValue.setU8Const(u8Const & constant.u8Const); break; case EbtInt16: returnValue.setI16Const(i16Const & constant.i16Const); break; case EbtUint16: returnValue.setU16Const(u16Const & constant.u16Const); break; case EbtInt64: returnValue.setI64Const(i64Const & constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const & constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -798,14 +768,12 @@ public: switch (type) { case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; case EbtUint: returnValue.setUConst(uConst | constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const | constant.i8Const); break; case EbtUint8: returnValue.setU8Const(u8Const | constant.u8Const); break; case EbtInt16: returnValue.setI16Const(i16Const | constant.i16Const); break; case EbtUint16: returnValue.setU16Const(u16Const | constant.u16Const); break; case EbtInt64: returnValue.setI64Const(i64Const | constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const | constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -819,14 +787,12 @@ public: switch (type) { case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; case EbtUint: returnValue.setUConst(uConst ^ constant.uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(i8Const ^ constant.i8Const); break; case EbtUint8: returnValue.setU8Const(u8Const ^ constant.u8Const); break; case EbtInt16: returnValue.setI16Const(i16Const ^ constant.i16Const); break; case EbtUint16: returnValue.setU16Const(u16Const ^ constant.u16Const); break; case EbtInt64: returnValue.setI64Const(i64Const ^ constant.i64Const); break; case EbtUint64: returnValue.setU64Const(u64Const ^ constant.u64Const); break; -#endif default: assert(false && "Default missing"); } @@ -839,14 +805,12 @@ public: switch (type) { case EbtInt: returnValue.setIConst(~iConst); break; case EbtUint: returnValue.setUConst(~uConst); break; -#ifndef GLSLANG_WEB case EbtInt8: returnValue.setI8Const(~i8Const); break; case EbtUint8: returnValue.setU8Const(~u8Const); break; case EbtInt16: returnValue.setI16Const(~i16Const); break; case EbtUint16: returnValue.setU16Const(~u16Const); break; case EbtInt64: returnValue.setI64Const(~i64Const); break; case EbtUint64: returnValue.setU64Const(~u64Const); break; -#endif default: assert(false && "Default missing"); } diff --git a/src/libraries/glslang/glslang/Include/InfoSink.h b/src/libraries/glslang/glslang/Include/InfoSink.h index dceb603cf..23f495dcb 100644 --- a/src/libraries/glslang/glslang/Include/InfoSink.h +++ b/src/libraries/glslang/glslang/Include/InfoSink.h @@ -36,6 +36,7 @@ #define _INFOSINK_INCLUDED_ #include "../Include/Common.h" +#include #include namespace glslang { @@ -67,7 +68,7 @@ enum TOutputStream { // class TInfoSinkBase { public: - TInfoSinkBase() : outputStream(4) {} + TInfoSinkBase() : outputStream(4), shaderFileName(nullptr) {} void erase() { sink.erase(); } TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; } TInfoSinkBase& operator<<(char c) { append(1, c); return *this; } @@ -94,11 +95,22 @@ public: default: append("UNKNOWN ERROR: "); break; } } - void location(const TSourceLoc& loc) { + void location(const TSourceLoc& loc, bool absolute = false) { const int maxSize = 24; char locText[maxSize]; snprintf(locText, maxSize, ":%d", loc.line); - append(loc.getStringNameOrNum(false).c_str()); + + if(loc.getFilename() == nullptr && shaderFileName != nullptr && absolute) { + append(std::filesystem::absolute(shaderFileName).string()); + } else { + std::string location = loc.getStringNameOrNum(false); + if (absolute) { + append(std::filesystem::absolute(location).string()); + } else { + append(location); + } + } + append(locText); append(": "); } @@ -119,6 +131,11 @@ public: outputStream = output; } + void setShaderFileName(const char* file = nullptr) + { + shaderFileName = file; + } + protected: void append(const char* s); @@ -131,6 +148,7 @@ protected: void appendToStream(const char* s); TPersistString sink; int outputStream; + const char* shaderFileName; }; } // end namespace glslang diff --git a/src/libraries/glslang/glslang/Include/InitializeGlobals.h b/src/libraries/glslang/glslang/Include/InitializeGlobals.h index 95d0a40e9..b7fdd7aab 100644 --- a/src/libraries/glslang/glslang/Include/InitializeGlobals.h +++ b/src/libraries/glslang/glslang/Include/InitializeGlobals.h @@ -37,7 +37,7 @@ namespace glslang { -bool InitializePoolIndex(); +inline bool InitializePoolIndex() { return true; } // DEPRECATED: No need to call } // end namespace glslang diff --git a/src/libraries/glslang/glslang/Include/PoolAlloc.h b/src/libraries/glslang/glslang/Include/PoolAlloc.h index 1f5cac76d..e84ac52cd 100644 --- a/src/libraries/glslang/glslang/Include/PoolAlloc.h +++ b/src/libraries/glslang/glslang/Include/PoolAlloc.h @@ -37,7 +37,7 @@ #ifndef _POOLALLOC_INCLUDED_ #define _POOLALLOC_INCLUDED_ -#ifdef _DEBUG +#ifndef NDEBUG # define GUARD_BLOCKS // define to enable guard block sanity checking #endif @@ -74,7 +74,7 @@ namespace glslang { class TAllocation { public: - TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : + TAllocation(size_t size, unsigned char* mem, TAllocation* prev = nullptr) : size(size), mem(mem), prevAlloc(prev) { // Allocations are bracketed: // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] @@ -118,11 +118,16 @@ private: unsigned char* mem; // beginning of our allocation (pts to header) TAllocation* prevAlloc; // prior allocation in the chain - const static unsigned char guardBlockBeginVal; - const static unsigned char guardBlockEndVal; - const static unsigned char userDataFill; + static inline constexpr unsigned char guardBlockBeginVal = 0xfb; + static inline constexpr unsigned char guardBlockEndVal = 0xfe; + static inline constexpr unsigned char userDataFill = 0xcd; + +# ifdef GUARD_BLOCKS + static inline constexpr size_t guardBlockSize = 16; +# else + static inline constexpr size_t guardBlockSize = 0; +# endif - const static size_t guardBlockSize; # ifdef GUARD_BLOCKS inline static size_t headerSize() { return sizeof(TAllocation); } # else @@ -171,7 +176,7 @@ public: void popAll(); // - // Call allocate() to actually acquire memory. Returns 0 if no memory + // Call allocate() to actually acquire memory. Returns nullptr if no memory // available, otherwise a properly aligned pointer to 'numBytes' of memory. // void* allocate(size_t numBytes); @@ -189,7 +194,7 @@ protected: struct tHeader { tHeader(tHeader* nextPage, size_t pageCount) : #ifdef GUARD_BLOCKS - lastAllocation(0), + lastAllocation(nullptr), #endif nextPage(nextPage), pageCount(pageCount) { } diff --git a/src/libraries/glslang/glslang/Include/ResourceLimits.h b/src/libraries/glslang/glslang/Include/ResourceLimits.h index b670cf163..b36c8d627 100644 --- a/src/libraries/glslang/glslang/Include/ResourceLimits.h +++ b/src/libraries/glslang/glslang/Include/ResourceLimits.h @@ -142,6 +142,15 @@ struct TBuiltInResource { int maxTaskWorkGroupSizeY_NV; int maxTaskWorkGroupSizeZ_NV; int maxMeshViewCountNV; + int maxMeshOutputVerticesEXT; + int maxMeshOutputPrimitivesEXT; + int maxMeshWorkGroupSizeX_EXT; + int maxMeshWorkGroupSizeY_EXT; + int maxMeshWorkGroupSizeZ_EXT; + int maxTaskWorkGroupSizeX_EXT; + int maxTaskWorkGroupSizeY_EXT; + int maxTaskWorkGroupSizeZ_EXT; + int maxMeshViewCountEXT; int maxDualSourceDrawBuffersEXT; TLimits limits; diff --git a/src/libraries/glslang/glslang/Include/ShHandle.h b/src/libraries/glslang/glslang/Include/ShHandle.h index df07bd8ed..dee47c0df 100644 --- a/src/libraries/glslang/glslang/Include/ShHandle.h +++ b/src/libraries/glslang/glslang/Include/ShHandle.h @@ -58,9 +58,9 @@ class TShHandleBase { public: TShHandleBase() { pool = new glslang::TPoolAllocator; } virtual ~TShHandleBase() { delete pool; } - virtual TCompiler* getAsCompiler() { return 0; } - virtual TLinker* getAsLinker() { return 0; } - virtual TUniformMap* getAsUniformMap() { return 0; } + virtual TCompiler* getAsCompiler() { return nullptr; } + virtual TLinker* getAsLinker() { return nullptr; } + virtual TUniformMap* getAsUniformMap() { return nullptr; } virtual glslang::TPoolAllocator* getPool() const { return pool; } private: glslang::TPoolAllocator* pool; @@ -123,11 +123,11 @@ public: infoSink(iSink), executable(e), haveReturnableObjectCode(false), - appAttributeBindings(0), - fixedAttributeBindings(0), - excludedAttributes(0), + appAttributeBindings(nullptr), + fixedAttributeBindings(nullptr), + excludedAttributes(nullptr), excludedCount(0), - uniformBindings(0) { } + uniformBindings(nullptr) { } virtual TLinker* getAsLinker() { return this; } virtual ~TLinker() { } virtual bool link(TCompilerList&, TUniformMap*) = 0; @@ -137,7 +137,7 @@ public: virtual void getAttributeBindings(ShBindingTable const **t) const = 0; virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; } virtual ShBindingTable* getUniformBindings() const { return uniformBindings; } - virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here + virtual const void* getObjectCode() const { return nullptr; } // a real compiler would be returning object code here virtual TInfoSink& getInfoSink() { return infoSink; } TInfoSink& infoSink; protected: diff --git a/src/libraries/glslang/glslang/Include/SpirvIntrinsics.h b/src/libraries/glslang/glslang/Include/SpirvIntrinsics.h index 3c7d72ce9..0082a4d4e 100644 --- a/src/libraries/glslang/glslang/Include/SpirvIntrinsics.h +++ b/src/libraries/glslang/glslang/Include/SpirvIntrinsics.h @@ -35,12 +35,11 @@ #pragma once -#ifndef GLSLANG_WEB - // // GL_EXT_spirv_intrinsics // #include "Common.h" +#include namespace glslang { @@ -98,12 +97,27 @@ struct TSpirvInstruction { struct TSpirvTypeParameter { POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TSpirvTypeParameter(const TIntermConstantUnion* arg) { constant = arg; } + TSpirvTypeParameter(const TIntermConstantUnion* arg) { value = arg; } + TSpirvTypeParameter(const TType* arg) { value = arg; } - bool operator==(const TSpirvTypeParameter& rhs) const { return constant == rhs.constant; } + const TIntermConstantUnion* getAsConstant() const + { + if (value.index() == 0) + return std::get(value); + return nullptr; + } + const TType* getAsType() const + { + if (value.index() == 1) + return std::get(value); + return nullptr; + } + + bool operator==(const TSpirvTypeParameter& rhs) const; bool operator!=(const TSpirvTypeParameter& rhs) const { return !operator==(rhs); } - const TIntermConstantUnion* constant; + // Parameter value: constant expression or type specifier + std::variant value; }; typedef TVector TSpirvTypeParameters; @@ -124,5 +138,3 @@ struct TSpirvType { }; } // end namespace glslang - -#endif // GLSLANG_WEB diff --git a/src/libraries/glslang/glslang/Include/Types.h b/src/libraries/glslang/glslang/Include/Types.h index 9c1f960ed..232622854 100644 --- a/src/libraries/glslang/glslang/Include/Types.h +++ b/src/libraries/glslang/glslang/Include/Types.h @@ -72,6 +72,7 @@ enum TSamplerDim { EsdRect, EsdBuffer, EsdSubpass, // goes only with non-sampled image (image is true) + EsdAttachmentEXT, EsdNumDims }; @@ -85,19 +86,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler, bool combined : 1; // true means texture is combined with a sampler, false means texture with no sampler bool sampler : 1; // true means a pure sampler, other fields should be clear() -#ifdef GLSLANG_WEB - bool is1D() const { return false; } - bool isBuffer() const { return false; } - bool isRect() const { return false; } - bool isSubpass() const { return false; } - bool isCombined() const { return true; } - bool isImage() const { return false; } - bool isImageClass() const { return false; } - bool isMultiSample() const { return false; } - bool isExternal() const { return false; } - void setExternal(bool e) { } - bool isYuv() const { return false; } -#else unsigned int vectorSize : 3; // vector return type size. // Some languages support structures as sample results. Storing the whole structure in the // TSampler is too large, so there is an index to a separate table. @@ -122,14 +110,14 @@ struct TSampler { // misnomer now; includes images, textures without sampler, bool isBuffer() const { return dim == EsdBuffer; } bool isRect() const { return dim == EsdRect; } bool isSubpass() const { return dim == EsdSubpass; } + bool isAttachmentEXT() const { return dim == EsdAttachmentEXT; } bool isCombined() const { return combined; } - bool isImage() const { return image && !isSubpass(); } + bool isImage() const { return image && !isSubpass() && !isAttachmentEXT();} bool isImageClass() const { return image; } bool isMultiSample() const { return ms; } bool isExternal() const { return external; } void setExternal(bool e) { external = e; } bool isYuv() const { return yuv; } -#endif bool isTexture() const { return !sampler && !image; } bool isPureSampler() const { return sampler; } @@ -149,10 +137,8 @@ struct TSampler { // misnomer now; includes images, textures without sampler, image = false; combined = false; sampler = false; -#ifndef GLSLANG_WEB external = false; yuv = false; -#endif #ifdef ENABLE_HLSL clearReturnStruct(); @@ -204,7 +190,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler, shadow = s; } -#ifndef GLSLANG_WEB // make a subpass input attachment void setSubpass(TBasicType t, bool m = false) { @@ -214,7 +199,15 @@ struct TSampler { // misnomer now; includes images, textures without sampler, dim = EsdSubpass; ms = m; } -#endif + + // make an AttachmentEXT + void setAttachmentEXT(TBasicType t) + { + clear(); + type = t; + image = true; + dim = EsdAttachmentEXT; + } bool operator==(const TSampler& right) const { @@ -252,7 +245,6 @@ struct TSampler { // misnomer now; includes images, textures without sampler, switch (type) { case EbtInt: s.append("i"); break; case EbtUint: s.append("u"); break; -#ifndef GLSLANG_WEB case EbtFloat16: s.append("f16"); break; case EbtInt8: s.append("i8"); break; case EbtUint16: s.append("u8"); break; @@ -260,11 +252,12 @@ struct TSampler { // misnomer now; includes images, textures without sampler, case EbtUint8: s.append("u16"); break; case EbtInt64: s.append("i64"); break; case EbtUint64: s.append("u64"); break; -#endif default: break; } if (isImageClass()) { - if (isSubpass()) + if (isAttachmentEXT()) + s.append("attachmentEXT"); + else if (isSubpass()) s.append("subpass"); else s.append("image"); @@ -284,12 +277,11 @@ struct TSampler { // misnomer now; includes images, textures without sampler, case Esd2D: s.append("2D"); break; case Esd3D: s.append("3D"); break; case EsdCube: s.append("Cube"); break; -#ifndef GLSLANG_WEB - case Esd1D: s.append("1D"); break; - case EsdRect: s.append("2DRect"); break; - case EsdBuffer: s.append("Buffer"); break; - case EsdSubpass: s.append("Input"); break; -#endif + case Esd1D: s.append("1D"); break; + case EsdRect: s.append("2DRect"); break; + case EsdBuffer: s.append("Buffer"); break; + case EsdSubpass: s.append("Input"); break; + case EsdAttachmentEXT: s.append(""); break; default: break; // some compilers want this } if (isMultiSample()) @@ -429,6 +421,12 @@ enum TLayoutFormat { ElfR16ui, ElfR8ui, ElfR64ui, + ElfExtSizeGuard, // to help with comparisons + ElfSize1x8, + ElfSize1x16, + ElfSize1x32, + ElfSize2x32, + ElfSize4x32, ElfCount }; @@ -443,6 +441,18 @@ enum TLayoutDepth { EldCount }; +enum TLayoutStencil { + ElsNone, + ElsRefUnchangedFrontAMD, + ElsRefGreaterFrontAMD, + ElsRefLessFrontAMD, + ElsRefUnchangedBackAMD, + ElsRefGreaterBackAMD, + ElsRefLessBackAMD, + + ElsCount +}; + enum TBlendEquationShift { // No 'EBlendNone': // These are used as bit-shift amounts. A mask of such shifts will have type 'int', @@ -500,12 +510,10 @@ public: invariant = false; makeTemporary(); declaredBuiltIn = EbvNone; -#ifndef GLSLANG_WEB noContraction = false; nullInit = false; spirvByReference = false; spirvLiteral = false; -#endif defaultBlock = false; } @@ -522,21 +530,17 @@ public: nullInit = false; defaultBlock = false; clearLayout(); -#ifndef GLSLANG_WEB spirvStorageClass = -1; spirvDecorate = nullptr; spirvByReference = false; spirvLiteral = false; -#endif } void clearInterstage() { clearInterpolation(); -#ifndef GLSLANG_WEB patch = false; sample = false; -#endif } void clearInterpolation() @@ -544,19 +548,17 @@ public: centroid = false; smooth = false; flat = false; -#ifndef GLSLANG_WEB nopersp = false; explicitInterp = false; pervertexNV = false; perPrimitiveNV = false; perViewNV = false; perTaskNV = false; -#endif + pervertexEXT = false; } void clearMemory() { -#ifndef GLSLANG_WEB coherent = false; devicecoherent = false; queuefamilycoherent = false; @@ -568,11 +570,11 @@ public: restrict = false; readonly = false; writeonly = false; -#endif } const char* semanticName; - TStorageQualifier storage : 6; + TStorageQualifier storage : 7; + static_assert(EvqLast < 64, "need to increase size of TStorageQualifier bitfields!"); TBuiltInVariable builtIn : 9; TBuiltInVariable declaredBuiltIn : 9; static_assert(EbvLast < 256, "need to increase size of TBuiltInVariable bitfields!"); @@ -587,34 +589,11 @@ public: bool explicitOffset : 1; bool defaultBlock : 1; // default blocks with matching names have structures merged when linking -#ifdef GLSLANG_WEB - bool isWriteOnly() const { return false; } - bool isReadOnly() const { return false; } - bool isRestrict() const { return false; } - bool isCoherent() const { return false; } - bool isVolatile() const { return false; } - bool isSample() const { return false; } - bool isMemory() const { return false; } - bool isMemoryQualifierImageAndSSBOOnly() const { return false; } - bool bufferReferenceNeedsVulkanMemoryModel() const { return false; } - bool isInterpolation() const { return flat || smooth; } - bool isExplicitInterpolation() const { return false; } - bool isAuxiliary() const { return centroid; } - bool isPatch() const { return false; } - bool isNoContraction() const { return false; } - void setNoContraction() { } - bool isPervertexNV() const { return false; } - void setNullInit() { } - bool isNullInit() const { return false; } - void setSpirvByReference() { } - bool isSpirvByReference() { return false; } - void setSpirvLiteral() { } - bool isSpirvLiteral() { return false; } -#else bool noContraction: 1; // prevent contraction and reassociation, e.g., for 'precise' keyword, and expressions it affects bool nopersp : 1; bool explicitInterp : 1; bool pervertexNV : 1; + bool pervertexEXT : 1; bool perPrimitiveNV : 1; bool perViewNV : 1; bool perTaskNV : 1; @@ -663,19 +642,19 @@ public: } bool isAuxiliary() const { - return centroid || patch || sample || pervertexNV; + return centroid || patch || sample || pervertexNV || pervertexEXT; } bool isPatch() const { return patch; } bool isNoContraction() const { return noContraction; } void setNoContraction() { noContraction = true; } bool isPervertexNV() const { return pervertexNV; } + bool isPervertexEXT() const { return pervertexEXT; } void setNullInit() { nullInit = true; } bool isNullInit() const { return nullInit; } void setSpirvByReference() { spirvByReference = true; } bool isSpirvByReference() const { return spirvByReference; } void setSpirvLiteral() { spirvLiteral = true; } bool isSpirvLiteral() const { return spirvLiteral; } -#endif bool isPipeInput() const { @@ -701,6 +680,7 @@ public: case EvqVaryingOut: case EvqFragColor: case EvqFragDepth: + case EvqFragStencil: return true; default: return false; @@ -768,6 +748,7 @@ public: case EvqVaryingOut: case EvqFragColor: case EvqFragDepth: + case EvqFragStencil: return true; default: return false; @@ -804,9 +785,7 @@ public: } void setBlockStorage(TBlockStorageClass newBacking) { -#ifndef GLSLANG_WEB layoutPushConstant = (newBacking == EbsPushConstant); -#endif switch (newBacking) { case EbsUniform : if (layoutPacking == ElpStd430) { @@ -815,35 +794,32 @@ public: } storage = EvqUniform; break; - case EbsStorageBuffer : + case EbsStorageBuffer : storage = EvqBuffer; break; -#ifndef GLSLANG_WEB case EbsPushConstant : storage = EvqUniform; layoutSet = TQualifier::layoutSetEnd; layoutBinding = TQualifier::layoutBindingEnd; break; -#endif default: break; } } -#ifdef GLSLANG_WEB - bool isPerView() const { return false; } - bool isTaskMemory() const { return false; } - bool isArrayedIo(EShLanguage language) const { return false; } -#else bool isPerPrimitive() const { return perPrimitiveNV; } bool isPerView() const { return perViewNV; } bool isTaskMemory() const { return perTaskNV; } + bool isTaskPayload() const { return storage == EvqtaskPayloadSharedEXT; } bool isAnyPayload() const { return storage == EvqPayload || storage == EvqPayloadIn; } bool isAnyCallable() const { return storage == EvqCallableData || storage == EvqCallableDataIn; } + bool isHitObjectAttrNV() const { + return storage == EvqHitObjectAttrNV; + } // True if this type of IO is supposed to be arrayed with extra level for per-vertex data bool isArrayedIo(EShLanguage language) const @@ -856,22 +832,20 @@ public: case EShLangTessEvaluation: return ! patch && isPipeInput(); case EShLangFragment: - return pervertexNV && isPipeInput(); - case EShLangMeshNV: + return (pervertexNV || pervertexEXT) && isPipeInput(); + case EShLangMesh: return ! perTaskNV && isPipeOutput(); default: return false; } } -#endif // Implementing an embedded layout-qualifier class here, since C++ can't have a real class bitfield void clearLayout() // all layout { clearUniformLayout(); -#ifndef GLSLANG_WEB layoutPushConstant = false; layoutBufferReference = false; layoutPassthrough = false; @@ -879,9 +853,13 @@ public: // -2048 as the default value indicating layoutSecondaryViewportRelative is not set layoutSecondaryViewportRelativeOffset = -2048; layoutShaderRecord = false; + layoutFullQuads = false; + layoutQuadDeriv = false; + layoutHitObjectShaderRecordNV = false; + layoutBindlessSampler = false; + layoutBindlessImage = false; layoutBufferReferenceAlign = layoutBufferReferenceAlignEnd; layoutFormat = ElfNone; -#endif clearInterstageLayout(); @@ -891,14 +869,11 @@ public: { layoutLocation = layoutLocationEnd; layoutComponent = layoutComponentEnd; -#ifndef GLSLANG_WEB layoutIndex = layoutIndexEnd; clearStreamLayout(); clearXfbLayout(); -#endif } -#ifndef GLSLANG_WEB void clearStreamLayout() { layoutStream = layoutStreamEnd; @@ -909,7 +884,6 @@ public: layoutXfbStride = layoutXfbStrideEnd; layoutXfbOffset = layoutXfbOffsetEnd; } -#endif bool hasNonXfbLayout() const { @@ -965,7 +939,6 @@ public: unsigned int layoutSpecConstantId : 11; static const unsigned int layoutSpecConstantIdEnd = 0x7FF; -#ifndef GLSLANG_WEB // stored as log2 of the actual alignment value unsigned int layoutBufferReferenceAlign : 6; static const unsigned int layoutBufferReferenceAlignEnd = 0x3F; @@ -978,11 +951,16 @@ public: bool layoutViewportRelative; int layoutSecondaryViewportRelativeOffset; bool layoutShaderRecord; + bool layoutFullQuads; + bool layoutQuadDeriv; + bool layoutHitObjectShaderRecordNV; // GL_EXT_spirv_intrinsics int spirvStorageClass; TSpirvDecorate* spirvDecorate; -#endif + + bool layoutBindlessSampler; + bool layoutBindlessImage; bool hasUniformLayout() const { @@ -1002,9 +980,7 @@ public: layoutSet = layoutSetEnd; layoutBinding = layoutBindingEnd; -#ifndef GLSLANG_WEB layoutAttachment = layoutAttachmentEnd; -#endif } bool hasMatrix() const @@ -1037,26 +1013,6 @@ public: { return layoutBinding != layoutBindingEnd; } -#ifdef GLSLANG_WEB - bool hasOffset() const { return false; } - bool isNonPerspective() const { return false; } - bool hasIndex() const { return false; } - unsigned getIndex() const { return 0; } - bool hasComponent() const { return false; } - bool hasStream() const { return false; } - bool hasFormat() const { return false; } - bool hasXfb() const { return false; } - bool hasXfbBuffer() const { return false; } - bool hasXfbStride() const { return false; } - bool hasXfbOffset() const { return false; } - bool hasAttachment() const { return false; } - TLayoutFormat getFormat() const { return ElfNone; } - bool isPushConstant() const { return false; } - bool isShaderRecord() const { return false; } - bool hasBufferReference() const { return false; } - bool hasBufferReferenceAlign() const { return false; } - bool isNonUniform() const { return false; } -#else bool hasOffset() const { return layoutOffset != layoutNotSet; @@ -1104,6 +1060,9 @@ public: TLayoutFormat getFormat() const { return layoutFormat; } bool isPushConstant() const { return layoutPushConstant; } bool isShaderRecord() const { return layoutShaderRecord; } + bool isFullQuads() const { return layoutFullQuads; } + bool isQuadDeriv() const { return layoutQuadDeriv; } + bool hasHitObjectShaderRecordNV() const { return layoutHitObjectShaderRecordNV; } bool hasBufferReference() const { return layoutBufferReference; } bool hasBufferReferenceAlign() const { @@ -1113,16 +1072,24 @@ public: { return nonUniform; } + bool isBindlessSampler() const + { + return layoutBindlessSampler; + } + bool isBindlessImage() const + { + return layoutBindlessImage; + } // GL_EXT_spirv_intrinsics - bool hasSprivDecorate() const { return spirvDecorate != nullptr; } + bool hasSpirvDecorate() const { return spirvDecorate != nullptr; } void setSpirvDecorate(int decoration, const TIntermAggregate* args = nullptr); void setSpirvDecorateId(int decoration, const TIntermAggregate* args); void setSpirvDecorateString(int decoration, const TIntermAggregate* args); const TSpirvDecorate& getSpirvDecorate() const { assert(spirvDecorate); return *spirvDecorate; } TSpirvDecorate& getSpirvDecorate() { assert(spirvDecorate); return *spirvDecorate; } TString getSpirvDecorateQualifierString() const; -#endif + bool hasSpecConstantId() const { // Not the same thing as being a specialization constant, this @@ -1156,12 +1123,10 @@ public: { switch (packing) { case ElpStd140: return "std140"; -#ifndef GLSLANG_WEB case ElpPacked: return "packed"; case ElpShared: return "shared"; case ElpStd430: return "std430"; case ElpScalar: return "scalar"; -#endif default: return "none"; } } @@ -1173,9 +1138,6 @@ public: default: return "none"; } } -#ifdef GLSLANG_WEB - static const char* getLayoutFormatString(TLayoutFormat f) { return "none"; } -#else static const char* getLayoutFormatString(TLayoutFormat f) { switch (f) { @@ -1222,6 +1184,11 @@ public: case ElfR8ui: return "r8ui"; case ElfR64ui: return "r64ui"; case ElfR64i: return "r64i"; + case ElfSize1x8: return "size1x8"; + case ElfSize1x16: return "size1x16"; + case ElfSize1x32: return "size1x32"; + case ElfSize2x32: return "size2x32"; + case ElfSize4x32: return "size4x32"; default: return "none"; } } @@ -1235,6 +1202,18 @@ public: default: return "none"; } } + static const char* getLayoutStencilString(TLayoutStencil s) + { + switch (s) { + case ElsRefUnchangedFrontAMD: return "stencil_ref_unchanged_front_amd"; + case ElsRefGreaterFrontAMD: return "stencil_ref_greater_front_amd"; + case ElsRefLessFrontAMD: return "stencil_ref_less_front_amd"; + case ElsRefUnchangedBackAMD: return "stencil_ref_unchanged_back_amd"; + case ElsRefGreaterBackAMD: return "stencil_ref_greater_back_amd"; + case ElsRefLessBackAMD: return "stencil_ref_less_back_amd"; + default: return "none"; + } + } static const char* getBlendEquationString(TBlendEquationShift e) { switch (e) { @@ -1312,7 +1291,6 @@ public: default: return "none"; } } -#endif }; // Qualifiers that don't need to be keep per object. They have shader scope, not object scope. @@ -1329,10 +1307,14 @@ struct TShaderQualifiers { int localSize[3]; // compute shader bool localSizeNotDefault[3]; // compute shader int localSizeSpecId[3]; // compute shader specialization id for gl_WorkGroupSize -#ifndef GLSLANG_WEB bool earlyFragmentTests; // fragment input bool postDepthCoverage; // fragment input + bool earlyAndLateFragmentTestsAMD; //fragment input + bool nonCoherentColorAttachmentReadEXT; // fragment input + bool nonCoherentDepthAttachmentReadEXT; // fragment input + bool nonCoherentStencilAttachmentReadEXT; // fragment input TLayoutDepth layoutDepth; + TLayoutStencil layoutStencil; bool blendEquation; // true if any blend equation was specified int numViews; // multiview extenstions TInterlockOrdering interlockOrdering; @@ -1342,9 +1324,7 @@ struct TShaderQualifiers { int primitives; // mesh shader "max_primitives"DerivativeGroupLinear; // true if layout derivative_group_linearNV set bool layoutPrimitiveCulling; // true if layout primitive_culling set TLayoutDepth getDepth() const { return layoutDepth; } -#else - TLayoutDepth getDepth() const { return EldNone; } -#endif + TLayoutStencil getStencil() const { return layoutStencil; } void init() { @@ -1365,10 +1345,14 @@ struct TShaderQualifiers { localSizeSpecId[0] = TQualifier::layoutNotSet; localSizeSpecId[1] = TQualifier::layoutNotSet; localSizeSpecId[2] = TQualifier::layoutNotSet; -#ifndef GLSLANG_WEB earlyFragmentTests = false; + earlyAndLateFragmentTestsAMD = false; postDepthCoverage = false; + nonCoherentColorAttachmentReadEXT = false; + nonCoherentDepthAttachmentReadEXT = false; + nonCoherentStencilAttachmentReadEXT = false; layoutDepth = EldNone; + layoutStencil = ElsNone; blendEquation = false; numViews = TQualifier::layoutNotSet; layoutOverrideCoverage = false; @@ -1377,14 +1361,9 @@ struct TShaderQualifiers { layoutPrimitiveCulling = false; primitives = TQualifier::layoutNotSet; interlockOrdering = EioNone; -#endif } -#ifdef GLSLANG_WEB - bool hasBlendEquation() const { return false; } -#else bool hasBlendEquation() const { return blendEquation; } -#endif // Merge in characteristics from the 'src' qualifier. They can override when // set, but never erase when not set. @@ -1417,13 +1396,22 @@ struct TShaderQualifiers { if (src.localSizeSpecId[i] != TQualifier::layoutNotSet) localSizeSpecId[i] = src.localSizeSpecId[i]; } -#ifndef GLSLANG_WEB if (src.earlyFragmentTests) earlyFragmentTests = true; + if (src.earlyAndLateFragmentTestsAMD) + earlyAndLateFragmentTestsAMD = true; if (src.postDepthCoverage) postDepthCoverage = true; + if (src.nonCoherentColorAttachmentReadEXT) + nonCoherentColorAttachmentReadEXT = true; + if (src.nonCoherentDepthAttachmentReadEXT) + nonCoherentDepthAttachmentReadEXT = true; + if (src.nonCoherentStencilAttachmentReadEXT) + nonCoherentStencilAttachmentReadEXT = true; if (src.layoutDepth) layoutDepth = src.layoutDepth; + if (src.layoutStencil) + layoutStencil = src.layoutStencil; if (src.blendEquation) blendEquation = src.blendEquation; if (src.numViews != TQualifier::layoutNotSet) @@ -1440,7 +1428,31 @@ struct TShaderQualifiers { interlockOrdering = src.interlockOrdering; if (src.layoutPrimitiveCulling) layoutPrimitiveCulling = src.layoutPrimitiveCulling; -#endif + } +}; + +class TTypeParameters { +public: + POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) + + TTypeParameters() : basicType(EbtVoid), arraySizes(nullptr), spirvType(nullptr) {} + + TBasicType basicType; + TArraySizes *arraySizes; + TSpirvType *spirvType; + + bool operator==(const TTypeParameters& rhs) const + { + bool same = basicType == rhs.basicType && *arraySizes == *rhs.arraySizes; + if (same && basicType == EbtSpirvType) { + assert(spirvType && rhs.spirvType); + return *spirvType == *rhs.spirvType; + } + return same; + } + bool operator!=(const TTypeParameters& rhs) const + { + return !(*this == rhs); } }; @@ -1458,39 +1470,35 @@ public: TSampler sampler; TQualifier qualifier; TShaderQualifiers shaderQualifiers; - int vectorSize : 4; - int matrixCols : 4; - int matrixRows : 4; - bool coopmat : 1; + uint32_t vectorSize : 4; + uint32_t matrixCols : 4; + uint32_t matrixRows : 4; + bool coopmatNV : 1; + bool coopmatKHR : 1; TArraySizes* arraySizes; const TType* userDef; TSourceLoc loc; - TArraySizes* typeParameters; -#ifndef GLSLANG_WEB + TTypeParameters* typeParameters; // SPIR-V type defined by spirv_type directive TSpirvType* spirvType; -#endif -#ifdef GLSLANG_WEB - bool isCoopmat() const { return false; } -#else - bool isCoopmat() const { return coopmat; } -#endif + bool isCoopmat() const { return coopmatNV || coopmatKHR; } + bool isCoopmatNV() const { return coopmatNV; } + bool isCoopmatKHR() const { return coopmatKHR; } void initType(const TSourceLoc& l) { basicType = EbtVoid; - vectorSize = 1; + vectorSize = 1u; matrixRows = 0; matrixCols = 0; arraySizes = nullptr; userDef = nullptr; loc = l; typeParameters = nullptr; - coopmat = false; -#ifndef GLSLANG_WEB + coopmatNV = false; + coopmatKHR = false; spirvType = nullptr; -#endif } void initQualifiers(bool global = false) @@ -1512,29 +1520,31 @@ public: { matrixRows = 0; matrixCols = 0; - vectorSize = s; + assert(s >= 0); + vectorSize = static_cast(s) & 0b1111; } void setMatrix(int c, int r) { - matrixRows = r; - matrixCols = c; + assert(r >= 0); + matrixRows = static_cast(r) & 0b1111; + assert(c >= 0); + matrixCols = static_cast(c) & 0b1111; vectorSize = 0; } bool isScalar() const { - return matrixCols == 0 && vectorSize == 1 && arraySizes == nullptr && userDef == nullptr; + return matrixCols == 0u && vectorSize == 1u && arraySizes == nullptr && userDef == nullptr; } -#ifndef GLSLANG_WEB // GL_EXT_spirv_intrinsics void setSpirvType(const TSpirvInstruction& spirvInst, const TSpirvTypeParameters* typeParams = nullptr); -#endif // "Image" is a superset of "Subpass" - bool isImage() const { return basicType == EbtSampler && sampler.isImage(); } - bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); } + bool isImage() const { return basicType == EbtSampler && sampler.isImage(); } + bool isSubpass() const { return basicType == EbtSampler && sampler.isSubpass(); } + bool isAttachmentEXT() const { return basicType == EbtSampler && sampler.isAttachmentEXT(); } }; // @@ -1547,12 +1557,14 @@ public: // for "empty" type (no args) or simple scalar/vector/matrix explicit TType(TBasicType t = EbtVoid, TStorageQualifier q = EvqTemporary, int vs = 1, int mc = 0, int mr = 0, bool isVector = false) : - basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false), - arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + basicType(t), vectorSize(static_cast(vs) & 0b1111), matrixCols(static_cast(mc) & 0b1111), matrixRows(static_cast(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), + arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr), + spirvType(nullptr) { + assert(vs >= 0); + assert(mc >= 0); + assert(mr >= 0); + sampler.clear(); qualifier.clear(); qualifier.storage = q; @@ -1561,12 +1573,14 @@ public: // for explicit precision qualifier TType(TBasicType t, TStorageQualifier q, TPrecisionQualifier p, int vs = 1, int mc = 0, int mr = 0, bool isVector = false) : - basicType(t), vectorSize(vs), matrixCols(mc), matrixRows(mr), vector1(isVector && vs == 1), coopmat(false), - arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + basicType(t), vectorSize(static_cast(vs) & 0b1111), matrixCols(static_cast(mc) & 0b1111), matrixRows(static_cast(mr) & 0b1111), vector1(isVector && vs == 1), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), + arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr), + spirvType(nullptr) { + assert(vs >= 0); + assert(mc >= 0); + assert(mr >= 0); + sampler.clear(); qualifier.clear(); qualifier.storage = q; @@ -1577,11 +1591,9 @@ public: // for turning a TPublicType into a TType, using a shallow copy explicit TType(const TPublicType& p) : basicType(p.basicType), - vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmat(p.coopmat), - arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters) -#ifndef GLSLANG_WEB - , spirvType(p.spirvType) -#endif + vectorSize(p.vectorSize), matrixCols(p.matrixCols), matrixRows(p.matrixRows), vector1(false), coopmatNV(p.coopmatNV), coopmatKHR(p.coopmatKHR), coopmatKHRuse(0), coopmatKHRUseValid(false), + arraySizes(p.arraySizes), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(p.typeParameters), + spirvType(p.spirvType) { if (basicType == EbtSampler) sampler = p.sampler; @@ -1597,28 +1609,46 @@ public: } typeName = NewPoolTString(p.userDef->getTypeName().c_str()); } - if (p.isCoopmat() && p.typeParameters && p.typeParameters->getNumDims() > 0) { - int numBits = p.typeParameters->getDimSize(0); + if (p.isCoopmatNV() && p.typeParameters && p.typeParameters->arraySizes->getNumDims() > 0) { + int numBits = p.typeParameters->arraySizes->getDimSize(0); if (p.basicType == EbtFloat && numBits == 16) { basicType = EbtFloat16; qualifier.precision = EpqNone; } else if (p.basicType == EbtUint && numBits == 8) { basicType = EbtUint8; qualifier.precision = EpqNone; + } else if (p.basicType == EbtUint && numBits == 16) { + basicType = EbtUint16; + qualifier.precision = EpqNone; } else if (p.basicType == EbtInt && numBits == 8) { basicType = EbtInt8; qualifier.precision = EpqNone; + } else if (p.basicType == EbtInt && numBits == 16) { + basicType = EbtInt16; + qualifier.precision = EpqNone; + } + } + if (p.isCoopmatKHR() && p.typeParameters && p.typeParameters->arraySizes->getNumDims() > 0) { + basicType = p.typeParameters->basicType; + if (isSpirvType()) { + assert(p.typeParameters->spirvType); + spirvType = p.typeParameters->spirvType; + } + + if (p.typeParameters->arraySizes->getNumDims() == 4) { + const int dimSize = p.typeParameters->arraySizes->getDimSize(3); + assert(dimSize >= 0); + coopmatKHRuse = static_cast(dimSize) & 0b111; + coopmatKHRUseValid = true; + p.typeParameters->arraySizes->removeLastSize(); } } } // for construction of sampler types TType(const TSampler& sampler, TStorageQualifier q = EvqUniform, TArraySizes* as = nullptr) : - basicType(EbtSampler), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), + basicType(EbtSampler), vectorSize(1u), matrixCols(0u), matrixRows(0u), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), arraySizes(as), structure(nullptr), fieldName(nullptr), typeName(nullptr), - sampler(sampler), typeParameters(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + sampler(sampler), typeParameters(nullptr), spirvType(nullptr) { qualifier.clear(); qualifier.storage = q; @@ -1660,18 +1690,19 @@ public: vectorSize = 1; vector1 = false; } else if (isCoopMat()) { - coopmat = false; + coopmatNV = false; + coopmatKHR = false; + coopmatKHRuse = 0; + coopmatKHRUseValid = false; typeParameters = nullptr; } } } // for making structures, ... TType(TTypeList* userDef, const TString& n) : - basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), - arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + basicType(EbtStruct), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), + arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr), + spirvType(nullptr) { sampler.clear(); qualifier.clear(); @@ -1679,25 +1710,22 @@ public: } // For interface blocks TType(TTypeList* userDef, const TString& n, const TQualifier& q) : - basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmat(false), - qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + basicType(EbtBlock), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), + qualifier(q), arraySizes(nullptr), structure(userDef), fieldName(nullptr), typeParameters(nullptr), + spirvType(nullptr) { sampler.clear(); typeName = NewPoolTString(n.c_str()); } // for block reference (first parameter must be EbtReference) explicit TType(TBasicType t, const TType &p, const TString& n) : - basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), - arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr) -#ifndef GLSLANG_WEB - , spirvType(nullptr) -#endif + basicType(t), vectorSize(1), matrixCols(0), matrixRows(0), vector1(false), coopmatNV(false), coopmatKHR(false), coopmatKHRuse(0), coopmatKHRUseValid(false), + arraySizes(nullptr), structure(nullptr), fieldName(nullptr), typeName(nullptr), typeParameters(nullptr), + spirvType(nullptr) { assert(t == EbtReference); typeName = NewPoolTString(n.c_str()); + sampler.clear(); qualifier.clear(); qualifier.storage = p.qualifier.storage; referentType = p.clone(); @@ -1725,10 +1753,11 @@ public: referentType = copyOf.referentType; } typeParameters = copyOf.typeParameters; -#ifndef GLSLANG_WEB spirvType = copyOf.spirvType; -#endif - coopmat = copyOf.isCoopMat(); + coopmatNV = copyOf.isCoopMatNV(); + coopmatKHR = copyOf.isCoopMatKHR(); + coopmatKHRuse = copyOf.coopmatKHRuse; + coopmatKHRUseValid = copyOf.coopmatKHRUseValid; } // Make complete copy of the whole type graph rooted at 'copyOf'. @@ -1758,7 +1787,7 @@ public: void makeVector() { vector1 = true; } - virtual void hideMember() { basicType = EbtVoid; vectorSize = 1; } + virtual void hideMember() { basicType = EbtVoid; vectorSize = 1u; } virtual bool hiddenMember() const { return basicType == EbtVoid; } virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); } @@ -1798,35 +1827,33 @@ public: virtual TQualifier& getQualifier() { return qualifier; } virtual const TQualifier& getQualifier() const { return qualifier; } - virtual int getVectorSize() const { return vectorSize; } // returns 1 for either scalar or vector of size 1, valid for both - virtual int getMatrixCols() const { return matrixCols; } - virtual int getMatrixRows() const { return matrixRows; } + virtual int getVectorSize() const { return static_cast(vectorSize); } // returns 1 for either scalar or vector of size 1, valid for both + virtual int getMatrixCols() const { return static_cast(matrixCols); } + virtual int getMatrixRows() const { return static_cast(matrixRows); } virtual int getOuterArraySize() const { return arraySizes->getOuterSize(); } virtual TIntermTyped* getOuterArrayNode() const { return arraySizes->getOuterNode(); } virtual int getCumulativeArraySize() const { return arraySizes->getCumulativeSize(); } -#ifdef GLSLANG_WEB - bool isArrayOfArrays() const { return false; } -#else bool isArrayOfArrays() const { return arraySizes != nullptr && arraySizes->getNumDims() > 1; } -#endif virtual int getImplicitArraySize() const { return arraySizes->getImplicitSize(); } virtual const TArraySizes* getArraySizes() const { return arraySizes; } virtual TArraySizes* getArraySizes() { return arraySizes; } virtual TType* getReferentType() const { return referentType; } - virtual const TArraySizes* getTypeParameters() const { return typeParameters; } - virtual TArraySizes* getTypeParameters() { return typeParameters; } + virtual const TTypeParameters* getTypeParameters() const { return typeParameters; } + virtual TTypeParameters* getTypeParameters() { return typeParameters; } virtual bool isScalar() const { return ! isVector() && ! isMatrix() && ! isStruct() && ! isArray(); } virtual bool isScalarOrVec1() const { return isScalar() || vector1; } virtual bool isScalarOrVector() const { return !isMatrix() && !isStruct() && !isArray(); } - virtual bool isVector() const { return vectorSize > 1 || vector1; } + virtual bool isVector() const { return vectorSize > 1u || vector1; } virtual bool isMatrix() const { return matrixCols ? true : false; } virtual bool isArray() const { return arraySizes != nullptr; } virtual bool isSizedArray() const { return isArray() && arraySizes->isSized(); } virtual bool isUnsizedArray() const { return isArray() && !arraySizes->isSized(); } + virtual bool isImplicitlySizedArray() const { return isArray() && arraySizes->isImplicitlySized(); } virtual bool isArrayVariablyIndexed() const { assert(isArray()); return arraySizes->isVariablyIndexed(); } virtual void setArrayVariablyIndexed() { assert(isArray()); arraySizes->setVariablyIndexed(); } virtual void updateImplicitArraySize(int size) { assert(isArray()); arraySizes->updateImplicitSize(size); } + virtual void setImplicitlySized(bool isImplicitSized) { arraySizes->setImplicitlySized(isImplicitSized); } virtual bool isStruct() const { return basicType == EbtStruct || basicType == EbtBlock; } virtual bool isFloatingDomain() const { return basicType == EbtFloat || basicType == EbtDouble || basicType == EbtFloat16; } virtual bool isIntegerDomain() const @@ -1848,30 +1875,26 @@ public: return false; } virtual bool isOpaque() const { return basicType == EbtSampler -#ifndef GLSLANG_WEB || basicType == EbtAtomicUint || basicType == EbtAccStruct || basicType == EbtRayQuery -#endif - ; } + || basicType == EbtHitObjectNV; } virtual bool isBuiltIn() const { return getQualifier().builtIn != EbvNone; } - // "Image" is a superset of "Subpass" - virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); } + virtual bool isAttachmentEXT() const { return basicType == EbtSampler && getSampler().isAttachmentEXT(); } + virtual bool isImage() const { return basicType == EbtSampler && getSampler().isImage(); } virtual bool isSubpass() const { return basicType == EbtSampler && getSampler().isSubpass(); } virtual bool isTexture() const { return basicType == EbtSampler && getSampler().isTexture(); } + virtual bool isBindlessImage() const { return isImage() && qualifier.layoutBindlessImage; } + virtual bool isBindlessTexture() const { return isTexture() && qualifier.layoutBindlessSampler; } // Check the block-name convention of creating a block without populating it's members: virtual bool isUnusableName() const { return isStruct() && structure == nullptr; } virtual bool isParameterized() const { return typeParameters != nullptr; } -#ifdef GLSLANG_WEB - bool isAtomic() const { return false; } - bool isCoopMat() const { return false; } - bool isReference() const { return false; } - bool isSpirvType() const { return false; } -#else bool isAtomic() const { return basicType == EbtAtomicUint; } - bool isCoopMat() const { return coopmat; } + bool isCoopMat() const { return coopmatNV || coopmatKHR; } + bool isCoopMatNV() const { return coopmatNV; } + bool isCoopMatKHR() const { return coopmatKHR; } bool isReference() const { return getBasicType() == EbtReference; } bool isSpirvType() const { return getBasicType() == EbtSpirvType; } -#endif + int getCoopMatKHRuse() const { return static_cast(coopmatKHRuse); } // return true if this type contains any subtype which satisfies the given predicate. template @@ -1914,6 +1937,11 @@ public: return contains([](const TType* t) { return t->isOpaque(); } ); } + virtual bool containsSampler() const + { + return contains([](const TType* t) { return t->isTexture() || t->isImage(); }); + } + // Recursively checks if the type contains a built-in variable virtual bool containsBuiltIn() const { @@ -1952,15 +1980,6 @@ public: return contains([](const TType* t) { return t->isArray() && t->arraySizes->isOuterSpecialization(); } ); } -#ifdef GLSLANG_WEB - bool containsDouble() const { return false; } - bool contains16BitFloat() const { return false; } - bool contains64BitInt() const { return false; } - bool contains16BitInt() const { return false; } - bool contains8BitInt() const { return false; } - bool containsCoopMat() const { return false; } - bool containsReference() const { return false; } -#else bool containsDouble() const { return containsBasicType(EbtDouble); @@ -1983,13 +2002,12 @@ public: } bool containsCoopMat() const { - return contains([](const TType* t) { return t->coopmat; } ); + return contains([](const TType* t) { return t->coopmatNV || t->coopmatKHR; } ); } bool containsReference() const { return containsBasicType(EbtReference); } -#endif // Array editing methods. Array descriptors can be shared across // type instances. This allows all uses of the same array @@ -2047,8 +2065,12 @@ public: // an explicit array. void adoptImplicitArraySizes(bool skipNonvariablyIndexed) { - if (isUnsizedArray() && !(skipNonvariablyIndexed || isArrayVariablyIndexed())) + if (isUnsizedArray() && + (qualifier.builtIn == EbvSampleMask || + !(skipNonvariablyIndexed || isArrayVariablyIndexed()))) { changeOuterArraySize(getImplicitArraySize()); + setImplicitlySized(true); + } // For multi-dim per-view arrays, set unsized inner dimension size to 1 if (qualifier.isPerView() && arraySizes && arraySizes->isInnerUnsized()) arraySizes->clearInnerUnsized(); @@ -2061,43 +2083,12 @@ public: } } - - void updateTypeParameters(const TType& type) - { - // For when we may already be sharing existing array descriptors, - // keeping the pointers the same, just updating the contents. - assert(typeParameters != nullptr); - assert(type.typeParameters != nullptr); - *typeParameters = *type.typeParameters; - } - void copyTypeParameters(const TArraySizes& s) + void copyTypeParameters(const TTypeParameters& s) { // For setting a fresh new set of type parameters, not yet worrying about sharing. - typeParameters = new TArraySizes; + typeParameters = new TTypeParameters; *typeParameters = s; } - void transferTypeParameters(TArraySizes* s) - { - // For setting an already allocated set of sizes that this type can use - // (no copy made). - typeParameters = s; - } - void clearTypeParameters() - { - typeParameters = nullptr; - } - - // Add inner array sizes, to any existing sizes, via copy; the - // sizes passed in can still be reused for other purposes. - void copyTypeParametersInnerSizes(const TArraySizes* s) - { - if (s != nullptr) { - if (typeParameters == nullptr) - copyTypeParameters(*s); - else - typeParameters->addInnerSizes(*s); - } - } const char* getBasicString() const { @@ -2111,7 +2102,6 @@ public: case EbtInt: return "int"; case EbtUint: return "uint"; case EbtSampler: return "sampler/image"; -#ifndef GLSLANG_WEB case EbtVoid: return "void"; case EbtDouble: return "double"; case EbtFloat16: return "float16_t"; @@ -2130,19 +2120,13 @@ public: case EbtReference: return "reference"; case EbtString: return "string"; case EbtSpirvType: return "spirv_type"; -#endif + case EbtCoopmat: return "coopmat"; default: return "unknown type"; } } -#ifdef GLSLANG_WEB - TString getCompleteString() const { return ""; } - const char* getStorageQualifierString() const { return ""; } - const char* getBuiltInVariableString() const { return ""; } - const char* getPrecisionQualifierString() const { return ""; } - TString getBasicTypeString() const { return ""; } -#else - TString getCompleteString() const + TString getCompleteString(bool syntactic = false, bool getQualifiers = true, bool getPrecision = true, + bool getType = true, TString name = "", TString structName = "") const { TString typeString; @@ -2150,232 +2134,358 @@ public: const auto appendUint = [&](unsigned int u) { typeString.append(std::to_string(u).c_str()); }; const auto appendInt = [&](int i) { typeString.append(std::to_string(i).c_str()); }; - if (qualifier.hasSprivDecorate()) + if (getQualifiers) { + if (qualifier.hasSpirvDecorate()) appendStr(qualifier.getSpirvDecorateQualifierString().c_str()); - if (qualifier.hasLayout()) { + if (qualifier.hasLayout()) { // To reduce noise, skip this if the only layout is an xfb_buffer // with no triggering xfb_offset. TQualifier noXfbBuffer = qualifier; noXfbBuffer.layoutXfbBuffer = TQualifier::layoutXfbBufferEnd; if (noXfbBuffer.hasLayout()) { - appendStr("layout("); - if (qualifier.hasAnyLocation()) { - appendStr(" location="); - appendUint(qualifier.layoutLocation); - if (qualifier.hasComponent()) { - appendStr(" component="); - appendUint(qualifier.layoutComponent); - } - if (qualifier.hasIndex()) { - appendStr(" index="); - appendUint(qualifier.layoutIndex); - } + appendStr("layout("); + if (qualifier.hasAnyLocation()) { + appendStr(" location="); + appendUint(qualifier.layoutLocation); + if (qualifier.hasComponent()) { + appendStr(" component="); + appendUint(qualifier.layoutComponent); } - if (qualifier.hasSet()) { - appendStr(" set="); - appendUint(qualifier.layoutSet); - } - if (qualifier.hasBinding()) { - appendStr(" binding="); - appendUint(qualifier.layoutBinding); - } - if (qualifier.hasStream()) { - appendStr(" stream="); - appendUint(qualifier.layoutStream); - } - if (qualifier.hasMatrix()) { - appendStr(" "); - appendStr(TQualifier::getLayoutMatrixString(qualifier.layoutMatrix)); - } - if (qualifier.hasPacking()) { - appendStr(" "); - appendStr(TQualifier::getLayoutPackingString(qualifier.layoutPacking)); - } - if (qualifier.hasOffset()) { - appendStr(" offset="); - appendInt(qualifier.layoutOffset); - } - if (qualifier.hasAlign()) { - appendStr(" align="); - appendInt(qualifier.layoutAlign); - } - if (qualifier.hasFormat()) { - appendStr(" "); - appendStr(TQualifier::getLayoutFormatString(qualifier.layoutFormat)); - } - if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) { - appendStr(" xfb_buffer="); - appendUint(qualifier.layoutXfbBuffer); - } - if (qualifier.hasXfbOffset()) { - appendStr(" xfb_offset="); - appendUint(qualifier.layoutXfbOffset); - } - if (qualifier.hasXfbStride()) { - appendStr(" xfb_stride="); - appendUint(qualifier.layoutXfbStride); - } - if (qualifier.hasAttachment()) { - appendStr(" input_attachment_index="); - appendUint(qualifier.layoutAttachment); - } - if (qualifier.hasSpecConstantId()) { - appendStr(" constant_id="); - appendUint(qualifier.layoutSpecConstantId); - } - if (qualifier.layoutPushConstant) - appendStr(" push_constant"); - if (qualifier.layoutBufferReference) - appendStr(" buffer_reference"); - if (qualifier.hasBufferReferenceAlign()) { - appendStr(" buffer_reference_align="); - appendUint(1u << qualifier.layoutBufferReferenceAlign); + if (qualifier.hasIndex()) { + appendStr(" index="); + appendUint(qualifier.layoutIndex); } + } + if (qualifier.hasSet()) { + appendStr(" set="); + appendUint(qualifier.layoutSet); + } + if (qualifier.hasBinding()) { + appendStr(" binding="); + appendUint(qualifier.layoutBinding); + } + if (qualifier.hasStream()) { + appendStr(" stream="); + appendUint(qualifier.layoutStream); + } + if (qualifier.hasMatrix()) { + appendStr(" "); + appendStr(TQualifier::getLayoutMatrixString(qualifier.layoutMatrix)); + } + if (qualifier.hasPacking()) { + appendStr(" "); + appendStr(TQualifier::getLayoutPackingString(qualifier.layoutPacking)); + } + if (qualifier.hasOffset()) { + appendStr(" offset="); + appendInt(qualifier.layoutOffset); + } + if (qualifier.hasAlign()) { + appendStr(" align="); + appendInt(qualifier.layoutAlign); + } + if (qualifier.hasFormat()) { + appendStr(" "); + appendStr(TQualifier::getLayoutFormatString(qualifier.layoutFormat)); + } + if (qualifier.hasXfbBuffer() && qualifier.hasXfbOffset()) { + appendStr(" xfb_buffer="); + appendUint(qualifier.layoutXfbBuffer); + } + if (qualifier.hasXfbOffset()) { + appendStr(" xfb_offset="); + appendUint(qualifier.layoutXfbOffset); + } + if (qualifier.hasXfbStride()) { + appendStr(" xfb_stride="); + appendUint(qualifier.layoutXfbStride); + } + if (qualifier.hasAttachment()) { + appendStr(" input_attachment_index="); + appendUint(qualifier.layoutAttachment); + } + if (qualifier.hasSpecConstantId()) { + appendStr(" constant_id="); + appendUint(qualifier.layoutSpecConstantId); + } + if (qualifier.layoutPushConstant) + appendStr(" push_constant"); + if (qualifier.layoutBufferReference) + appendStr(" buffer_reference"); + if (qualifier.hasBufferReferenceAlign()) { + appendStr(" buffer_reference_align="); + appendUint(1u << qualifier.layoutBufferReferenceAlign); + } - if (qualifier.layoutPassthrough) - appendStr(" passthrough"); - if (qualifier.layoutViewportRelative) - appendStr(" layoutViewportRelative"); - if (qualifier.layoutSecondaryViewportRelativeOffset != -2048) { - appendStr(" layoutSecondaryViewportRelativeOffset="); - appendInt(qualifier.layoutSecondaryViewportRelativeOffset); - } - if (qualifier.layoutShaderRecord) - appendStr(" shaderRecordNV"); + if (qualifier.layoutPassthrough) + appendStr(" passthrough"); + if (qualifier.layoutViewportRelative) + appendStr(" layoutViewportRelative"); + if (qualifier.layoutSecondaryViewportRelativeOffset != -2048) { + appendStr(" layoutSecondaryViewportRelativeOffset="); + appendInt(qualifier.layoutSecondaryViewportRelativeOffset); + } + + if (qualifier.layoutShaderRecord) + appendStr(" shaderRecordNV"); + if (qualifier.layoutFullQuads) + appendStr(" full_quads"); + if (qualifier.layoutQuadDeriv) + appendStr(" quad_derivatives"); + if (qualifier.layoutHitObjectShaderRecordNV) + appendStr(" hitobjectshaderrecordnv"); - appendStr(")"); + if (qualifier.layoutBindlessSampler) + appendStr(" layoutBindlessSampler"); + if (qualifier.layoutBindlessImage) + appendStr(" layoutBindlessImage"); + + appendStr(")"); } - } + } - if (qualifier.invariant) + if (qualifier.invariant) appendStr(" invariant"); - if (qualifier.noContraction) + if (qualifier.noContraction) appendStr(" noContraction"); - if (qualifier.centroid) + if (qualifier.centroid) appendStr(" centroid"); - if (qualifier.smooth) + if (qualifier.smooth) appendStr(" smooth"); - if (qualifier.flat) + if (qualifier.flat) appendStr(" flat"); - if (qualifier.nopersp) + if (qualifier.nopersp) appendStr(" noperspective"); - if (qualifier.explicitInterp) + if (qualifier.explicitInterp) appendStr(" __explicitInterpAMD"); - if (qualifier.pervertexNV) + if (qualifier.pervertexNV) appendStr(" pervertexNV"); - if (qualifier.perPrimitiveNV) + if (qualifier.pervertexEXT) + appendStr(" pervertexEXT"); + if (qualifier.perPrimitiveNV) appendStr(" perprimitiveNV"); - if (qualifier.perViewNV) + if (qualifier.perViewNV) appendStr(" perviewNV"); - if (qualifier.perTaskNV) + if (qualifier.perTaskNV) appendStr(" taskNV"); - if (qualifier.patch) + if (qualifier.patch) appendStr(" patch"); - if (qualifier.sample) + if (qualifier.sample) appendStr(" sample"); - if (qualifier.coherent) + if (qualifier.coherent) appendStr(" coherent"); - if (qualifier.devicecoherent) + if (qualifier.devicecoherent) appendStr(" devicecoherent"); - if (qualifier.queuefamilycoherent) + if (qualifier.queuefamilycoherent) appendStr(" queuefamilycoherent"); - if (qualifier.workgroupcoherent) + if (qualifier.workgroupcoherent) appendStr(" workgroupcoherent"); - if (qualifier.subgroupcoherent) + if (qualifier.subgroupcoherent) appendStr(" subgroupcoherent"); - if (qualifier.shadercallcoherent) + if (qualifier.shadercallcoherent) appendStr(" shadercallcoherent"); - if (qualifier.nonprivate) + if (qualifier.nonprivate) appendStr(" nonprivate"); - if (qualifier.volatil) + if (qualifier.volatil) appendStr(" volatile"); - if (qualifier.restrict) + if (qualifier.restrict) appendStr(" restrict"); - if (qualifier.readonly) + if (qualifier.readonly) appendStr(" readonly"); - if (qualifier.writeonly) + if (qualifier.writeonly) appendStr(" writeonly"); - if (qualifier.specConstant) + if (qualifier.specConstant) appendStr(" specialization-constant"); - if (qualifier.nonUniform) + if (qualifier.nonUniform) appendStr(" nonuniform"); - if (qualifier.isNullInit()) + if (qualifier.isNullInit()) appendStr(" null-init"); - if (qualifier.isSpirvByReference()) + if (qualifier.isSpirvByReference()) appendStr(" spirv_by_reference"); - if (qualifier.isSpirvLiteral()) + if (qualifier.isSpirvLiteral()) appendStr(" spirv_literal"); - appendStr(" "); - appendStr(getStorageQualifierString()); - if (isArray()) { - for(int i = 0; i < (int)arraySizes->getNumDims(); ++i) { + appendStr(" "); + appendStr(getStorageQualifierString()); + } + if (getType) { + if (syntactic) { + if (getPrecision && qualifier.precision != EpqNone) { + appendStr(" "); + appendStr(getPrecisionQualifierString()); + } + if (isVector() || isMatrix()) { + appendStr(" "); + switch (basicType) { + case EbtDouble: + appendStr("d"); + break; + case EbtInt: + appendStr("i"); + break; + case EbtUint: + appendStr("u"); + break; + case EbtBool: + appendStr("b"); + break; + case EbtFloat: + default: + break; + } + if (isVector()) { + appendStr("vec"); + appendInt(vectorSize); + } else { + appendStr("mat"); + appendInt(matrixCols); + appendStr("x"); + appendInt(matrixRows); + } + } else if (isStruct() && structure) { + appendStr(" "); + appendStr(structName.c_str()); + appendStr("{"); + bool hasHiddenMember = true; + for (size_t i = 0; i < structure->size(); ++i) { + if (!(*structure)[i].type->hiddenMember()) { + if (!hasHiddenMember) + appendStr(", "); + typeString.append((*structure)[i].type->getCompleteString(syntactic, getQualifiers, getPrecision, getType, (*structure)[i].type->getFieldName())); + hasHiddenMember = false; + } + } + appendStr("}"); + } else { + appendStr(" "); + switch (basicType) { + case EbtDouble: + appendStr("double"); + break; + case EbtInt: + appendStr("int"); + break; + case EbtUint: + appendStr("uint"); + break; + case EbtBool: + appendStr("bool"); + break; + case EbtFloat: + appendStr("float"); + break; + default: + appendStr("unexpected"); + break; + } + } + if (name.length() > 0) { + appendStr(" "); + appendStr(name.c_str()); + } + if (isArray()) { + for (int i = 0; i < (int)arraySizes->getNumDims(); ++i) { int size = arraySizes->getDimSize(i); if (size == UnsizedArraySize && i == 0 && arraySizes->isVariablyIndexed()) - appendStr(" runtime-sized array of"); + appendStr("[]"); else { - if (size == UnsizedArraySize) { - appendStr(" unsized"); - if (i == 0) { - appendStr(" "); - appendInt(arraySizes->getImplicitSize()); - } - } else { - appendStr(" "); - appendInt(arraySizes->getDimSize(i)); + if (size == UnsizedArraySize) { + appendStr("["); + if (i == 0) + appendInt(arraySizes->getImplicitSize()); + appendStr("]"); + } + else { + appendStr("["); + appendInt(arraySizes->getDimSize(i)); + appendStr("]"); + } + } + } + } + } + else { + if (isArray()) { + for (int i = 0; i < (int)arraySizes->getNumDims(); ++i) { + int size = arraySizes->getDimSize(i); + if (size == UnsizedArraySize && i == 0 && arraySizes->isVariablyIndexed()) + appendStr(" runtime-sized array of"); + else { + if (size == UnsizedArraySize) { + appendStr(" unsized"); + if (i == 0) { + appendStr(" "); + appendInt(arraySizes->getImplicitSize()); } - appendStr("-element array of"); + } + else { + appendStr(" "); + appendInt(arraySizes->getDimSize(i)); + } + appendStr("-element array of"); } + } } - } - if (isParameterized()) { - appendStr("<"); - for(int i = 0; i < (int)typeParameters->getNumDims(); ++i) { - appendInt(typeParameters->getDimSize(i)); - if (i != (int)typeParameters->getNumDims() - 1) + if (isParameterized()) { + if (isCoopMatKHR()) { + appendStr(" "); + appendStr("coopmat"); + } + + appendStr("<"); + for (int i = 0; i < (int)typeParameters->arraySizes->getNumDims(); ++i) { + appendInt(typeParameters->arraySizes->getDimSize(i)); + if (i != (int)typeParameters->arraySizes->getNumDims() - 1) + appendStr(", "); + } + if (coopmatKHRUseValid) { + appendStr(", "); + appendInt(coopmatKHRuse); + } + appendStr(">"); + } + if (getPrecision && qualifier.precision != EpqNone) { + appendStr(" "); + appendStr(getPrecisionQualifierString()); + } + if (isMatrix()) { + appendStr(" "); + appendInt(matrixCols); + appendStr("X"); + appendInt(matrixRows); + appendStr(" matrix of"); + } + else if (isVector()) { + appendStr(" "); + appendInt(vectorSize); + appendStr("-component vector of"); + } + + appendStr(" "); + typeString.append(getBasicTypeString()); + + if (qualifier.builtIn != EbvNone) { + appendStr(" "); + appendStr(getBuiltInVariableString()); + } + + // Add struct/block members + if (isStruct() && structure) { + appendStr("{"); + bool hasHiddenMember = true; + for (size_t i = 0; i < structure->size(); ++i) { + if (!(*structure)[i].type->hiddenMember()) { + if (!hasHiddenMember) appendStr(", "); - } - appendStr(">"); - } - if (qualifier.precision != EpqNone) { - appendStr(" "); - appendStr(getPrecisionQualifierString()); - } - if (isMatrix()) { - appendStr(" "); - appendInt(matrixCols); - appendStr("X"); - appendInt(matrixRows); - appendStr(" matrix of"); - } else if (isVector()) { - appendStr(" "); - appendInt(vectorSize); - appendStr("-component vector of"); - } - - appendStr(" "); - typeString.append(getBasicTypeString()); - - if (qualifier.builtIn != EbvNone) { - appendStr(" "); - appendStr(getBuiltInVariableString()); - } - - // Add struct/block members - if (isStruct() && structure) { - appendStr("{"); - bool hasHiddenMember = true; - for (size_t i = 0; i < structure->size(); ++i) { - if (! (*structure)[i].type->hiddenMember()) { - if (!hasHiddenMember) - appendStr(", "); - typeString.append((*structure)[i].type->getCompleteString()); - typeString.append(" "); - typeString.append((*structure)[i].type->getFieldName()); - hasHiddenMember = false; + typeString.append((*structure)[i].type->getCompleteString()); + typeString.append(" "); + typeString.append((*structure)[i].type->getFieldName()); + hasHiddenMember = false; } + } + appendStr("}"); } - appendStr("}"); + } } return typeString; @@ -2392,16 +2502,19 @@ public: const char* getStorageQualifierString() const { return GetStorageQualifierString(qualifier.storage); } const char* getBuiltInVariableString() const { return GetBuiltInVariableString(qualifier.builtIn); } const char* getPrecisionQualifierString() const { return GetPrecisionQualifierString(qualifier.precision); } -#endif const TTypeList* getStruct() const { assert(isStruct()); return structure; } void setStruct(TTypeList* s) { assert(isStruct()); structure = s; } TTypeList* getWritableStruct() const { assert(isStruct()); return structure; } // This should only be used when known to not be sharing with other threads void setBasicType(const TBasicType& t) { basicType = t; } - + void setVectorSize(int s) { + assert(s >= 0); + vectorSize = static_cast(s) & 0b1111; + } + int computeNumComponents() const { - int components = 0; + uint32_t components = 0; if (getBasicType() == EbtStruct || getBasicType() == EbtBlock) { for (TTypeList::const_iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++) @@ -2415,7 +2528,7 @@ public: components *= arraySizes->getCumulativeSize(); } - return components; + return static_cast(components); } // append this type's mangled name to the passed in 'name' @@ -2444,13 +2557,27 @@ public: // type definitions, and member names to be considered the same type. // This rule applies recursively for nested or embedded types." // - bool sameStructType(const TType& right) const + // If type mismatch in structure, return member indices through lpidx and rpidx. + // If matching members for either block are exhausted, return -1 for exhausted + // block and the index of the unmatched member. Otherwise return {-1,-1}. + // + bool sameStructType(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const { + // Initialize error to general type mismatch. + if (lpidx != nullptr) { + *lpidx = -1; + *rpidx = -1; + } + // Most commonly, they are both nullptr, or the same pointer to the same actual structure + // TODO: Why return true when neither types are structures? if ((!isStruct() && !right.isStruct()) || (isStruct() && right.isStruct() && structure == right.structure)) return true; + if (!isStruct() || !right.isStruct()) + return false; + // Structure names have to match if (*typeName != *right.typeName) return false; @@ -2460,12 +2587,17 @@ public: bool isGLPerVertex = *typeName == "gl_PerVertex"; // Both being nullptr was caught above, now they both have to be structures of the same number of elements - if (!isStruct() || !right.isStruct() || - (structure->size() != right.structure->size() && !isGLPerVertex)) + if (lpidx == nullptr && + (structure->size() != right.structure->size() && !isGLPerVertex)) { return false; + } // Compare the names and types of all the members, which have to match for (size_t li = 0, ri = 0; li < structure->size() || ri < right.structure->size(); ++li, ++ri) { + if (lpidx != nullptr) { + *lpidx = static_cast(li); + *rpidx = static_cast(ri); + } if (li < structure->size() && ri < right.structure->size()) { if ((*structure)[li].type->getFieldName() == (*right.structure)[ri].type->getFieldName()) { if (*(*structure)[li].type != *(*right.structure)[ri].type) @@ -2495,11 +2627,19 @@ public: } // If we get here, then there should only be inconsistently declared members left } else if (li < structure->size()) { - if (!(*structure)[li].type->hiddenMember() && !isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) + if (!(*structure)[li].type->hiddenMember() && !isInconsistentGLPerVertexMember((*structure)[li].type->getFieldName())) { + if (lpidx != nullptr) { + *rpidx = -1; + } return false; + } } else { - if (!(*right.structure)[ri].type->hiddenMember() && !isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) + if (!(*right.structure)[ri].type->hiddenMember() && !isInconsistentGLPerVertexMember((*right.structure)[ri].type->getFieldName())) { + if (lpidx != nullptr) { + *lpidx = -1; + } return false; + } } } @@ -2523,17 +2663,25 @@ public: return *referentType == *right.referentType; } - // See if two types match, in all aspects except arrayness - bool sameElementType(const TType& right) const + // See if two types match, in all aspects except arrayness + // If mismatch in structure members, return member indices in lpidx and rpidx. + bool sameElementType(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const { - return basicType == right.basicType && sameElementShape(right); + if (lpidx != nullptr) { + *lpidx = -1; + *rpidx = -1; + } + return basicType == right.basicType && sameElementShape(right, lpidx, rpidx); } // See if two type's arrayness match bool sameArrayness(const TType& right) const { return ((arraySizes == nullptr && right.arraySizes == nullptr) || - (arraySizes != nullptr && right.arraySizes != nullptr && *arraySizes == *right.arraySizes)); + (arraySizes != nullptr && right.arraySizes != nullptr && + (*arraySizes == *right.arraySizes || + (arraySizes->isImplicitlySized() && right.arraySizes->isDefaultImplicitlySized()) || + (right.arraySizes->isImplicitlySized() && arraySizes->isDefaultImplicitlySized())))); } // See if two type's arrayness match in everything except their outer dimension @@ -2550,25 +2698,29 @@ public: (typeParameters != nullptr && right.typeParameters != nullptr && *typeParameters == *right.typeParameters)); } -#ifndef GLSLANG_WEB // See if two type's SPIR-V type contents match bool sameSpirvType(const TType& right) const { return ((spirvType == nullptr && right.spirvType == nullptr) || (spirvType != nullptr && right.spirvType != nullptr && *spirvType == *right.spirvType)); } -#endif // See if two type's elements match in all ways except basic type - bool sameElementShape(const TType& right) const + // If mismatch in structure members, return member indices in lpidx and rpidx. + bool sameElementShape(const TType& right, int* lpidx = nullptr, int* rpidx = nullptr) const { - return sampler == right.sampler && + if (lpidx != nullptr) { + *lpidx = -1; + *rpidx = -1; + } + return ((basicType != EbtSampler && right.basicType != EbtSampler) || sampler == right.sampler) && vectorSize == right.vectorSize && matrixCols == right.matrixCols && matrixRows == right.matrixRows && vector1 == right.vector1 && - isCoopMat() == right.isCoopMat() && - sameStructType(right) && + isCoopMatNV() == right.isCoopMatNV() && + isCoopMatKHR() == right.isCoopMatKHR() && + sameStructType(right, lpidx, rpidx) && sameReferenceType(right); } @@ -2576,32 +2728,70 @@ public: // an OK function parameter bool coopMatParameterOK(const TType& right) const { - return isCoopMat() && right.isCoopMat() && (getBasicType() == right.getBasicType()) && - typeParameters == nullptr && right.typeParameters != nullptr; + if (isCoopMatNV()) { + return right.isCoopMatNV() && (getBasicType() == right.getBasicType()) && typeParameters == nullptr && + right.typeParameters != nullptr; + } + if (isCoopMatKHR() && right.isCoopMatKHR()) { + return ((getBasicType() == right.getBasicType()) || (getBasicType() == EbtCoopmat) || + (right.getBasicType() == EbtCoopmat)) && + ((typeParameters == nullptr && right.typeParameters != nullptr) || + (typeParameters != nullptr && right.typeParameters == nullptr)); + } + return false; } bool sameCoopMatBaseType(const TType &right) const { - bool rv = coopmat && right.coopmat; - if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16) - rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16; - else if (getBasicType() == EbtUint || getBasicType() == EbtUint8) - rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8; - else if (getBasicType() == EbtInt || getBasicType() == EbtInt8) - rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8; - else - rv = false; + bool rv = false; + + if (isCoopMatNV()) { + rv = isCoopMatNV() && right.isCoopMatNV(); + if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16) + rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16; + else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16) + rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16; + else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16) + rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8 || right.getBasicType() == EbtInt16; + else + rv = false; + } else if (isCoopMatKHR() && right.isCoopMatKHR()) { + if (getBasicType() == EbtFloat || getBasicType() == EbtFloat16) + rv = right.getBasicType() == EbtFloat || right.getBasicType() == EbtFloat16 || right.getBasicType() == EbtCoopmat; + else if (getBasicType() == EbtUint || getBasicType() == EbtUint8 || getBasicType() == EbtUint16) + rv = right.getBasicType() == EbtUint || right.getBasicType() == EbtUint8 || right.getBasicType() == EbtUint16 || right.getBasicType() == EbtCoopmat; + else if (getBasicType() == EbtInt || getBasicType() == EbtInt8 || getBasicType() == EbtInt16) + rv = right.getBasicType() == EbtInt || right.getBasicType() == EbtInt8 || right.getBasicType() == EbtInt16 || right.getBasicType() == EbtCoopmat; + else + rv = false; + } return rv; } + bool sameCoopMatUse(const TType &right) const { + return coopmatKHRuse == right.coopmatKHRuse; + } + + bool sameCoopMatShapeAndUse(const TType &right) const + { + if (!isCoopMat() || !right.isCoopMat() || isCoopMatKHR() != right.isCoopMatKHR()) + return false; + + if (coopmatKHRuse != right.coopmatKHRuse) + return false; + + // Skip bit width type parameter (first array size) for coopmatNV + int firstArrayDimToCompare = isCoopMatNV() ? 1 : 0; + for (int i = firstArrayDimToCompare; i < typeParameters->arraySizes->getNumDims(); ++i) { + if (typeParameters->arraySizes->getDimSize(i) != right.typeParameters->arraySizes->getDimSize(i)) + return false; + } + return true; + } // See if two types match in all ways (just the actual type, not qualification) bool operator==(const TType& right) const { -#ifndef GLSLANG_WEB - return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right) && sameSpirvType(right); -#else - return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right); -#endif + return sameElementType(right) && sameArrayness(right) && sameTypeParameters(right) && sameCoopMatUse(right) && sameSpirvType(right); } bool operator!=(const TType& right) const @@ -2611,18 +2801,14 @@ public: unsigned int getBufferReferenceAlignment() const { -#ifndef GLSLANG_WEB if (getBasicType() == glslang::EbtReference) { return getReferentType()->getQualifier().hasBufferReferenceAlign() ? (1u << getReferentType()->getQualifier().layoutBufferReferenceAlign) : 16u; } -#endif return 0; } -#ifndef GLSLANG_WEB const TSpirvType& getSpirvType() const { assert(spirvType); return *spirvType; } -#endif protected: // Require consumer to pick between deep copy and shallow copy. @@ -2636,7 +2822,6 @@ protected: { shallowCopy(copyOf); -#ifndef GLSLANG_WEB // GL_EXT_spirv_intrinsics if (copyOf.qualifier.spirvDecorate) { qualifier.spirvDecorate = new TSpirvDecorate; @@ -2647,7 +2832,6 @@ protected: spirvType = new TSpirvType; *spirvType = *copyOf.spirvType; } -#endif if (copyOf.arraySizes) { arraySizes = new TArraySizes; @@ -2655,8 +2839,11 @@ protected: } if (copyOf.typeParameters) { - typeParameters = new TArraySizes; - *typeParameters = *copyOf.typeParameters; + typeParameters = new TTypeParameters; + typeParameters->arraySizes = new TArraySizes; + *typeParameters->arraySizes = *copyOf.typeParameters->arraySizes; + *typeParameters->spirvType = *copyOf.typeParameters->spirvType; + typeParameters->basicType = copyOf.basicType; } if (copyOf.isStruct() && copyOf.structure) { @@ -2686,15 +2873,18 @@ protected: void buildMangledName(TString&) const; TBasicType basicType : 8; - int vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate. - int matrixCols : 4; - int matrixRows : 4; + uint32_t vectorSize : 4; // 1 means either scalar or 1-component vector; see vector1 to disambiguate. + uint32_t matrixCols : 4; + uint32_t matrixRows : 4; bool vector1 : 1; // Backward-compatible tracking of a 1-component vector distinguished from a scalar. // GLSL 4.5 never has a 1-component vector; so this will always be false until such // functionality is added. // HLSL does have a 1-component vectors, so this will be true to disambiguate // from a scalar. - bool coopmat : 1; + bool coopmatNV : 1; + bool coopmatKHR : 1; + uint32_t coopmatKHRuse : 3; // Accepts one of three values: 0, 1, 2 (gl_MatrixUseA, gl_MatrixUseB, gl_MatrixUseAccumulator) + bool coopmatKHRUseValid : 1; // True if coopmatKHRuse has been set TQualifier qualifier; TArraySizes* arraySizes; // nullptr unless an array; can be shared across types @@ -2707,10 +2897,8 @@ protected: TString *fieldName; // for structure field names TString *typeName; // for structure type name TSampler sampler; - TArraySizes* typeParameters;// nullptr unless a parameterized type; can be shared across types -#ifndef GLSLANG_WEB + TTypeParameters *typeParameters;// nullptr unless a parameterized type; can be shared across types TSpirvType* spirvType; // SPIR-V type defined by spirv_type directive -#endif }; } // end namespace glslang diff --git a/src/libraries/glslang/glslang/Include/arrays.h b/src/libraries/glslang/glslang/Include/arrays.h index 7f047d9fb..91e190835 100644 --- a/src/libraries/glslang/glslang/Include/arrays.h +++ b/src/libraries/glslang/glslang/Include/arrays.h @@ -147,6 +147,15 @@ struct TSmallArrayVector { sizes->erase(sizes->begin()); } + void pop_back() + { + assert(sizes != nullptr && sizes->size() > 0); + if (sizes->size() == 1) + dealloc(); + else + sizes->resize(sizes->size() - 1); + } + // 'this' should currently not be holding anything, and copyNonFront // will make it hold a copy of all but the first element of rhs. // (This would be useful for making a type that is dereferenced by @@ -222,7 +231,7 @@ protected: struct TArraySizes { POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TArraySizes() : implicitArraySize(1), variablyIndexed(false) { } + TArraySizes() : implicitArraySize(0), implicitlySized(true), variablyIndexed(false){ } // For breaking into two non-shared copies, independently modifiable. TArraySizes& operator=(const TArraySizes& from) @@ -230,6 +239,7 @@ struct TArraySizes { implicitArraySize = from.implicitArraySize; variablyIndexed = from.variablyIndexed; sizes = from.sizes; + implicitlySized = from.implicitlySized; return *this; } @@ -256,11 +266,17 @@ struct TArraySizes { void addInnerSize(int s, TIntermTyped* n) { sizes.push_back((unsigned)s, n); } void addInnerSize(TArraySize pair) { sizes.push_back(pair.size, pair.node); + implicitlySized = false; } void addInnerSizes(const TArraySizes& s) { sizes.push_back(s.sizes); } - void changeOuterSize(int s) { sizes.changeFront((unsigned)s); } - int getImplicitSize() const { return implicitArraySize; } - void updateImplicitSize(int s) { implicitArraySize = std::max(implicitArraySize, s); } + void changeOuterSize(int s) { + sizes.changeFront((unsigned)s); + implicitlySized = false; + } + int getImplicitSize() const { return implicitArraySize > 0 ? implicitArraySize : 1; } + void updateImplicitSize(int s) { + implicitArraySize = (std::max)(implicitArraySize, s); + } bool isInnerUnsized() const { for (int d = 1; d < sizes.size(); ++d) { @@ -295,7 +311,11 @@ struct TArraySizes { bool hasUnsized() const { return getOuterSize() == UnsizedArraySize || isInnerUnsized(); } bool isSized() const { return getOuterSize() != UnsizedArraySize; } + bool isImplicitlySized() const { return implicitlySized; } + bool isDefaultImplicitlySized() const { return implicitlySized && implicitArraySize == 0; } + void setImplicitlySized(bool isImplicitSizing) { implicitlySized = isImplicitSizing; } void dereference() { sizes.pop_front(); } + void removeLastSize() { sizes.pop_back(); } void copyDereferenced(const TArraySizes& rhs) { assert(sizes.size() == 0); @@ -333,6 +353,7 @@ protected: // the implicit size of the array, if not variably indexed and // otherwise legal. int implicitArraySize; + bool implicitlySized; bool variablyIndexed; // true if array is indexed with a non compile-time constant }; diff --git a/src/libraries/glslang/glslang/Include/glslang_c_interface.h b/src/libraries/glslang/glslang/Include/glslang_c_interface.h deleted file mode 100644 index 14ab6acbc..000000000 --- a/src/libraries/glslang/glslang/Include/glslang_c_interface.h +++ /dev/null @@ -1,253 +0,0 @@ -/** - This code is based on the glslang_c_interface implementation by Viktor Latypov -**/ - -/** -BSD 2-Clause License - -Copyright (c) 2019, Viktor Latypov -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 GLSLANG_C_IFACE_H_INCLUDED -#define GLSLANG_C_IFACE_H_INCLUDED - -#include -#include - -#include "glslang_c_shader_types.h" - -typedef struct glslang_shader_s glslang_shader_t; -typedef struct glslang_program_s glslang_program_t; - -/* TLimits counterpart */ -typedef struct glslang_limits_s { - bool non_inductive_for_loops; - bool while_loops; - bool do_while_loops; - bool general_uniform_indexing; - bool general_attribute_matrix_vector_indexing; - bool general_varying_indexing; - bool general_sampler_indexing; - bool general_variable_indexing; - bool general_constant_matrix_vector_indexing; -} glslang_limits_t; - -/* TBuiltInResource counterpart */ -typedef struct glslang_resource_s { - int max_lights; - int max_clip_planes; - int max_texture_units; - int max_texture_coords; - int max_vertex_attribs; - int max_vertex_uniform_components; - int max_varying_floats; - int max_vertex_texture_image_units; - int max_combined_texture_image_units; - int max_texture_image_units; - int max_fragment_uniform_components; - int max_draw_buffers; - int max_vertex_uniform_vectors; - int max_varying_vectors; - int max_fragment_uniform_vectors; - int max_vertex_output_vectors; - int max_fragment_input_vectors; - int min_program_texel_offset; - int max_program_texel_offset; - int max_clip_distances; - int max_compute_work_group_count_x; - int max_compute_work_group_count_y; - int max_compute_work_group_count_z; - int max_compute_work_group_size_x; - int max_compute_work_group_size_y; - int max_compute_work_group_size_z; - int max_compute_uniform_components; - int max_compute_texture_image_units; - int max_compute_image_uniforms; - int max_compute_atomic_counters; - int max_compute_atomic_counter_buffers; - int max_varying_components; - int max_vertex_output_components; - int max_geometry_input_components; - int max_geometry_output_components; - int max_fragment_input_components; - int max_image_units; - int max_combined_image_units_and_fragment_outputs; - int max_combined_shader_output_resources; - int max_image_samples; - int max_vertex_image_uniforms; - int max_tess_control_image_uniforms; - int max_tess_evaluation_image_uniforms; - int max_geometry_image_uniforms; - int max_fragment_image_uniforms; - int max_combined_image_uniforms; - int max_geometry_texture_image_units; - int max_geometry_output_vertices; - int max_geometry_total_output_components; - int max_geometry_uniform_components; - int max_geometry_varying_components; - int max_tess_control_input_components; - int max_tess_control_output_components; - int max_tess_control_texture_image_units; - int max_tess_control_uniform_components; - int max_tess_control_total_output_components; - int max_tess_evaluation_input_components; - int max_tess_evaluation_output_components; - int max_tess_evaluation_texture_image_units; - int max_tess_evaluation_uniform_components; - int max_tess_patch_components; - int max_patch_vertices; - int max_tess_gen_level; - int max_viewports; - int max_vertex_atomic_counters; - int max_tess_control_atomic_counters; - int max_tess_evaluation_atomic_counters; - int max_geometry_atomic_counters; - int max_fragment_atomic_counters; - int max_combined_atomic_counters; - int max_atomic_counter_bindings; - int max_vertex_atomic_counter_buffers; - int max_tess_control_atomic_counter_buffers; - int max_tess_evaluation_atomic_counter_buffers; - int max_geometry_atomic_counter_buffers; - int max_fragment_atomic_counter_buffers; - int max_combined_atomic_counter_buffers; - int max_atomic_counter_buffer_size; - int max_transform_feedback_buffers; - int max_transform_feedback_interleaved_components; - int max_cull_distances; - int max_combined_clip_and_cull_distances; - int max_samples; - int max_mesh_output_vertices_nv; - int max_mesh_output_primitives_nv; - int max_mesh_work_group_size_x_nv; - int max_mesh_work_group_size_y_nv; - int max_mesh_work_group_size_z_nv; - int max_task_work_group_size_x_nv; - int max_task_work_group_size_y_nv; - int max_task_work_group_size_z_nv; - int max_mesh_view_count_nv; - int maxDualSourceDrawBuffersEXT; - - glslang_limits_t limits; -} glslang_resource_t; - -typedef struct glslang_input_s { - glslang_source_t language; - glslang_stage_t stage; - glslang_client_t client; - glslang_target_client_version_t client_version; - glslang_target_language_t target_language; - glslang_target_language_version_t target_language_version; - /** Shader source code */ - const char* code; - int default_version; - glslang_profile_t default_profile; - int force_default_version_and_profile; - int forward_compatible; - glslang_messages_t messages; - const glslang_resource_t* resource; -} glslang_input_t; - -/* Inclusion result structure allocated by C include_local/include_system callbacks */ -typedef struct glsl_include_result_s { - /* Header file name or NULL if inclusion failed */ - const char* header_name; - - /* Header contents or NULL */ - const char* header_data; - size_t header_length; - -} glsl_include_result_t; - -/* Callback for local file inclusion */ -typedef glsl_include_result_t* (*glsl_include_local_func)(void* ctx, const char* header_name, const char* includer_name, - size_t include_depth); - -/* Callback for system file inclusion */ -typedef glsl_include_result_t* (*glsl_include_system_func)(void* ctx, const char* header_name, - const char* includer_name, size_t include_depth); - -/* Callback for include result destruction */ -typedef int (*glsl_free_include_result_func)(void* ctx, glsl_include_result_t* result); - -/* Collection of callbacks for GLSL preprocessor */ -typedef struct glsl_include_callbacks_s { - glsl_include_system_func include_system; - glsl_include_local_func include_local; - glsl_free_include_result_func free_include_result; -} glsl_include_callbacks_t; - -#ifdef __cplusplus -extern "C" { -#endif - -#ifdef GLSLANG_IS_SHARED_LIBRARY - #ifdef _WIN32 - #ifdef GLSLANG_EXPORTING - #define GLSLANG_EXPORT __declspec(dllexport) - #else - #define GLSLANG_EXPORT __declspec(dllimport) - #endif - #elif __GNUC__ >= 4 - #define GLSLANG_EXPORT __attribute__((visibility("default"))) - #endif -#endif // GLSLANG_IS_SHARED_LIBRARY - -#ifndef GLSLANG_EXPORT -#define GLSLANG_EXPORT -#endif - -GLSLANG_EXPORT int glslang_initialize_process(); -GLSLANG_EXPORT void glslang_finalize_process(); - -GLSLANG_EXPORT glslang_shader_t* glslang_shader_create(const glslang_input_t* input); -GLSLANG_EXPORT void glslang_shader_delete(glslang_shader_t* shader); -GLSLANG_EXPORT void glslang_shader_shift_binding(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base); -GLSLANG_EXPORT void glslang_shader_shift_binding_for_set(glslang_shader_t* shader, glslang_resource_type_t res, unsigned int base, unsigned int set); -GLSLANG_EXPORT void glslang_shader_set_options(glslang_shader_t* shader, int options); // glslang_shader_options_t -GLSLANG_EXPORT int glslang_shader_preprocess(glslang_shader_t* shader, const glslang_input_t* input); -GLSLANG_EXPORT int glslang_shader_parse(glslang_shader_t* shader, const glslang_input_t* input); -GLSLANG_EXPORT const char* glslang_shader_get_preprocessed_code(glslang_shader_t* shader); -GLSLANG_EXPORT const char* glslang_shader_get_info_log(glslang_shader_t* shader); -GLSLANG_EXPORT const char* glslang_shader_get_info_debug_log(glslang_shader_t* shader); - -GLSLANG_EXPORT glslang_program_t* glslang_program_create(); -GLSLANG_EXPORT void glslang_program_delete(glslang_program_t* program); -GLSLANG_EXPORT void glslang_program_add_shader(glslang_program_t* program, glslang_shader_t* shader); -GLSLANG_EXPORT int glslang_program_link(glslang_program_t* program, int messages); // glslang_messages_t -GLSLANG_EXPORT int glslang_program_map_io(glslang_program_t* program); -GLSLANG_EXPORT void glslang_program_SPIRV_generate(glslang_program_t* program, glslang_stage_t stage); -GLSLANG_EXPORT size_t glslang_program_SPIRV_get_size(glslang_program_t* program); -GLSLANG_EXPORT void glslang_program_SPIRV_get(glslang_program_t* program, unsigned int*); -GLSLANG_EXPORT unsigned int* glslang_program_SPIRV_get_ptr(glslang_program_t* program); -GLSLANG_EXPORT const char* glslang_program_SPIRV_get_messages(glslang_program_t* program); -GLSLANG_EXPORT const char* glslang_program_get_info_log(glslang_program_t* program); -GLSLANG_EXPORT const char* glslang_program_get_info_debug_log(glslang_program_t* program); - -#ifdef __cplusplus -} -#endif - -#endif /* #ifdef GLSLANG_C_IFACE_INCLUDED */ diff --git a/src/libraries/glslang/glslang/Include/glslang_c_shader_types.h b/src/libraries/glslang/glslang/Include/glslang_c_shader_types.h deleted file mode 100644 index fc8028065..000000000 --- a/src/libraries/glslang/glslang/Include/glslang_c_shader_types.h +++ /dev/null @@ -1,207 +0,0 @@ -/** - This code is based on the glslang_c_interface implementation by Viktor Latypov -**/ - -/** -BSD 2-Clause License - -Copyright (c) 2019, Viktor Latypov -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 C_SHADER_TYPES_H_INCLUDED -#define C_SHADER_TYPES_H_INCLUDED - -#define LAST_ELEMENT_MARKER(x) x - -/* EShLanguage counterpart */ -typedef enum { - GLSLANG_STAGE_VERTEX, - GLSLANG_STAGE_TESSCONTROL, - GLSLANG_STAGE_TESSEVALUATION, - GLSLANG_STAGE_GEOMETRY, - GLSLANG_STAGE_FRAGMENT, - GLSLANG_STAGE_COMPUTE, - GLSLANG_STAGE_RAYGEN_NV, - GLSLANG_STAGE_INTERSECT_NV, - GLSLANG_STAGE_ANYHIT_NV, - GLSLANG_STAGE_CLOSESTHIT_NV, - GLSLANG_STAGE_MISS_NV, - GLSLANG_STAGE_CALLABLE_NV, - GLSLANG_STAGE_TASK_NV, - GLSLANG_STAGE_MESH_NV, - LAST_ELEMENT_MARKER(GLSLANG_STAGE_COUNT), -} glslang_stage_t; // would be better as stage, but this is ancient now - -/* EShLanguageMask counterpart */ -typedef enum { - GLSLANG_STAGE_VERTEX_MASK = (1 << GLSLANG_STAGE_VERTEX), - GLSLANG_STAGE_TESSCONTROL_MASK = (1 << GLSLANG_STAGE_TESSCONTROL), - GLSLANG_STAGE_TESSEVALUATION_MASK = (1 << GLSLANG_STAGE_TESSEVALUATION), - GLSLANG_STAGE_GEOMETRY_MASK = (1 << GLSLANG_STAGE_GEOMETRY), - GLSLANG_STAGE_FRAGMENT_MASK = (1 << GLSLANG_STAGE_FRAGMENT), - GLSLANG_STAGE_COMPUTE_MASK = (1 << GLSLANG_STAGE_COMPUTE), - GLSLANG_STAGE_RAYGEN_NV_MASK = (1 << GLSLANG_STAGE_RAYGEN_NV), - GLSLANG_STAGE_INTERSECT_NV_MASK = (1 << GLSLANG_STAGE_INTERSECT_NV), - GLSLANG_STAGE_ANYHIT_NV_MASK = (1 << GLSLANG_STAGE_ANYHIT_NV), - GLSLANG_STAGE_CLOSESTHIT_NV_MASK = (1 << GLSLANG_STAGE_CLOSESTHIT_NV), - GLSLANG_STAGE_MISS_NV_MASK = (1 << GLSLANG_STAGE_MISS_NV), - GLSLANG_STAGE_CALLABLE_NV_MASK = (1 << GLSLANG_STAGE_CALLABLE_NV), - GLSLANG_STAGE_TASK_NV_MASK = (1 << GLSLANG_STAGE_TASK_NV), - GLSLANG_STAGE_MESH_NV_MASK = (1 << GLSLANG_STAGE_MESH_NV), - LAST_ELEMENT_MARKER(GLSLANG_STAGE_MASK_COUNT), -} glslang_stage_mask_t; - -/* EShSource counterpart */ -typedef enum { - GLSLANG_SOURCE_NONE, - GLSLANG_SOURCE_GLSL, - GLSLANG_SOURCE_HLSL, - LAST_ELEMENT_MARKER(GLSLANG_SOURCE_COUNT), -} glslang_source_t; - -/* EShClient counterpart */ -typedef enum { - GLSLANG_CLIENT_NONE, - GLSLANG_CLIENT_VULKAN, - GLSLANG_CLIENT_OPENGL, - LAST_ELEMENT_MARKER(GLSLANG_CLIENT_COUNT), -} glslang_client_t; - -/* EShTargetLanguage counterpart */ -typedef enum { - GLSLANG_TARGET_NONE, - GLSLANG_TARGET_SPV, - LAST_ELEMENT_MARKER(GLSLANG_TARGET_COUNT), -} glslang_target_language_t; - -/* SH_TARGET_ClientVersion counterpart */ -typedef enum { - GLSLANG_TARGET_VULKAN_1_0 = (1 << 22), - GLSLANG_TARGET_VULKAN_1_1 = (1 << 22) | (1 << 12), - GLSLANG_TARGET_VULKAN_1_2 = (1 << 22) | (2 << 12), - GLSLANG_TARGET_OPENGL_450 = 450, - LAST_ELEMENT_MARKER(GLSLANG_TARGET_CLIENT_VERSION_COUNT = 4), -} glslang_target_client_version_t; - -/* SH_TARGET_LanguageVersion counterpart */ -typedef enum { - GLSLANG_TARGET_SPV_1_0 = (1 << 16), - GLSLANG_TARGET_SPV_1_1 = (1 << 16) | (1 << 8), - GLSLANG_TARGET_SPV_1_2 = (1 << 16) | (2 << 8), - GLSLANG_TARGET_SPV_1_3 = (1 << 16) | (3 << 8), - GLSLANG_TARGET_SPV_1_4 = (1 << 16) | (4 << 8), - GLSLANG_TARGET_SPV_1_5 = (1 << 16) | (5 << 8), - GLSLANG_TARGET_SPV_1_6 = (1 << 16) | (6 << 8), - LAST_ELEMENT_MARKER(GLSLANG_TARGET_LANGUAGE_VERSION_COUNT = 7), -} glslang_target_language_version_t; - -/* EShExecutable counterpart */ -typedef enum { GLSLANG_EX_VERTEX_FRAGMENT, GLSLANG_EX_FRAGMENT } glslang_executable_t; - -/* EShOptimizationLevel counterpart */ -typedef enum { - GLSLANG_OPT_NO_GENERATION, - GLSLANG_OPT_NONE, - GLSLANG_OPT_SIMPLE, - GLSLANG_OPT_FULL, - LAST_ELEMENT_MARKER(GLSLANG_OPT_LEVEL_COUNT), -} glslang_optimization_level_t; - -/* EShTextureSamplerTransformMode counterpart */ -typedef enum { - GLSLANG_TEX_SAMP_TRANS_KEEP, - GLSLANG_TEX_SAMP_TRANS_UPGRADE_TEXTURE_REMOVE_SAMPLER, - LAST_ELEMENT_MARKER(GLSLANG_TEX_SAMP_TRANS_COUNT), -} glslang_texture_sampler_transform_mode_t; - -/* EShMessages counterpart */ -typedef enum { - GLSLANG_MSG_DEFAULT_BIT = 0, - GLSLANG_MSG_RELAXED_ERRORS_BIT = (1 << 0), - GLSLANG_MSG_SUPPRESS_WARNINGS_BIT = (1 << 1), - GLSLANG_MSG_AST_BIT = (1 << 2), - GLSLANG_MSG_SPV_RULES_BIT = (1 << 3), - GLSLANG_MSG_VULKAN_RULES_BIT = (1 << 4), - GLSLANG_MSG_ONLY_PREPROCESSOR_BIT = (1 << 5), - GLSLANG_MSG_READ_HLSL_BIT = (1 << 6), - GLSLANG_MSG_CASCADING_ERRORS_BIT = (1 << 7), - GLSLANG_MSG_KEEP_UNCALLED_BIT = (1 << 8), - GLSLANG_MSG_HLSL_OFFSETS_BIT = (1 << 9), - GLSLANG_MSG_DEBUG_INFO_BIT = (1 << 10), - GLSLANG_MSG_HLSL_ENABLE_16BIT_TYPES_BIT = (1 << 11), - GLSLANG_MSG_HLSL_LEGALIZATION_BIT = (1 << 12), - GLSLANG_MSG_HLSL_DX9_COMPATIBLE_BIT = (1 << 13), - GLSLANG_MSG_BUILTIN_SYMBOL_TABLE_BIT = (1 << 14), - LAST_ELEMENT_MARKER(GLSLANG_MSG_COUNT), -} glslang_messages_t; - -/* EShReflectionOptions counterpart */ -typedef enum { - GLSLANG_REFLECTION_DEFAULT_BIT = 0, - GLSLANG_REFLECTION_STRICT_ARRAY_SUFFIX_BIT = (1 << 0), - GLSLANG_REFLECTION_BASIC_ARRAY_SUFFIX_BIT = (1 << 1), - GLSLANG_REFLECTION_INTERMEDIATE_IOO_BIT = (1 << 2), - GLSLANG_REFLECTION_SEPARATE_BUFFERS_BIT = (1 << 3), - GLSLANG_REFLECTION_ALL_BLOCK_VARIABLES_BIT = (1 << 4), - GLSLANG_REFLECTION_UNWRAP_IO_BLOCKS_BIT = (1 << 5), - GLSLANG_REFLECTION_ALL_IO_VARIABLES_BIT = (1 << 6), - GLSLANG_REFLECTION_SHARED_STD140_SSBO_BIT = (1 << 7), - GLSLANG_REFLECTION_SHARED_STD140_UBO_BIT = (1 << 8), - LAST_ELEMENT_MARKER(GLSLANG_REFLECTION_COUNT), -} glslang_reflection_options_t; - -/* EProfile counterpart (from Versions.h) */ -typedef enum { - GLSLANG_BAD_PROFILE = 0, - GLSLANG_NO_PROFILE = (1 << 0), - GLSLANG_CORE_PROFILE = (1 << 1), - GLSLANG_COMPATIBILITY_PROFILE = (1 << 2), - GLSLANG_ES_PROFILE = (1 << 3), - LAST_ELEMENT_MARKER(GLSLANG_PROFILE_COUNT), -} glslang_profile_t; - -/* Shader options */ -typedef enum { - GLSLANG_SHADER_DEFAULT_BIT = 0, - GLSLANG_SHADER_AUTO_MAP_BINDINGS = (1 << 0), - GLSLANG_SHADER_AUTO_MAP_LOCATIONS = (1 << 1), - GLSLANG_SHADER_VULKAN_RULES_RELAXED = (1 << 2), - LAST_ELEMENT_MARKER(GLSLANG_SHADER_COUNT), -} glslang_shader_options_t; - -/* TResourceType counterpart */ -typedef enum { - GLSLANG_RESOURCE_TYPE_SAMPLER, - GLSLANG_RESOURCE_TYPE_TEXTURE, - GLSLANG_RESOURCE_TYPE_IMAGE, - GLSLANG_RESOURCE_TYPE_UBO, - GLSLANG_RESOURCE_TYPE_SSBO, - GLSLANG_RESOURCE_TYPE_UAV, - LAST_ELEMENT_MARKER(GLSLANG_RESOURCE_TYPE_COUNT), -} glslang_resource_type_t; - -#undef LAST_ELEMENT_MARKER - -#endif diff --git a/src/libraries/glslang/glslang/Include/intermediate.h b/src/libraries/glslang/glslang/Include/intermediate.h index 595bd623d..bcce91d3a 100644 --- a/src/libraries/glslang/glslang/Include/intermediate.h +++ b/src/libraries/glslang/glslang/Include/intermediate.h @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. @@ -48,14 +48,9 @@ #ifndef __INTERMEDIATE_H #define __INTERMEDIATE_H -#if defined(_MSC_VER) && _MSC_VER >= 1900 - #pragma warning(disable : 4464) // relative include path contains '..' - #pragma warning(disable : 5026) // 'glslang::TIntermUnary': move constructor was implicitly defined as deleted -#endif - -#include "../Include/Common.h" -#include "../Include/Types.h" -#include "../Include/ConstantUnion.h" +#include "Common.h" +#include "Types.h" +#include "ConstantUnion.h" namespace glslang { @@ -67,13 +62,12 @@ class TIntermediate; enum TOperator { EOpNull, // if in a node, should only mean a node is still being built EOpSequence, // denotes a list of statements, or parameters, etc. + EOpScope, // Used by debugging to denote a scoped list of statements EOpLinkerObjects, // for aggregate node of objects the linker may need, if not reference by the rest of the AST EOpFunctionCall, EOpFunction, // For function definition EOpParameters, // an aggregate listing the parameters to a function -#ifndef GLSLANG_WEB EOpSpirvInst, -#endif // // Unary operators @@ -91,6 +85,8 @@ enum TOperator { EOpCopyObject, + EOpDeclare, // Used by debugging to force declaration of variable in correct scope + // (u)int* -> bool EOpConvInt8ToBool, EOpConvUint8ToBool, @@ -510,6 +506,8 @@ enum TOperator { EOpSubgroupShuffleXor, EOpSubgroupShuffleUp, EOpSubgroupShuffleDown, + EOpSubgroupRotate, + EOpSubgroupClusteredRotate, EOpSubgroupAdd, EOpSubgroupMul, EOpSubgroupMin, @@ -542,6 +540,8 @@ enum TOperator { EOpSubgroupQuadSwapHorizontal, EOpSubgroupQuadSwapVertical, EOpSubgroupQuadSwapDiagonal, + EOpSubgroupQuadAll, + EOpSubgroupQuadAny, EOpSubgroupPartition, EOpSubgroupPartitionedAdd, @@ -626,6 +626,9 @@ enum TOperator { EOpCooperativeMatrixLoad, EOpCooperativeMatrixStore, EOpCooperativeMatrixMulAdd, + EOpCooperativeMatrixLoadNV, + EOpCooperativeMatrixStoreNV, + EOpCooperativeMatrixMulAddNV, EOpBeginInvocationInterlock, // Fragment only EOpEndInvocationInterlock, // Fragment only @@ -763,7 +766,8 @@ enum TOperator { EOpConstructTextureSampler, EOpConstructNonuniform, // expected to be transformed away, not present in final AST EOpConstructReference, - EOpConstructCooperativeMatrix, + EOpConstructCooperativeMatrixNV, + EOpConstructCooperativeMatrixKHR, EOpConstructAccStruct, EOpConstructGuardEnd, @@ -824,6 +828,7 @@ enum TOperator { EOpSubpassLoadMS, EOpSparseImageLoad, EOpSparseImageLoadLod, + EOpColorAttachmentReadEXT, // Fragment only EOpImageGuardEnd, @@ -934,6 +939,8 @@ enum TOperator { EOpExecuteCallableNV, EOpExecuteCallableKHR, EOpWritePackedPrimitiveIndices4x8NV, + EOpEmitMeshTasksEXT, + EOpSetMeshOutputsEXT, // // GL_EXT_ray_query operations @@ -963,7 +970,44 @@ enum TOperator { EOpRayQueryGetIntersectionObjectToWorld, EOpRayQueryGetIntersectionWorldToObject, + // + // GL_NV_shader_invocation_reorder // + + EOpHitObjectTraceRayNV, + EOpHitObjectTraceRayMotionNV, + EOpHitObjectRecordHitNV, + EOpHitObjectRecordHitMotionNV, + EOpHitObjectRecordHitWithIndexNV, + EOpHitObjectRecordHitWithIndexMotionNV, + EOpHitObjectRecordMissNV, + EOpHitObjectRecordMissMotionNV, + EOpHitObjectRecordEmptyNV, + EOpHitObjectExecuteShaderNV, + EOpHitObjectIsEmptyNV, + EOpHitObjectIsMissNV, + EOpHitObjectIsHitNV, + EOpHitObjectGetRayTMinNV, + EOpHitObjectGetRayTMaxNV, + EOpHitObjectGetObjectRayOriginNV, + EOpHitObjectGetObjectRayDirectionNV, + EOpHitObjectGetWorldRayOriginNV, + EOpHitObjectGetWorldRayDirectionNV, + EOpHitObjectGetWorldToObjectNV, + EOpHitObjectGetObjectToWorldNV, + EOpHitObjectGetInstanceCustomIndexNV, + EOpHitObjectGetInstanceIdNV, + EOpHitObjectGetGeometryIndexNV, + EOpHitObjectGetPrimitiveIndexNV, + EOpHitObjectGetHitKindNV, + EOpHitObjectGetShaderBindingTableRecordIndexNV, + EOpHitObjectGetShaderRecordBufferHandleNV, + EOpHitObjectGetAttributesNV, + EOpHitObjectGetCurrentTimeNV, + EOpReorderThreadNV, + EOpFetchMicroTriangleVertexPositionNV, + EOpFetchMicroTriangleVertexBarycentricNV, + // HLSL operations // @@ -1047,9 +1091,37 @@ enum TOperator { EOpWaveActiveCountBits, // Will decompose to subgroupBallotBitCount(subgroupBallot()). EOpWavePrefixCountBits, // Will decompose to subgroupBallotInclusiveBitCount(subgroupBallot()). + // GL_EXT_expect_assume + EOpAssumeEXT, + EOpExpectEXT, + // Shader Clock Ops EOpReadClockSubgroupKHR, EOpReadClockDeviceKHR, + + // GL_EXT_ray_tracing_position_fetch + EOpRayQueryGetIntersectionTriangleVertexPositionsEXT, + + // Shader tile image ops + EOpStencilAttachmentReadEXT, // Fragment only + EOpDepthAttachmentReadEXT, // Fragment only + + // Image processing + EOpImageSampleWeightedQCOM, + EOpImageBoxFilterQCOM, + EOpImageBlockMatchSADQCOM, + EOpImageBlockMatchSSDQCOM, + + // Image processing2 + EOpImageBlockMatchWindowSSDQCOM, + EOpImageBlockMatchWindowSADQCOM, + EOpImageBlockMatchGatherSSDQCOM, + EOpImageBlockMatchGatherSADQCOM, +}; + +enum TLinkType { + ELinkNone, + ELinkExport, }; class TIntermTraverser; @@ -1081,31 +1153,31 @@ public: virtual const glslang::TSourceLoc& getLoc() const { return loc; } virtual void setLoc(const glslang::TSourceLoc& l) { loc = l; } virtual void traverse(glslang::TIntermTraverser*) = 0; - virtual glslang::TIntermTyped* getAsTyped() { return 0; } - virtual glslang::TIntermOperator* getAsOperator() { return 0; } - virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return 0; } - virtual glslang::TIntermAggregate* getAsAggregate() { return 0; } - virtual glslang::TIntermUnary* getAsUnaryNode() { return 0; } - virtual glslang::TIntermBinary* getAsBinaryNode() { return 0; } - virtual glslang::TIntermSelection* getAsSelectionNode() { return 0; } - virtual glslang::TIntermSwitch* getAsSwitchNode() { return 0; } - virtual glslang::TIntermMethod* getAsMethodNode() { return 0; } - virtual glslang::TIntermSymbol* getAsSymbolNode() { return 0; } - virtual glslang::TIntermBranch* getAsBranchNode() { return 0; } - virtual glslang::TIntermLoop* getAsLoopNode() { return 0; } + virtual glslang::TIntermTyped* getAsTyped() { return nullptr; } + virtual glslang::TIntermOperator* getAsOperator() { return nullptr; } + virtual glslang::TIntermConstantUnion* getAsConstantUnion() { return nullptr; } + virtual glslang::TIntermAggregate* getAsAggregate() { return nullptr; } + virtual glslang::TIntermUnary* getAsUnaryNode() { return nullptr; } + virtual glslang::TIntermBinary* getAsBinaryNode() { return nullptr; } + virtual glslang::TIntermSelection* getAsSelectionNode() { return nullptr; } + virtual glslang::TIntermSwitch* getAsSwitchNode() { return nullptr; } + virtual glslang::TIntermMethod* getAsMethodNode() { return nullptr; } + virtual glslang::TIntermSymbol* getAsSymbolNode() { return nullptr; } + virtual glslang::TIntermBranch* getAsBranchNode() { return nullptr; } + virtual glslang::TIntermLoop* getAsLoopNode() { return nullptr; } - virtual const glslang::TIntermTyped* getAsTyped() const { return 0; } - virtual const glslang::TIntermOperator* getAsOperator() const { return 0; } - virtual const glslang::TIntermConstantUnion* getAsConstantUnion() const { return 0; } - virtual const glslang::TIntermAggregate* getAsAggregate() const { return 0; } - virtual const glslang::TIntermUnary* getAsUnaryNode() const { return 0; } - virtual const glslang::TIntermBinary* getAsBinaryNode() const { return 0; } - virtual const glslang::TIntermSelection* getAsSelectionNode() const { return 0; } - virtual const glslang::TIntermSwitch* getAsSwitchNode() const { return 0; } - virtual const glslang::TIntermMethod* getAsMethodNode() const { return 0; } - virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return 0; } - virtual const glslang::TIntermBranch* getAsBranchNode() const { return 0; } - virtual const glslang::TIntermLoop* getAsLoopNode() const { return 0; } + virtual const glslang::TIntermTyped* getAsTyped() const { return nullptr; } + virtual const glslang::TIntermOperator* getAsOperator() const { return nullptr; } + virtual const glslang::TIntermConstantUnion* getAsConstantUnion() const { return nullptr; } + virtual const glslang::TIntermAggregate* getAsAggregate() const { return nullptr; } + virtual const glslang::TIntermUnary* getAsUnaryNode() const { return nullptr; } + virtual const glslang::TIntermBinary* getAsBinaryNode() const { return nullptr; } + virtual const glslang::TIntermSelection* getAsSelectionNode() const { return nullptr; } + virtual const glslang::TIntermSwitch* getAsSwitchNode() const { return nullptr; } + virtual const glslang::TIntermMethod* getAsMethodNode() const { return nullptr; } + virtual const glslang::TIntermSymbol* getAsSymbolNode() const { return nullptr; } + virtual const glslang::TIntermBranch* getAsBranchNode() const { return nullptr; } + virtual const glslang::TIntermLoop* getAsLoopNode() const { return nullptr; } virtual ~TIntermNode() { } protected: @@ -1155,7 +1227,7 @@ public: virtual bool isIntegerDomain() const { return type.isIntegerDomain(); } bool isAtomic() const { return type.isAtomic(); } bool isReference() const { return type.isReference(); } - TString getCompleteString() const { return type.getCompleteString(); } + TString getCompleteString(bool enhanced = false) const { return type.getCompleteString(enhanced); } protected: TIntermTyped& operator=(const TIntermTyped&); @@ -1269,9 +1341,11 @@ public: virtual const TString& getMethodName() const { return method; } virtual TIntermTyped* getObject() const { return object; } virtual void traverse(TIntermTraverser*); + void setExport() { linkType = ELinkExport; } protected: TIntermTyped* object; TString method; + TLinkType linkType; }; // @@ -1283,12 +1357,7 @@ public: // per process threadPoolAllocator, then it causes increased memory usage per compile // it is essential to use "symbol = sym" to assign to symbol TIntermSymbol(long long i, const TString& n, const TType& t) - : TIntermTyped(t), id(i), -#ifndef GLSLANG_WEB - flattenSubset(-1), -#endif - constSubtree(nullptr) - { name = n; } + : TIntermTyped(t), id(i), flattenSubset(-1), constSubtree(nullptr) { name = n; } virtual long long getId() const { return id; } virtual void changeId(long long i) { id = i; } virtual const TString& getName() const { return name; } @@ -1299,12 +1368,10 @@ public: const TConstUnionArray& getConstArray() const { return constArray; } void setConstSubtree(TIntermTyped* subtree) { constSubtree = subtree; } TIntermTyped* getConstSubtree() const { return constSubtree; } -#ifndef GLSLANG_WEB void setFlattenSubset(int subset) { flattenSubset = subset; } virtual const TString& getAccessName() const; int getFlattenSubset() const { return flattenSubset; } // -1 means full object -#endif // This is meant for cases where a node has already been constructed, and // later on, it becomes necessary to switch to a different symbol. @@ -1312,9 +1379,7 @@ public: protected: long long id; // the unique id of the symbol this node represents -#ifndef GLSLANG_WEB int flattenSubset; // how deeply the flattened object rooted at id has been dereferenced -#endif TString name; // the name of the symbol this node represents TConstUnionArray constArray; // if the symbol is a front-end compile-time constant, this is its value TIntermTyped* constSubtree; @@ -1353,6 +1418,7 @@ struct TCrackedTextureOp { bool subpass; bool lodClamp; bool fragMask; + bool attachmentEXT; }; // @@ -1368,19 +1434,11 @@ public: bool isConstructor() const; bool isTexture() const { return op > EOpTextureGuardBegin && op < EOpTextureGuardEnd; } bool isSampling() const { return op > EOpSamplingGuardBegin && op < EOpSamplingGuardEnd; } -#ifdef GLSLANG_WEB - bool isImage() const { return false; } - bool isSparseTexture() const { return false; } - bool isImageFootprint() const { return false; } - bool isSparseImage() const { return false; } - bool isSubgroup() const { return false; } -#else bool isImage() const { return op > EOpImageGuardBegin && op < EOpImageGuardEnd; } bool isSparseTexture() const { return op > EOpSparseTextureGuardBegin && op < EOpSparseTextureGuardEnd; } bool isImageFootprint() const { return op > EOpImageFootprintGuardBegin && op < EOpImageFootprintGuardEnd; } bool isSparseImage() const { return op == EOpSparseImageLoad; } bool isSubgroup() const { return op > EOpSubgroupGuardStart && op < EOpSubgroupGuardStop; } -#endif void setOperationPrecision(TPrecisionQualifier p) { operationPrecision = p; } TPrecisionQualifier getOperationPrecision() const { return operationPrecision != EpqNone ? @@ -1409,6 +1467,7 @@ public: cracked.gather = false; cracked.grad = false; cracked.subpass = false; + cracked.attachmentEXT = false; cracked.lodClamp = false; cracked.fragMask = false; @@ -1485,7 +1544,6 @@ public: cracked.offset = true; cracked.proj = true; break; -#ifndef GLSLANG_WEB case EOpTextureClamp: case EOpSparseTextureClamp: cracked.lodClamp = true; @@ -1569,7 +1627,9 @@ public: case EOpSubpassLoadMS: cracked.subpass = true; break; -#endif + case EOpColorAttachmentReadEXT: + cracked.attachmentEXT = true; + break; default: break; } @@ -1611,8 +1671,8 @@ protected: // class TIntermUnary : public TIntermOperator { public: - TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {} - TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {} + TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(nullptr) {} + TIntermUnary(TOperator o) : TIntermOperator(o), operand(nullptr) {} virtual void traverse(TIntermTraverser*); virtual void setOperand(TIntermTyped* o) { operand = o; } virtual TIntermTyped* getOperand() { return operand; } @@ -1620,15 +1680,11 @@ public: virtual TIntermUnary* getAsUnaryNode() { return this; } virtual const TIntermUnary* getAsUnaryNode() const { return this; } virtual void updatePrecision(); -#ifndef GLSLANG_WEB void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; } const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } -#endif protected: TIntermTyped* operand; -#ifndef GLSLANG_WEB TSpirvInstruction spirvInst; -#endif }; typedef TVector TIntermSequence; @@ -1660,10 +1716,11 @@ public: bool getDebug() const { return debug; } void setPragmaTable(const TPragmaTable& pTable); const TPragmaTable& getPragmaTable() const { return *pragmaTable; } -#ifndef GLSLANG_WEB void setSpirvInstruction(const TSpirvInstruction& inst) { spirvInst = inst; } const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } -#endif + + void setLinkType(TLinkType l) { linkType = l; } + TLinkType getLinkType() const { return linkType; } protected: TIntermAggregate(const TIntermAggregate&); // disallow copy constructor TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator @@ -1674,9 +1731,8 @@ protected: bool optimize; bool debug; TPragmaTable* pragmaTable; -#ifndef GLSLANG_WEB TSpirvInstruction spirvInst; -#endif + TLinkType linkType = ELinkNone; }; // @@ -1814,7 +1870,7 @@ public: TIntermNode *getParentNode() { - return path.size() == 0 ? NULL : path.back(); + return path.size() == 0 ? nullptr : path.back(); } const bool preVisit; diff --git a/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp b/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp index 5fc61dbb7..ac7fc8cd1 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Constant.cpp @@ -177,7 +177,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right newConstArray[i].setUConst(leftUnionArray[i].getUConst() / rightUnionArray[i].getUConst()); break; -#ifndef GLSLANG_WEB case EbtInt8: if (rightUnionArray[i] == (signed char)0) newConstArray[i].setI8Const((signed char)0x7F); @@ -212,9 +211,9 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right case EbtInt64: if (rightUnionArray[i] == 0ll) - newConstArray[i].setI64Const(0x7FFFFFFFFFFFFFFFll); - else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == (long long)-0x8000000000000000ll) - newConstArray[i].setI64Const((long long)-0x8000000000000000ll); + newConstArray[i].setI64Const(LLONG_MAX); + else if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == LLONG_MIN) + newConstArray[i].setI64Const(LLONG_MIN); else newConstArray[i].setI64Const(leftUnionArray[i].getI64Const() / rightUnionArray[i].getI64Const()); break; @@ -226,8 +225,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right newConstArray[i].setU64Const(leftUnionArray[i].getU64Const() / rightUnionArray[i].getU64Const()); break; default: - return 0; -#endif + return nullptr; } } break; @@ -266,7 +264,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right newConstArray[i].setIConst(0); break; } else goto modulo_default; -#ifndef GLSLANG_WEB case EbtInt64: if (rightUnionArray[i].getI64Const() == -1 && leftUnionArray[i].getI64Const() == LLONG_MIN) { newConstArray[i].setI64Const(0); @@ -277,7 +274,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right newConstArray[i].setIConst(0); break; } else goto modulo_default; -#endif default: modulo_default: newConstArray[i] = leftUnionArray[i] % rightUnionArray[i]; @@ -354,7 +350,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TIntermTyped* right break; default: - return 0; + return nullptr; } TIntermConstantUnion *newNode = new TIntermConstantUnion(newConstArray, returnType); @@ -507,14 +503,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) : -unionArray[i].getIConst()); break; case EbtUint: newConstArray[i].setUConst(static_cast(-static_cast(unionArray[i].getUConst()))); break; -#ifndef GLSLANG_WEB case EbtInt8: newConstArray[i].setI8Const(-unionArray[i].getI8Const()); break; case EbtUint8: newConstArray[i].setU8Const(static_cast(-static_cast(unionArray[i].getU8Const()))); break; case EbtInt16: newConstArray[i].setI16Const(-unionArray[i].getI16Const()); break; case EbtUint16:newConstArray[i].setU16Const(static_cast(-static_cast(unionArray[i].getU16Const()))); break; case EbtInt64: newConstArray[i].setI64Const(-unionArray[i].getI64Const()); break; case EbtUint64: newConstArray[i].setU64Const(static_cast(-static_cast(unionArray[i].getU64Const()))); break; -#endif default: return nullptr; } @@ -634,12 +628,12 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpIsNan: { - newConstArray[i].setBConst(IsNan(unionArray[i].getDConst())); + newConstArray[i].setBConst(std::isnan(unionArray[i].getDConst())); break; } case EOpIsInf: { - newConstArray[i].setBConst(IsInfinity(unionArray[i].getDConst())); + newConstArray[i].setBConst(std::isinf(unionArray[i].getDConst())); break; } @@ -684,7 +678,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpConvDoubleToInt: newConstArray[i].setIConst(static_cast(unionArray[i].getDConst())); break; -#ifndef GLSLANG_WEB case EOpConvInt8ToBool: newConstArray[i].setBConst(unionArray[i].getI8Const() != 0); break; case EOpConvUint8ToBool: @@ -696,7 +689,7 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpConvInt64ToBool: newConstArray[i].setBConst(unionArray[i].getI64Const() != 0); break; case EOpConvUint64ToBool: - newConstArray[i].setBConst(unionArray[i].getI64Const() != 0); break; + newConstArray[i].setBConst(unionArray[i].getU64Const() != 0); break; case EOpConvFloat16ToBool: newConstArray[i].setBConst(unionArray[i].getDConst() != 0); break; @@ -919,7 +912,6 @@ TIntermTyped* TIntermConstantUnion::fold(TOperator op, const TType& returnType) case EOpConvUint64ToPtr: case EOpConstructReference: newConstArray[i].setU64Const(unionArray[i].getU64Const()); break; -#endif // TODO: 3.0 Functionality: unary constant folding: the rest of the ops have to be fleshed out @@ -1066,7 +1058,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EbtUint: newConstArray[comp].setUConst(std::min(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; -#ifndef GLSLANG_WEB case EbtInt8: newConstArray[comp].setI8Const(std::min(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const())); break; @@ -1085,7 +1076,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EbtUint64: newConstArray[comp].setU64Const(std::min(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); break; -#endif default: assert(false && "Default missing"); } break; @@ -1102,7 +1092,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EbtUint: newConstArray[comp].setUConst(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst())); break; -#ifndef GLSLANG_WEB case EbtInt8: newConstArray[comp].setI8Const(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const())); break; @@ -1121,7 +1110,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) case EbtUint64: newConstArray[comp].setU64Const(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const())); break; -#endif default: assert(false && "Default missing"); } break; @@ -1137,7 +1125,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) newConstArray[comp].setUConst(std::min(std::max(childConstUnions[0][arg0comp].getUConst(), childConstUnions[1][arg1comp].getUConst()), childConstUnions[2][arg2comp].getUConst())); break; -#ifndef GLSLANG_WEB case EbtInt8: newConstArray[comp].setI8Const(std::min(std::max(childConstUnions[0][arg0comp].getI8Const(), childConstUnions[1][arg1comp].getI8Const()), childConstUnions[2][arg2comp].getI8Const())); @@ -1166,7 +1153,6 @@ TIntermTyped* TIntermediate::fold(TIntermAggregate* aggrNode) newConstArray[comp].setU64Const(std::min(std::max(childConstUnions[0][arg0comp].getU64Const(), childConstUnions[1][arg1comp].getU64Const()), childConstUnions[2][arg2comp].getU64Const())); break; -#endif default: assert(false && "Default missing"); } break; @@ -1345,7 +1331,7 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, cons { TType dereferencedType(node->getType(), index); dereferencedType.getQualifier().storage = EvqConst; - TIntermTyped* result = 0; + TIntermTyped* result = nullptr; int size = dereferencedType.computeNumComponents(); // arrays, vectors, matrices, all use simple multiplicative math @@ -1365,7 +1351,7 @@ TIntermTyped* TIntermediate::foldDereference(TIntermTyped* node, int index, cons result = addConstantUnion(TConstUnionArray(node->getAsConstantUnion()->getConstArray(), start, size), node->getType(), loc); - if (result == 0) + if (result == nullptr) result = node; else result->setType(dereferencedType); @@ -1387,7 +1373,7 @@ TIntermTyped* TIntermediate::foldSwizzle(TIntermTyped* node, TSwizzleSelectorsgetType(), loc); - if (result == 0) + if (result == nullptr) result = node; else result->setType(TType(node->getBasicType(), EvqConst, selectors.size())); diff --git a/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp b/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp old mode 100644 new mode 100755 index daf34d385..daaab38c3 --- a/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Initialize.cpp @@ -2,7 +2,7 @@ // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. // Copyright (C) 2015-2020 Google, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Modifications Copyright (C) 2020-2021 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. @@ -51,8 +51,9 @@ // including identifying what extensions are needed if a version does not allow a symbol // -#include "../Include/intermediate.h" +#include #include "Initialize.h" +#include "span.h" namespace glslang { @@ -61,10 +62,6 @@ const bool ARBCompatibility = false; const bool ForwardCompatibility = true; -// change this back to false if depending on textual spellings of texturing calls when consuming the AST -// Using PureOperatorBuiltins=false is deprecated. -bool PureOperatorBuiltins = true; - namespace { // @@ -144,29 +141,17 @@ struct Versioning { EProfile EDesktopProfile = static_cast(ENoProfile | ECoreProfile | ECompatibilityProfile); // Declare pointers to put into the table for versioning. -#ifdef GLSLANG_WEB - const Versioning* Es300Desktop130 = nullptr; - const Versioning* Es310Desktop420 = nullptr; -#elif defined(GLSLANG_ANGLE) - const Versioning* Es300Desktop130 = nullptr; - const Versioning* Es310Desktop420 = nullptr; - const Versioning* Es310Desktop450 = nullptr; -#else - const Versioning Es300Desktop130Version[] = { { EEsProfile, 0, 300, 0, nullptr }, - { EDesktopProfile, 0, 130, 0, nullptr }, - { EBadProfile } }; - const Versioning* Es300Desktop130 = &Es300Desktop130Version[0]; + const std::array Es300Desktop130Version = { Versioning{ EEsProfile, 0, 300, 0, nullptr }, + Versioning{ EDesktopProfile, 0, 130, 0, nullptr }, + }; - const Versioning Es310Desktop420Version[] = { { EEsProfile, 0, 310, 0, nullptr }, - { EDesktopProfile, 0, 420, 0, nullptr }, - { EBadProfile } }; - const Versioning* Es310Desktop420 = &Es310Desktop420Version[0]; + const std::array Es310Desktop400Version = { Versioning{ EEsProfile, 0, 310, 0, nullptr }, + Versioning{ EDesktopProfile, 0, 400, 0, nullptr }, + }; - const Versioning Es310Desktop450Version[] = { { EEsProfile, 0, 310, 0, nullptr }, - { EDesktopProfile, 0, 450, 0, nullptr }, - { EBadProfile } }; - const Versioning* Es310Desktop450 = &Es310Desktop450Version[0]; -#endif + const std::array Es310Desktop450Version = { Versioning{ EEsProfile, 0, 310, 0, nullptr }, + Versioning{ EDesktopProfile, 0, 450, 0, nullptr }, + }; // The main descriptor of what a set of function prototypes can look like, and // a pointer to extra versioning information, when needed. @@ -176,7 +161,7 @@ struct BuiltInFunction { int numArguments; // number of arguments (overloads with varying arguments need different entries) ArgType types; // ArgType mask ArgClass classes; // the ways this particular function entry manifests - const Versioning* versioning; // nullptr means always a valid version + const span versioning; // An empty span means always a valid version }; // The tables can have the same built-in function name more than one time, @@ -188,153 +173,146 @@ struct BuiltInFunction { // // Table is terminated by an OpNull TOperator. -const BuiltInFunction BaseFunctions[] = { +const std::array BaseFunctions = { // TOperator, name, arg-count, ArgType, ArgClass, versioning // --------- ---- --------- ------- -------- ---------- - { EOpRadians, "radians", 1, TypeF, ClassRegular, nullptr }, - { EOpDegrees, "degrees", 1, TypeF, ClassRegular, nullptr }, - { EOpSin, "sin", 1, TypeF, ClassRegular, nullptr }, - { EOpCos, "cos", 1, TypeF, ClassRegular, nullptr }, - { EOpTan, "tan", 1, TypeF, ClassRegular, nullptr }, - { EOpAsin, "asin", 1, TypeF, ClassRegular, nullptr }, - { EOpAcos, "acos", 1, TypeF, ClassRegular, nullptr }, - { EOpAtan, "atan", 2, TypeF, ClassRegular, nullptr }, - { EOpAtan, "atan", 1, TypeF, ClassRegular, nullptr }, - { EOpPow, "pow", 2, TypeF, ClassRegular, nullptr }, - { EOpExp, "exp", 1, TypeF, ClassRegular, nullptr }, - { EOpLog, "log", 1, TypeF, ClassRegular, nullptr }, - { EOpExp2, "exp2", 1, TypeF, ClassRegular, nullptr }, - { EOpLog2, "log2", 1, TypeF, ClassRegular, nullptr }, - { EOpSqrt, "sqrt", 1, TypeF, ClassRegular, nullptr }, - { EOpInverseSqrt, "inversesqrt", 1, TypeF, ClassRegular, nullptr }, - { EOpAbs, "abs", 1, TypeF, ClassRegular, nullptr }, - { EOpSign, "sign", 1, TypeF, ClassRegular, nullptr }, - { EOpFloor, "floor", 1, TypeF, ClassRegular, nullptr }, - { EOpCeil, "ceil", 1, TypeF, ClassRegular, nullptr }, - { EOpFract, "fract", 1, TypeF, ClassRegular, nullptr }, - { EOpMod, "mod", 2, TypeF, ClassLS, nullptr }, - { EOpMin, "min", 2, TypeF, ClassLS, nullptr }, - { EOpMax, "max", 2, TypeF, ClassLS, nullptr }, - { EOpClamp, "clamp", 3, TypeF, ClassLS2, nullptr }, - { EOpMix, "mix", 3, TypeF, ClassLS, nullptr }, - { EOpStep, "step", 2, TypeF, ClassFS, nullptr }, - { EOpSmoothStep, "smoothstep", 3, TypeF, ClassFS2, nullptr }, - { EOpNormalize, "normalize", 1, TypeF, ClassRegular, nullptr }, - { EOpFaceForward, "faceforward", 3, TypeF, ClassRegular, nullptr }, - { EOpReflect, "reflect", 2, TypeF, ClassRegular, nullptr }, - { EOpRefract, "refract", 3, TypeF, ClassXLS, nullptr }, - { EOpLength, "length", 1, TypeF, ClassRS, nullptr }, - { EOpDistance, "distance", 2, TypeF, ClassRS, nullptr }, - { EOpDot, "dot", 2, TypeF, ClassRS, nullptr }, - { EOpCross, "cross", 2, TypeF, ClassV3, nullptr }, - { EOpLessThan, "lessThan", 2, TypeFI, ClassBNS, nullptr }, - { EOpLessThanEqual, "lessThanEqual", 2, TypeFI, ClassBNS, nullptr }, - { EOpGreaterThan, "greaterThan", 2, TypeFI, ClassBNS, nullptr }, - { EOpGreaterThanEqual, "greaterThanEqual", 2, TypeFI, ClassBNS, nullptr }, - { EOpVectorEqual, "equal", 2, TypeFIB, ClassBNS, nullptr }, - { EOpVectorNotEqual, "notEqual", 2, TypeFIB, ClassBNS, nullptr }, - { EOpAny, "any", 1, TypeB, ClassRSNS, nullptr }, - { EOpAll, "all", 1, TypeB, ClassRSNS, nullptr }, - { EOpVectorLogicalNot, "not", 1, TypeB, ClassNS, nullptr }, - { EOpSinh, "sinh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpCosh, "cosh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpTanh, "tanh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpAsinh, "asinh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpAcosh, "acosh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpAtanh, "atanh", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpAbs, "abs", 1, TypeI, ClassRegular, Es300Desktop130 }, - { EOpSign, "sign", 1, TypeI, ClassRegular, Es300Desktop130 }, - { EOpTrunc, "trunc", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpRound, "round", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpRoundEven, "roundEven", 1, TypeF, ClassRegular, Es300Desktop130 }, - { EOpModf, "modf", 2, TypeF, ClassLO, Es300Desktop130 }, - { EOpMin, "min", 2, TypeIU, ClassLS, Es300Desktop130 }, - { EOpMax, "max", 2, TypeIU, ClassLS, Es300Desktop130 }, - { EOpClamp, "clamp", 3, TypeIU, ClassLS2, Es300Desktop130 }, - { EOpMix, "mix", 3, TypeF, ClassLB, Es300Desktop130 }, - { EOpIsInf, "isinf", 1, TypeF, ClassB, Es300Desktop130 }, - { EOpIsNan, "isnan", 1, TypeF, ClassB, Es300Desktop130 }, - { EOpLessThan, "lessThan", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpLessThanEqual, "lessThanEqual", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpGreaterThan, "greaterThan", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpGreaterThanEqual, "greaterThanEqual", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpVectorEqual, "equal", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpVectorNotEqual, "notEqual", 2, TypeU, ClassBNS, Es300Desktop130 }, - { EOpAtomicAdd, "atomicAdd", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicMin, "atomicMin", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicMax, "atomicMax", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicAnd, "atomicAnd", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicOr, "atomicOr", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicXor, "atomicXor", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicExchange, "atomicExchange", 2, TypeIU, ClassV1FIOCV, Es310Desktop420 }, - { EOpAtomicCompSwap, "atomicCompSwap", 3, TypeIU, ClassV1FIOCV, Es310Desktop420 }, -#ifndef GLSLANG_WEB - { EOpMix, "mix", 3, TypeB, ClassRegular, Es310Desktop450 }, - { EOpMix, "mix", 3, TypeIU, ClassLB, Es310Desktop450 }, -#endif - - { EOpNull } + BuiltInFunction{ EOpRadians, "radians", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpDegrees, "degrees", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpSin, "sin", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpCos, "cos", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpTan, "tan", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpAsin, "asin", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpAcos, "acos", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpAtan, "atan", 2, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpAtan, "atan", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpPow, "pow", 2, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpExp, "exp", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpLog, "log", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpExp2, "exp2", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpLog2, "log2", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpSqrt, "sqrt", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpInverseSqrt, "inversesqrt", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpAbs, "abs", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpSign, "sign", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpFloor, "floor", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpCeil, "ceil", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpFract, "fract", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpMod, "mod", 2, TypeF, ClassLS, {} }, + BuiltInFunction{ EOpMin, "min", 2, TypeF, ClassLS, {} }, + BuiltInFunction{ EOpMax, "max", 2, TypeF, ClassLS, {} }, + BuiltInFunction{ EOpClamp, "clamp", 3, TypeF, ClassLS2, {} }, + BuiltInFunction{ EOpMix, "mix", 3, TypeF, ClassLS, {} }, + BuiltInFunction{ EOpStep, "step", 2, TypeF, ClassFS, {} }, + BuiltInFunction{ EOpSmoothStep, "smoothstep", 3, TypeF, ClassFS2, {} }, + BuiltInFunction{ EOpNormalize, "normalize", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpFaceForward, "faceforward", 3, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpReflect, "reflect", 2, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpRefract, "refract", 3, TypeF, ClassXLS, {} }, + BuiltInFunction{ EOpLength, "length", 1, TypeF, ClassRS, {} }, + BuiltInFunction{ EOpDistance, "distance", 2, TypeF, ClassRS, {} }, + BuiltInFunction{ EOpDot, "dot", 2, TypeF, ClassRS, {} }, + BuiltInFunction{ EOpCross, "cross", 2, TypeF, ClassV3, {} }, + BuiltInFunction{ EOpLessThan, "lessThan", 2, TypeFI, ClassBNS, {} }, + BuiltInFunction{ EOpLessThanEqual, "lessThanEqual", 2, TypeFI, ClassBNS, {} }, + BuiltInFunction{ EOpGreaterThan, "greaterThan", 2, TypeFI, ClassBNS, {} }, + BuiltInFunction{ EOpGreaterThanEqual, "greaterThanEqual", 2, TypeFI, ClassBNS, {} }, + BuiltInFunction{ EOpVectorEqual, "equal", 2, TypeFIB, ClassBNS, {} }, + BuiltInFunction{ EOpVectorNotEqual, "notEqual", 2, TypeFIB, ClassBNS, {} }, + BuiltInFunction{ EOpAny, "any", 1, TypeB, ClassRSNS, {} }, + BuiltInFunction{ EOpAll, "all", 1, TypeB, ClassRSNS, {} }, + BuiltInFunction{ EOpVectorLogicalNot, "not", 1, TypeB, ClassNS, {} }, + BuiltInFunction{ EOpSinh, "sinh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpCosh, "cosh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpTanh, "tanh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpAsinh, "asinh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpAcosh, "acosh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpAtanh, "atanh", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpAbs, "abs", 1, TypeI, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpSign, "sign", 1, TypeI, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpTrunc, "trunc", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpRound, "round", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpRoundEven, "roundEven", 1, TypeF, ClassRegular, {Es300Desktop130Version} }, + BuiltInFunction{ EOpModf, "modf", 2, TypeF, ClassLO, {Es300Desktop130Version} }, + BuiltInFunction{ EOpMin, "min", 2, TypeIU, ClassLS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpMax, "max", 2, TypeIU, ClassLS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpClamp, "clamp", 3, TypeIU, ClassLS2, {Es300Desktop130Version} }, + BuiltInFunction{ EOpMix, "mix", 3, TypeF, ClassLB, {Es300Desktop130Version} }, + BuiltInFunction{ EOpIsInf, "isinf", 1, TypeF, ClassB, {Es300Desktop130Version} }, + BuiltInFunction{ EOpIsNan, "isnan", 1, TypeF, ClassB, {Es300Desktop130Version} }, + BuiltInFunction{ EOpLessThan, "lessThan", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpLessThanEqual, "lessThanEqual", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpGreaterThan, "greaterThan", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpGreaterThanEqual, "greaterThanEqual", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpVectorEqual, "equal", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpVectorNotEqual, "notEqual", 2, TypeU, ClassBNS, {Es300Desktop130Version} }, + BuiltInFunction{ EOpAtomicAdd, "atomicAdd", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicMin, "atomicMin", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicMax, "atomicMax", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicAnd, "atomicAnd", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicOr, "atomicOr", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicXor, "atomicXor", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicExchange, "atomicExchange", 2, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpAtomicCompSwap, "atomicCompSwap", 3, TypeIU, ClassV1FIOCV, {Es310Desktop400Version} }, + BuiltInFunction{ EOpMix, "mix", 3, TypeB, ClassRegular, {Es310Desktop450Version} }, + BuiltInFunction{ EOpMix, "mix", 3, TypeIU, ClassLB, {Es310Desktop450Version} }, }; -const BuiltInFunction DerivativeFunctions[] = { - { EOpDPdx, "dFdx", 1, TypeF, ClassRegular, nullptr }, - { EOpDPdy, "dFdy", 1, TypeF, ClassRegular, nullptr }, - { EOpFwidth, "fwidth", 1, TypeF, ClassRegular, nullptr }, - { EOpNull } +const std::array DerivativeFunctions = { + BuiltInFunction{ EOpDPdx, "dFdx", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpDPdy, "dFdy", 1, TypeF, ClassRegular, {} }, + BuiltInFunction{ EOpFwidth, "fwidth", 1, TypeF, ClassRegular, {} }, }; // For functions declared some other way, but still use the table to relate to operator. struct CustomFunction { TOperator op; // operator to map the name to const char* name; // function name - const Versioning* versioning; // nullptr means always a valid version + const span versioning; // An empty span means always a valid version }; const CustomFunction CustomFunctions[] = { - { EOpBarrier, "barrier", nullptr }, - { EOpMemoryBarrierShared, "memoryBarrierShared", nullptr }, - { EOpGroupMemoryBarrier, "groupMemoryBarrier", nullptr }, - { EOpMemoryBarrier, "memoryBarrier", nullptr }, - { EOpMemoryBarrierBuffer, "memoryBarrierBuffer", nullptr }, + { EOpBarrier, "barrier", {} }, + { EOpMemoryBarrierShared, "memoryBarrierShared", {} }, + { EOpGroupMemoryBarrier, "groupMemoryBarrier", {} }, + { EOpMemoryBarrier, "memoryBarrier", {} }, + { EOpMemoryBarrierBuffer, "memoryBarrierBuffer", {} }, - { EOpPackSnorm2x16, "packSnorm2x16", nullptr }, - { EOpUnpackSnorm2x16, "unpackSnorm2x16", nullptr }, - { EOpPackUnorm2x16, "packUnorm2x16", nullptr }, - { EOpUnpackUnorm2x16, "unpackUnorm2x16", nullptr }, - { EOpPackHalf2x16, "packHalf2x16", nullptr }, - { EOpUnpackHalf2x16, "unpackHalf2x16", nullptr }, + { EOpPackSnorm2x16, "packSnorm2x16", {} }, + { EOpUnpackSnorm2x16, "unpackSnorm2x16", {} }, + { EOpPackUnorm2x16, "packUnorm2x16", {} }, + { EOpUnpackUnorm2x16, "unpackUnorm2x16", {} }, + { EOpPackHalf2x16, "packHalf2x16", {} }, + { EOpUnpackHalf2x16, "unpackHalf2x16", {} }, - { EOpMul, "matrixCompMult", nullptr }, - { EOpOuterProduct, "outerProduct", nullptr }, - { EOpTranspose, "transpose", nullptr }, - { EOpDeterminant, "determinant", nullptr }, - { EOpMatrixInverse, "inverse", nullptr }, - { EOpFloatBitsToInt, "floatBitsToInt", nullptr }, - { EOpFloatBitsToUint, "floatBitsToUint", nullptr }, - { EOpIntBitsToFloat, "intBitsToFloat", nullptr }, - { EOpUintBitsToFloat, "uintBitsToFloat", nullptr }, + { EOpMul, "matrixCompMult", {} }, + { EOpOuterProduct, "outerProduct", {} }, + { EOpTranspose, "transpose", {} }, + { EOpDeterminant, "determinant", {} }, + { EOpMatrixInverse, "inverse", {} }, + { EOpFloatBitsToInt, "floatBitsToInt", {} }, + { EOpFloatBitsToUint, "floatBitsToUint", {} }, + { EOpIntBitsToFloat, "intBitsToFloat", {} }, + { EOpUintBitsToFloat, "uintBitsToFloat", {} }, - { EOpTextureQuerySize, "textureSize", nullptr }, - { EOpTextureQueryLod, "textureQueryLod", nullptr }, - { EOpTextureQueryLod, "textureQueryLOD", nullptr }, // extension GL_ARB_texture_query_lod - { EOpTextureQueryLevels, "textureQueryLevels", nullptr }, - { EOpTextureQuerySamples, "textureSamples", nullptr }, - { EOpTexture, "texture", nullptr }, - { EOpTextureProj, "textureProj", nullptr }, - { EOpTextureLod, "textureLod", nullptr }, - { EOpTextureOffset, "textureOffset", nullptr }, - { EOpTextureFetch, "texelFetch", nullptr }, - { EOpTextureFetchOffset, "texelFetchOffset", nullptr }, - { EOpTextureProjOffset, "textureProjOffset", nullptr }, - { EOpTextureLodOffset, "textureLodOffset", nullptr }, - { EOpTextureProjLod, "textureProjLod", nullptr }, - { EOpTextureProjLodOffset, "textureProjLodOffset", nullptr }, - { EOpTextureGrad, "textureGrad", nullptr }, - { EOpTextureGradOffset, "textureGradOffset", nullptr }, - { EOpTextureProjGrad, "textureProjGrad", nullptr }, - { EOpTextureProjGradOffset, "textureProjGradOffset", nullptr }, - - { EOpNull } + { EOpTextureQuerySize, "textureSize", {} }, + { EOpTextureQueryLod, "textureQueryLod", {} }, + { EOpTextureQueryLod, "textureQueryLOD", {} }, // extension GL_ARB_texture_query_lod + { EOpTextureQueryLevels, "textureQueryLevels", {} }, + { EOpTextureQuerySamples, "textureSamples", {} }, + { EOpTexture, "texture", {} }, + { EOpTextureProj, "textureProj", {} }, + { EOpTextureLod, "textureLod", {} }, + { EOpTextureOffset, "textureOffset", {} }, + { EOpTextureFetch, "texelFetch", {} }, + { EOpTextureFetchOffset, "texelFetchOffset", {} }, + { EOpTextureProjOffset, "textureProjOffset", {} }, + { EOpTextureLodOffset, "textureLodOffset", {} }, + { EOpTextureProjLod, "textureProjLod", {} }, + { EOpTextureProjLodOffset, "textureProjLodOffset", {} }, + { EOpTextureGrad, "textureGrad", {} }, + { EOpTextureGradOffset, "textureGradOffset", {} }, + { EOpTextureProjGrad, "textureProjGrad", {} }, + { EOpTextureProjGradOffset, "textureProjGradOffset", {} }, }; // For the given table of functions, add all the indicated prototypes for each @@ -390,10 +368,8 @@ void AddTabledBuiltin(TString& decls, const BuiltInFunction& function) if (arg == function.numArguments - 1 && (function.classes & ClassLO)) decls.append("out "); if (arg == 0) { -#ifndef GLSLANG_WEB if (function.classes & ClassCV) decls.append("coherent volatile "); -#endif if (function.classes & ClassFIO) decls.append("inout "); if (function.classes & ClassFO) @@ -420,19 +396,14 @@ void AddTabledBuiltin(TString& decls, const BuiltInFunction& function) // See if the tabled versioning information allows the current version. bool ValidVersion(const BuiltInFunction& function, int version, EProfile profile, const SpvVersion& /* spVersion */) { -#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) - // all entries in table are valid - return true; -#endif - // nullptr means always valid - if (function.versioning == nullptr) + if (function.versioning.empty()) return true; // check for what is said about our current profile - for (const Versioning* v = function.versioning; v->profiles != EBadProfile; ++v) { - if ((v->profiles & profile) != 0) { - if (v->minCoreVersion <= version || (v->numExtensions > 0 && v->minExtendedVersion <= version)) + for (const auto& v : function.versioning) { + if ((v.profiles & profile) != 0) { + if (v.minCoreVersion <= version || (v.numExtensions > 0 && v.minExtendedVersion <= version)) return true; } } @@ -445,12 +416,11 @@ bool ValidVersion(const BuiltInFunction& function, int version, EProfile profile // called once per stage). This is a performance issue only, not a correctness // concern. It is done for quality arising from simplicity, as there are subtleties // to get correct if instead trying to do it surgically. -template -void RelateTabledBuiltins(const FunctionT* functions, TSymbolTable& symbolTable) +template +void RelateTabledBuiltins(const FunctionContainer& functions, TSymbolTable& symbolTable) { - while (functions->op != EOpNull) { - symbolTable.relateToOperator(functions->name, functions->op); - ++functions; + for (const auto& fn : functions) { + symbolTable.relateToOperator(fn.name, fn.op); } } @@ -459,11 +429,10 @@ void RelateTabledBuiltins(const FunctionT* functions, TSymbolTable& symbolTable) // Add declarations for all tables of built-in functions. void TBuiltIns::addTabledBuiltins(int version, EProfile profile, const SpvVersion& spvVersion) { - const auto forEachFunction = [&](TString& decls, const BuiltInFunction* function) { - while (function->op != EOpNull) { - if (ValidVersion(*function, version, profile, spvVersion)) - AddTabledBuiltin(decls, *function); - ++function; + const auto forEachFunction = [&](TString& decls, const span& functions) { + for (const auto& fn : functions) { + if (ValidVersion(fn, version, profile, spvVersion)) + AddTabledBuiltin(decls, fn); } }; @@ -505,7 +474,6 @@ TBuiltIns::TBuiltIns() prefixes[EbtFloat] = ""; prefixes[EbtInt] = "i"; prefixes[EbtUint] = "u"; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) prefixes[EbtFloat16] = "f16"; prefixes[EbtInt8] = "i8"; prefixes[EbtUint8] = "u8"; @@ -513,7 +481,6 @@ TBuiltIns::TBuiltIns() prefixes[EbtUint16] = "u16"; prefixes[EbtInt64] = "i64"; prefixes[EbtUint64] = "u64"; -#endif postfixes[2] = "2"; postfixes[3] = "3"; @@ -523,14 +490,11 @@ TBuiltIns::TBuiltIns() dimMap[Esd2D] = 2; dimMap[Esd3D] = 3; dimMap[EsdCube] = 3; -#ifndef GLSLANG_WEB -#ifndef GLSLANG_ANGLE dimMap[Esd1D] = 1; -#endif dimMap[EsdRect] = 2; dimMap[EsdBuffer] = 1; dimMap[EsdSubpass] = 2; // potentially unused for now -#endif + dimMap[EsdAttachmentEXT] = 2; // potentially unused for now } TBuiltIns::~TBuiltIns() @@ -548,13 +512,6 @@ TBuiltIns::~TBuiltIns() // void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvVersion) { -#ifdef GLSLANG_WEB - version = 310; - profile = EEsProfile; -#elif defined(GLSLANG_ANGLE) - version = 450; - profile = ECoreProfile; -#endif addTabledBuiltins(version, profile, spvVersion); //============================================================================ @@ -563,7 +520,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // //============================================================================ -#ifndef GLSLANG_WEB // // Derivatives Functions. // @@ -599,7 +555,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 fwidthCoarse(vec4 p);" ); -#ifndef GLSLANG_ANGLE TString derivativesAndControl16bits ( "float16_t dFdx(float16_t);" "f16vec2 dFdx(f16vec2);" @@ -1393,7 +1348,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n" ); } -#endif // !GLSLANG_ANGLE if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 430)) { @@ -1431,7 +1385,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 440) { commonBuiltins.append( "uint64_t atomicMin(coherent volatile inout uint64_t, uint64_t);" @@ -1511,8 +1464,20 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void atomicStore(coherent volatile out double, double, int, int, int);" "\n"); } -#endif // !GLSLANG_ANGLE -#endif // !GLSLANG_WEB + + // NV_shader_atomic_fp16_vector + if (profile != EEsProfile && version >= 430) { + commonBuiltins.append( + "f16vec2 atomicAdd(coherent volatile inout f16vec2, f16vec2);" + "f16vec4 atomicAdd(coherent volatile inout f16vec4, f16vec4);" + "f16vec2 atomicMin(coherent volatile inout f16vec2, f16vec2);" + "f16vec4 atomicMin(coherent volatile inout f16vec4, f16vec4);" + "f16vec2 atomicMax(coherent volatile inout f16vec2, f16vec2);" + "f16vec4 atomicMax(coherent volatile inout f16vec4, f16vec4);" + "f16vec2 atomicExchange(coherent volatile inout f16vec2, f16vec2);" + "f16vec4 atomicExchange(coherent volatile inout f16vec4, f16vec4);" + "\n"); + } if ((profile == EEsProfile && version >= 300) || (profile != EEsProfile && version >= 150)) { // GL_ARB_shader_bit_encoding @@ -1540,7 +1505,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_WEB if ((profile != EEsProfile && version >= 400) || (profile == EEsProfile && version >= 310)) { // GL_OES_gpu_shader5 @@ -1552,7 +1516,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 150) { // ARB_gpu_shader_fp64 commonBuiltins.append( "double fma(double, double, double);" @@ -1570,7 +1533,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "f64vec4 fma(f64vec4, f64vec4, f64vec4 );" "\n"); } -#endif if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 400)) { @@ -1588,7 +1550,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 150) { // ARB_gpu_shader_fp64 commonBuiltins.append( "double frexp(double, out int);" @@ -1621,8 +1582,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#endif -#endif if ((profile == EEsProfile && version >= 300) || (profile != EEsProfile && version >= 150)) { @@ -1651,7 +1610,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_WEB if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 150)) { commonBuiltins.append( @@ -1671,7 +1629,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 unpackUnorm4x8(highp uint);" "\n"); } -#endif // // Matrix Functions. @@ -1730,8 +1687,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } } -#ifndef GLSLANG_WEB -#ifndef GLSLANG_ANGLE // // Original-style texture functions existing in all stages. // (Per-stage functions below.) @@ -1752,7 +1707,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 textureCube(samplerCube, vec3);" - "vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array + "vec4 texture2DArray(sampler2DArray, vec3);" // GL_EXT_texture_array + "vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array "\n"); } @@ -1782,7 +1738,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 texture1DArray(sampler1DArray, vec2);" // GL_EXT_texture_array "vec4 shadow1DArray(sampler1DArrayShadow, vec3);" // GL_EXT_texture_array "vec4 shadow2DArray(sampler2DArrayShadow, vec4);" // GL_EXT_texture_array - + "vec4 texture1DArray(sampler1DArray, vec2, float);" // GL_EXT_texture_array + "vec4 shadow1DArray(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array + "vec4 texture1DArrayLod(sampler1DArray, vec2, float);" // GL_EXT_texture_array + "vec4 texture2DArrayLod(sampler2DArray, vec3, float);" // GL_EXT_texture_array + "vec4 shadow1DArrayLod(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array "\n"); } } @@ -1932,7 +1892,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } } -#endif // !GLSLANG_ANGLE // Bitfield if ((profile == EEsProfile && version >= 310) || @@ -2075,7 +2034,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE // GL_ARB_shader_ballot if (profile != EEsProfile && version >= 450) { commonBuiltins.append( @@ -2156,6 +2114,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "%s subgroupShuffleXor(%s, uint);\n", "%s subgroupShuffleUp(%s, uint delta);\n", "%s subgroupShuffleDown(%s, uint delta);\n", + "%s subgroupRotate(%s, uint);\n", + "%s subgroupClusteredRotate(%s, uint, uint);\n", "%s subgroupAdd(%s);\n", "%s subgroupMul(%s);\n", "%s subgroupMin(%s);\n", @@ -2274,16 +2234,25 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n" ); - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "void subgroupMemoryBarrierShared();" "\n" ); - stageBuiltins[EShLangTaskNV].append( + stageBuiltins[EShLangTask].append( "void subgroupMemoryBarrierShared();" "\n" ); } + // GL_EXT_shader_quad_control + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + commonBuiltins.append( + "bool subgroupQuadAll(bool);\n" + "bool subgroupQuadAny(bool);\n" + ); + } + if (profile != EEsProfile && version >= 460) { commonBuiltins.append( "bool anyInvocation(bool);" @@ -3396,7 +3365,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bool textureFootprintGradClampNV(sampler2D, vec2, vec2, vec2, float, int, bool, out gl_TextureFootprint2DNV);" "\n"); } -#endif // !GLSLANG_ANGLE if ((profile == EEsProfile && version >= 300 && version < 310) || (profile != EEsProfile && version >= 150 && version < 450)) { // GL_EXT_shader_integer_mix @@ -3416,7 +3384,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE // GL_AMD_gpu_shader_half_float/Explicit types if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 310)) { commonBuiltins.append( @@ -4166,6 +4133,50 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "u16vec4 unpack16(uint64_t);" "i32vec2 unpack32(int64_t);" "u32vec2 unpack32(uint64_t);" + + // GL_EXT_expect_assume + "int8_t expectEXT(int8_t, int8_t);" + "i8vec2 expectEXT(i8vec2, i8vec2);" + "i8vec3 expectEXT(i8vec3, i8vec3);" + "i8vec4 expectEXT(i8vec4, i8vec4);" + + "uint8_t expectEXT(uint8_t, uint8_t);" + "u8vec2 expectEXT(u8vec2, u8vec2);" + "u8vec3 expectEXT(u8vec3, u8vec3);" + "u8vec4 expectEXT(u8vec4, u8vec4);" + + "int16_t expectEXT(int16_t, int16_t);" + "i16vec2 expectEXT(i16vec2, i16vec2);" + "i16vec3 expectEXT(i16vec3, i16vec3);" + "i16vec4 expectEXT(i16vec4, i16vec4);" + + "uint16_t expectEXT(uint16_t, uint16_t);" + "u16vec2 expectEXT(u16vec2, u16vec2);" + "u16vec3 expectEXT(u16vec3, u16vec3);" + "u16vec4 expectEXT(u16vec4, u16vec4);" + + "int64_t expectEXT(int64_t, int64_t);" + "i64vec2 expectEXT(i64vec2, i64vec2);" + "i64vec3 expectEXT(i64vec3, i64vec3);" + "i64vec4 expectEXT(i64vec4, i64vec4);" + + "uint64_t expectEXT(uint64_t, uint64_t);" + "u64vec2 expectEXT(u64vec2, u64vec2);" + "u64vec3 expectEXT(u64vec3, u64vec3);" + "u64vec4 expectEXT(u64vec4, u64vec4);" + "\n"); + } + + // Builtins for GL_EXT_texture_shadow_lod + if ((profile == EEsProfile && version >= 300) || ((profile != EEsProfile && version >= 130))) { + commonBuiltins.append( + "float texture(sampler2DArrayShadow, vec4, float);" + "float texture(samplerCubeArrayShadow, vec4, float, float);" + "float textureLod(sampler2DArrayShadow, vec4, float);" + "float textureLod(samplerCubeShadow, vec4, float);" + "float textureLod(samplerCubeArrayShadow, vec4, float, float);" + "float textureLodOffset(sampler2DArrayShadow, vec4, float, ivec2);" + "float textureOffset(sampler2DArrayShadow, vec4 , ivec2, float);" "\n"); } @@ -4190,7 +4201,46 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#endif // !GLSLANG_ANGLE + + // GL_EXT_expect_assume + if ((profile == EEsProfile && version >= 310) || + ((profile != EEsProfile && version >= 140))) { + commonBuiltins.append( + "void assumeEXT(bool);" + + "bool expectEXT(bool, bool);" + "bvec2 expectEXT(bvec2, bvec2);" + "bvec3 expectEXT(bvec3, bvec3);" + "bvec4 expectEXT(bvec4, bvec4);" + + "int expectEXT(int, int);" + "ivec2 expectEXT(ivec2, ivec2);" + "ivec3 expectEXT(ivec3, ivec3);" + "ivec4 expectEXT(ivec4, ivec4);" + + "uint expectEXT(uint, uint);" + "uvec2 expectEXT(uvec2, uvec2);" + "uvec3 expectEXT(uvec3, uvec3);" + "uvec4 expectEXT(uvec4, uvec4);" + "\n"); + } + + // QCOM_image_processing + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + commonBuiltins.append( + "vec4 textureWeightedQCOM(sampler2D, vec2, sampler2DArray);" + "vec4 textureWeightedQCOM(sampler2D, vec2, sampler1DArray);" + "vec4 textureBoxFilterQCOM(sampler2D, vec2, vec2);" + "vec4 textureBlockMatchSADQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + "vec4 textureBlockMatchSSDQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + + "vec4 textureBlockMatchWindowSSDQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + "vec4 textureBlockMatchWindowSADQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + "vec4 textureBlockMatchGatherSSDQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + "vec4 textureBlockMatchGatherSADQCOM(sampler2D, uvec2, sampler2D, uvec2, uvec2);" + "\n"); + } //============================================================================ // @@ -4206,7 +4256,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if (spvVersion.vulkan == 0 && IncludeLegacy(version, profile, spvVersion)) stageBuiltins[EShLangVertex].append("vec4 ftransform();"); -#ifndef GLSLANG_ANGLE // // Original-style texture Functions with lod. // @@ -4228,8 +4277,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 texture3DProjLod(sampler3D, vec4, float);" // GL_ARB_shader_texture_lod // OES_texture_3D, but caught by keyword check "vec4 textureCubeLod(samplerCube, vec3, float);" // GL_ARB_shader_texture_lod - "vec4 texture2DArrayLod(sampler2DArray, vec3, float);" // GL_EXT_texture_array - "\n"); } } @@ -4265,14 +4312,9 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 shadow2DRectGradARB( sampler2DRectShadow, vec3, vec2, vec2);" // GL_ARB_shader_texture_lod "vec4 shadow2DRectProjGradARB(sampler2DRectShadow, vec4, vec2, vec2);" // GL_ARB_shader_texture_lod - "vec4 texture1DArrayLod(sampler1DArray, vec2, float);" // GL_EXT_texture_array - "vec4 shadow1DArrayLod(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array - "vec4 shadow2DArrayLod(sampler2DArrayShadow, vec4, float);" // GL_EXT_texture_array - "\n"); } } -#endif // !GLSLANG_ANGLE if ((profile != EEsProfile && version >= 150) || (profile == EEsProfile && version >= 310)) { @@ -4282,7 +4324,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // //============================================================================ - if (profile != EEsProfile && version >= 400) { + if (profile != EEsProfile && (version >= 400 || version == 150)) { stageBuiltins[EShLangGeometry].append( "void EmitStreamVertex(int);" "void EndStreamPrimitive(int);" @@ -4293,7 +4335,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void EndPrimitive();" "\n"); } -#endif // !GLSLANG_WEB //============================================================================ // @@ -4310,10 +4351,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void barrier();" ); if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "void barrier();" ); - stageBuiltins[EShLangTaskNV].append( + stageBuiltins[EShLangTask].append( "void barrier();" ); } @@ -4330,7 +4371,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void groupMemoryBarrier();" ); } -#ifndef GLSLANG_WEB if ((profile != EEsProfile && version >= 420) || esBarrier) { if (spvVersion.vulkan == 0 || spvVersion.vulkanRelaxed) { commonBuiltins.append("void memoryBarrierAtomicCounter();"); @@ -4338,11 +4378,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append("void memoryBarrierImage();"); } if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "void memoryBarrierShared();" "void groupMemoryBarrier();" ); - stageBuiltins[EShLangTaskNV].append( + stageBuiltins[EShLangTask].append( "void memoryBarrierShared();" "void groupMemoryBarrier();" ); @@ -4353,7 +4393,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV commonBuiltins.append("void debugPrintfEXT();\n"); -#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 450) { // coopMatStoreNV perhaps ought to have "out" on the buf parameter, but // adding it introduces undesirable tempArgs on the stack. What we want @@ -4434,6 +4473,94 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "icoopmatNV coopMatMulAddNV(icoopmatNV A, icoopmatNV B, icoopmatNV C);\n" "ucoopmatNV coopMatMulAddNV(ucoopmatNV A, ucoopmatNV B, ucoopmatNV C);\n" ); + + std::string cooperativeMatrixFuncs = + "void coopMatLoad(out coopmat m, volatile coherent int8_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent int16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent int32_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent int64_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent uint8_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent uint16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent uint32_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent uint64_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent float16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent float[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent float64_t[] buf, uint element, uint stride, int matrixLayout);\n" + + "void coopMatLoad(out coopmat m, volatile coherent i8vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u8vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + + "void coopMatLoad(out coopmat m, volatile coherent i8vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent i64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u8vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent u64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatLoad(out coopmat m, volatile coherent f64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + + "void coopMatStore(coopmat m, volatile coherent int8_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent int16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent int32_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent int64_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent uint8_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent uint16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent uint32_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent uint64_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent float16_t[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent float[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent float64_t[] buf, uint element, uint stride, int matrixLayout);\n" + + "void coopMatStore(coopmat m, volatile coherent i8vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u8vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f16vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f32vec2[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f64vec2[] buf, uint element, uint stride, int matrixLayout);\n" + + "void coopMatStore(coopmat m, volatile coherent i8vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent i64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u8vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent u64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f16vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f32vec4[] buf, uint element, uint stride, int matrixLayout);\n" + "void coopMatStore(coopmat m, volatile coherent f64vec4[] buf, uint element, uint stride, int matrixLayout);\n" + + "coopmat coopMatMulAdd(coopmat A, coopmat B, coopmat C);\n" + "coopmat coopMatMulAdd(coopmat A, coopmat B, coopmat C, int matrixOperands);\n"; + + commonBuiltins.append(cooperativeMatrixFuncs.c_str()); + + commonBuiltins.append( + "const int gl_MatrixUseA = 0;\n" + "const int gl_MatrixUseB = 1;\n" + "const int gl_MatrixUseAccumulator = 2;\n" + "const int gl_MatrixOperandsSaturatingAccumulation = 0x10;\n" + "const int gl_CooperativeMatrixLayoutRowMajor = 0;\n" + "const int gl_CooperativeMatrixLayoutColumnMajor = 1;\n" + "\n" + ); } //============================================================================ @@ -4453,7 +4580,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 texture3D(sampler3D, vec3, float);" // OES_texture_3D "vec4 texture3DProj(sampler3D, vec4, float);" // OES_texture_3D "vec4 textureCube(samplerCube, vec3, float);" - "vec4 texture2DArray(sampler2DArray, vec3, float);" // GL_EXT_texture_array "\n"); } @@ -4466,9 +4592,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec4 shadow2D(sampler2DShadow, vec3, float);" "vec4 shadow1DProj(sampler1DShadow, vec4, float);" "vec4 shadow2DProj(sampler2DShadow, vec4, float);" - "vec4 texture1DArray(sampler1DArray, vec2, float);" // GL_EXT_texture_array - "vec4 shadow1DArray(sampler1DArrayShadow, vec3, float);" // GL_EXT_texture_array - "vec4 shadow2DArray(sampler2DArrayShadow, vec4, float);" // GL_EXT_texture_array + "\n"); } if (spvVersion.spv == 0 && profile == EEsProfile) { @@ -4480,7 +4604,24 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#endif // !GLSLANG_ANGLE + + // GL_EXT_shader_tile_image + if (spvVersion.vulkan > 0) { + stageBuiltins[EShLangFragment].append( + "lowp uint stencilAttachmentReadEXT();" + "lowp uint stencilAttachmentReadEXT(int);" + "highp float depthAttachmentReadEXT();" + "highp float depthAttachmentReadEXT(int);" + "\n"); + stageBuiltins[EShLangFragment].append( + "vec4 colorAttachmentReadEXT(attachmentEXT);" + "vec4 colorAttachmentReadEXT(attachmentEXT, int);" + "ivec4 colorAttachmentReadEXT(iattachmentEXT);" + "ivec4 colorAttachmentReadEXT(iattachmentEXT, int);" + "uvec4 colorAttachmentReadEXT(uattachmentEXT);" + "uvec4 colorAttachmentReadEXT(uattachmentEXT, int);" + "\n"); + } // GL_ARB_derivative_control if (profile != EEsProfile && version >= 400) { @@ -4518,7 +4659,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "bool helperInvocationEXT();" "\n"); -#ifndef GLSLANG_ANGLE // GL_AMD_shader_explicit_vertex_parameter if (profile != EEsProfile && version >= 450) { stageBuiltins[EShLangFragment].append( @@ -4591,9 +4731,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "uvec4 fragmentFetchAMD(usubpassInputMS, uint);" "\n"); - } + } - // Builtins for GL_NV_ray_tracing/GL_NV_ray_tracing_motion_blur/GL_EXT_ray_tracing/GL_EXT_ray_query + // Builtins for GL_NV_ray_tracing/GL_NV_ray_tracing_motion_blur/GL_EXT_ray_tracing/GL_EXT_ray_query/ + // GL_NV_shader_invocation_reorder/GL_KHR_ray_tracing_position_Fetch if (profile != EEsProfile && version >= 460) { commonBuiltins.append("void rayQueryInitializeEXT(rayQueryEXT, accelerationStructureEXT, uint, uint, vec3, float, vec3, float);" "void rayQueryTerminateEXT(rayQueryEXT);" @@ -4618,6 +4759,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "vec3 rayQueryGetIntersectionObjectRayOriginEXT(rayQueryEXT, bool);" "mat4x3 rayQueryGetIntersectionObjectToWorldEXT(rayQueryEXT, bool);" "mat4x3 rayQueryGetIntersectionWorldToObjectEXT(rayQueryEXT, bool);" + "void rayQueryGetIntersectionTriangleVertexPositionsEXT(rayQueryEXT, bool, out vec3[3]);" "\n"); stageBuiltins[EShLangRayGen].append( @@ -4626,6 +4768,41 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" "void executeCallableEXT(uint, int);" + "void hitObjectTraceRayNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectTraceRayMotionNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitMotionNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitWithIndexNV(hitObjectNV, accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitWithIndexMotionNV(hitObjectNV, accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordMissNV(hitObjectNV,uint,vec3,float,vec3,float);" + "void hitObjectRecordMissMotionNV(hitObjectNV,uint,vec3,float,vec3,float,float);" + "void hitObjectRecordEmptyNV(hitObjectNV);" + "void hitObjectExecuteShaderNV(hitObjectNV,int);" + "bool hitObjectIsEmptyNV(hitObjectNV);" + "bool hitObjectIsMissNV(hitObjectNV);" + "bool hitObjectIsHitNV(hitObjectNV);" + "float hitObjectGetRayTMinNV(hitObjectNV);" + "float hitObjectGetRayTMaxNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayDirectionNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayDirectionNV(hitObjectNV);" + "mat4x3 hitObjectGetWorldToObjectNV(hitObjectNV);" + "mat4x3 hitObjectGetObjectToWorldNV(hitObjectNV);" + "int hitObjectGetInstanceCustomIndexNV(hitObjectNV);" + "int hitObjectGetInstanceIdNV(hitObjectNV);" + "int hitObjectGetGeometryIndexNV(hitObjectNV);" + "int hitObjectGetPrimitiveIndexNV(hitObjectNV);" + "uint hitObjectGetHitKindNV(hitObjectNV);" + "void hitObjectGetAttributesNV(hitObjectNV,int);" + "float hitObjectGetCurrentTimeNV(hitObjectNV);" + "uint hitObjectGetShaderBindingTableRecordIndexNV(hitObjectNV);" + "uvec2 hitObjectGetShaderRecordBufferHandleNV(hitObjectNV);" + "void reorderThreadNV(uint, uint);" + "void reorderThreadNV(hitObjectNV);" + "void reorderThreadNV(hitObjectNV, uint, uint);" + "vec3 fetchMicroTriangleVertexPositionNV(accelerationStructureEXT, int, int, int, ivec2);" + "vec2 fetchMicroTriangleVertexBarycentricNV(accelerationStructureEXT, int, int, int, ivec2);" "\n"); stageBuiltins[EShLangIntersect].append( "bool reportIntersectionNV(float, uint);" @@ -4641,6 +4818,36 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" "void executeCallableEXT(uint, int);" + "void hitObjectTraceRayNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectTraceRayMotionNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitMotionNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitWithIndexNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitWithIndexMotionNV(hitObjectNV, accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordMissNV(hitObjectNV, uint, vec3, float, vec3, float);" + "void hitObjectRecordMissMotionNV(hitObjectNV,uint,vec3,float,vec3,float,float);" + "void hitObjectRecordEmptyNV(hitObjectNV);" + "void hitObjectExecuteShaderNV(hitObjectNV, int);" + "bool hitObjectIsEmptyNV(hitObjectNV);" + "bool hitObjectIsMissNV(hitObjectNV);" + "bool hitObjectIsHitNV(hitObjectNV);" + "float hitObjectGetRayTMinNV(hitObjectNV);" + "float hitObjectGetRayTMaxNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayDirectionNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayDirectionNV(hitObjectNV);" + "mat4x3 hitObjectGetWorldToObjectNV(hitObjectNV);" + "mat4x3 hitObjectGetObjectToWorldNV(hitObjectNV);" + "int hitObjectGetInstanceCustomIndexNV(hitObjectNV);" + "int hitObjectGetInstanceIdNV(hitObjectNV);" + "int hitObjectGetGeometryIndexNV(hitObjectNV);" + "int hitObjectGetPrimitiveIndexNV(hitObjectNV);" + "uint hitObjectGetHitKindNV(hitObjectNV);" + "void hitObjectGetAttributesNV(hitObjectNV,int);" + "float hitObjectGetCurrentTimeNV(hitObjectNV);" + "uint hitObjectGetShaderBindingTableRecordIndexNV(hitObjectNV);" + "uvec2 hitObjectGetShaderRecordBufferHandleNV(hitObjectNV);" "\n"); stageBuiltins[EShLangMiss].append( "void traceNV(accelerationStructureNV,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" @@ -4648,20 +4855,48 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "void traceRayEXT(accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" "void executeCallableNV(uint, int);" "void executeCallableEXT(uint, int);" + "void hitObjectTraceRayNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectTraceRayMotionNV(hitObjectNV,accelerationStructureEXT,uint,uint,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitMotionNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordHitWithIndexNV(hitObjectNV,accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,int);" + "void hitObjectRecordHitWithIndexMotionNV(hitObjectNV, accelerationStructureEXT,int,int,int,uint,uint,vec3,float,vec3,float,float,int);" + "void hitObjectRecordMissNV(hitObjectNV, uint, vec3, float, vec3, float);" + "void hitObjectRecordMissMotionNV(hitObjectNV,uint,vec3,float,vec3,float,float);" + "void hitObjectRecordEmptyNV(hitObjectNV);" + "void hitObjectExecuteShaderNV(hitObjectNV, int);" + "bool hitObjectIsEmptyNV(hitObjectNV);" + "bool hitObjectIsMissNV(hitObjectNV);" + "bool hitObjectIsHitNV(hitObjectNV);" + "float hitObjectGetRayTMinNV(hitObjectNV);" + "float hitObjectGetRayTMaxNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetWorldRayDirectionNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayOriginNV(hitObjectNV);" + "vec3 hitObjectGetObjectRayDirectionNV(hitObjectNV);" + "mat4x3 hitObjectGetWorldToObjectNV(hitObjectNV);" + "mat4x3 hitObjectGetObjectToWorldNV(hitObjectNV);" + "int hitObjectGetInstanceCustomIndexNV(hitObjectNV);" + "int hitObjectGetInstanceIdNV(hitObjectNV);" + "int hitObjectGetGeometryIndexNV(hitObjectNV);" + "int hitObjectGetPrimitiveIndexNV(hitObjectNV);" + "uint hitObjectGetHitKindNV(hitObjectNV);" + "void hitObjectGetAttributesNV(hitObjectNV,int);" + "float hitObjectGetCurrentTimeNV(hitObjectNV);" + "uint hitObjectGetShaderBindingTableRecordIndexNV(hitObjectNV);" + "uvec2 hitObjectGetShaderRecordBufferHandleNV(hitObjectNV);" "\n"); stageBuiltins[EShLangCallable].append( "void executeCallableNV(uint, int);" "void executeCallableEXT(uint, int);" "\n"); } -#endif // !GLSLANG_ANGLE //E_SPV_NV_compute_shader_derivatives if ((profile == EEsProfile && version >= 320) || (profile != EEsProfile && version >= 450)) { stageBuiltins[EShLangCompute].append(derivativeControls); stageBuiltins[EShLangCompute].append("\n"); } -#ifndef GLSLANG_ANGLE if (profile != EEsProfile && version >= 450) { stageBuiltins[EShLangCompute].append(derivativesAndControl16bits); stageBuiltins[EShLangCompute].append(derivativesAndControl64bits); @@ -4670,12 +4905,35 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV // Builtins for GL_NV_mesh_shader if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "void writePackedPrimitiveIndices4x8NV(uint, uint);" "\n"); } -#endif // !GLSLANG_ANGLE -#endif // !GLSLANG_WEB + // Builtins for GL_EXT_mesh_shader + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { + // Builtins for GL_EXT_mesh_shader + stageBuiltins[EShLangTask].append( + "void EmitMeshTasksEXT(uint, uint, uint);" + "\n"); + + stageBuiltins[EShLangMesh].append( + "void SetMeshOutputsEXT(uint, uint);" + "\n"); + } + // Builtins for GL_NV_displacement_micromap + if ((profile != EEsProfile && version >= 460) || (profile == EEsProfile && version >= 320)) { + stageBuiltins[EShLangMesh].append( + "vec3 fetchMicroTriangleVertexPositionNV(accelerationStructureEXT, int, int, int, ivec2);" + "vec2 fetchMicroTriangleVertexBarycentricNV(accelerationStructureEXT, int, int, int, ivec2);" + "\n"); + + stageBuiltins[EShLangCompute].append( + "vec3 fetchMicroTriangleVertexPositionNV(accelerationStructureEXT, int, int, int, ivec2);" + "vec2 fetchMicroTriangleVertexBarycentricNV(accelerationStructureEXT, int, int, int, ivec2);" + "\n"); + + } + //============================================================================ // @@ -4697,13 +4955,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "highp float diff;" // f - n ); } else { -#ifndef GLSLANG_WEB commonBuiltins.append( "float near;" // n "float far;" // f "float diff;" // f - n ); -#endif } commonBuiltins.append( @@ -4712,7 +4968,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (spvVersion.spv == 0 && IncludeLegacy(version, profile, spvVersion)) { // // Matrix state. p. 31, 32, 37, 39, 40. @@ -4830,7 +5085,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE //============================================================================ // @@ -4860,8 +5114,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_WEB -#ifndef GLSLANG_ANGLE //============================================================================ // // Define the interface to the mesh/task shader. @@ -4870,7 +5122,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { // per-vertex attributes - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "out gl_MeshPerVertexNV {" "vec4 gl_Position;" "float gl_PointSize;" @@ -4883,7 +5135,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV ); // per-primitive attributes - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "perprimitiveNV out gl_MeshPerPrimitiveNV {" "int gl_PrimitiveID;" "int gl_Layer;" @@ -4894,7 +5146,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "} gl_MeshPrimitivesNV[];" ); - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "out uint gl_PrimitiveCountNV;" "out uint gl_PrimitiveIndicesNV[];" @@ -4908,10 +5160,38 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp uvec3 gl_GlobalInvocationID;" "in highp uint gl_LocalInvocationIndex;" - "\n"); - stageBuiltins[EShLangTaskNV].append( + // GL_EXT_mesh_shader + stageBuiltins[EShLangMesh].append( + "out uint gl_PrimitivePointIndicesEXT[];" + "out uvec2 gl_PrimitiveLineIndicesEXT[];" + "out uvec3 gl_PrimitiveTriangleIndicesEXT[];" + "in highp uvec3 gl_NumWorkGroups;" + "\n"); + + // per-vertex attributes + stageBuiltins[EShLangMesh].append( + "out gl_MeshPerVertexEXT {" + "vec4 gl_Position;" + "float gl_PointSize;" + "float gl_ClipDistance[];" + "float gl_CullDistance[];" + "} gl_MeshVerticesEXT[];" + ); + + // per-primitive attributes + stageBuiltins[EShLangMesh].append( + "perprimitiveEXT out gl_MeshPerPrimitiveEXT {" + "int gl_PrimitiveID;" + "int gl_Layer;" + "int gl_ViewportIndex;" + "bool gl_CullPrimitiveEXT;" + "int gl_PrimitiveShadingRateEXT;" + "} gl_MeshPrimitivesEXT[];" + ); + + stageBuiltins[EShLangTask].append( "out uint gl_TaskCountNV;" "const highp uvec3 gl_WorkGroupSize = uvec3(1,1,1);" @@ -4924,32 +5204,32 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in uint gl_MeshViewCountNV;" "in uint gl_MeshViewIndicesNV[4];" - + "in highp uvec3 gl_NumWorkGroups;" "\n"); } if (profile != EEsProfile && version >= 450) { - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "in highp int gl_DeviceIndex;" // GL_EXT_device_group "in int gl_DrawIDARB;" // GL_ARB_shader_draw_parameters + "in int gl_ViewIndex;" // GL_EXT_multiview "\n"); - stageBuiltins[EShLangTaskNV].append( + stageBuiltins[EShLangTask].append( "in highp int gl_DeviceIndex;" // GL_EXT_device_group "in int gl_DrawIDARB;" // GL_ARB_shader_draw_parameters "\n"); if (version >= 460) { - stageBuiltins[EShLangMeshNV].append( + stageBuiltins[EShLangMesh].append( "in int gl_DrawID;" "\n"); - stageBuiltins[EShLangTaskNV].append( + stageBuiltins[EShLangTask].append( "in int gl_DrawID;" "\n"); } } -#endif // !GLSLANG_ANGLE //============================================================================ // @@ -5053,7 +5333,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangVertex].append( "int gl_VertexID;" // needs qualifier fixed later ); - if (version >= 140 && spvVersion.vulkan == 0) + if (spvVersion.vulkan == 0) stageBuiltins[EShLangVertex].append( "int gl_InstanceID;" // needs qualifier fixed later ); @@ -5108,6 +5388,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangVertex].append( "highp vec4 gl_Position;" // needs qualifier fixed later "mediump float gl_PointSize;" // needs qualifier fixed later + "highp int gl_InstanceID;" // needs qualifier fixed later ); } else { if (spvVersion.vulkan == 0 || spvVersion.vulkanRelaxed) @@ -5116,19 +5397,15 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp int gl_InstanceID;" // needs qualifier fixed later ); if (spvVersion.vulkan > 0) -#endif stageBuiltins[EShLangVertex].append( "in highp int gl_VertexIndex;" "in highp int gl_InstanceIndex;" ); -#ifndef GLSLANG_WEB if (version < 310) -#endif stageBuiltins[EShLangVertex].append( "highp vec4 gl_Position;" // needs qualifier fixed later "highp float gl_PointSize;" // needs qualifier fixed later ); -#ifndef GLSLANG_WEB else stageBuiltins[EShLangVertex].append( "out gl_PerVertex {" @@ -5586,6 +5863,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "flat in int gl_InvocationsPerPixelNV;" "in vec3 gl_BaryCoordNV;" // GL_NV_fragment_shader_barycentric "in vec3 gl_BaryCoordNoPerspNV;" + "in vec3 gl_BaryCoordEXT;" // GL_EXT_fragment_shader_barycentric + "in vec3 gl_BaryCoordNoPerspEXT;" ); if (version >= 450) @@ -5604,7 +5883,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "mediump vec2 gl_PointCoord;" // needs qualifier fixed later ); } -#endif if (version >= 300) { stageBuiltins[EShLangFragment].append( "highp vec4 gl_FragCoord;" // needs qualifier fixed later @@ -5613,7 +5891,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "highp float gl_FragDepth;" // needs qualifier fixed later ); } -#ifndef GLSLANG_WEB if (version >= 310) { stageBuiltins[EShLangFragment].append( "bool gl_HelperInvocation;" // needs qualifier fixed later @@ -5650,21 +5927,20 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangFragment].append( "in vec3 gl_BaryCoordNV;" "in vec3 gl_BaryCoordNoPerspNV;" - ); + "in vec3 gl_BaryCoordEXT;" + "in vec3 gl_BaryCoordNoPerspEXT;" + ); if (version >= 310) stageBuiltins[EShLangFragment].append( "flat in highp int gl_ShadingRateEXT;" // GL_EXT_fragment_shading_rate ); } -#endif stageBuiltins[EShLangFragment].append("\n"); if (version >= 130) add2ndGenerationSamplingImaging(version, profile, spvVersion); -#ifndef GLSLANG_WEB - if ((profile != EEsProfile && version >= 140) || (profile == EEsProfile && version >= 310)) { stageBuiltins[EShLangFragment].append( @@ -5679,7 +5955,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "\n"); } -#ifndef GLSLANG_ANGLE // GL_ARB_shader_ballot if (profile != EEsProfile && version >= 450) { const char* ballotDecls = @@ -5715,8 +5990,8 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangGeometry] .append(ballotDecls); stageBuiltins[EShLangCompute] .append(ballotDecls); stageBuiltins[EShLangFragment] .append(fragmentBallotDecls); - stageBuiltins[EShLangMeshNV] .append(ballotDecls); - stageBuiltins[EShLangTaskNV] .append(ballotDecls); + stageBuiltins[EShLangMesh] .append(ballotDecls); + stageBuiltins[EShLangTask] .append(ballotDecls); stageBuiltins[EShLangRayGen] .append(rtBallotDecls); stageBuiltins[EShLangIntersect] .append(rtBallotDecls); // No volatile qualifier on these builtins in any-hit @@ -5742,6 +6017,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp uint gl_SMCountNV;" "in highp uint gl_WarpIDNV;" "in highp uint gl_SMIDNV;" + // GL_ARM_shader_core_builtins + "in highp uint gl_CoreIDARM;" + "in highp uint gl_CoreCountARM;" + "in highp uint gl_CoreMaxIDARM;" + "in highp uint gl_WarpIDARM;" + "in highp uint gl_WarpMaxIDARM;" "\n"; const char* fragmentSubgroupDecls = "flat in mediump uint gl_SubgroupSize;" @@ -5756,6 +6037,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "flat in highp uint gl_SMCountNV;" "flat in highp uint gl_WarpIDNV;" "flat in highp uint gl_SMIDNV;" + // GL_ARM_shader_core_builtins + "flat in highp uint gl_CoreIDARM;" + "flat in highp uint gl_CoreCountARM;" + "flat in highp uint gl_CoreMaxIDARM;" + "flat in highp uint gl_WarpIDARM;" + "flat in highp uint gl_WarpMaxIDARM;" "\n"; const char* computeSubgroupDecls = "in highp uint gl_NumSubgroups;" @@ -5775,6 +6062,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in highp uint gl_SMCountNV;" "in highp volatile uint gl_WarpIDNV;" "in highp volatile uint gl_SMIDNV;" + // GL_ARM_shader_core_builtins + "in highp uint gl_CoreIDARM;" + "in highp uint gl_CoreCountARM;" + "in highp uint gl_CoreMaxIDARM;" + "in highp uint gl_WarpIDARM;" + "in highp uint gl_WarpMaxIDARM;" "\n"; stageBuiltins[EShLangVertex] .append(subgroupDecls); @@ -5784,10 +6077,10 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV stageBuiltins[EShLangCompute] .append(subgroupDecls); stageBuiltins[EShLangCompute] .append(computeSubgroupDecls); stageBuiltins[EShLangFragment] .append(fragmentSubgroupDecls); - stageBuiltins[EShLangMeshNV] .append(subgroupDecls); - stageBuiltins[EShLangMeshNV] .append(computeSubgroupDecls); - stageBuiltins[EShLangTaskNV] .append(subgroupDecls); - stageBuiltins[EShLangTaskNV] .append(computeSubgroupDecls); + stageBuiltins[EShLangMesh] .append(subgroupDecls); + stageBuiltins[EShLangMesh] .append(computeSubgroupDecls); + stageBuiltins[EShLangTask] .append(subgroupDecls); + stageBuiltins[EShLangTask] .append(computeSubgroupDecls); stageBuiltins[EShLangRayGen] .append(rtSubgroupDecls); stageBuiltins[EShLangIntersect] .append(rtSubgroupDecls); // No volatile qualifier on these builtins in any-hit @@ -5821,8 +6114,11 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "const uint gl_RayFlagsCullNoOpaqueEXT = 128U;" "const uint gl_RayFlagsSkipTrianglesEXT = 256U;" "const uint gl_RayFlagsSkipAABBEXT = 512U;" + "const uint gl_RayFlagsForceOpacityMicromap2StateEXT = 1024U;" "const uint gl_HitKindFrontFacingTriangleEXT = 254U;" "const uint gl_HitKindBackFacingTriangleEXT = 255U;" + "in uint gl_HitKindFrontFacingMicroTriangleNV;" + "in uint gl_HitKindBackFacingMicroTriangleNV;" "\n"; const char *constRayQueryIntersection = @@ -5872,6 +6168,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in uint gl_IncomingRayFlagsNV;" "in uint gl_IncomingRayFlagsEXT;" "in float gl_CurrentRayTimeNV;" + "in uint gl_CullMaskEXT;" "\n"; const char *hitDecls = "in uvec3 gl_LaunchIDNV;" @@ -5908,7 +6205,12 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in uint gl_IncomingRayFlagsNV;" "in uint gl_IncomingRayFlagsEXT;" "in float gl_CurrentRayTimeNV;" + "in uint gl_CullMaskEXT;" + "in vec3 gl_HitTriangleVertexPositionsEXT[3];" + "in vec3 gl_HitMicroTriangleVertexPositionsNV[3];" + "in vec2 gl_HitMicroTriangleVertexBarycentricsNV[3];" "\n"; + const char *missDecls = "in uvec3 gl_LaunchIDNV;" "in uvec3 gl_LaunchIDEXT;" @@ -5927,6 +6229,7 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV "in uint gl_IncomingRayFlagsNV;" "in uint gl_IncomingRayFlagsEXT;" "in float gl_CurrentRayTimeNV;" + "in uint gl_CullMaskEXT;" "\n"; const char *callableDecls = @@ -6034,9 +6337,6 @@ void TBuiltIns::initialize(int version, EProfile profile, const SpvVersion& spvV } } } -#endif // !GLSLANG_ANGLE - -#endif // !GLSLANG_WEB // printf("%s\n", commonBuiltins.c_str()); // printf("%s\n", stageBuiltins[EShLangFragment].c_str()); @@ -6055,30 +6355,18 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c // enumerate all the types const TBasicType bTypes[] = { EbtFloat, EbtInt, EbtUint, -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - EbtFloat16 -#endif + EbtFloat16 }; -#ifdef GLSLANG_WEB - bool skipBuffer = true; - bool skipCubeArrayed = true; - const int image = 0; -#else bool skipBuffer = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 140); bool skipCubeArrayed = (profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 130); for (int image = 0; image <= 1; ++image) // loop over "bool" image vs sampler -#endif { for (int shadow = 0; shadow <= 1; ++shadow) { // loop over "bool" shadow or not -#ifdef GLSLANG_WEB - const int ms = 0; -#else for (int ms = 0; ms <= 1; ++ms) // loop over "bool" multisample or not -#endif { if ((ms || image) && shadow) continue; - if (ms && profile != EEsProfile && version < 150) + if (ms && profile != EEsProfile && version < 140) continue; if (ms && image && profile == EEsProfile) continue; @@ -6086,14 +6374,9 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c continue; for (int arrayed = 0; arrayed <= 1; ++arrayed) { // loop over "bool" arrayed or not -#ifdef GLSLANG_WEB - for (int dim = Esd2D; dim <= EsdCube; ++dim) { // 2D, 3D, and Cube -#else -#if defined(GLSLANG_ANGLE) - for (int dim = Esd2D; dim < EsdNumDims; ++dim) { // 2D, ..., buffer, subpass -#else for (int dim = Esd1D; dim < EsdNumDims; ++dim) { // 1D, ..., buffer, subpass -#endif + if (dim == EsdAttachmentEXT) + continue; if (dim == EsdSubpass && spvVersion.vulkan == 0) continue; if (dim == EsdSubpass && (image || shadow || arrayed)) @@ -6114,7 +6397,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c continue; if (ms && arrayed && profile == EEsProfile && version < 310) continue; -#endif if (dim == Esd3D && shadow) continue; if (dim == EsdCube && arrayed && skipCubeArrayed) @@ -6124,23 +6406,21 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c // Loop over the bTypes for (size_t bType = 0; bType < sizeof(bTypes)/sizeof(TBasicType); ++bType) { -#ifndef GLSLANG_WEB if (bTypes[bType] == EbtFloat16 && (profile == EEsProfile || version < 450)) continue; if (dim == EsdRect && version < 140 && bType > 0) continue; -#endif if (shadow && (bTypes[bType] == EbtInt || bTypes[bType] == EbtUint)) continue; // // Now, make all the function prototypes for the type we just built... // TSampler sampler; -#ifndef GLSLANG_WEB if (dim == EsdSubpass) { sampler.setSubpass(bTypes[bType], ms ? true : false); + } else if (dim == EsdAttachmentEXT) { + sampler.setAttachmentEXT(bTypes[bType]); } else -#endif if (image) { sampler.setImage(bTypes[bType], (TSamplerDim)dim, arrayed ? true : false, shadow ? true : false, @@ -6153,12 +6433,10 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c TString typeName = sampler.getString(); -#ifndef GLSLANG_WEB if (dim == EsdSubpass) { addSubpassSampling(sampler, typeName, version, profile); continue; } -#endif addQueryFunctions(sampler, typeName, version, profile); @@ -6166,7 +6444,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c addImageFunctions(sampler, typeName, version, profile); else { addSamplingFunctions(sampler, typeName, version, profile); -#ifndef GLSLANG_WEB addGatherFunctions(sampler, typeName, version, profile); if (spvVersion.vulkan > 0 && sampler.isCombined() && !sampler.shadow) { // Base Vulkan allows texelFetch() for @@ -6182,7 +6459,6 @@ void TBuiltIns::add2ndGenerationSamplingImaging(int version, EProfile profile, c addSamplingFunctions(sampler, textureTypeName, version, profile); addQueryFunctions(sampler, textureTypeName, version, profile); } -#endif } } } @@ -6213,16 +6489,6 @@ void TBuiltIns::addQueryFunctions(TSampler sampler, const TString& typeName, int int sizeDims = dimMap[sampler.dim] + (sampler.arrayed ? 1 : 0) - (sampler.dim == EsdCube ? 1 : 0); -#ifdef GLSLANG_WEB - commonBuiltins.append("highp "); - commonBuiltins.append("ivec"); - commonBuiltins.append(postfixes[sizeDims]); - commonBuiltins.append(" textureSize("); - commonBuiltins.append(typeName); - commonBuiltins.append(",int);\n"); - return; -#endif - if (sampler.isImage() && ((profile == EEsProfile && version < 310) || (profile != EEsProfile && version < 420))) return; @@ -6432,6 +6698,34 @@ void TBuiltIns::addImageFunctions(TSampler sampler, const TString& typeName, int commonBuiltins.append(imageParams); commonBuiltins.append(", float);\n"); } + + // GL_NV_shader_atomic_fp16_vector + if (profile != EEsProfile && version >= 430) { + const int numFp16Builtins = 4; + const char* atomicFp16Func[numFp16Builtins] = { + " imageAtomicAdd(volatile coherent ", + " imageAtomicMin(volatile coherent ", + " imageAtomicMax(volatile coherent ", + " imageAtomicExchange(volatile coherent " + }; + const int numFp16DataTypes = 2; + const char* atomicFp16DataTypes[numFp16DataTypes] = { + "f16vec2", + "f16vec4" + }; + // Loop twice to add prototypes with/without scope/semantics + for (int j = 0; j < numFp16DataTypes; ++j) { + for (int i = 0; i < numFp16Builtins; ++i) { + commonBuiltins.append(atomicFp16DataTypes[j]); + commonBuiltins.append(atomicFp16Func[i]); + commonBuiltins.append(imageParams); + commonBuiltins.append(", "); + commonBuiltins.append(atomicFp16DataTypes[j]); + commonBuiltins.append(");\n"); + } + } + } + if (profile != EEsProfile && version >= 450) { commonBuiltins.append("float imageAtomicAdd(volatile coherent "); commonBuiltins.append(imageParams); @@ -6542,14 +6836,6 @@ void TBuiltIns::addSubpassSampling(TSampler sampler, const TString& typeName, in // void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { -#ifdef GLSLANG_WEB - profile = EEsProfile; - version = 310; -#elif defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif - // // texturing // @@ -6624,11 +6910,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, continue; // loop over 16-bit floating-point texel addressing -#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) - const int f16TexAddr = 0; -#else for (int f16TexAddr = 0; f16TexAddr <= 1; ++f16TexAddr) -#endif { if (f16TexAddr && sampler.type != EbtFloat16) continue; @@ -6637,11 +6919,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, totalDims--; } // loop over "bool" lod clamp -#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) - const int lodClamp = 0; -#else for (int lodClamp = 0; lodClamp <= 1 ;++lodClamp) -#endif { if (lodClamp && (profile == EEsProfile || version < 450)) continue; @@ -6649,11 +6927,7 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, continue; // loop over "bool" sparse or not -#if defined(GLSLANG_WEB) || defined(GLSLANG_ANGLE) - const int sparse = 0; -#else for (int sparse = 0; sparse <= 1; ++sparse) -#endif { if (sparse && (profile == EEsProfile || version < 450)) continue; @@ -6830,14 +7104,6 @@ void TBuiltIns::addSamplingFunctions(TSampler sampler, const TString& typeName, // void TBuiltIns::addGatherFunctions(TSampler sampler, const TString& typeName, int version, EProfile profile) { -#ifdef GLSLANG_WEB - profile = EEsProfile; - version = 310; -#elif defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif - switch (sampler.dim) { case Esd2D: case EsdRect: @@ -7076,14 +7342,6 @@ void TBuiltIns::addGatherFunctions(TSampler sampler, const TString& typeName, in // void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language) { -#ifdef GLSLANG_WEB - version = 310; - profile = EEsProfile; -#elif defined(GLSLANG_ANGLE) - version = 450; - profile = ECoreProfile; -#endif - // // Initialize the context-dependent (resource-dependent) built-in strings for parsing. // @@ -7141,7 +7399,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); } -#ifndef GLSLANG_WEB if (version >= 310) { // geometry @@ -7464,7 +7721,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf snprintf(builtInConstant, maxSize, "const int gl_MaxTransformFeedbackInterleavedComponents = %d;", resources.maxTransformFeedbackInterleavedComponents); s.append(builtInConstant); } -#endif } // compute @@ -7486,7 +7742,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } -#ifndef GLSLANG_WEB // images (some in compute below) if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 130)) { @@ -7514,7 +7769,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } -#ifndef GLSLANG_ANGLE // atomic counters (some in compute below) if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 420)) { @@ -7551,7 +7805,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } -#endif // !GLSLANG_ANGLE // GL_ARB_cull_distance if (profile != EEsProfile && version >= 450) { @@ -7568,7 +7821,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append(builtInConstant); } -#ifndef GLSLANG_ANGLE // SPV_NV_mesh_shader if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { snprintf(builtInConstant, maxSize, "const int gl_MaxMeshOutputVerticesNV = %d;", resources.maxMeshOutputVerticesNV); @@ -7591,8 +7843,6 @@ void TBuiltIns::initialize(const TBuiltInResource &resources, int version, EProf s.append("\n"); } -#endif -#endif s.append("\n"); } @@ -7621,6 +7871,23 @@ static void SpecialQualifier(const char* name, TStorageQualifier qualifier, TBui symQualifier.builtIn = builtIn; } +// +// Modify the symbol's flat decoration. +// +// Safe to call even if name is not present. +// +// Originally written to transform gl_SubGroupSizeARB from uniform to fragment input in Vulkan. +// +static void ModifyFlatDecoration(const char* name, bool flat, TSymbolTable& symbolTable) +{ + TSymbol* symbol = symbolTable.find(name); + if (symbol == nullptr) + return; + + TQualifier& symQualifier = symbol->getWritableType().getQualifier(); + symQualifier.flat = flat; +} + // // To tag built-in variables with their TBuiltInVariable enum. Use this when the // normal declaration text already gets the qualifier right, and all that's needed @@ -7678,14 +7945,6 @@ static void BuiltInVariable(const char* blockName, const char* name, TBuiltInVar // void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable) { -#ifdef GLSLANG_WEB - version = 310; - profile = EEsProfile; -#elif defined(GLSLANG_ANGLE) - version = 450; - profile = ECoreProfile; -#endif - // // Tag built-in variables and functions with additional qualifier and extension information // that cannot be declared with the text strings. @@ -7705,10 +7964,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_InstanceIndex", EbvInstanceIndex, symbolTable); } -#ifndef GLSLANG_WEB if (spvVersion.vulkan == 0) { SpecialQualifier("gl_VertexID", EvqVertexId, EbvVertexId, symbolTable); SpecialQualifier("gl_InstanceID", EvqInstanceId, EbvInstanceId, symbolTable); + if (version < 140) + symbolTable.setVariableExtensions("gl_InstanceID", 1, &E_GL_EXT_draw_instanced); } if (spvVersion.vulkan > 0 && spvVersion.vulkanRelaxed) { @@ -7860,7 +8120,21 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("shadow2DEXT", 1, &E_GL_EXT_shadow_samplers); symbolTable.setFunctionExtensions("shadow2DProjEXT", 1, &E_GL_EXT_shadow_samplers); } - // Fall through + + // E_GL_EXT_texture_array + if (spvVersion.spv == 0) { + symbolTable.setFunctionExtensions("texture2DArray", 1, &E_GL_EXT_texture_array); + } + if (profile != EEsProfile && spvVersion.spv == 0) { + symbolTable.setFunctionExtensions("texture1DArray", 1, &E_GL_EXT_texture_array); + symbolTable.setFunctionExtensions("shadow1DArray", 1, &E_GL_EXT_texture_array); + symbolTable.setFunctionExtensions("shadow2DArray", 1, &E_GL_EXT_texture_array); + + symbolTable.setFunctionExtensions("texture1DArrayLod", 1, &E_GL_EXT_texture_array); + symbolTable.setFunctionExtensions("texture2DArrayLod", 1, &E_GL_EXT_texture_array); + symbolTable.setFunctionExtensions("shadow1DArrayLod", 1, &E_GL_EXT_texture_array); + } + [[fallthrough]]; case EShLangTessControl: if (profile == EEsProfile && version >= 310) { @@ -7875,11 +8149,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_BoundingBox", EbvBoundingBox, symbolTable); } } - // Fall through + [[fallthrough]]; case EShLangTessEvaluation: case EShLangGeometry: -#endif // !GLSLANG_WEB SpecialQualifier("gl_Position", EvqPosition, EbvPosition, symbolTable); SpecialQualifier("gl_PointSize", EvqPointSize, EbvPointSize, symbolTable); @@ -7889,7 +8162,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_out", "gl_Position", EbvPosition, symbolTable); BuiltInVariable("gl_out", "gl_PointSize", EbvPointSize, symbolTable); -#ifndef GLSLANG_WEB SpecialQualifier("gl_ClipVertex", EvqClipVertex, EbvClipVertex, symbolTable); BuiltInVariable("gl_in", "gl_ClipDistance", EbvClipDistance, symbolTable); @@ -7996,7 +8268,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); } - if (profile != EEsProfile) { + if (profile != EEsProfile) { BuiltInVariable("gl_SubGroupInvocationARB", EbvSubGroupInvocation, symbolTable); BuiltInVariable("gl_SubGroupEqMaskARB", EbvSubGroupEqMask, symbolTable); BuiltInVariable("gl_SubGroupGeMaskARB", EbvSubGroupGeMask, symbolTable); @@ -8004,9 +8276,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); } @@ -8039,6 +8314,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } if (language == EShLangGeometry || language == EShLangVertex) { @@ -8053,8 +8341,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); } } - -#endif // !GLSLANG_WEB break; case EShLangFragment: @@ -8071,8 +8357,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion } } SpecialQualifier("gl_FragDepth", EvqFragDepth, EbvFragDepth, symbolTable); -#ifndef GLSLANG_WEB SpecialQualifier("gl_FragDepthEXT", EvqFragDepth, EbvFragDepth, symbolTable); + SpecialQualifier("gl_FragStencilRefARB", EvqFragStencil, EbvFragStencilRef, symbolTable); SpecialQualifier("gl_HelperInvocation", EvqVaryingIn, EbvHelperInvocation, symbolTable); BuiltInVariable("gl_ClipDistance", EbvClipDistance, symbolTable); @@ -8112,8 +8398,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("rayQueryGetIntersectionWorldToObjectEXT", 1, &E_GL_EXT_ray_query); symbolTable.setFunctionExtensions("rayQueryGetWorldRayOriginEXT", 1, &E_GL_EXT_ray_query); symbolTable.setFunctionExtensions("rayQueryGetWorldRayDirectionEXT", 1, &E_GL_EXT_ray_query); + symbolTable.setFunctionExtensions("rayQueryGetIntersectionTriangleVertexPositionsEXT", 1, &E_GL_EXT_ray_tracing_position_fetch); symbolTable.setVariableExtensions("gl_RayFlagsSkipAABBEXT", 1, &E_GL_EXT_ray_flags_primitive_culling); symbolTable.setVariableExtensions("gl_RayFlagsSkipTrianglesEXT", 1, &E_GL_EXT_ray_flags_primitive_culling); + symbolTable.setVariableExtensions("gl_RayFlagsForceOpacityMicromap2StateEXT", 1, &E_GL_EXT_opacity_micromap); } if ((profile != EEsProfile && version >= 130) || @@ -8216,27 +8504,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("shadow2DRectProjGradARB", 1, &E_GL_ARB_shader_texture_lod); } - // E_GL_EXT_texture_array - if (spvVersion.spv == 0) { - symbolTable.setFunctionExtensions("texture2DArray", 1, &E_GL_EXT_texture_array); - } - if (profile != EEsProfile && spvVersion.spv == 0) { - int nLodExtensions = 2; - const char *lodExtensions[] = {E_GL_EXT_texture_array, E_GL_ARB_shader_texture_lod}; - - if (version >= 130) - nLodExtensions = 1; - - symbolTable.setFunctionExtensions("texture1DArray", 1, &E_GL_EXT_texture_array); - symbolTable.setFunctionExtensions("shadow1DArray", 1, &E_GL_EXT_texture_array); - symbolTable.setFunctionExtensions("shadow2DArray", 1, &E_GL_EXT_texture_array); - - symbolTable.setFunctionExtensions("texture1DArrayLod", nLodExtensions, lodExtensions); - symbolTable.setFunctionExtensions("texture2DArrayLod", nLodExtensions, lodExtensions); - symbolTable.setFunctionExtensions("shadow1DArrayLod", nLodExtensions, lodExtensions); - symbolTable.setFunctionExtensions("shadow2DArrayLod", nLodExtensions, lodExtensions); - } - // E_GL_ARB_shader_image_load_store if (profile != EEsProfile && version < 420) symbolTable.setFunctionExtensions("memoryBarrier", 1, &E_GL_ARB_shader_image_load_store); @@ -8354,6 +8621,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_BaryCoordNoPerspNV", 1, &E_GL_NV_fragment_shader_barycentric); BuiltInVariable("gl_BaryCoordNV", EbvBaryCoordNV, symbolTable); BuiltInVariable("gl_BaryCoordNoPerspNV", EbvBaryCoordNoPerspNV, symbolTable); + symbolTable.setVariableExtensions("gl_BaryCoordEXT", 1, &E_GL_EXT_fragment_shader_barycentric); + symbolTable.setVariableExtensions("gl_BaryCoordNoPerspEXT", 1, &E_GL_EXT_fragment_shader_barycentric); + BuiltInVariable("gl_BaryCoordEXT", EbvBaryCoordEXT, symbolTable); + BuiltInVariable("gl_BaryCoordNoPerspEXT", EbvBaryCoordNoPerspEXT, symbolTable); } if ((profile != EEsProfile && version >= 450) || @@ -8389,10 +8660,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion } if (profile != EEsProfile && version < 330 ) { - symbolTable.setFunctionExtensions("floatBitsToInt", 1, &E_GL_ARB_shader_bit_encoding); - symbolTable.setFunctionExtensions("floatBitsToUint", 1, &E_GL_ARB_shader_bit_encoding); - symbolTable.setFunctionExtensions("intBitsToFloat", 1, &E_GL_ARB_shader_bit_encoding); - symbolTable.setFunctionExtensions("uintBitsToFloat", 1, &E_GL_ARB_shader_bit_encoding); + const char* bitsConvertExt[2] = {E_GL_ARB_shader_bit_encoding, E_GL_ARB_gpu_shader5}; + symbolTable.setFunctionExtensions("floatBitsToInt", 2, bitsConvertExt); + symbolTable.setFunctionExtensions("floatBitsToUint", 2, bitsConvertExt); + symbolTable.setFunctionExtensions("intBitsToFloat", 2, bitsConvertExt); + symbolTable.setFunctionExtensions("uintBitsToFloat", 2, bitsConvertExt); } if (profile != EEsProfile && version < 430 ) { @@ -8453,13 +8725,23 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); } + // GL_EXT_expect_assume + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + symbolTable.setFunctionExtensions("assumeEXT", 1, &E_GL_EXT_expect_assume); + symbolTable.setFunctionExtensions("expectEXT", 1, &E_GL_EXT_expect_assume); + } + // GL_KHR_shader_subgroup if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 140)) { @@ -8501,6 +8783,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("subgroupShuffleXor", 1, &E_GL_KHR_shader_subgroup_shuffle); symbolTable.setFunctionExtensions("subgroupShuffleUp", 1, &E_GL_KHR_shader_subgroup_shuffle_relative); symbolTable.setFunctionExtensions("subgroupShuffleDown", 1, &E_GL_KHR_shader_subgroup_shuffle_relative); + symbolTable.setFunctionExtensions("subgroupRotate", 1, &E_GL_KHR_shader_subgroup_rotate); + symbolTable.setFunctionExtensions("subgroupClusteredRotate", 1, &E_GL_KHR_shader_subgroup_rotate); symbolTable.setFunctionExtensions("subgroupAdd", 1, &E_GL_KHR_shader_subgroup_arithmetic); symbolTable.setFunctionExtensions("subgroupMul", 1, &E_GL_KHR_shader_subgroup_arithmetic); symbolTable.setFunctionExtensions("subgroupMin", 1, &E_GL_KHR_shader_subgroup_arithmetic); @@ -8565,6 +8849,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } if (profile == EEsProfile) { @@ -8605,7 +8902,32 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); } -#endif // !GLSLANG_WEB + + // GL_EXT_shader_quad_control + if ((profile != EEsProfile && version >= 140) || + (profile == EEsProfile && version >= 310)) { + symbolTable.setFunctionExtensions("subgroupQuadAll", 1, &E_GL_KHR_shader_subgroup_vote); + symbolTable.setFunctionExtensions("subgroupQuadAny", 1, &E_GL_KHR_shader_subgroup_vote); + } + + // GL_EXT_shader_tile_image + symbolTable.setFunctionExtensions("stencilAttachmentReadEXT", 1, &E_GL_EXT_shader_tile_image); + symbolTable.setFunctionExtensions("depthAttachmentReadEXT", 1, &E_GL_EXT_shader_tile_image); + symbolTable.setFunctionExtensions("colorAttachmentReadEXT", 1, &E_GL_EXT_shader_tile_image); + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + + symbolTable.setFunctionExtensions("textureWeightedQCOM", 1, &E_GL_QCOM_image_processing); + symbolTable.setFunctionExtensions("textureBoxFilterQCOM", 1, &E_GL_QCOM_image_processing); + symbolTable.setFunctionExtensions("textureBlockMatchSADQCOM", 1, &E_GL_QCOM_image_processing); + symbolTable.setFunctionExtensions("textureBlockMatchSSDQCOM", 1, &E_GL_QCOM_image_processing); + + symbolTable.setFunctionExtensions("textureBlockMatchWindowSSDQCOM", 1, &E_GL_QCOM_image_processing2); + symbolTable.setFunctionExtensions("textureBlockMatchWindowSADQCOM", 1, &E_GL_QCOM_image_processing2); + symbolTable.setFunctionExtensions("textureBlockMatchGatherSSDQCOM", 1, &E_GL_QCOM_image_processing2); + symbolTable.setFunctionExtensions("textureBlockMatchGatherSADQCOM", 1, &E_GL_QCOM_image_processing2); + } break; case EShLangCompute: @@ -8618,7 +8940,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); -#ifndef GLSLANG_WEB if ((profile != EEsProfile && version >= 140) || (profile == EEsProfile && version >= 310)) { symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); @@ -8670,9 +8991,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); } @@ -8705,6 +9029,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } // GL_KHR_shader_subgroup @@ -8726,6 +9063,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("coopMatMulAddNV", 2, coopExt); } + { + symbolTable.setFunctionExtensions("coopMatLoad", 1, &E_GL_KHR_cooperative_matrix); + symbolTable.setFunctionExtensions("coopMatStore", 1, &E_GL_KHR_cooperative_matrix); + symbolTable.setFunctionExtensions("coopMatMulAdd", 1, &E_GL_KHR_cooperative_matrix); + } + if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { symbolTable.setFunctionExtensions("dFdx", 1, &E_GL_NV_compute_shader_derivatives); symbolTable.setFunctionExtensions("dFdy", 1, &E_GL_NV_compute_shader_derivatives); @@ -8745,10 +9088,13 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); } -#endif // !GLSLANG_WEB + + if ((profile != EEsProfile && version >= 460)) { + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexPositionNV", 1, &E_GL_NV_displacement_micromap); + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexBarycentricNV", 1, &E_GL_NV_displacement_micromap); + } break; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) case EShLangRayGen: case EShLangIntersect: case EShLangAnyHit: @@ -8778,6 +9124,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_RayTminEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_RayTmaxNV", 1, &E_GL_NV_ray_tracing); symbolTable.setVariableExtensions("gl_RayTmaxEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setVariableExtensions("gl_CullMaskEXT", 1, &E_GL_EXT_ray_cull_mask); symbolTable.setVariableExtensions("gl_HitTNV", 1, &E_GL_NV_ray_tracing); symbolTable.setVariableExtensions("gl_HitTEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_HitKindNV", 1, &E_GL_NV_ray_tracing); @@ -8791,6 +9138,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_IncomingRayFlagsNV", 1, &E_GL_NV_ray_tracing); symbolTable.setVariableExtensions("gl_IncomingRayFlagsEXT", 1, &E_GL_EXT_ray_tracing); symbolTable.setVariableExtensions("gl_CurrentRayTimeNV", 1, &E_GL_NV_ray_tracing_motion_blur); + symbolTable.setVariableExtensions("gl_HitTriangleVertexPositionsEXT", 1, &E_GL_EXT_ray_tracing_position_fetch); + symbolTable.setVariableExtensions("gl_HitMicroTriangleVertexPositionsNV", 1, &E_GL_NV_displacement_micromap); + symbolTable.setVariableExtensions("gl_HitMicroTriangleVertexBarycentricsNV", 1, &E_GL_NV_displacement_micromap); symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); @@ -8805,6 +9155,40 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setFunctionExtensions("executeCallableNV", 1, &E_GL_NV_ray_tracing); symbolTable.setFunctionExtensions("executeCallableEXT", 1, &E_GL_EXT_ray_tracing); + symbolTable.setFunctionExtensions("hitObjectTraceRayNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectTraceRayMotionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordHitNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordHitMotionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordHitWithIndexNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordHitWithIndexMotionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordMissNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordMissMotionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectRecordEmptyNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectExecuteShaderNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectIsEmptyNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectIsMissNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectIsHitNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetRayTMinNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetRayTMaxNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetObjectRayOriginNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetObjectRayDirectionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetWorldRayOriginNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetWorldRayDirectionNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetWorldToObjectNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetbjectToWorldNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetInstanceCustomIndexNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetInstanceIdNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetGeometryIndexNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetPrimitiveIndexNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetHitKindNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetAttributesNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetCurrentTimeNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetShaderBindingTableRecordIndexNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("hitObjectGetShaderRecordBufferHandleNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("reorderThreadNV", 1, &E_GL_NV_shader_invocation_reorder); + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexPositionNV", 1, &E_GL_NV_displacement_micromap); + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexBarycentricNV", 1, &E_GL_NV_displacement_micromap); + BuiltInVariable("gl_LaunchIDNV", EbvLaunchId, symbolTable); BuiltInVariable("gl_LaunchIDEXT", EbvLaunchId, symbolTable); @@ -8827,6 +9211,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_RayTminEXT", EbvRayTmin, symbolTable); BuiltInVariable("gl_RayTmaxNV", EbvRayTmax, symbolTable); BuiltInVariable("gl_RayTmaxEXT", EbvRayTmax, symbolTable); + BuiltInVariable("gl_CullMaskEXT", EbvCullMask, symbolTable); BuiltInVariable("gl_HitTNV", EbvHitT, symbolTable); BuiltInVariable("gl_HitTEXT", EbvHitT, symbolTable); BuiltInVariable("gl_HitKindNV", EbvHitKind, symbolTable); @@ -8841,6 +9226,11 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_IncomingRayFlagsEXT", EbvIncomingRayFlags, symbolTable); BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); BuiltInVariable("gl_CurrentRayTimeNV", EbvCurrentRayTimeNV, symbolTable); + BuiltInVariable("gl_HitTriangleVertexPositionsEXT", EbvPositionFetch, symbolTable); + BuiltInVariable("gl_HitMicroTriangleVertexPositionsNV", EbvMicroTrianglePositionNV, symbolTable); + BuiltInVariable("gl_HitMicroTriangleVertexBarycentricsNV", EbvMicroTriangleBaryNV, symbolTable); + BuiltInVariable("gl_HitKindFrontFacingMicroTriangleNV", EbvHitKindFrontFacingMicroTriangleNV, symbolTable); + BuiltInVariable("gl_HitKindBackFacingMicroTriangleNV", EbvHitKindBackFacingMicroTriangleNV, symbolTable); // GL_ARB_shader_ballot symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); @@ -8858,9 +9248,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); @@ -8894,6 +9287,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 450)) { @@ -8904,7 +9310,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion } break; - case EShLangMeshNV: + case EShLangMesh: if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { // per-vertex builtins symbolTable.setVariableExtensions("gl_MeshVerticesNV", "gl_Position", 1, &E_GL_NV_mesh_shader); @@ -8948,12 +9354,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_PrimitiveIndicesNV", 1, &E_GL_NV_mesh_shader); symbolTable.setVariableExtensions("gl_MeshViewCountNV", 1, &E_GL_NV_mesh_shader); symbolTable.setVariableExtensions("gl_MeshViewIndicesNV", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_WorkGroupSize", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_WorkGroupID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_LocalInvocationID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_GlobalInvocationID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader); - + if (profile != EEsProfile) { + symbolTable.setVariableExtensions("gl_WorkGroupSize", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_WorkGroupID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_GlobalInvocationID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationIndex", Num_AEP_mesh_shader, AEP_mesh_shader); + } else { + symbolTable.setVariableExtensions("gl_WorkGroupSize", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_WorkGroupID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_GlobalInvocationID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader); + } BuiltInVariable("gl_PrimitiveCountNV", EbvPrimitiveCountNV, symbolTable); BuiltInVariable("gl_PrimitiveIndicesNV", EbvPrimitiveIndicesNV, symbolTable); BuiltInVariable("gl_MeshViewCountNV", EbvMeshViewCountNV, symbolTable); @@ -8971,12 +9384,58 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV", 1, &E_GL_NV_mesh_shader); // builtin functions - symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader); - symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader); - symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_NV_mesh_shader); + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("barrier", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setFunctionExtensions("memoryBarrierShared", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setFunctionExtensions("groupMemoryBarrier", Num_AEP_mesh_shader, AEP_mesh_shader); + } else { + symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader); + symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader); + symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_NV_mesh_shader); + } + symbolTable.setFunctionExtensions("writePackedPrimitiveIndices4x8NV", 1, &E_GL_NV_mesh_shader); } if (profile != EEsProfile && version >= 450) { + // GL_EXT_Mesh_shader + symbolTable.setVariableExtensions("gl_PrimitivePointIndicesEXT", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_PrimitiveLineIndicesEXT", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_PrimitiveTriangleIndicesEXT", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_NumWorkGroups", 1, &E_GL_EXT_mesh_shader); + + BuiltInVariable("gl_PrimitivePointIndicesEXT", EbvPrimitivePointIndicesEXT, symbolTable); + BuiltInVariable("gl_PrimitiveLineIndicesEXT", EbvPrimitiveLineIndicesEXT, symbolTable); + BuiltInVariable("gl_PrimitiveTriangleIndicesEXT", EbvPrimitiveTriangleIndicesEXT, symbolTable); + BuiltInVariable("gl_NumWorkGroups", EbvNumWorkGroups, symbolTable); + + symbolTable.setVariableExtensions("gl_MeshVerticesEXT", "gl_Position", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshVerticesEXT", "gl_PointSize", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshVerticesEXT", "gl_ClipDistance", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshVerticesEXT", "gl_CullDistance", 1, &E_GL_EXT_mesh_shader); + + BuiltInVariable("gl_MeshVerticesEXT", "gl_Position", EbvPosition, symbolTable); + BuiltInVariable("gl_MeshVerticesEXT", "gl_PointSize", EbvPointSize, symbolTable); + BuiltInVariable("gl_MeshVerticesEXT", "gl_ClipDistance", EbvClipDistance, symbolTable); + BuiltInVariable("gl_MeshVerticesEXT", "gl_CullDistance", EbvCullDistance, symbolTable); + + symbolTable.setVariableExtensions("gl_MeshPrimitivesEXT", "gl_PrimitiveID", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshPrimitivesEXT", "gl_Layer", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshPrimitivesEXT", "gl_ViewportIndex", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_MeshPrimitivesEXT", "gl_CullPrimitiveEXT", 1, &E_GL_EXT_mesh_shader); + + // note: technically this member requires both GL_EXT_mesh_shader and GL_EXT_fragment_shading_rate + // since setVariableExtensions only needs *one of* the extensions to validate, it's more useful to specify EXT_fragment_shading_rate + // GL_EXT_mesh_shader will be required in practice by use of other fields of gl_MeshPrimitivesEXT + symbolTable.setVariableExtensions("gl_MeshPrimitivesEXT", "gl_PrimitiveShadingRateEXT", 1, &E_GL_EXT_fragment_shading_rate); + + BuiltInVariable("gl_MeshPrimitivesEXT", "gl_PrimitiveID", EbvPrimitiveId, symbolTable); + BuiltInVariable("gl_MeshPrimitivesEXT", "gl_Layer", EbvLayer, symbolTable); + BuiltInVariable("gl_MeshPrimitivesEXT", "gl_ViewportIndex", EbvViewportIndex, symbolTable); + BuiltInVariable("gl_MeshPrimitivesEXT", "gl_CullPrimitiveEXT", EbvCullPrimitiveEXT, symbolTable); + BuiltInVariable("gl_MeshPrimitivesEXT", "gl_PrimitiveShadingRateEXT", EbvPrimitiveShadingRateKHR, symbolTable); + + symbolTable.setFunctionExtensions("SetMeshOutputsEXT", 1, &E_GL_EXT_mesh_shader); + // GL_EXT_device_group symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); @@ -8987,6 +9446,9 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion if (version >= 460) { BuiltInVariable("gl_DrawID", EbvDrawId, symbolTable); } + // GL_EXT_multiview + BuiltInVariable("gl_ViewIndex", EbvViewIndex, symbolTable); + symbolTable.setVariableExtensions("gl_ViewIndex", 1, &E_GL_EXT_multiview); // GL_ARB_shader_ballot symbolTable.setVariableExtensions("gl_SubGroupSizeARB", 1, &E_GL_ARB_shader_ballot); @@ -9004,9 +9466,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); } @@ -9045,6 +9510,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } if ((profile == EEsProfile && version >= 310) || @@ -9054,18 +9532,33 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_ShadingRateFlag2HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); } + + // Builtins for GL_NV_displacment_micromap + if ((profile != EEsProfile && version >= 460)) { + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexPositionNV", 1, &E_GL_NV_displacement_micromap); + symbolTable.setFunctionExtensions("fetchMicroTriangleVertexBarycentricNV", 1, &E_GL_NV_displacement_micromap); + } + break; - case EShLangTaskNV: + case EShLangTask: if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { symbolTable.setVariableExtensions("gl_TaskCountNV", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_WorkGroupSize", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_WorkGroupID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_LocalInvocationID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_GlobalInvocationID", 1, &E_GL_NV_mesh_shader); - symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader); symbolTable.setVariableExtensions("gl_MeshViewCountNV", 1, &E_GL_NV_mesh_shader); symbolTable.setVariableExtensions("gl_MeshViewIndicesNV", 1, &E_GL_NV_mesh_shader); + if (profile != EEsProfile) { + symbolTable.setVariableExtensions("gl_WorkGroupSize", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_WorkGroupID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_GlobalInvocationID", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationIndex", Num_AEP_mesh_shader, AEP_mesh_shader); + } else { + symbolTable.setVariableExtensions("gl_WorkGroupSize", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_WorkGroupID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_GlobalInvocationID", 1, &E_GL_NV_mesh_shader); + symbolTable.setVariableExtensions("gl_LocalInvocationIndex", 1, &E_GL_NV_mesh_shader); + } BuiltInVariable("gl_TaskCountNV", EbvTaskCountNV, symbolTable); BuiltInVariable("gl_WorkGroupSize", EbvWorkGroupSize, symbolTable); @@ -9079,12 +9572,23 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_MaxTaskWorkGroupSizeNV", 1, &E_GL_NV_mesh_shader); symbolTable.setVariableExtensions("gl_MaxMeshViewCountNV", 1, &E_GL_NV_mesh_shader); - symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader); - symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader); - symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_NV_mesh_shader); + if (profile != EEsProfile) { + symbolTable.setFunctionExtensions("barrier", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setFunctionExtensions("memoryBarrierShared", Num_AEP_mesh_shader, AEP_mesh_shader); + symbolTable.setFunctionExtensions("groupMemoryBarrier", Num_AEP_mesh_shader, AEP_mesh_shader); + } else { + symbolTable.setFunctionExtensions("barrier", 1, &E_GL_NV_mesh_shader); + symbolTable.setFunctionExtensions("memoryBarrierShared", 1, &E_GL_NV_mesh_shader); + symbolTable.setFunctionExtensions("groupMemoryBarrier", 1, &E_GL_NV_mesh_shader); + } } if (profile != EEsProfile && version >= 450) { + // GL_EXT_mesh_shader + symbolTable.setFunctionExtensions("EmitMeshTasksEXT", 1, &E_GL_EXT_mesh_shader); + symbolTable.setVariableExtensions("gl_NumWorkGroups", 1, &E_GL_EXT_mesh_shader); + BuiltInVariable("gl_NumWorkGroups", EbvNumWorkGroups, symbolTable); + // GL_EXT_device_group symbolTable.setVariableExtensions("gl_DeviceIndex", 1, &E_GL_EXT_device_group); BuiltInVariable("gl_DeviceIndex", EbvDeviceIndex, symbolTable); @@ -9112,9 +9616,12 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SubGroupLeMaskARB", EbvSubGroupLeMask, symbolTable); BuiltInVariable("gl_SubGroupLtMaskARB", EbvSubGroupLtMask, symbolTable); - if (spvVersion.vulkan > 0) + if (spvVersion.vulkan > 0) { // Treat "gl_SubGroupSizeARB" as shader input instead of uniform for Vulkan SpecialQualifier("gl_SubGroupSizeARB", EvqVaryingIn, EbvSubGroupSize, symbolTable); + if (language == EShLangFragment) + ModifyFlatDecoration("gl_SubGroupSizeARB", true, symbolTable); + } else BuiltInVariable("gl_SubGroupSizeARB", EbvSubGroupSize, symbolTable); } @@ -9153,6 +9660,19 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion BuiltInVariable("gl_SMCountNV", EbvSMCount, symbolTable); BuiltInVariable("gl_WarpIDNV", EbvWarpID, symbolTable); BuiltInVariable("gl_SMIDNV", EbvSMID, symbolTable); + + // GL_ARM_shader_core_builtins + symbolTable.setVariableExtensions("gl_CoreCountARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_CoreMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpIDARM", 1, &E_GL_ARM_shader_core_builtins); + symbolTable.setVariableExtensions("gl_WarpMaxIDARM", 1, &E_GL_ARM_shader_core_builtins); + + BuiltInVariable("gl_CoreCountARM", EbvCoreCountARM, symbolTable); + BuiltInVariable("gl_CoreIDARM", EbvCoreIDARM, symbolTable); + BuiltInVariable("gl_CoreMaxIDARM", EbvCoreMaxIDARM, symbolTable); + BuiltInVariable("gl_WarpIDARM", EbvWarpIDARM, symbolTable); + BuiltInVariable("gl_WarpMaxIDARM", EbvWarpMaxIDARM, symbolTable); } if ((profile == EEsProfile && version >= 310) || (profile != EEsProfile && version >= 450)) { @@ -9162,7 +9682,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.setVariableExtensions("gl_ShadingRateFlag4HorizontalPixelsEXT", 1, &E_GL_EXT_fragment_shading_rate); } break; -#endif default: assert(false && "Language not supported"); @@ -9178,7 +9697,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion relateTabledBuiltins(version, profile, spvVersion, language, symbolTable); -#ifndef GLSLANG_WEB symbolTable.relateToOperator("doubleBitsToInt64", EOpDoubleBitsToInt64); symbolTable.relateToOperator("doubleBitsToUint64", EOpDoubleBitsToUint64); symbolTable.relateToOperator("int64BitsToDouble", EOpInt64BitsToDouble); @@ -9331,6 +9849,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("averageRounded", EOpAverageRounded); symbolTable.relateToOperator("multiply32x16", EOpMul32x16); symbolTable.relateToOperator("debugPrintfEXT", EOpDebugPrintf); + symbolTable.relateToOperator("assumeEXT", EOpAssumeEXT); + symbolTable.relateToOperator("expectEXT", EOpExpectEXT); if (PureOperatorBuiltins) { @@ -9400,15 +9920,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("texture2DProjLod", EOpTextureProjLod); symbolTable.relateToOperator("texture2DProjLodEXT", EOpTextureProjLod); - symbolTable.relateToOperator("texture1DArray", EOpTexture); - symbolTable.relateToOperator("texture2DArray", EOpTexture); - symbolTable.relateToOperator("shadow1DArray", EOpTexture); - symbolTable.relateToOperator("shadow2DArray", EOpTexture); - symbolTable.relateToOperator("texture1DArrayLod", EOpTextureLod); - symbolTable.relateToOperator("texture2DArrayLod", EOpTextureLod); - symbolTable.relateToOperator("shadow1DArrayLod", EOpTextureLod); - symbolTable.relateToOperator("shadow2DArrayLod", EOpTextureLod); - symbolTable.relateToOperator("texture3D", EOpTexture); symbolTable.relateToOperator("texture3DGradARB", EOpTextureGrad); symbolTable.relateToOperator("texture3DProj", EOpTextureProj); @@ -9543,6 +10054,8 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("subgroupShuffleXor", EOpSubgroupShuffleXor); symbolTable.relateToOperator("subgroupShuffleUp", EOpSubgroupShuffleUp); symbolTable.relateToOperator("subgroupShuffleDown", EOpSubgroupShuffleDown); + symbolTable.relateToOperator("subgroupRotate", EOpSubgroupRotate); + symbolTable.relateToOperator("subgroupClusteredRotate", EOpSubgroupClusteredRotate); symbolTable.relateToOperator("subgroupAdd", EOpSubgroupAdd); symbolTable.relateToOperator("subgroupMul", EOpSubgroupMul); symbolTable.relateToOperator("subgroupMin", EOpSubgroupMin); @@ -9604,6 +10117,39 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("shadow2DEXT", EOpTexture); symbolTable.relateToOperator("shadow2DProjEXT", EOpTextureProj); } + + // GL_EXT_shader_quad_control + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + symbolTable.relateToOperator("subgroupQuadAll", EOpSubgroupQuadAll); + symbolTable.relateToOperator("subgroupQuadAny", EOpSubgroupQuadAny); + } + + if ((profile == EEsProfile && version >= 310) || + (profile != EEsProfile && version >= 140)) { + symbolTable.relateToOperator("textureWeightedQCOM", EOpImageSampleWeightedQCOM); + symbolTable.relateToOperator("textureBoxFilterQCOM", EOpImageBoxFilterQCOM); + symbolTable.relateToOperator("textureBlockMatchSADQCOM", EOpImageBlockMatchSADQCOM); + symbolTable.relateToOperator("textureBlockMatchSSDQCOM", EOpImageBlockMatchSSDQCOM); + + symbolTable.relateToOperator("textureBlockMatchWindowSSDQCOM", EOpImageBlockMatchWindowSSDQCOM); + symbolTable.relateToOperator("textureBlockMatchWindowSADQCOM", EOpImageBlockMatchWindowSADQCOM); + symbolTable.relateToOperator("textureBlockMatchGatherSSDQCOM", EOpImageBlockMatchGatherSSDQCOM); + symbolTable.relateToOperator("textureBlockMatchGatherSADQCOM", EOpImageBlockMatchGatherSADQCOM); + } + + if (spvVersion.spv == 0) { + symbolTable.relateToOperator("texture2DArray", EOpTexture); + } + if (profile != EEsProfile && spvVersion.spv == 0) { + symbolTable.relateToOperator("texture1DArray", EOpTexture); + symbolTable.relateToOperator("shadow1DArray", EOpTexture); + symbolTable.relateToOperator("shadow2DArray", EOpTexture); + + symbolTable.relateToOperator("texture1DArrayLod", EOpTextureLod); + symbolTable.relateToOperator("texture2DArrayLod", EOpTextureLod); + symbolTable.relateToOperator("shadow1DArrayLod", EOpTextureLod); + } } switch(language) { @@ -9655,6 +10201,7 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("rayQueryGetWorldRayOriginEXT", EOpRayQueryGetWorldRayOrigin); symbolTable.relateToOperator("rayQueryGetIntersectionObjectToWorldEXT", EOpRayQueryGetIntersectionObjectToWorld); symbolTable.relateToOperator("rayQueryGetIntersectionWorldToObjectEXT", EOpRayQueryGetIntersectionWorldToObject); + symbolTable.relateToOperator("rayQueryGetIntersectionTriangleVertexPositionsEXT", EOpRayQueryGetIntersectionTriangleVertexPositionsEXT); } symbolTable.relateToOperator("interpolateAtCentroid", EOpInterpolateAtCentroid); @@ -9667,6 +10214,10 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("beginInvocationInterlockARB", EOpBeginInvocationInterlock); symbolTable.relateToOperator("endInvocationInterlockARB", EOpEndInvocationInterlock); + symbolTable.relateToOperator("stencilAttachmentReadEXT", EOpStencilAttachmentReadEXT); + symbolTable.relateToOperator("depthAttachmentReadEXT", EOpDepthAttachmentReadEXT); + symbolTable.relateToOperator("colorAttachmentReadEXT", EOpColorAttachmentReadEXT); + break; case EShLangCompute: @@ -9683,12 +10234,26 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("dFdyCoarse", EOpDPdyCoarse); symbolTable.relateToOperator("fwidthCoarse",EOpFwidthCoarse); } - symbolTable.relateToOperator("coopMatLoadNV", EOpCooperativeMatrixLoad); - symbolTable.relateToOperator("coopMatStoreNV", EOpCooperativeMatrixStore); - symbolTable.relateToOperator("coopMatMulAddNV", EOpCooperativeMatrixMulAdd); + symbolTable.relateToOperator("coopMatLoadNV", EOpCooperativeMatrixLoadNV); + symbolTable.relateToOperator("coopMatStoreNV", EOpCooperativeMatrixStoreNV); + symbolTable.relateToOperator("coopMatMulAddNV", EOpCooperativeMatrixMulAddNV); + + symbolTable.relateToOperator("coopMatLoad", EOpCooperativeMatrixLoad); + symbolTable.relateToOperator("coopMatStore", EOpCooperativeMatrixStore); + symbolTable.relateToOperator("coopMatMulAdd", EOpCooperativeMatrixMulAdd); + + if (profile != EEsProfile && version >= 460) { + symbolTable.relateToOperator("fetchMicroTriangleVertexPositionNV", EOpFetchMicroTriangleVertexPositionNV); + symbolTable.relateToOperator("fetchMicroTriangleVertexBarycentricNV", EOpFetchMicroTriangleVertexBarycentricNV); + } break; case EShLangRayGen: + if (profile != EEsProfile && version >= 460) { + symbolTable.relateToOperator("fetchMicroTriangleVertexPositionNV", EOpFetchMicroTriangleVertexPositionNV); + symbolTable.relateToOperator("fetchMicroTriangleVertexBarycentricNV", EOpFetchMicroTriangleVertexBarycentricNV); + } + [[fallthrough]]; case EShLangClosestHit: case EShLangMiss: if (profile != EEsProfile && version >= 460) { @@ -9697,13 +10262,45 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("traceRayEXT", EOpTraceKHR); symbolTable.relateToOperator("executeCallableNV", EOpExecuteCallableNV); symbolTable.relateToOperator("executeCallableEXT", EOpExecuteCallableKHR); + + symbolTable.relateToOperator("hitObjectTraceRayNV", EOpHitObjectTraceRayNV); + symbolTable.relateToOperator("hitObjectTraceRayMotionNV", EOpHitObjectTraceRayMotionNV); + symbolTable.relateToOperator("hitObjectRecordHitNV", EOpHitObjectRecordHitNV); + symbolTable.relateToOperator("hitObjectRecordHitMotionNV", EOpHitObjectRecordHitMotionNV); + symbolTable.relateToOperator("hitObjectRecordHitWithIndexNV", EOpHitObjectRecordHitWithIndexNV); + symbolTable.relateToOperator("hitObjectRecordHitWithIndexMotionNV", EOpHitObjectRecordHitWithIndexMotionNV); + symbolTable.relateToOperator("hitObjectRecordMissNV", EOpHitObjectRecordMissNV); + symbolTable.relateToOperator("hitObjectRecordMissMotionNV", EOpHitObjectRecordMissMotionNV); + symbolTable.relateToOperator("hitObjectRecordEmptyNV", EOpHitObjectRecordEmptyNV); + symbolTable.relateToOperator("hitObjectExecuteShaderNV", EOpHitObjectExecuteShaderNV); + symbolTable.relateToOperator("hitObjectIsEmptyNV", EOpHitObjectIsEmptyNV); + symbolTable.relateToOperator("hitObjectIsMissNV", EOpHitObjectIsMissNV); + symbolTable.relateToOperator("hitObjectIsHitNV", EOpHitObjectIsHitNV); + symbolTable.relateToOperator("hitObjectGetRayTMinNV", EOpHitObjectGetRayTMinNV); + symbolTable.relateToOperator("hitObjectGetRayTMaxNV", EOpHitObjectGetRayTMaxNV); + symbolTable.relateToOperator("hitObjectGetObjectRayOriginNV", EOpHitObjectGetObjectRayOriginNV); + symbolTable.relateToOperator("hitObjectGetObjectRayDirectionNV", EOpHitObjectGetObjectRayDirectionNV); + symbolTable.relateToOperator("hitObjectGetWorldRayOriginNV", EOpHitObjectGetWorldRayOriginNV); + symbolTable.relateToOperator("hitObjectGetWorldRayDirectionNV", EOpHitObjectGetWorldRayDirectionNV); + symbolTable.relateToOperator("hitObjectGetWorldToObjectNV", EOpHitObjectGetWorldToObjectNV); + symbolTable.relateToOperator("hitObjectGetObjectToWorldNV", EOpHitObjectGetObjectToWorldNV); + symbolTable.relateToOperator("hitObjectGetInstanceCustomIndexNV", EOpHitObjectGetInstanceCustomIndexNV); + symbolTable.relateToOperator("hitObjectGetInstanceIdNV", EOpHitObjectGetInstanceIdNV); + symbolTable.relateToOperator("hitObjectGetGeometryIndexNV", EOpHitObjectGetGeometryIndexNV); + symbolTable.relateToOperator("hitObjectGetPrimitiveIndexNV", EOpHitObjectGetPrimitiveIndexNV); + symbolTable.relateToOperator("hitObjectGetHitKindNV", EOpHitObjectGetHitKindNV); + symbolTable.relateToOperator("hitObjectGetAttributesNV", EOpHitObjectGetAttributesNV); + symbolTable.relateToOperator("hitObjectGetCurrentTimeNV", EOpHitObjectGetCurrentTimeNV); + symbolTable.relateToOperator("hitObjectGetShaderBindingTableRecordIndexNV", EOpHitObjectGetShaderBindingTableRecordIndexNV); + symbolTable.relateToOperator("hitObjectGetShaderRecordBufferHandleNV", EOpHitObjectGetShaderRecordBufferHandleNV); + symbolTable.relateToOperator("reorderThreadNV", EOpReorderThreadNV); } break; case EShLangIntersect: if (profile != EEsProfile && version >= 460) { symbolTable.relateToOperator("reportIntersectionNV", EOpReportIntersection); symbolTable.relateToOperator("reportIntersectionEXT", EOpReportIntersection); - } + } break; case EShLangAnyHit: if (profile != EEsProfile && version >= 460) { @@ -9717,23 +10314,38 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion symbolTable.relateToOperator("executeCallableEXT", EOpExecuteCallableKHR); } break; - case EShLangMeshNV: + case EShLangMesh: if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { symbolTable.relateToOperator("writePackedPrimitiveIndices4x8NV", EOpWritePackedPrimitiveIndices4x8NV); + symbolTable.relateToOperator("memoryBarrierShared", EOpMemoryBarrierShared); + symbolTable.relateToOperator("groupMemoryBarrier", EOpGroupMemoryBarrier); + symbolTable.relateToOperator("subgroupMemoryBarrierShared", EOpSubgroupMemoryBarrierShared); } - // fall through - case EShLangTaskNV: + + if (profile != EEsProfile && version >= 450) { + symbolTable.relateToOperator("SetMeshOutputsEXT", EOpSetMeshOutputsEXT); + } + + if (profile != EEsProfile && version >= 460) { + // Builtins for GL_NV_displacement_micromap. + symbolTable.relateToOperator("fetchMicroTriangleVertexPositionNV", EOpFetchMicroTriangleVertexPositionNV); + symbolTable.relateToOperator("fetchMicroTriangleVertexBarycentricNV", EOpFetchMicroTriangleVertexBarycentricNV); + } + break; + case EShLangTask: if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) { symbolTable.relateToOperator("memoryBarrierShared", EOpMemoryBarrierShared); symbolTable.relateToOperator("groupMemoryBarrier", EOpGroupMemoryBarrier); symbolTable.relateToOperator("subgroupMemoryBarrierShared", EOpSubgroupMemoryBarrierShared); } + if (profile != EEsProfile && version >= 450) { + symbolTable.relateToOperator("EmitMeshTasksEXT", EOpEmitMeshTasksEXT); + } break; default: assert(false && "Language not supported"); } -#endif // !GLSLANG_WEB } // @@ -9747,11 +10359,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion // void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion& spvVersion, EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) { -#ifndef GLSLANG_WEB -#if defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif if (profile != EEsProfile && version >= 430 && version < 440) { symbolTable.setVariableExtensions("gl_MaxTransformFeedbackBuffers", 1, &E_GL_ARB_enhanced_layouts); symbolTable.setVariableExtensions("gl_MaxTransformFeedbackInterleavedComponents", 1, &E_GL_ARB_enhanced_layouts); @@ -9823,7 +10430,6 @@ void TBuiltIns::identifyBuiltIns(int version, EProfile profile, const SpvVersion default: break; } -#endif } } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/Initialize.h b/src/libraries/glslang/glslang/MachineIndependent/Initialize.h index ac8ec33e9..42c32ddbb 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Initialize.h +++ b/src/libraries/glslang/glslang/MachineIndependent/Initialize.h @@ -107,6 +107,9 @@ protected: int dimMap[EsdNumDims]; }; +// change this back to false if depending on textual spellings of texturing calls when consuming the AST +// Using PureOperatorBuiltins=false is deprecated. +constexpr bool PureOperatorBuiltins = true; } // end namespace glslang #endif // _INITIALIZE_INCLUDED_ diff --git a/src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp b/src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp index 6aea5b3d7..63e176e3a 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Intermediate.cpp @@ -352,7 +352,7 @@ TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermT TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, const TSourceLoc& loc) { - if (child == 0) + if (child == nullptr) return nullptr; if (child->getType().getBasicType() == EbtBlock) @@ -376,6 +376,7 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, case EOpNegative: if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) return nullptr; + break; default: break; // some compilers want this } @@ -388,7 +389,6 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, case EOpConstructFloat: newType = EbtFloat; break; case EOpConstructInt: newType = EbtInt; break; case EOpConstructUint: newType = EbtUint; break; -#ifndef GLSLANG_WEB case EOpConstructInt8: newType = EbtInt8; break; case EOpConstructUint8: newType = EbtUint8; break; case EOpConstructInt16: newType = EbtInt16; break; @@ -397,7 +397,6 @@ TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermTyped* child, case EOpConstructUint64: newType = EbtUint64; break; case EOpConstructDouble: newType = EbtDouble; break; case EOpConstructFloat16: newType = EbtFloat16; break; -#endif default: break; // some compilers want this } @@ -569,7 +568,6 @@ bool TIntermediate::isConversionAllowed(TOperator op, TIntermTyped* node) const bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& newOp) const { switch (dst) { -#ifndef GLSLANG_WEB case EbtDouble: switch (src) { case EbtUint: newOp = EOpConvUintToDouble; break; @@ -587,13 +585,11 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne return false; } break; -#endif case EbtFloat: switch (src) { case EbtInt: newOp = EOpConvIntToFloat; break; case EbtUint: newOp = EOpConvUintToFloat; break; case EbtBool: newOp = EOpConvBoolToFloat; break; -#ifndef GLSLANG_WEB case EbtDouble: newOp = EOpConvDoubleToFloat; break; case EbtInt8: newOp = EOpConvInt8ToFloat; break; case EbtUint8: newOp = EOpConvUint8ToFloat; break; @@ -602,12 +598,10 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne case EbtFloat16: newOp = EOpConvFloat16ToFloat; break; case EbtInt64: newOp = EOpConvInt64ToFloat; break; case EbtUint64: newOp = EOpConvUint64ToFloat; break; -#endif default: return false; } break; -#ifndef GLSLANG_WEB case EbtFloat16: switch (src) { case EbtInt8: newOp = EOpConvInt8ToFloat16; break; @@ -625,13 +619,11 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne return false; } break; -#endif case EbtBool: switch (src) { case EbtInt: newOp = EOpConvIntToBool; break; case EbtUint: newOp = EOpConvUintToBool; break; case EbtFloat: newOp = EOpConvFloatToBool; break; -#ifndef GLSLANG_WEB case EbtDouble: newOp = EOpConvDoubleToBool; break; case EbtInt8: newOp = EOpConvInt8ToBool; break; case EbtUint8: newOp = EOpConvUint8ToBool; break; @@ -640,12 +632,10 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne case EbtFloat16: newOp = EOpConvFloat16ToBool; break; case EbtInt64: newOp = EOpConvInt64ToBool; break; case EbtUint64: newOp = EOpConvUint64ToBool; break; -#endif default: return false; } break; -#ifndef GLSLANG_WEB case EbtInt8: switch (src) { case EbtUint8: newOp = EOpConvUint8ToInt8; break; @@ -715,14 +705,12 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne return false; } break; -#endif case EbtInt: switch (src) { case EbtUint: newOp = EOpConvUintToInt; break; case EbtBool: newOp = EOpConvBoolToInt; break; case EbtFloat: newOp = EOpConvFloatToInt; break; -#ifndef GLSLANG_WEB case EbtInt8: newOp = EOpConvInt8ToInt; break; case EbtUint8: newOp = EOpConvUint8ToInt; break; case EbtInt16: newOp = EOpConvInt16ToInt; break; @@ -731,7 +719,6 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne case EbtFloat16: newOp = EOpConvFloat16ToInt; break; case EbtInt64: newOp = EOpConvInt64ToInt; break; case EbtUint64: newOp = EOpConvUint64ToInt; break; -#endif default: return false; } @@ -741,7 +728,6 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne case EbtInt: newOp = EOpConvIntToUint; break; case EbtBool: newOp = EOpConvBoolToUint; break; case EbtFloat: newOp = EOpConvFloatToUint; break; -#ifndef GLSLANG_WEB case EbtInt8: newOp = EOpConvInt8ToUint; break; case EbtUint8: newOp = EOpConvUint8ToUint; break; case EbtInt16: newOp = EOpConvInt16ToUint; break; @@ -750,12 +736,15 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne case EbtFloat16: newOp = EOpConvFloat16ToUint; break; case EbtInt64: newOp = EOpConvInt64ToUint; break; case EbtUint64: newOp = EOpConvUint64ToUint; break; -#endif + // For bindless texture type conversion, add a dummy convert op, just + // to generate a new TIntermTyped + // uvec2(any sampler type) + // uvec2(any image type) + case EbtSampler: newOp = EOpConvIntToUint; break; default: return false; } break; -#ifndef GLSLANG_WEB case EbtInt64: switch (src) { case EbtInt8: newOp = EOpConvInt8ToInt64; break; @@ -790,7 +779,6 @@ bool TIntermediate::buildConvertOp(TBasicType dst, TBasicType src, TOperator& ne return false; } break; -#endif default: return false; } @@ -806,7 +794,6 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped // Add a new newNode for the conversion. // -#ifndef GLSLANG_WEB bool convertToIntTypes = (convertTo == EbtInt8 || convertTo == EbtUint8 || convertTo == EbtInt16 || convertTo == EbtUint16 || convertTo == EbtInt || convertTo == EbtUint || @@ -843,7 +830,6 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped return nullptr; } } -#endif TIntermUnary* newNode = nullptr; TOperator newOp = EOpNull; @@ -855,13 +841,11 @@ TIntermTyped* TIntermediate::createConversion(TBasicType convertTo, TIntermTyped newNode = addUnaryNode(newOp, node, node->getLoc(), newType); if (node->getAsConstantUnion()) { -#ifndef GLSLANG_WEB // 8/16-bit storage extensions don't support 8/16-bit constants, so don't fold conversions // to those types if ((getArithemeticInt8Enabled() || !(convertTo == EbtInt8 || convertTo == EbtUint8)) && (getArithemeticInt16Enabled() || !(convertTo == EbtInt16 || convertTo == EbtUint16)) && (getArithemeticFloat16Enabled() || !(convertTo == EbtFloat16))) -#endif { TIntermTyped* folded = node->getAsConstantUnion()->fold(newOp, newType); if (folded) @@ -1044,6 +1028,12 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt if (type.isArray() || node->getType().isArray()) return nullptr; + // Reject implicit conversions to cooperative matrix types + if (node->getType().isCoopMat() && + op != EOpConstructCooperativeMatrixNV && + op != EOpConstructCooperativeMatrixKHR) + return nullptr; + // Note: callers are responsible for other aspects of shape, // like vector and matrix sizes. @@ -1055,7 +1045,6 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpConstructFloat: case EOpConstructInt: case EOpConstructUint: -#ifndef GLSLANG_WEB case EOpConstructDouble: case EOpConstructFloat16: case EOpConstructInt8: @@ -1066,8 +1055,6 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpConstructUint64: break; -#endif - // // Implicit conversions // @@ -1112,7 +1099,8 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt case EOpSequence: case EOpConstructStruct: - case EOpConstructCooperativeMatrix: + case EOpConstructCooperativeMatrixNV: + case EOpConstructCooperativeMatrixKHR: if (type.isReference() || node->getType().isReference()) { // types must match to assign a reference @@ -1154,7 +1142,6 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt } bool canPromoteConstant = true; -#ifndef GLSLANG_WEB // GL_EXT_shader_16bit_storage can't do OpConstantComposite with // 16-bit types, so disable promotion for those types. // Many issues with this, from JohnK: @@ -1182,7 +1169,6 @@ TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TInt default: break; } -#endif if (canPromoteConstant && node->getAsConstantUnion()) return promoteConstantUnion(type.getBasicType(), node->getAsConstantUnion()); @@ -1292,6 +1278,7 @@ void TIntermediate::addBiShapeConversion(TOperator op, TIntermTyped*& lhsNode, T // matrix multiply does not change shapes if (lhsNode->isMatrix() && rhsNode->isMatrix()) return; + [[fallthrough]]; case EOpAdd: case EOpSub: case EOpDiv: @@ -1479,10 +1466,6 @@ bool TIntermediate::isFPPromotion(TBasicType from, TBasicType to) const bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const { -#ifdef GLSLANG_WEB - return false; -#endif - switch (from) { case EbtInt: switch(to) { @@ -1563,10 +1546,6 @@ bool TIntermediate::isIntegralConversion(TBasicType from, TBasicType to) const bool TIntermediate::isFPConversion(TBasicType from, TBasicType to) const { -#ifdef GLSLANG_WEB - return false; -#endif - if (to == EbtFloat && from == EbtFloat16) { return true; } else { @@ -1587,7 +1566,6 @@ bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const break; } break; -#ifndef GLSLANG_WEB case EbtInt8: case EbtUint8: case EbtInt16: @@ -1607,7 +1585,6 @@ bool TIntermediate::isFPIntegralConversion(TBasicType from, TBasicType to) const return true; } break; -#endif default: break; } @@ -1809,10 +1786,6 @@ bool TIntermediate::canImplicitlyPromote(TBasicType from, TBasicType to, TOperat static bool canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType, TBasicType uintType) { -#ifdef GLSLANG_WEB - return false; -#endif - switch(sintType) { case EbtInt8: switch(uintType) { @@ -1873,11 +1846,6 @@ static bool canSignedIntTypeRepresentAllUnsignedValues(TBasicType sintType, TBas static TBasicType getCorrespondingUnsignedType(TBasicType type) { -#ifdef GLSLANG_WEB - assert(type == EbtInt); - return EbtUint; -#endif - switch(type) { case EbtInt8: return EbtUint8; @@ -2003,8 +1971,11 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const if (type.getQualifier().isNonUniform()) return EOpConstructNonuniform; - if (type.isCoopMat()) - return EOpConstructCooperativeMatrix; + if (type.isCoopMatNV()) + return EOpConstructCooperativeMatrixNV; + + if (type.isCoopMatKHR()) + return EOpConstructCooperativeMatrixKHR; switch (type.getBasicType()) { case EbtStruct: @@ -2167,7 +2138,6 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const } } break; -#ifndef GLSLANG_WEB case EbtDouble: if (type.getMatrixCols()) { switch (type.getMatrixCols()) { @@ -2306,7 +2276,6 @@ TOperator TIntermediate::mapTypeToConstructorOp(const TType& type) const case EbtAccStruct: op = EOpConstructAccStruct; break; -#endif default: break; } @@ -2350,6 +2319,40 @@ TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* r return aggNode; } +TIntermAggregate* TIntermediate::mergeAggregate(TIntermNode* left, TIntermNode* right) +{ + if (left == nullptr && right == nullptr) + return nullptr; + + TIntermAggregate* aggNode = nullptr; + if (left != nullptr) + aggNode = left->getAsAggregate(); + if (aggNode == nullptr || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left != nullptr) + aggNode->getSequence().push_back(left); + } + + TIntermAggregate* rhsagg = right->getAsAggregate(); + if (rhsagg == nullptr || rhsagg->getOp() != EOpNull) + aggNode->getSequence().push_back(right); + else + aggNode->getSequence().insert(aggNode->getSequence().end(), + rhsagg->getSequence().begin(), + rhsagg->getSequence().end()); + + return aggNode; +} + +TIntermAggregate* TIntermediate::mergeAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc& loc) +{ + TIntermAggregate* aggNode = mergeAggregate(left, right); + if (aggNode) + aggNode->setLoc(loc); + + return aggNode; +} + // // Turn an existing node into an aggregate. // @@ -2623,6 +2626,18 @@ TIntermConstantUnion* TIntermediate::addConstantUnion(double d, TBasicType baseT { assert(baseType == EbtFloat || baseType == EbtDouble || baseType == EbtFloat16); + if (isEsProfile() && (baseType == EbtFloat || baseType == EbtFloat16)) { + int exponent = 0; + frexp(d, &exponent); + int minExp = baseType == EbtFloat ? -126 : -14; + int maxExp = baseType == EbtFloat ? 127 : 15; + if (exponent > maxExp) { //overflow, d = inf + d = std::numeric_limits::infinity(); + } else if (exponent < minExp) { //underflow, d = 0.0; + d = 0.0; + } + } + TConstUnionArray unionArray(1); unionArray[0].setDConst(d); @@ -2680,28 +2695,42 @@ TIntermTyped* TIntermediate::addSwizzle(TSwizzleSelectors& selecto // 'swizzleOkay' says whether or not it is okay to consider a swizzle // a valid part of the dereference chain. // -// 'BufferReferenceOk' says if type is buffer_reference, the routine stop to find the most left node. +// 'bufferReferenceOk' says if type is buffer_reference, the routine will stop to find the most left node. // +// 'proc' is an optional function to run on each node that is processed during the traversal. 'proc' must +// return true to continue the traversal, or false to end the traversal early. // -const TIntermTyped* TIntermediate::findLValueBase(const TIntermTyped* node, bool swizzleOkay , bool bufferReferenceOk) +const TIntermTyped* TIntermediate::traverseLValueBase(const TIntermTyped* node, bool swizzleOkay, + bool bufferReferenceOk, + std::function proc) { do { const TIntermBinary* binary = node->getAsBinaryNode(); - if (binary == nullptr) + if (binary == nullptr) { + if (proc) { + proc(*node); + } return node; + } TOperator op = binary->getOp(); - if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && op != EOpMatrixSwizzle) + if (op != EOpIndexDirect && op != EOpIndexIndirect && op != EOpIndexDirectStruct && op != EOpVectorSwizzle && + op != EOpMatrixSwizzle) return nullptr; - if (! swizzleOkay) { + if (!swizzleOkay) { if (op == EOpVectorSwizzle || op == EOpMatrixSwizzle) return nullptr; if ((op == EOpIndexDirect || op == EOpIndexIndirect) && (binary->getLeft()->getType().isVector() || binary->getLeft()->getType().isScalar()) && - ! binary->getLeft()->getType().isArray()) + !binary->getLeft()->getType().isArray()) return nullptr; } - node = node->getAsBinaryNode()->getLeft(); + if (proc) { + if (!proc(*node)) { + return node; + } + } + node = binary->getLeft(); if (bufferReferenceOk && node->isReference()) return node; } while (true); @@ -2733,10 +2762,10 @@ TIntermAggregate* TIntermediate::addForLoop(TIntermNode* body, TIntermNode* init TIntermAggregate* loopSequence = (initializer == nullptr || initializer->getAsAggregate() == nullptr) ? makeAggregate(initializer, loc) : initializer->getAsAggregate(); - if (loopSequence != nullptr && loopSequence->getOp() == EOpSequence) + if (loopSequence != nullptr && (loopSequence->getOp() == EOpSequence || loopSequence->getOp() == EOpScope)) loopSequence->setOp(EOpNull); loopSequence = growAggregate(loopSequence, node); - loopSequence->setOperator(EOpSequence); + loopSequence->setOperator(getDebugInfo() ? EOpScope : EOpSequence); return loopSequence; } @@ -2766,7 +2795,7 @@ void TIntermBranch::updatePrecision(TPrecisionQualifier parentPrecision) return; if (exp->getBasicType() == EbtInt || exp->getBasicType() == EbtUint || - exp->getBasicType() == EbtFloat || exp->getBasicType() == EbtFloat16) { + exp->getBasicType() == EbtFloat) { if (parentPrecision != EpqNone && exp->getQualifier().precision == EpqNone) { exp->propagatePrecision(parentPrecision); } @@ -2787,7 +2816,6 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) if (aggRoot && aggRoot->getOp() == EOpNull) aggRoot->setOperator(EOpSequence); -#ifndef GLSLANG_WEB // Propagate 'noContraction' label in backward from 'precise' variables. glslang::PropagateNoContraction(*this); @@ -2801,7 +2829,6 @@ bool TIntermediate::postProcess(TIntermNode* root, EShLanguage /*language*/) assert(0); break; } -#endif return true; } @@ -2830,10 +2857,9 @@ void TIntermediate::addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguag //} if (language == EShLangVertex) { - // the names won't be found in the symbol table unless the versions are right, - // so version logic does not need to be repeated here addSymbolLinkageNode(linkage, symbolTable, "gl_VertexID"); - addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID"); + if ((version < 140 && requestedExtensions.find(E_GL_EXT_draw_instanced) != requestedExtensions.end()) || version >= 140) + addSymbolLinkageNode(linkage, symbolTable, "gl_InstanceID"); } // Add a child to the root node for the linker objects @@ -3284,7 +3310,7 @@ bool TIntermediate::promoteUnary(TIntermUnary& node) void TIntermUnary::updatePrecision() { if (getBasicType() == EbtInt || getBasicType() == EbtUint || - getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { + getBasicType() == EbtFloat) { if (operand->getQualifier().precision > getQualifier().precision) getQualifier().precision = operand->getQualifier().precision; } @@ -3465,6 +3491,7 @@ bool TIntermediate::promoteBinary(TIntermBinary& node) // check for non-Boolean operands if (left->getBasicType() == EbtBool || right->getBasicType() == EbtBool) return false; + break; default: break; @@ -3508,33 +3535,42 @@ bool TIntermediate::promoteBinary(TIntermBinary& node) if (left->getType() == right->getType()) return true; - // Fall through + [[fallthrough]]; case EOpMul: case EOpMulAssign: // At least the basic type has to match if (left->getBasicType() != right->getBasicType()) return false; + break; default: break; } if (left->getType().isCoopMat() || right->getType().isCoopMat()) { + // Operations on two cooperative matrices must have identical types if (left->getType().isCoopMat() && right->getType().isCoopMat() && - *left->getType().getTypeParameters() != *right->getType().getTypeParameters()) { + left->getType() != right->getType()) { return false; } switch (op) { case EOpMul: case EOpMulAssign: - if (left->getType().isCoopMat() && right->getType().isCoopMat()) { + // Mul not supported in NV_cooperative_matrix + if (left->getType().isCoopMatNV() && right->getType().isCoopMatNV()) { return false; } - if (op == EOpMulAssign && right->getType().isCoopMat()) { + // NV_cooperative_matrix supports MulAssign is for mat*=scalar only. + // KHR_cooperative_matrix supports it for mat*=mat as well. + if (op == EOpMulAssign && right->getType().isCoopMatNV()) { return false; } - node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar); + // Use MatrixTimesScalar if either operand is not a matrix. Otherwise use Mul. + if (!left->getType().isCoopMat() || !right->getType().isCoopMat()) { + node.setOp(op == EOpMulAssign ? EOpMatrixTimesScalarAssign : EOpMatrixTimesScalar); + } + // In case of scalar*matrix, take the result type from the matrix. if (right->getType().isCoopMat()) { node.setType(right->getType()); } @@ -3649,7 +3685,7 @@ bool TIntermediate::promoteBinary(TIntermBinary& node) case EOpAssign: if (left->getVectorSize() != right->getVectorSize() || left->getMatrixCols() != right->getMatrixCols() || left->getMatrixRows() != right->getMatrixRows()) return false; - // fall through + [[fallthrough]]; case EOpAdd: case EOpSub: @@ -3785,7 +3821,7 @@ bool TIntermediate::promoteAggregate(TIntermAggregate& node) void TIntermAggregate::updatePrecision() { if (getBasicType() == EbtInt || getBasicType() == EbtUint || - getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { + getBasicType() == EbtFloat) { TPrecisionQualifier maxPrecision = EpqNone; TIntermSequence operands = getSequence(); for (unsigned int i = 0; i < operands.size(); ++i) { @@ -3807,7 +3843,7 @@ void TIntermAggregate::updatePrecision() void TIntermBinary::updatePrecision() { if (getBasicType() == EbtInt || getBasicType() == EbtUint || - getBasicType() == EbtFloat || getBasicType() == EbtFloat16) { + getBasicType() == EbtFloat) { if (op == EOpRightShift || op == EOpLeftShift) { // For shifts get precision from left side only and thus no need to propagate getQualifier().precision = left->getQualifier().precision; @@ -3887,16 +3923,6 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC #define PROMOTE(Set, CType, Get) leftUnionArray[i].Set(static_cast(rightUnionArray[i].Get())) #define PROMOTE_TO_BOOL(Get) leftUnionArray[i].setBConst(rightUnionArray[i].Get() != 0) -#ifdef GLSLANG_WEB -#define TO_ALL(Get) \ - switch (promoteTo) { \ - case EbtFloat: PROMOTE(setDConst, double, Get); break; \ - case EbtInt: PROMOTE(setIConst, int, Get); break; \ - case EbtUint: PROMOTE(setUConst, unsigned int, Get); break; \ - case EbtBool: PROMOTE_TO_BOOL(Get); break; \ - default: return node; \ - } -#else #define TO_ALL(Get) \ switch (promoteTo) { \ case EbtFloat16: PROMOTE(setDConst, double, Get); break; \ @@ -3913,14 +3939,12 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC case EbtBool: PROMOTE_TO_BOOL(Get); break; \ default: return node; \ } -#endif switch (node->getType().getBasicType()) { case EbtFloat: TO_ALL(getDConst); break; case EbtInt: TO_ALL(getIConst); break; case EbtUint: TO_ALL(getUConst); break; case EbtBool: TO_ALL(getBConst); break; -#ifndef GLSLANG_WEB case EbtFloat16: TO_ALL(getDConst); break; case EbtDouble: TO_ALL(getDConst); break; case EbtInt8: TO_ALL(getI8Const); break; @@ -3929,7 +3953,6 @@ TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermC case EbtUint8: TO_ALL(getU8Const); break; case EbtUint16: TO_ALL(getU16Const); break; case EbtUint64: TO_ALL(getU64Const); break; -#endif default: return node; } } diff --git a/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp b/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp index 1da50d62f..591dfc718 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ParseContextBase.cpp @@ -59,7 +59,7 @@ void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReaso safe_vsprintf(szExtraInfo, maxSize, szExtraInfoFormat, args); infoSink.info.prefix(prefix); - infoSink.info.location(loc); + infoSink.info.location(loc, messages & EShMsgAbsolutePath); infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; if (prefix == EPrefixError) { @@ -67,13 +67,14 @@ void TParseContextBase::outputMessage(const TSourceLoc& loc, const char* szReaso } } -#if !defined(GLSLANG_WEB) || defined(GLSLANG_WEB_DEVEL) - void C_DECL TParseContextBase::error(const TSourceLoc& loc, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...) { if (messages & EShMsgOnlyPreprocessor) return; + // If enhanced msg readability, only print one error + if (messages & EShMsgEnhanced && numErrors > 0) + return; va_list args; va_start(args, szExtraInfoFormat); outputMessage(loc, szReason, szToken, szExtraInfoFormat, EPrefixError, args); @@ -115,8 +116,6 @@ void C_DECL TParseContextBase::ppWarn(const TSourceLoc& loc, const char* szReaso va_end(args); } -#endif - // // Both test and if necessary, spit out an error, to see if the node is really // an l-value that can be operated on this way. @@ -137,7 +136,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, case EvqConst: message = "can't modify a const"; break; case EvqConstReadOnly: message = "can't modify a const"; break; case EvqUniform: message = "can't modify a uniform"; break; -#ifndef GLSLANG_WEB case EvqBuffer: if (node->getQualifier().isReadOnly()) message = "can't modify a readonly buffer"; @@ -148,7 +146,6 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, if (language != EShLangIntersect) message = "cannot modify hitAttributeNV in this stage"; break; -#endif default: // @@ -156,12 +153,12 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, // switch (node->getBasicType()) { case EbtSampler: - message = "can't modify a sampler"; + if (extensionTurnedOn(E_GL_ARB_bindless_texture) == false) + message = "can't modify a sampler"; break; case EbtVoid: message = "can't modify void"; break; -#ifndef GLSLANG_WEB case EbtAtomicUint: message = "can't modify an atomic_uint"; break; @@ -171,7 +168,9 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, case EbtRayQuery: message = "can't modify rayQueryEXT"; break; -#endif + case EbtHitObjectNV: + message = "can't modify hitObjectNV"; + break; default: break; } @@ -209,7 +208,7 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, // // If we get here, we have an error and a message. // - const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true); + const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); if (symNode) error(loc, " l-value required", op, "\"%s\" (%s)", symbol, message); @@ -228,14 +227,14 @@ bool TParseContextBase::lValueErrorCheck(const TSourceLoc& loc, const char* op, // Test for and give an error if the node can't be read from. void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, TIntermTyped* node) { - TIntermBinary* binaryNode = node->getAsBinaryNode(); - const TIntermSymbol* symNode = node->getAsSymbolNode(); - if (! node) return; + TIntermBinary* binaryNode = node->getAsBinaryNode(); + const TIntermSymbol* symNode = node->getAsSymbolNode(); + if (node->getQualifier().isWriteOnly()) { - const TIntermTyped* leftMostTypeNode = TIntermediate::findLValueBase(node, true); + const TIntermTyped* leftMostTypeNode = TIntermediate::traverseLValueBase(node, true); if (symNode != nullptr) error(loc, "can't read from writeonly object: ", op, symNode->getName().c_str()); @@ -258,6 +257,7 @@ void TParseContextBase::rValueErrorCheck(const TSourceLoc& loc, const char* op, case EOpVectorSwizzle: case EOpMatrixSwizzle: rValueErrorCheck(loc, op, binaryNode->getLeft()); + break; default: break; } @@ -627,10 +627,8 @@ void TParseContextBase::growGlobalUniformBlock(const TSourceLoc& loc, TType& mem if (symbol) { if (memberType != symbol->getType()) { TString err; - err += "\"" + memberType.getCompleteString() + "\""; - err += " versus "; - err += "\"" + symbol->getType().getCompleteString() + "\""; - error(loc, "Types must match:", memberType.getFieldName().c_str(), err.c_str()); + err += "Redeclaration: already declared as \"" + symbol->getType().getCompleteString() + "\""; + error(loc, "", memberName.c_str(), err.c_str()); } return; } @@ -725,6 +723,24 @@ void TParseContextBase::finish() if (parsingBuiltins) return; + for (const TString& relaxedSymbol : relaxedSymbols) + { + TSymbol* symbol = symbolTable.find(relaxedSymbol); + TType& type = symbol->getWritableType(); + for (const TTypeLoc& typeLoc : *type.getStruct()) + { + if (typeLoc.type->isOpaque()) + { + typeLoc.type->getSampler() = TSampler{}; + typeLoc.type->setBasicType(EbtInt); + TString fieldName("/*"); + fieldName.append(typeLoc.type->getFieldName()); + fieldName.append("*/"); + typeLoc.type->setFieldName(fieldName); + } + } + } + // Transfer the linkage symbols to AST nodes, preserving order. TIntermAggregate* linkage = new TIntermAggregate; for (auto i = linkageSymbols.begin(); i != linkageSymbols.end(); ++i) diff --git a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp index 0f8d05e9a..ff4e90397 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.cpp @@ -38,6 +38,7 @@ // #include "ParseHelper.h" +#include "Initialize.h" #include "Scan.h" #include "../OSDependent/osinclude.h" @@ -57,11 +58,8 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b infoSink, forwardCompatible, messages, entryPoint), inMain(false), blockName(nullptr), - limits(resources.limits) -#ifndef GLSLANG_WEB - , + limits(resources.limits), atomicUintOffsets(nullptr), anyIndexLimits(false) -#endif { // decide whether precision qualifiers should be ignored or respected if (isEsProfile() || spvVersion.vulkan > 0) { @@ -80,10 +78,6 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b globalBufferDefaults.layoutMatrix = ElmColumnMajor; globalBufferDefaults.layoutPacking = spvVersion.spv != 0 ? ElpStd430 : ElpShared; - // use storage buffer on SPIR-V 1.3 and up - if (spvVersion.spv >= EShTargetSpv_1_3) - intermediate.setUseStorageBuffer(); - globalInputDefaults.clear(); globalOutputDefaults.clear(); @@ -91,7 +85,6 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b globalSharedDefaults.layoutMatrix = ElmColumnMajor; globalSharedDefaults.layoutPacking = ElpStd430; -#ifndef GLSLANG_WEB // "Shaders in the transform // feedback capturing mode have an initial global default of // layout(xfb_buffer = 0) out;" @@ -103,7 +96,6 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b if (language == EShLangGeometry) globalOutputDefaults.layoutStream = 0; -#endif if (entryPoint != nullptr && entryPoint->size() > 0 && *entryPoint != "main") infoSink.info.message(EPrefixError, "Source entry point must be \"main\""); @@ -111,9 +103,7 @@ TParseContext::TParseContext(TSymbolTable& symbolTable, TIntermediate& interm, b TParseContext::~TParseContext() { -#ifndef GLSLANG_WEB delete [] atomicUintOffsets; -#endif } // Set up all default precisions as needed by the current environment. @@ -177,7 +167,6 @@ void TParseContext::setLimits(const TBuiltInResource& r) resources = r; intermediate.setLimits(r); -#ifndef GLSLANG_WEB anyIndexLimits = ! limits.generalAttributeMatrixVectorIndexing || ! limits.generalConstantMatrixVectorIndexing || ! limits.generalSamplerIndexing || @@ -192,7 +181,6 @@ void TParseContext::setLimits(const TBuiltInResource& r) atomicUintOffsets = new int[resources.maxAtomicCounterBindings]; for (int b = 0; b < resources.maxAtomicCounterBindings; ++b) atomicUintOffsets[b] = 0; -#endif } // @@ -339,7 +327,6 @@ void TParseContext::setInvariant(const TSourceLoc& loc, const char* builtin) { void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& tokens) { -#ifndef GLSLANG_WEB if (pragmaCallback) pragmaCallback(loc.line, tokens); @@ -441,7 +428,6 @@ void TParseContext::handlePragma(const TSourceLoc& loc, const TVector& setInvariant(loc, "gl_FragColor"); setInvariant(loc, "gl_FragData"); } -#endif } // @@ -455,7 +441,6 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb if (symbol && symbol->getNumExtensions()) requireExtensions(loc, symbol->getNumExtensions(), symbol->getExtensions(), symbol->getName().c_str()); -#ifndef GLSLANG_WEB if (symbol && symbol->isReadOnly()) { // All shared things containing an unsized array must be copied up // on first use, so that all future references will share its array structure, @@ -475,7 +460,6 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb makeEditable(symbol); } } -#endif const TVariable* variable; const TAnonMember* anon = symbol ? symbol->getAsAnonMember() : nullptr; @@ -502,6 +486,16 @@ TIntermTyped* TParseContext::handleVariable(const TSourceLoc& loc, TSymbol* symb error(loc, "cannot be used (maybe an instance name is needed)", string->c_str(), ""); variable = nullptr; } + + if (language == EShLangMesh && variable) { + TLayoutGeometry primitiveType = intermediate.getOutputPrimitive(); + if ((variable->getMangledName() == "gl_PrimitiveTriangleIndicesEXT" && primitiveType != ElgTriangles) || + (variable->getMangledName() == "gl_PrimitiveLineIndicesEXT" && primitiveType != ElgLines) || + (variable->getMangledName() == "gl_PrimitivePointIndicesEXT" && primitiveType != ElgPoints)) { + error(loc, "cannot be used (ouput primitive type mismatch)", string->c_str(), ""); + variable = nullptr; + } + } } else { if (symbol) error(loc, "variable name expected", string->c_str(), ""); @@ -570,7 +564,6 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn // at least one of base and index is not a front-end constant variable... TIntermTyped* result = nullptr; -#ifndef GLSLANG_WEB if (base->isReference() && ! base->isArray()) { requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "buffer reference indexing"); if (base->getType().getReferentType()->containsUnsizedArray()) { @@ -589,15 +582,22 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } if (base->getAsSymbolNode() && isIoResizeArray(base->getType())) handleIoResizeArrayAccess(loc, base); -#endif if (index->getQualifier().isFrontEndConstant()) checkIndex(loc, base->getType(), indexValue); if (index->getQualifier().isFrontEndConstant()) { -#ifndef GLSLANG_WEB if (base->getType().isUnsizedArray()) { base->getWritableType().updateImplicitArraySize(indexValue + 1); + base->getWritableType().setImplicitlySized(true); + if (base->getQualifier().builtIn == EbvClipDistance && + indexValue >= resources.maxClipDistances) { + error(loc, "gl_ClipDistance", "[", "array index out of range '%d'", indexValue); + } + else if (base->getQualifier().builtIn == EbvCullDistance && + indexValue >= resources.maxCullDistances) { + error(loc, "gl_CullDistance", "[", "array index out of range '%d'", indexValue); + } // For 2D per-view builtin arrays, update the inner dimension size in parent type if (base->getQualifier().isPerView() && base->getQualifier().builtIn != EbvNone) { TIntermBinary* binaryNode = base->getAsBinaryNode(); @@ -609,11 +609,9 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } } } else -#endif checkIndex(loc, base->getType(), indexValue); result = intermediate.addIndex(EOpIndexDirect, base, index, loc); } else { -#ifndef GLSLANG_WEB if (base->getType().isUnsizedArray()) { // we have a variable index into an unsized array, which is okay, // depending on the situation @@ -625,7 +623,6 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } base->getWritableType().setArrayVariablyIndexed(); } -#endif if (base->getBasicType() == EbtBlock) { if (base->getQualifier().storage == EvqBuffer) requireProfile(base->getLoc(), ~EEsProfile, "variable indexing buffer block array"); @@ -635,7 +632,7 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn else { // input/output blocks either don't exist or can't be variably indexed } - } else if (language == EShLangFragment && base->getQualifier().isPipeOutput()) + } else if (language == EShLangFragment && base->getQualifier().isPipeOutput() && base->getQualifier().builtIn != EbvSampleMask) requireProfile(base->getLoc(), ~EEsProfile, "variable indexing fragment shader output array"); else if (base->getBasicType() == EbtSampler && version >= 130) { const char* explanation = "variable indexing sampler array"; @@ -661,7 +658,6 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn } result->setType(newType); -#ifndef GLSLANG_WEB inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier()); // Propagate nonuniform @@ -670,13 +666,10 @@ TIntermTyped* TParseContext::handleBracketDereference(const TSourceLoc& loc, TIn if (anyIndexLimits) handleIndexLimits(loc, base, index); -#endif return result; } -#ifndef GLSLANG_WEB - // for ES 2.0 (version 100) limitations for almost all index operations except vertex-shader uniforms void TParseContext::handleIndexLimits(const TSourceLoc& /*loc*/, TIntermTyped* base, TIntermTyped* index) { @@ -716,8 +709,8 @@ bool TParseContext::isIoResizeArray(const TType& type) const (language == EShLangTessControl && type.getQualifier().storage == EvqVaryingOut && ! type.getQualifier().patch) || (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && - type.getQualifier().pervertexNV) || - (language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut && + (type.getQualifier().pervertexNV || type.getQualifier().pervertexEXT)) || + (language == EShLangMesh && type.getQualifier().storage == EvqVaryingOut && !type.getQualifier().perTaskNV)); } @@ -794,7 +787,7 @@ void TParseContext::checkIoArraysConsistency(const TSourceLoc &loc, bool tailOnl // As I/O array sizes don't change, fetch requiredSize only once, // except for mesh shaders which could have different I/O array sizes based on type qualifiers. - if (firstIteration || (language == EShLangMeshNV)) { + if (firstIteration || (language == EShLangMesh)) { requiredSize = getIoArrayImplicitSize(type.getQualifier(), &featureString); if (requiredSize == 0) break; @@ -823,7 +816,7 @@ int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString * // Number of vertices for Fragment shader is always three. expectedSize = 3; str = "vertices"; - } else if (language == EShLangMeshNV) { + } else if (language == EShLangMesh) { unsigned int maxPrimitives = intermediate.getPrimitives() != TQualifier::layoutNotSet ? intermediate.getPrimitives() : 0; if (qualifier.builtIn == EbvPrimitiveIndicesNV) { @@ -831,6 +824,11 @@ int TParseContext::getIoArrayImplicitSize(const TQualifier &qualifier, TString * str = "max_primitives*"; str += TQualifier::getGeometryString(intermediate.getOutputPrimitive()); } + else if (qualifier.builtIn == EbvPrimitiveTriangleIndicesEXT || qualifier.builtIn == EbvPrimitiveLineIndicesEXT || + qualifier.builtIn == EbvPrimitivePointIndicesEXT) { + expectedSize = maxPrimitives; + str = "max_primitives"; + } else if (qualifier.isPerPrimitive()) { expectedSize = maxPrimitives; str = "max_primitives"; @@ -856,17 +854,15 @@ void TParseContext::checkIoArrayConsistency(const TSourceLoc& loc, int requiredS error(loc, "inconsistent output number of vertices for array size of", feature, name.c_str()); else if (language == EShLangFragment) { if (type.getOuterArraySize() > requiredSize) - error(loc, " cannot be greater than 3 for pervertexNV", feature, name.c_str()); + error(loc, " cannot be greater than 3 for pervertexEXT", feature, name.c_str()); } - else if (language == EShLangMeshNV) + else if (language == EShLangMesh) error(loc, "inconsistent output array size of", feature, name.c_str()); else assert(0); } } -#endif // GLSLANG_WEB - // Handle seeing a binary node with a math operation. // Returns nullptr if not semantically allowed. TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* str, TOperator op, TIntermTyped* left, TIntermTyped* right) @@ -902,8 +898,10 @@ TIntermTyped* TParseContext::handleBinaryMath(const TSourceLoc& loc, const char* result = intermediate.addBinaryMath(op, left, right, loc); } - if (result == nullptr) - binaryOpError(loc, str, left->getCompleteString(), right->getCompleteString()); + if (result == nullptr) { + bool enhanced = intermediate.getEnhancedMsgs(); + binaryOpError(loc, str, left->getCompleteString(enhanced), right->getCompleteString(enhanced)); + } return result; } @@ -926,8 +924,10 @@ TIntermTyped* TParseContext::handleUnaryMath(const TSourceLoc& loc, const char* if (result) return result; - else - unaryOpError(loc, str, childNode->getCompleteString()); + else { + bool enhanced = intermediate.getEnhancedMsgs(); + unaryOpError(loc, str, childNode->getCompleteString(enhanced)); + } return childNode; } @@ -953,8 +953,8 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm requireProfile(loc, ~EEsProfile, feature); profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, feature); } else if (!base->getType().isCoopMat()) { - error(loc, "does not operate on this type:", field.c_str(), base->getType().getCompleteString().c_str()); - + bool enhanced = intermediate.getEnhancedMsgs(); + error(loc, "does not operate on this type:", field.c_str(), base->getType().getCompleteString(enhanced).c_str()); return base; } @@ -993,22 +993,44 @@ TIntermTyped* TParseContext::handleDotDereference(const TSourceLoc& loc, TInterm break; } } + if (fieldFound) { - if (base->getType().getQualifier().isFrontEndConstant()) - result = intermediate.foldDereference(base, member, loc); - else { - blockMemberExtensionCheck(loc, base, member, field); - TIntermTyped* index = intermediate.addConstantUnion(member, loc); - result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc); - result->setType(*(*fields)[member].type); - if ((*fields)[member].type->getQualifier().isIo()) - intermediate.addIoAccessed(field); + if (spvVersion.vulkan != 0 && spvVersion.vulkanRelaxed) + result = vkRelaxedRemapDotDereference(loc, *base, *(*fields)[member].type, field); + + if (result == base) + { + if (base->getType().getQualifier().isFrontEndConstant()) + result = intermediate.foldDereference(base, member, loc); + else { + blockMemberExtensionCheck(loc, base, member, field); + TIntermTyped* index = intermediate.addConstantUnion(member, loc); + result = intermediate.addIndex(EOpIndexDirectStruct, base, index, loc); + result->setType(*(*fields)[member].type); + if ((*fields)[member].type->getQualifier().isIo()) + intermediate.addIoAccessed(field); + } } + inheritMemoryQualifiers(base->getQualifier(), result->getWritableType().getQualifier()); - } else - error(loc, "no such field in structure", field.c_str(), ""); + } else { + auto baseSymbol = base; + while (baseSymbol->getAsSymbolNode() == nullptr) { + auto binaryNode = baseSymbol->getAsBinaryNode(); + if (binaryNode == nullptr) break; + baseSymbol = binaryNode->getLeft(); + } + if (baseSymbol->getAsSymbolNode() != nullptr) { + TString structName; + structName.append("\'").append(baseSymbol->getAsSymbolNode()->getName().c_str()).append("\'"); + error(loc, "no such field in structure", field.c_str(), structName.c_str()); + } else { + error(loc, "no such field in structure", field.c_str(), ""); + } + } } else - error(loc, "does not apply to this type:", field.c_str(), base->getType().getCompleteString().c_str()); + error(loc, "does not apply to this type:", field.c_str(), + base->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str()); // Propagate noContraction up the dereference chain if (base->getQualifier().isNoContraction()) @@ -1127,7 +1149,6 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct TSymbol* symbol = symbolTable.find(function.getMangledName(), &builtIn); if (symbol && symbol->getAsFunction() && builtIn) requireProfile(loc, ~EEsProfile, "redefinition of built-in function"); -#ifndef GLSLANG_WEB // Check the validity of using spirv_literal qualifier for (int i = 0; i < function.getParamCount(); ++i) { if (function[i].type->getQualifier().isSpirvLiteral() && function.getBuiltInOp() != EOpSpirvInst) @@ -1139,19 +1160,16 @@ TFunction* TParseContext::handleFunctionDeclarator(const TSourceLoc& loc, TFunct // respect this redeclared one. if (symbol && builtIn && function.getBuiltInOp() == EOpSpirvInst) symbol = nullptr; -#endif - const TFunction* prevDec = symbol ? symbol->getAsFunction() : 0; + const TFunction* prevDec = symbol ? symbol->getAsFunction() : nullptr; if (prevDec) { if (prevDec->isPrototyped() && prototype) profileRequires(loc, EEsProfile, 300, nullptr, "multiple prototypes for same function"); if (prevDec->getType() != function.getType()) error(loc, "overloaded functions must have the same return type", function.getName().c_str(), ""); -#ifndef GLSLANG_WEB if (prevDec->getSpirvInstruction() != function.getSpirvInstruction()) { error(loc, "overloaded functions must have the same qualifiers", function.getName().c_str(), "spirv_instruction"); } -#endif for (int i = 0; i < prevDec->getParamCount(); ++i) { if ((*prevDec)[i].type->getQualifier().storage != function[i].type->getQualifier().storage) error(loc, "overloaded functions must have the same parameter storage qualifiers for argument", function[i].type->getStorageQualifierString(), "%d", i+1); @@ -1233,6 +1251,8 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, error(loc, "function cannot take any parameter(s)", function.getName().c_str(), ""); if (function.getType().getBasicType() != EbtVoid) error(loc, "", function.getType().getBasicTypeString().c_str(), "entry point cannot return a value"); + if (function.getLinkType() != ELinkNone) + error(loc, "main function cannot be exported", "", ""); } // @@ -1269,6 +1289,7 @@ TIntermAggregate* TParseContext::handleFunctionDefinition(const TSourceLoc& loc, } else paramNodes = intermediate.growAggregate(paramNodes, intermediate.addSymbol(*param.type, loc), loc); } + paramNodes->setLinkType(function.getLinkType()); intermediate.setAggregateOperator(paramNodes, EOpParameters, TType(EbtVoid), loc); loopNestingLevel = 0; statementNestingLevel = 0; @@ -1314,14 +1335,14 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction // result = addConstructor(loc, arguments, type); if (result == nullptr) - error(loc, "cannot construct with these arguments", type.getCompleteString().c_str(), ""); + error(loc, "cannot construct with these arguments", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str(), ""); } } else { // // Find it in the symbol table. // const TFunction* fnCandidate; - bool builtIn; + bool builtIn {false}; fnCandidate = findFunction(loc, *function, builtIn); if (fnCandidate) { // This is a declared function that might map to @@ -1330,6 +1351,10 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction // - a user function. // Error check for a function requiring specific extensions present. + if (builtIn && + (fnCandidate->getBuiltInOp() == EOpSubgroupQuadAll || fnCandidate->getBuiltInOp() == EOpSubgroupQuadAny)) + requireExtensions(loc, 1, &E_GL_EXT_shader_quad_control, fnCandidate->getName().c_str()); + if (builtIn && fnCandidate->getNumExtensions()) requireExtensions(loc, fnCandidate->getNumExtensions(), fnCandidate->getExtensions(), fnCandidate->getName().c_str()); @@ -1339,7 +1364,10 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction requireInt16Arithmetic(loc, "built-in function", "(u)int16 types can only be in uniform block or buffer storage"); if (builtIn && fnCandidate->getType().contains8BitInt()) requireInt8Arithmetic(loc, "built-in function", "(u)int8 types can only be in uniform block or buffer storage"); - + if (builtIn && (fnCandidate->getBuiltInOp() == EOpTextureFetch || fnCandidate->getBuiltInOp() == EOpTextureQuerySize)) { + if ((*fnCandidate)[0].type->getSampler().isMultiSample() && version <= 140) + requireExtensions(loc, 1, &E_GL_ARB_texture_multisample, fnCandidate->getName().c_str()); + } if (arguments != nullptr) { // Make sure qualifications work for these arguments. TIntermAggregate* aggregate = arguments->getAsAggregate(); @@ -1353,7 +1381,6 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (lValueErrorCheck(arguments->getLoc(), "assign", arg->getAsTyped())) error(arguments->getLoc(), "Non-L-value cannot be passed for 'out' or 'inout' parameters.", "out", ""); } -#ifndef GLSLANG_WEB if (formalQualifier.isSpirvLiteral()) { if (!arg->getAsTyped()->getQualifier().isFrontEndConstant()) { error(arguments->getLoc(), @@ -1361,12 +1388,11 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction "spirv_literal", ""); } } -#endif const TType& argType = arg->getAsTyped()->getType(); const TQualifier& argQualifier = argType.getQualifier(); - if (argQualifier.isMemory() && (argType.containsOpaque() || argType.isReference())) { + bool containsBindlessSampler = intermediate.getBindlessMode() && argType.containsSampler(); + if (argQualifier.isMemory() && !containsBindlessSampler && (argType.containsOpaque() || argType.isReference())) { const char* message = "argument cannot drop memory qualifier when passed to formal parameter"; -#ifndef GLSLANG_WEB if (argQualifier.volatil && ! formalQualifier.volatil) error(arguments->getLoc(), message, "volatile", ""); if (argQualifier.coherent && ! (formalQualifier.devicecoherent || formalQualifier.coherent)) @@ -1386,7 +1412,6 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction // Don't check 'restrict', it is different than the rest: // "...but only restrict can be taken away from a calling argument, by a formal parameter that // lacks the restrict qualifier..." -#endif } if (!builtIn && argQualifier.getFormat() != formalQualifier.getFormat()) { // we have mismatched formats, which should only be allowed if writeonly @@ -1416,11 +1441,9 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (builtIn && fnCandidate->getBuiltInOp() != EOpNull) { // A function call mapped to a built-in operation. result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate); -#ifndef GLSLANG_WEB } else if (fnCandidate->getBuiltInOp() == EOpSpirvInst) { // When SPIR-V instruction qualifier is specified, the function call is still mapped to a built-in operation. result = handleBuiltInFunctionCall(loc, arguments, *fnCandidate); -#endif } else { // This is a function call not mapped to built-in operator. // It could still be a built-in function, but only if PureOperatorBuiltins == false. @@ -1440,11 +1463,9 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction intermediate.addToCallGraph(infoSink, currentCaller, fnCandidate->getMangledName()); } -#ifndef GLSLANG_WEB if (builtIn) nonOpBuiltInCheck(loc, *fnCandidate, *call); else -#endif userFunctionCallCheck(loc, *call); } @@ -1462,7 +1483,8 @@ TIntermTyped* TParseContext::handleFunctionCall(const TSourceLoc& loc, TFunction if (result->getAsTyped()->getType().isCoopMat() && !result->getAsTyped()->getType().isParameterized()) { - assert(fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAdd); + assert(fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAdd || + fnCandidate->getBuiltInOp() == EOpCooperativeMatrixMulAddNV); result->setType(result->getAsAggregate()->getSequence()[2]->getAsTyped()->getType()); } @@ -1494,11 +1516,10 @@ TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNo else error(arguments->getLoc(), " wrong operand type", "Internal Error", "built in unary operator function. Type: %s", - static_cast(arguments)->getCompleteString().c_str()); + static_cast(arguments)->getCompleteString(intermediate.getEnhancedMsgs()).c_str()); } else if (result->getAsOperator()) builtInOpCheck(loc, function, *result->getAsOperator()); -#ifndef GLSLANG_WEB // Special handling for function call with SPIR-V instruction qualifier specified if (function.getBuiltInOp() == EOpSpirvInst) { if (auto agg = result->getAsAggregate()) { @@ -1525,7 +1546,6 @@ TIntermTyped* TParseContext::handleBuiltInFunctionCall(TSourceLoc loc, TIntermNo } else assert(0); } -#endif return result; } @@ -1628,9 +1648,7 @@ void TParseContext::computeBuiltinPrecisions(TIntermTyped& node, const TFunction TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermTyped* value) { -#ifndef GLSLANG_WEB storage16BitAssignmentCheck(loc, value->getType(), "return"); -#endif functionReturnsValue = true; TIntermBranch* branch = nullptr; @@ -1650,9 +1668,15 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType error(loc, "type does not match, or is not convertible to, the function's return type", "return", ""); branch = intermediate.addBranch(EOpReturn, value, loc); } - } else + } else { + if (value->getType().isTexture() || value->getType().isImage()) { + if (spvVersion.spv != 0) + error(loc, "sampler or image cannot be used as return type when generating SPIR-V", "return", ""); + else if (!extensionTurnedOn(E_GL_ARB_bindless_texture)) + error(loc, "sampler or image can be used as return type only when the extension GL_ARB_bindless_texture enabled", "return", ""); + } branch = intermediate.addBranch(EOpReturn, value, loc); - + } branch->updatePrecision(currentFunctionType->getQualifier().precision); return branch; } @@ -1660,7 +1684,6 @@ TIntermNode* TParseContext::handleReturnValue(const TSourceLoc& loc, TIntermType // See if the operation is being done in an illegal location. void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op) { -#ifndef GLSLANG_WEB switch (op) { case EOpBarrier: if (language == EShLangTessControl) { @@ -1713,7 +1736,6 @@ void TParseContext::checkLocation(const TSourceLoc& loc, TOperator op) default: break; } -#endif } // Finish processing object.length(). This started earlier in handleDotDereference(), where @@ -1731,7 +1753,6 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction const TType& type = intermNode->getAsTyped()->getType(); if (type.isArray()) { if (type.isUnsizedArray()) { -#ifndef GLSLANG_WEB if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) { // We could be between a layout declaration that gives a built-in io array implicit size and // a user redeclaration of that array, meaning we have to substitute its implicit size here @@ -1742,17 +1763,19 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction name == "gl_MeshPrimitivesNV") { length = getIoArrayImplicitSize(type.getQualifier()); } + } else if (const auto typed = intermNode->getAsTyped()) { + if (typed->getQualifier().builtIn == EbvSampleMask) { + requireProfile(loc, EEsProfile, "the array size of gl_SampleMask and gl_SampleMaskIn is ceil(gl_MaxSamples/32)"); + length = (resources.maxSamples + 31) / 32; + } } -#endif if (length == 0) { -#ifndef GLSLANG_WEB if (intermNode->getAsSymbolNode() && isIoResizeArray(type)) error(loc, "", function->getName().c_str(), "array must first be sized by a redeclaration or layout qualifier"); else if (isRuntimeLength(*intermNode->getAsTyped())) { // Create a unary op and let the back end handle it return intermediate.addBuiltInFunctionCall(loc, EOpArrayLength, true, intermNode, TType(EbtInt)); } else -#endif error(loc, "", function->getName().c_str(), "array must be declared with a size before using this method"); } } else if (type.getOuterArrayNode()) { @@ -1785,7 +1808,6 @@ TIntermTyped* TParseContext::handleLengthMethod(const TSourceLoc& loc, TFunction // void TParseContext::addInputArgumentConversions(const TFunction& function, TIntermNode*& arguments) const { -#ifndef GLSLANG_WEB TIntermAggregate* aggregate = arguments->getAsAggregate(); // Process each argument's conversion @@ -1813,7 +1835,6 @@ void TParseContext::addInputArgumentConversions(const TFunction& function, TInte } } } -#endif } // @@ -1825,9 +1846,6 @@ void TParseContext::addInputArgumentConversions(const TFunction& function, TInte // TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& function, TIntermAggregate& intermNode) const { -#ifdef GLSLANG_WEB - return &intermNode; -#else TIntermSequence& arguments = intermNode.getSequence(); // Will there be any output conversions? @@ -1895,7 +1913,6 @@ TIntermTyped* TParseContext::addOutputArgumentConversions(const TFunction& funct conversionTree = intermediate.setAggregateOperator(conversionTree, EOpComma, intermNode.getType(), intermNode.getLoc()); return conversionTree; -#endif } TIntermTyped* TParseContext::addAssign(const TSourceLoc& loc, TOperator op, TIntermTyped* left, TIntermTyped* right) @@ -1903,6 +1920,9 @@ TIntermTyped* TParseContext::addAssign(const TSourceLoc& loc, TOperator op, TInt if ((op == EOpAddAssign || op == EOpSubAssign) && left->isReference()) requireExtensions(loc, 1, &E_GL_EXT_buffer_reference2, "+= and -= on a buffer reference"); + if (op == EOpAssign && left->getBasicType() == EbtSampler && right->getBasicType() == EbtSampler) + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler assignment for bindless texture"); + return intermediate.addAssign(op, left, right, loc); } @@ -1990,18 +2010,18 @@ void TParseContext::memorySemanticsCheck(const TSourceLoc& loc, const TFunction& break; } - if ((semantics & gl_SemanticsAcquire) && + if ((semantics & gl_SemanticsAcquire) && (callNode.getOp() == EOpAtomicStore || callNode.getOp() == EOpImageAtomicStore)) { error(loc, "gl_SemanticsAcquire must not be used with (image) atomic store", fnCandidate.getName().c_str(), ""); } - if ((semantics & gl_SemanticsRelease) && + if ((semantics & gl_SemanticsRelease) && (callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpImageAtomicLoad)) { error(loc, "gl_SemanticsRelease must not be used with (image) atomic load", fnCandidate.getName().c_str(), ""); } - if ((semantics & gl_SemanticsAcquireRelease) && - (callNode.getOp() == EOpAtomicStore || callNode.getOp() == EOpImageAtomicStore || + if ((semantics & gl_SemanticsAcquireRelease) && + (callNode.getOp() == EOpAtomicStore || callNode.getOp() == EOpImageAtomicStore || callNode.getOp() == EOpAtomicLoad || callNode.getOp() == EOpImageAtomicLoad)) { error(loc, "gl_SemanticsAcquireRelease must not be used with (image) atomic load/store", fnCandidate.getName().c_str(), ""); @@ -2102,7 +2122,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan TString featureString; const char* feature = nullptr; switch (callNode.getOp()) { -#ifndef GLSLANG_WEB case EOpTextureGather: case EOpTextureGatherOffset: case EOpTextureGatherOffsets: @@ -2175,6 +2194,37 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } break; } + + case EOpTexture: + case EOpTextureLod: + { + if ((fnCandidate.getParamCount() > 2) && ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) && + ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) && fnCandidate[0].type->getSampler().shadow) { + featureString = fnCandidate.getName(); + if (callNode.getOp() == EOpTexture) + featureString += "(..., float bias)"; + else + featureString += "(..., float lod)"; + feature = featureString.c_str(); + + if ((fnCandidate[0].type->getSampler().dim == Esd2D && fnCandidate[0].type->getSampler().arrayed) || //2D Array Shadow + (fnCandidate[0].type->getSampler().dim == EsdCube && fnCandidate[0].type->getSampler().arrayed && fnCandidate.getParamCount() > 3) || // Cube Array Shadow + (fnCandidate[0].type->getSampler().dim == EsdCube && callNode.getOp() == EOpTextureLod)) { // Cube Shadow + requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature); + if (isEsProfile()) { + if (version < 320 && + !extensionsTurnedOn(Num_AEP_texture_cube_map_array, AEP_texture_cube_map_array)) + error(loc, "GL_EXT_texture_shadow_lod not supported for this ES version", feature, ""); + else + profileRequires(loc, EEsProfile, 320, nullptr, feature); + } else { // Desktop + profileRequires(loc, ~EEsProfile, 130, nullptr, feature); + } + } + } + break; + } + case EOpSparseTextureGather: case EOpSparseTextureGatherOffset: case EOpSparseTextureGatherOffsets: @@ -2243,7 +2293,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan break; } -#endif case EOpTextureOffset: case EOpTextureFetchOffset: @@ -2271,12 +2320,10 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (arg > 0) { -#ifndef GLSLANG_WEB bool f16ShadowCompare = (*argp)[1]->getAsTyped()->getBasicType() == EbtFloat16 && arg0->getType().getSampler().shadow; if (f16ShadowCompare) ++arg; -#endif if (! (*argp)[arg]->getAsTyped()->getQualifier().isConstant()) error(loc, "argument must be compile-time constant", "texel offset", ""); else if ((*argp)[arg]->getAsConstantUnion()) { @@ -2292,18 +2339,41 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan if (callNode.getOp() == EOpTextureOffset) { TSampler s = arg0->getType().getSampler(); if (s.is2D() && s.isArrayed() && s.isShadow()) { - if (isEsProfile()) + if ( + ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) && + ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) && + (fnCandidate.getParamCount() == 4)) { + featureString = fnCandidate.getName() + " for sampler2DArrayShadow"; + feature = featureString.c_str(); + requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature); + profileRequires(loc, EEsProfile, 300, nullptr, feature); + profileRequires(loc, ~EEsProfile, 130, nullptr, feature); + } + else if (isEsProfile()) error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "ES Profile"); else if (version <= 420) error(loc, "TextureOffset does not support sampler2DArrayShadow : ", "sampler", "version <= 420"); } } + + if (callNode.getOp() == EOpTextureLodOffset) { + TSampler s = arg0->getType().getSampler(); + if (s.is2D() && s.isArrayed() && s.isShadow() && + ((*argp)[1]->getAsTyped()->getType().getBasicType() == EbtFloat) && + ((*argp)[1]->getAsTyped()->getType().getVectorSize() == 4) && + (fnCandidate.getParamCount() == 4)) { + featureString = fnCandidate.getName() + " for sampler2DArrayShadow"; + feature = featureString.c_str(); + profileRequires(loc, EEsProfile, 300, nullptr, feature); + profileRequires(loc, ~EEsProfile, 130, nullptr, feature); + requireExtensions(loc, 1, &E_GL_EXT_texture_shadow_lod, feature); + } + } } break; } -#ifndef GLSLANG_WEB case EOpTraceNV: if (!(*argp)[10]->getAsConstantUnion()) error(loc, "argument must be compile-time constant", "payload number", "a"); @@ -2317,7 +2387,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan error(loc, "argument must be compile-time constant", "payload number", "a"); else { unsigned int location = (*argp)[10]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); - if (intermediate.checkLocationRT(0, location) < 0) + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); } break; @@ -2330,11 +2400,84 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan error(loc, "argument must be compile-time constant", "callable data number", ""); else { unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); - if (intermediate.checkLocationRT(1, location) < 0) + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(1, location) < 0) error(loc, "with layout(location =", "no callableDataEXT/callableDataInEXT declared", "%d)", location); } break; + case EOpHitObjectTraceRayNV: + if (!(*argp)[11]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectTraceRayMotionNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectExecuteShaderNV: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "payload number", ""); + else { + unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(0, location) < 0) + error(loc, "with layout(location =", "no rayPayloadEXT/rayPayloadInEXT declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitMotionNV: + if (!(*argp)[13]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[13]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitWithIndexNV: + if (!(*argp)[11]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[11]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectRecordHitWithIndexMotionNV: + if (!(*argp)[12]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[12]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpHitObjectGetAttributesNV: + if (!(*argp)[1]->getAsConstantUnion()) + error(loc, "argument must be compile-time constant", "hitobjectattribute number", ""); + else { + unsigned int location = (*argp)[1]->getAsConstantUnion()->getAsConstantUnion()->getConstArray()[0].getUConst(); + if (!extensionTurnedOn(E_GL_EXT_spirv_intrinsics) && intermediate.checkLocationRT(2, location) < 0) + error(loc, "with layout(location =", "no hitObjectAttributeNV declared", "%d)", location); + } + break; + case EOpRayQueryGetIntersectionType: case EOpRayQueryGetIntersectionT: case EOpRayQueryGetIntersectionInstanceCustomIndex: @@ -2348,6 +2491,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan case EOpRayQueryGetIntersectionObjectRayOrigin: case EOpRayQueryGetIntersectionObjectToWorld: case EOpRayQueryGetIntersectionWorldToObject: + case EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: if (!(*argp)[1]->getAsConstantUnion()) error(loc, "argument must be compile-time constant", "committed", ""); break; @@ -2380,15 +2524,26 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan error(loc, "only supported on image with format r64i", fnCandidate.getName().c_str(), ""); else if (callNode.getType().getBasicType() == EbtUint64 && imageType.getQualifier().getFormat() != ElfR64ui) error(loc, "only supported on image with format r64ui", fnCandidate.getName().c_str(), ""); + } else if(callNode.getType().getBasicType() == EbtFloat16 && + ((callNode.getType().getVectorSize() == 2 && arg0->getType().getQualifier().getFormat() == ElfRg16f) || + (callNode.getType().getVectorSize() == 4 && arg0->getType().getQualifier().getFormat() == ElfRgba16f))) { + if (StartsWith(fnCandidate.getName(), "imageAtomicAdd") || + StartsWith(fnCandidate.getName(), "imageAtomicExchange") || + StartsWith(fnCandidate.getName(), "imageAtomicMin") || + StartsWith(fnCandidate.getName(), "imageAtomicMax")) { + requireExtensions(loc, 1, &E_GL_NV_shader_atomic_fp16_vector, fnCandidate.getName().c_str()); + } else { + error(loc, "f16vec2/4 operation not supported on: ", fnCandidate.getName().c_str(), ""); + } } else if (imageType.getSampler().type == EbtFloat) { - if (fnCandidate.getName().compare(0, 19, "imageAtomicExchange") == 0) { + if (StartsWith(fnCandidate.getName(), "imageAtomicExchange")) { // imageAtomicExchange doesn't require an extension - } else if ((fnCandidate.getName().compare(0, 14, "imageAtomicAdd") == 0) || - (fnCandidate.getName().compare(0, 15, "imageAtomicLoad") == 0) || - (fnCandidate.getName().compare(0, 16, "imageAtomicStore") == 0)) { + } else if (StartsWith(fnCandidate.getName(), "imageAtomicAdd") || + StartsWith(fnCandidate.getName(), "imageAtomicLoad") || + StartsWith(fnCandidate.getName(), "imageAtomicStore")) { requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float, fnCandidate.getName().c_str()); - } else if ((fnCandidate.getName().compare(0, 14, "imageAtomicMin") == 0) || - (fnCandidate.getName().compare(0, 14, "imageAtomicMax") == 0)) { + } else if (StartsWith(fnCandidate.getName(), "imageAtomicMin") || + StartsWith(fnCandidate.getName(), "imageAtomicMax")) { requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); } else { error(loc, "only supported on integer images", fnCandidate.getName().c_str(), ""); @@ -2438,6 +2593,11 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan const char* const extensions[2] = { E_GL_NV_shader_atomic_int64, E_GL_EXT_shader_atomic_int64 }; requireExtensions(loc, 2, extensions, fnCandidate.getName().c_str()); + } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange || + callNode.getOp() == EOpAtomicMin || callNode.getOp() == EOpAtomicMax) && + arg0->getType().getBasicType() == EbtFloat16 && + (arg0->getType().getVectorSize() == 2 || arg0->getType().getVectorSize() == 4 )) { + requireExtensions(loc, 1, &E_GL_NV_shader_atomic_fp16_vector, fnCandidate.getName().c_str()); } else if ((callNode.getOp() == EOpAtomicAdd || callNode.getOp() == EOpAtomicExchange) && (arg0->getType().getBasicType() == EbtFloat || arg0->getType().getBasicType() == EbtDouble)) { @@ -2449,12 +2609,19 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan requireExtensions(loc, 1, &E_GL_EXT_shader_atomic_float2, fnCandidate.getName().c_str()); } - const TIntermTyped* base = TIntermediate::findLValueBase(arg0, true , true); - const TType* refType = (base->getType().isReference()) ? base->getType().getReferentType() : nullptr; - const TQualifier& qualifier = (refType != nullptr) ? refType->getQualifier() : base->getType().getQualifier(); - if (qualifier.storage != EvqShared && qualifier.storage != EvqBuffer) - error(loc,"Atomic memory function can only be used for shader storage block member or shared variable.", - fnCandidate.getName().c_str(), ""); + const TIntermTyped* base = TIntermediate::traverseLValueBase(arg0, true, true); + const char* errMsg = "Only l-values corresponding to shader block storage or shared variables can be used with " + "atomic memory functions."; + if (base) { + const TType* refType = (base->getType().isReference()) ? base->getType().getReferentType() : nullptr; + const TQualifier& qualifier = + (refType != nullptr) ? refType->getQualifier() : base->getType().getQualifier(); + if (qualifier.storage != EvqShared && qualifier.storage != EvqBuffer && + qualifier.storage != EvqtaskPayloadSharedEXT) + error(loc, errMsg, fnCandidate.getName().c_str(), ""); + } else { + error(loc, errMsg, fnCandidate.getName().c_str(), ""); + } break; } @@ -2462,20 +2629,57 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan case EOpInterpolateAtCentroid: case EOpInterpolateAtSample: case EOpInterpolateAtOffset: - case EOpInterpolateAtVertex: - // Make sure the first argument is an interpolant, or an array element of an interpolant + case EOpInterpolateAtVertex: { if (arg0->getType().getQualifier().storage != EvqVaryingIn) { - // It might still be an array element. + // Traverse down the left branch of arg0 to ensure this argument is a valid interpolant. // - // We could check more, but the semantics of the first argument are already met; the - // only way to turn an array into a float/vec* is array dereference and swizzle. + // For desktop GL >4.3 we effectively only need to ensure that arg0 represents an l-value from an + // input declaration. // - // ES and desktop 4.3 and earlier: swizzles may not be used - // desktop 4.4 and later: swizzles may be used - bool swizzleOkay = (!isEsProfile()) && (version >= 440); - const TIntermTyped* base = TIntermediate::findLValueBase(arg0, swizzleOkay); - if (base == nullptr || base->getType().getQualifier().storage != EvqVaryingIn) - error(loc, "first argument must be an interpolant, or interpolant-array element", fnCandidate.getName().c_str(), ""); + // For desktop GL <= 4.3 and ES, we must also ensure that swizzling is not used + // + // For ES, we must also ensure that a field selection operator (i.e., '.') is not used on a named + // struct. + + const bool esProfile = isEsProfile(); + const bool swizzleOkay = !esProfile && (version >= 440); + + std::string interpolantErrorMsg = "first argument must be an interpolant, or interpolant-array element"; + bool isValid = true; // Assume that the interpolant is valid until we find a condition making it invalid + bool isIn = false; // Checks whether or not the interpolant is a shader input + bool structAccessOp = false; // Whether or not the previous node in the chain is a struct accessor + TIntermediate::traverseLValueBase( + arg0, swizzleOkay, false, + [&isValid, &isIn, &interpolantErrorMsg, esProfile, &structAccessOp](const TIntermNode& n) -> bool { + auto* type = n.getAsTyped(); + if (type) { + if (type->getType().getQualifier().storage == EvqVaryingIn) { + isIn = true; + } + // If a field accessor was used, it can only be used to access a field with an input block, not a struct. + if (structAccessOp && (type->getType().getBasicType() != EbtBlock)) { + interpolantErrorMsg += + ". Using the field of a named struct as an interpolant argument is not " + "allowed (ES-only)."; + isValid = false; + } + } + + // ES has different requirements for interpolants than GL + if (esProfile) { + // Swizzling will be taken care of by the 'swizzleOkay' argument passsed to traverseLValueBase, + // so we only ned to check whether or not a field accessor has been used with a named struct. + auto* binary = n.getAsBinaryNode(); + if (binary && (binary->getOp() == EOpIndexDirectStruct)) { + structAccessOp = true; + } + } + // Don't continue traversing if we know we have an invalid interpolant at this point. + return isValid; + }); + if (!isIn || !isValid) { + error(loc, interpolantErrorMsg.c_str(), fnCandidate.getName().c_str(), ""); + } } if (callNode.getOp() == EOpInterpolateAtVertex) { @@ -2491,10 +2695,12 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } } } - break; + } break; case EOpEmitStreamVertex: case EOpEndStreamPrimitive: + if (version == 150) + requireExtensions(loc, 1, &E_GL_ARB_gpu_shader5, "if the verison is 150 , the EmitStreamVertex and EndStreamPrimitive only support at extension GL_ARB_gpu_shader5"); intermediate.setMultiStream(); break; @@ -2548,7 +2754,7 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } if (profile != EEsProfile && version < 450) { - if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat && + if ((*argp)[0]->getAsTyped()->getBasicType() != EbtFloat && (*argp)[0]->getAsTyped()->getBasicType() != EbtDouble && (*argp)[1]->getAsTyped()->getBasicType() != EbtFloat && (*argp)[1]->getAsTyped()->getBasicType() != EbtDouble && @@ -2558,7 +2764,6 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan } break; -#endif default: break; @@ -2597,32 +2802,30 @@ void TParseContext::builtInOpCheck(const TSourceLoc& loc, const TFunction& fnCan // Check that if extended types are being used that the correct extensions are enabled. if (arg0 != nullptr) { const TType& type = arg0->getType(); + bool enhanced = intermediate.getEnhancedMsgs(); switch (type.getBasicType()) { default: break; case EbtInt8: case EbtUint8: - requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int8, type.getCompleteString().c_str()); + requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int8, type.getCompleteString(enhanced).c_str()); break; case EbtInt16: case EbtUint16: - requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int16, type.getCompleteString().c_str()); + requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int16, type.getCompleteString(enhanced).c_str()); break; case EbtInt64: case EbtUint64: - requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int64, type.getCompleteString().c_str()); + requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_int64, type.getCompleteString(enhanced).c_str()); break; case EbtFloat16: - requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_float16, type.getCompleteString().c_str()); + requireExtensions(loc, 1, &E_GL_EXT_shader_subgroup_extended_types_float16, type.getCompleteString(enhanced).c_str()); break; } } } } -#ifndef GLSLANG_WEB - -extern bool PureOperatorBuiltins; // Deprecated! Use PureOperatorBuiltins == true instead, in which case this // functionality is handled in builtInOpCheck() instead of here. @@ -2748,8 +2951,6 @@ void TParseContext::nonOpBuiltInCheck(const TSourceLoc& loc, const TFunction& fn } } -#endif - // // Do any extra checking for a user function call. // @@ -2783,10 +2984,21 @@ TFunction* TParseContext::handleConstructorCall(const TSourceLoc& loc, const TPu profileRequires(loc, EEsProfile, 300, nullptr, "arrayed constructor"); } + // Reuse EOpConstructTextureSampler for bindless image constructor + // uvec2 imgHandle; + // imageLoad(image1D(imgHandle), 0); + if (type.isImage() && extensionTurnedOn(E_GL_ARB_bindless_texture)) + { + intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc); + } + TOperator op = intermediate.mapTypeToConstructorOp(type); if (op == EOpNull) { - error(loc, "cannot construct this type", type.getBasicString(), ""); + if (intermediate.getEnhancedMsgs() && type.getBasicType() == EbtSampler) + error(loc, "function not supported in this version; use texture() instead", "texture*D*", ""); + else + error(loc, "cannot construct this type", type.getBasicString(), ""); op = EOpConstructFloat; TType errorType(EbtFloat); type.shallowCopy(errorType); @@ -2897,7 +3109,6 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt bool errorReturn = false; switch(binaryNode->getOp()) { -#ifndef GLSLANG_WEB case EOpIndexDirect: case EOpIndexIndirect: // ... tessellation control shader ... @@ -2914,7 +3125,6 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt } } break; // left node is checked by base class -#endif case EOpVectorSwizzle: errorReturn = lValueErrorCheck(loc, op, binaryNode->getLeft()); if (!errorReturn) { @@ -2972,7 +3182,17 @@ bool TParseContext::lValueErrorCheck(const TSourceLoc& loc, const char* op, TInt if (isEsProfile() && intermediate.getEarlyFragmentTests()) message = "can't modify gl_FragDepth if using early_fragment_tests"; break; + case EvqFragStencil: + intermediate.setStencilReplacing(); + // "In addition, it is an error to statically write to gl_FragDepth in the fragment shader." + if (isEsProfile() && intermediate.getEarlyFragmentTests()) + message = "can't modify EvqFragStencil if using early_fragment_tests"; + break; + case EvqtaskPayloadSharedEXT: + if (language == EShLangMesh) + message = "can't modify variable with storage qualifier taskPayloadSharedEXT in mesh shaders"; + break; default: break; } @@ -3011,7 +3231,7 @@ void TParseContext::rValueErrorCheck(const TSourceLoc& loc, const char* op, TInt if (symNode && symNode->getQualifier().isExplicitInterpolation()) error(loc, "can't read from explicitly-interpolated object: ", op, symNode->getName().c_str()); - // local_size_{xyz} must be assigned or specialized before gl_WorkGroupSize can be assigned. + // local_size_{xyz} must be assigned or specialized before gl_WorkGroupSize can be assigned. if(node->getQualifier().builtIn == EbvWorkGroupSize && !(intermediate.isLocalSizeSet() || intermediate.isLocalSizeSpecialized())) error(loc, "can't read from gl_WorkGroupSize before a fixed workgroup size has been declared", op, ""); @@ -3099,7 +3319,7 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden ppWarn(loc, "\"defined\" is (un)defined:", op, identifier); else ppError(loc, "\"defined\" can't be (un)defined:", op, identifier); - else if (strstr(identifier, "__") != 0 && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { + else if (strstr(identifier, "__") != nullptr && !extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) { // The extension GL_EXT_spirv_intrinsics allows us to declare macros prefixed with "__". if (isEsProfile() && version >= 300 && (strcmp(identifier, "__LINE__") == 0 || @@ -3122,10 +3342,6 @@ void TParseContext::reservedPpErrorCheck(const TSourceLoc& loc, const char* iden // bool TParseContext::lineContinuationCheck(const TSourceLoc& loc, bool endOfComment) { -#ifdef GLSLANG_WEB - return true; -#endif - const char* message = "line continuation"; bool lineContinuationAllowed = (isEsProfile() && version >= 300) || @@ -3182,7 +3398,6 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // it, in which case the type comes from the argument instead of from the // constructor function. switch (op) { -#ifndef GLSLANG_WEB case EOpConstructNonuniform: if (node != nullptr && node->getAsTyped() != nullptr) { type.shallowCopy(node->getAsTyped()->getType()); @@ -3190,12 +3405,17 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T type.getQualifier().nonUniform = true; } break; -#endif default: type.shallowCopy(function.getType()); break; } + TString constructorString; + if (intermediate.getEnhancedMsgs()) + constructorString.append(type.getCompleteString(true, false, false, true)).append(" constructor"); + else + constructorString.append("constructor"); + // See if it's a matrix bool constructingMatrix = false; switch (op) { @@ -3210,7 +3430,6 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructMat4x2: case EOpConstructMat4x3: case EOpConstructMat4x4: -#ifndef GLSLANG_WEB case EOpConstructDMat2x2: case EOpConstructDMat2x3: case EOpConstructDMat2x4: @@ -3229,7 +3448,6 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructF16Mat4x2: case EOpConstructF16Mat4x3: case EOpConstructF16Mat4x4: -#endif constructingMatrix = true; break; default: @@ -3253,7 +3471,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T if (function[arg].type->isArray()) { if (function[arg].type->isUnsizedArray()) { // Can't construct from an unsized array. - error(loc, "array argument must be sized", "constructor", ""); + error(loc, "array argument must be sized", constructorString.c_str(), ""); return true; } arrayArg = true; @@ -3283,29 +3501,28 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T intArgument = true; if (type.isStruct()) { if (function[arg].type->contains16BitFloat()) { - requireFloat16Arithmetic(loc, "constructor", "can't construct structure containing 16-bit type"); + requireFloat16Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 16-bit type"); } if (function[arg].type->contains16BitInt()) { - requireInt16Arithmetic(loc, "constructor", "can't construct structure containing 16-bit type"); + requireInt16Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 16-bit type"); } if (function[arg].type->contains8BitInt()) { - requireInt8Arithmetic(loc, "constructor", "can't construct structure containing 8-bit type"); + requireInt8Arithmetic(loc, constructorString.c_str(), "can't construct structure containing 8-bit type"); } } } if (op == EOpConstructNonuniform) constType = false; -#ifndef GLSLANG_WEB switch (op) { case EOpConstructFloat16: case EOpConstructF16Vec2: case EOpConstructF16Vec3: case EOpConstructF16Vec4: if (type.isArray()) - requireFloat16Arithmetic(loc, "constructor", "16-bit arrays not supported"); + requireFloat16Arithmetic(loc, constructorString.c_str(), "16-bit arrays not supported"); if (type.isVector() && function.getParamCount() != 1) - requireFloat16Arithmetic(loc, "constructor", "16-bit vectors only take vector types"); + requireFloat16Arithmetic(loc, constructorString.c_str(), "16-bit vectors only take vector types"); break; case EOpConstructUint16: case EOpConstructU16Vec2: @@ -3316,9 +3533,9 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructI16Vec3: case EOpConstructI16Vec4: if (type.isArray()) - requireInt16Arithmetic(loc, "constructor", "16-bit arrays not supported"); + requireInt16Arithmetic(loc, constructorString.c_str(), "16-bit arrays not supported"); if (type.isVector() && function.getParamCount() != 1) - requireInt16Arithmetic(loc, "constructor", "16-bit vectors only take vector types"); + requireInt16Arithmetic(loc, constructorString.c_str(), "16-bit vectors only take vector types"); break; case EOpConstructUint8: case EOpConstructU8Vec2: @@ -3329,14 +3546,13 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructI8Vec3: case EOpConstructI8Vec4: if (type.isArray()) - requireInt8Arithmetic(loc, "constructor", "8-bit arrays not supported"); + requireInt8Arithmetic(loc, constructorString.c_str(), "8-bit arrays not supported"); if (type.isVector() && function.getParamCount() != 1) - requireInt8Arithmetic(loc, "constructor", "8-bit vectors only take vector types"); + requireInt8Arithmetic(loc, constructorString.c_str(), "8-bit vectors only take vector types"); break; default: break; } -#endif // inherit constness from children if (constType) { @@ -3357,7 +3573,6 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructUVec2: case EOpConstructUVec3: case EOpConstructUVec4: -#ifndef GLSLANG_WEB case EOpConstructUint8: case EOpConstructInt16: case EOpConstructUint16: @@ -3381,7 +3596,6 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T case EOpConstructU64Vec2: case EOpConstructU64Vec3: case EOpConstructU64Vec4: -#endif // This was the list of valid ones, if they aren't converting from float // and aren't making an array. makeSpecConst = ! floatArgument && ! type.isArray(); @@ -3413,7 +3627,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T if (type.isArray()) { if (function.getParamCount() == 0) { - error(loc, "array constructor must have at least one argument", "constructor", ""); + error(loc, "array constructor must have at least one argument", constructorString.c_str(), ""); return true; } @@ -3421,7 +3635,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // auto adapt the constructor type to the number of arguments type.changeOuterArraySize(function.getParamCount()); } else if (type.getOuterArraySize() != function.getParamCount()) { - error(loc, "array constructor needs one argument per array element", "constructor", ""); + error(loc, "array constructor needs one argument per array element", constructorString.c_str(), ""); return true; } @@ -3434,7 +3648,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // At least the dimensionalities have to match. if (! function[0].type->isArray() || arraySizes.getNumDims() != function[0].type->getArraySizes()->getNumDims() + 1) { - error(loc, "array constructor argument not correct type to construct array element", "constructor", ""); + error(loc, "array constructor argument not correct type to construct array element", constructorString.c_str(), ""); return true; } @@ -3451,7 +3665,7 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T } if (arrayArg && op != EOpConstructStruct && ! type.isArrayOfArrays()) { - error(loc, "constructing non-array constituent from array argument", "constructor", ""); + error(loc, "constructing non-array constituent from array argument", constructorString.c_str(), ""); return true; } @@ -3461,51 +3675,62 @@ bool TParseContext::constructorError(const TSourceLoc& loc, TIntermNode* node, T // "If a matrix argument is given to a matrix constructor, // it is a compile-time error to have any other arguments." if (function.getParamCount() != 1) - error(loc, "matrix constructed from matrix can only have one argument", "constructor", ""); + error(loc, "matrix constructed from matrix can only have one argument", constructorString.c_str(), ""); return false; } if (overFull) { - error(loc, "too many arguments", "constructor", ""); + error(loc, "too many arguments", constructorString.c_str(), ""); return true; } if (op == EOpConstructStruct && ! type.isArray() && (int)type.getStruct()->size() != function.getParamCount()) { - error(loc, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); + error(loc, "Number of constructor parameters does not match the number of structure fields", constructorString.c_str(), ""); return true; } if ((op != EOpConstructStruct && size != 1 && size < type.computeNumComponents()) || (op == EOpConstructStruct && size < type.computeNumComponents())) { - error(loc, "not enough data provided for construction", "constructor", ""); + error(loc, "not enough data provided for construction", constructorString.c_str(), ""); return true; } if (type.isCoopMat() && function.getParamCount() != 1) { - error(loc, "wrong number of arguments", "constructor", ""); + error(loc, "wrong number of arguments", constructorString.c_str(), ""); return true; } if (type.isCoopMat() && !(function[0].type->isScalar() || function[0].type->isCoopMat())) { - error(loc, "Cooperative matrix constructor argument must be scalar or cooperative matrix", "constructor", ""); + error(loc, "Cooperative matrix constructor argument must be scalar or cooperative matrix", constructorString.c_str(), ""); return true; } TIntermTyped* typed = node->getAsTyped(); + if (type.isCoopMat() && typed->getType().isCoopMat() && + !type.sameCoopMatShapeAndUse(typed->getType())) { + error(loc, "Cooperative matrix type parameters mismatch", constructorString.c_str(), ""); + return true; + } + if (typed == nullptr) { - error(loc, "constructor argument does not have a type", "constructor", ""); + error(loc, "constructor argument does not have a type", constructorString.c_str(), ""); return true; } if (op != EOpConstructStruct && op != EOpConstructNonuniform && typed->getBasicType() == EbtSampler) { - error(loc, "cannot convert a sampler", "constructor", ""); - return true; + if (op == EOpConstructUVec2 && extensionTurnedOn(E_GL_ARB_bindless_texture)) { + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc); + } + else { + error(loc, "cannot convert a sampler", constructorString.c_str(), ""); + return true; + } } if (op != EOpConstructStruct && typed->isAtomic()) { - error(loc, "cannot convert an atomic_uint", "constructor", ""); + error(loc, "cannot convert an atomic_uint", constructorString.c_str(), ""); return true; } if (typed->getBasicType() == EbtVoid) { - error(loc, "cannot convert a void", "constructor", ""); + error(loc, "cannot convert a void", constructorString.c_str(), ""); return true; } @@ -3518,6 +3743,26 @@ bool TParseContext::constructorTextureSamplerError(const TSourceLoc& loc, const { TString constructorName = function.getType().getBasicTypeString(); // TODO: performance: should not be making copy; interface needs to change const char* token = constructorName.c_str(); + // verify the constructor for bindless texture, the input must be ivec2 or uvec2 + if (function.getParamCount() == 1) { + TType* pType = function[0].type; + TBasicType basicType = pType->getBasicType(); + bool isIntegerVec2 = ((basicType == EbtUint || basicType == EbtInt) && pType->getVectorSize() == 2); + bool bindlessMode = extensionTurnedOn(E_GL_ARB_bindless_texture); + if (isIntegerVec2 && bindlessMode) { + if (pType->getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeFunc); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeFunc); + return false; + } else { + if (!bindlessMode) + error(loc, "sampler-constructor requires the extension GL_ARB_bindless_texture enabled", token, ""); + else + error(loc, "sampler-constructor requires the input to be ivec2 or uvec2", token, ""); + return true; + } + } // exactly two arguments needed if (function.getParamCount() != 2) { @@ -3613,18 +3858,38 @@ void TParseContext::samplerCheck(const TSourceLoc& loc, const TType& type, const if (type.getQualifier().storage == EvqUniform) return; - if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler)) - error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str()); + if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtSampler)) { + // For bindless texture, sampler can be declared as an struct member + if (extensionTurnedOn(E_GL_ARB_bindless_texture)) { + if (type.getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar); + } + else { + error(loc, "non-uniform struct contains a sampler or image:", type.getBasicTypeString().c_str(), identifier.c_str()); + } + } else if (type.getBasicType() == EbtSampler && type.getQualifier().storage != EvqUniform) { - // non-uniform sampler - // not yet: okay if it has an initializer - // if (! initializer) - error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + // For bindless texture, sampler can be declared as an input/output/block member + if (extensionTurnedOn(E_GL_ARB_bindless_texture)) { + if (type.getSampler().isImage()) + intermediate.setBindlessImageMode(currentCaller, AstRefTypeVar); + else + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeVar); + } + else { + // non-uniform sampler + // not yet: okay if it has an initializer + // if (! initializer) + if (type.getSampler().isAttachmentEXT() && type.getQualifier().storage != EvqTileImageEXT) + error(loc, "can only be used in tileImageEXT variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + else if (type.getQualifier().storage != EvqTileImageEXT) + error(loc, "sampler/image types can only be used in uniform variables or function parameters:", type.getBasicTypeString().c_str(), identifier.c_str()); + } } } -#ifndef GLSLANG_WEB - void TParseContext::atomicUintCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) { if (type.getQualifier().storage == EvqUniform) @@ -3649,8 +3914,6 @@ void TParseContext::accStructCheck(const TSourceLoc& loc, const TType& type, con } -#endif // GLSLANG_WEB - void TParseContext::transparentOpaqueCheck(const TSourceLoc& loc, const TType& type, const TString& identifier) { if (parsingBuiltins) @@ -3685,7 +3948,7 @@ void TParseContext::memberQualifierCheck(glslang::TPublicType& publicType) // // Check/fix just a full qualifier (no variables or types yet, but qualifier is complete) at global level. // -void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck) +void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& qualifier, bool isMemberCheck, const TPublicType* publicType) { bool nonuniformOkay = false; @@ -3721,6 +3984,11 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q { requireExtensions(loc, 1, &E_GL_EXT_scalar_block_layout, "default std430 layout for uniform"); } + + if (publicType != nullptr && publicType->isImage() && + (qualifier.layoutFormat > ElfExtSizeGuard && qualifier.layoutFormat < ElfCount)) + qualifier.layoutFormat = mapLegacyLayoutFormat(qualifier.layoutFormat, publicType->sampler.getBasicType()); + break; default: break; @@ -3729,17 +3997,27 @@ void TParseContext::globalQualifierFixCheck(const TSourceLoc& loc, TQualifier& q if (!nonuniformOkay && qualifier.isNonUniform()) error(loc, "for non-parameter, can only apply to 'in' or no storage qualifier", "nonuniformEXT", ""); -#ifndef GLSLANG_WEB if (qualifier.isSpirvByReference()) error(loc, "can only apply to parameter", "spirv_by_reference", ""); if (qualifier.isSpirvLiteral()) error(loc, "can only apply to parameter", "spirv_literal", ""); -#endif // Storage qualifier isn't ready for memberQualifierCheck, we should skip invariantCheck for it. if (!isMemberCheck || structNestingLevel > 0) invariantCheck(loc, qualifier); + + if (qualifier.isFullQuads()) { + if (qualifier.storage != EvqVaryingIn) + error(loc, "can only apply to input layout", "full_quads ", ""); + intermediate.setReqFullQuadsMode(); + } + + if (qualifier.isQuadDeriv()) { + if (qualifier.storage != EvqVaryingIn) + error(loc, "can only apply to input layout", "quad_derivatives", ""); + intermediate.setQuadDerivMode(); + } } // @@ -3781,10 +4059,12 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali return; } - if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) - profileRequires(loc, EEsProfile, 300, nullptr, "shader input/output"); + if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble) { + profileRequires(loc, EEsProfile, 300, nullptr, "non-float shader input/output"); + profileRequires(loc, ~EEsProfile, 130, nullptr, "non-float shader input/output"); + } - if (!qualifier.flat && !qualifier.isExplicitInterpolation() && !qualifier.isPervertexNV()) { + if (!qualifier.flat && !qualifier.isExplicitInterpolation() && !qualifier.isPervertexNV() && !qualifier.isPervertexEXT()) { if (isTypeInt(publicType.basicType) || publicType.basicType == EbtDouble || (publicType.userDef && ( publicType.userDef->containsBasicType(EbtInt) @@ -3803,6 +4083,9 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali if (qualifier.isPatch() && qualifier.isInterpolation()) error(loc, "cannot use interpolation qualifiers with patch", "patch", ""); + if (qualifier.isTaskPayload() && publicType.basicType == EbtBlock) + error(loc, "taskPayloadSharedEXT variables should not be declared as interface blocks", "taskPayloadSharedEXT", ""); + if (qualifier.isTaskMemory() && publicType.basicType != EbtBlock) error(loc, "taskNV variables can be declared only as blocks", "taskNV", ""); @@ -3810,7 +4093,7 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali switch (language) { case EShLangVertex: if (publicType.basicType == EbtStruct) { - error(loc, "cannot be a structure or array", GetStorageQualifierString(qualifier.storage), ""); + error(loc, "cannot be a structure", GetStorageQualifierString(qualifier.storage), ""); return; } if (publicType.arraySizes) { @@ -3836,12 +4119,10 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali if (! symbolTable.atBuiltInLevel()) error(loc, "global storage input qualifier cannot be used in a compute shader", "in", ""); break; -#ifndef GLSLANG_WEB case EShLangTessControl: if (qualifier.patch) error(loc, "can only use on output in tessellation-control shader", "patch", ""); break; -#endif default: break; } @@ -3880,12 +4161,10 @@ void TParseContext::globalQualifierTypeCheck(const TSourceLoc& loc, const TQuali case EShLangCompute: error(loc, "global storage output qualifier cannot be used in a compute shader", "out", ""); break; -#ifndef GLSLANG_WEB case EShLangTessEvaluation: if (qualifier.patch) error(loc, "can only use on input in tessellation-evaluation shader", "patch", ""); break; -#endif default: break; } @@ -3953,17 +4232,16 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons if (dst.precision == EpqNone || (force && src.precision != EpqNone)) dst.precision = src.precision; -#ifndef GLSLANG_WEB if (!force && ((src.coherent && (dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || (src.devicecoherent && (dst.coherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || (src.queuefamilycoherent && (dst.coherent || dst.devicecoherent || dst.workgroupcoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || (src.workgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.subgroupcoherent || dst.shadercallcoherent)) || (src.subgroupcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.shadercallcoherent)) || (src.shadercallcoherent && (dst.coherent || dst.devicecoherent || dst.queuefamilycoherent || dst.workgroupcoherent || dst.subgroupcoherent)))) { - error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent/shadercallcoherent qualifier allowed", + error(loc, "only one coherent/devicecoherent/queuefamilycoherent/workgroupcoherent/subgroupcoherent/shadercallcoherent qualifier allowed", GetPrecisionQualifierString(src.precision), ""); } -#endif + // Layout qualifiers mergeObjectLayoutQualifiers(dst, src, false); @@ -3975,7 +4253,6 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(smooth); MERGE_SINGLETON(flat); MERGE_SINGLETON(specConstant); -#ifndef GLSLANG_WEB MERGE_SINGLETON(noContraction); MERGE_SINGLETON(nopersp); MERGE_SINGLETON(explicitInterp); @@ -3996,15 +4273,13 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons MERGE_SINGLETON(readonly); MERGE_SINGLETON(writeonly); MERGE_SINGLETON(nonUniform); -#endif -#ifndef GLSLANG_WEB // SPIR-V storage class qualifier (GL_EXT_spirv_intrinsics) dst.spirvStorageClass = src.spirvStorageClass; // SPIR-V decorate qualifiers (GL_EXT_spirv_intrinsics) - if (src.hasSprivDecorate()) { - if (dst.hasSprivDecorate()) { + if (src.hasSpirvDecorate()) { + if (dst.hasSpirvDecorate()) { const TSpirvDecorate& srcSpirvDecorate = src.getSpirvDecorate(); TSpirvDecorate& dstSpirvDecorate = dst.getSpirvDecorate(); for (auto& decorate : srcSpirvDecorate.decorates) { @@ -4025,13 +4300,12 @@ void TParseContext::mergeQualifiers(const TSourceLoc& loc, TQualifier& dst, cons if (dstSpirvDecorate.decorates.find(decorateString.first) != dstSpirvDecorate.decorates.end()) error(loc, "too many SPIR-V decorate qualifiers", "spirv_decorate_string", "(decoration=%u)", decorateString.first); else - dstSpirvDecorate.decorates.insert(decorateString); + dstSpirvDecorate.decorateStrings.insert(decorateString); } } else { dst.spirvDecorate = src.spirvDecorate; } } -#endif if (repeated) error(loc, "replicated qualifiers", "", ""); @@ -4095,17 +4369,18 @@ TPrecisionQualifier TParseContext::getDefaultPrecision(TPublicType& publicType) return defaultPrecision[publicType.basicType]; } -void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType baseType, TQualifier& qualifier) +void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType baseType, TQualifier& qualifier, bool isCoopMat) { // Built-in symbols are allowed some ambiguous precisions, to be pinned down // later by context. if (! obeyPrecisionQualifiers() || parsingBuiltins) return; -#ifndef GLSLANG_WEB if (baseType == EbtAtomicUint && qualifier.precision != EpqNone && qualifier.precision != EpqHigh) error(loc, "atomic counters can only be highp", "atomic_uint", ""); -#endif + + if (isCoopMat) + return; if (baseType == EbtFloat || baseType == EbtUint || baseType == EbtInt || baseType == EbtSampler || baseType == EbtAtomicUint) { if (qualifier.precision == EpqNone) { @@ -4122,7 +4397,7 @@ void TParseContext::precisionQualifierCheck(const TSourceLoc& loc, TBasicType ba void TParseContext::parameterTypeCheck(const TSourceLoc& loc, TStorageQualifier qualifier, const TType& type) { - if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque()) + if ((qualifier == EvqOut || qualifier == EvqInOut) && type.isOpaque() && !intermediate.getBindlessMode()) error(loc, "samplers and atomic_uints cannot be output parameters", type.getBasicTypeString().c_str(), ""); if (!parsingBuiltins && type.contains16BitFloat()) requireFloat16Arithmetic(loc, type.getBasicTypeString().c_str(), "float16 types can only be in uniform block or buffer storage"); @@ -4151,7 +4426,8 @@ bool TParseContext::containsFieldWithBasicType(const TType& type, TBasicType bas // // Do size checking for an array type's size. // -void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair, const char *sizeType) +void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TArraySize& sizePair, + const char* sizeType, const bool allowZero) { bool isConst = false; sizePair.node = nullptr; @@ -4171,9 +4447,8 @@ void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TA TIntermSymbol* symbol = expr->getAsSymbolNode(); if (symbol && symbol->getConstArray().size() > 0) size = symbol->getConstArray()[0].getIConst(); - } else if (expr->getAsUnaryNode() && - expr->getAsUnaryNode()->getOp() == glslang::EOpArrayLength && - expr->getAsUnaryNode()->getOperand()->getType().isCoopMat()) { + } else if (expr->getAsUnaryNode() && expr->getAsUnaryNode()->getOp() == glslang::EOpArrayLength && + expr->getAsUnaryNode()->getOperand()->getType().isCoopMatNV()) { isConst = true; size = 1; sizePair.node = expr->getAsUnaryNode(); @@ -4187,9 +4462,16 @@ void TParseContext::arraySizeCheck(const TSourceLoc& loc, TIntermTyped* expr, TA return; } - if (size <= 0) { - error(loc, sizeType, "", "must be a positive integer"); - return; + if (allowZero) { + if (size < 0) { + error(loc, sizeType, "", "must be a non-negative integer"); + return; + } + } else { + if (size <= 0) { + error(loc, sizeType, "", "must be a positive integer"); + return; + } } } @@ -4287,8 +4569,6 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua (qualifier.storage != EvqTemporary && qualifier.storage != EvqGlobal && qualifier.storage != EvqShared && qualifier.storage != EvqConst)) error(loc, "only outermost dimension of an array of arrays can be a specialization constant", "[]", ""); -#ifndef GLSLANG_WEB - // desktop always allows outer-dimension-unsized variable arrays, if (!isEsProfile()) return; @@ -4318,18 +4598,16 @@ void TParseContext::arraySizesCheck(const TSourceLoc& loc, const TQualifier& qua extensionsTurnedOn(Num_AEP_tessellation_shader, AEP_tessellation_shader)) return; break; - case EShLangMeshNV: + case EShLangMesh: if (qualifier.storage == EvqVaryingOut) if ((isEsProfile() && version >= 320) || - extensionTurnedOn(E_GL_NV_mesh_shader)) + extensionsTurnedOn(Num_AEP_mesh_shader, AEP_mesh_shader)) return; break; default: break; } -#endif - // last member of ssbo block exception: if (qualifier.storage == EvqBuffer && lastMember) return; @@ -4374,7 +4652,6 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie if (symbolTable.atGlobalLevel()) trackLinkage(*symbol); -#ifndef GLSLANG_WEB if (! symbolTable.atBuiltInLevel()) { if (isIoResizeArray(type)) { ioArraySymbolResizeList.push_back(symbol); @@ -4382,7 +4659,6 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie } else fixIoArraySize(loc, symbol->getWritableType()); } -#endif return; } @@ -4420,7 +4696,6 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie return; } -#ifndef GLSLANG_WEB if (existingType.isSizedArray()) { // be more leniant for input arrays to geometry shaders and tessellation control outputs, where the redeclaration is the same size if (! (isIoResizeArray(type) && existingType.getOuterArraySize() == type.getOuterArraySize())) @@ -4434,11 +4709,8 @@ void TParseContext::declareArray(const TSourceLoc& loc, const TString& identifie if (isIoResizeArray(type)) checkIoArraysConsistency(loc); -#endif } -#ifndef GLSLANG_WEB - // Policy and error check for needing a runtime sized array. void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermTyped& base) { @@ -4466,7 +4738,7 @@ void TParseContext::checkRuntimeSizable(const TSourceLoc& loc, const TIntermType // check for additional things allowed by GL_EXT_nonuniform_qualifier if (base.getBasicType() == EbtSampler || base.getBasicType() == EbtAccStruct || base.getBasicType() == EbtRayQuery || - (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer())) + base.getBasicType() == EbtHitObjectNV || (base.getBasicType() == EbtBlock && base.getType().getQualifier().isUniformOrBuffer())) requireExtensions(loc, 1, &E_GL_EXT_nonuniform_qualifier, "variable index"); else error(loc, "", "[", "array must be redeclared with a size before being indexed with a variable"); @@ -4521,8 +4793,6 @@ void TParseContext::checkAndResizeMeshViewDim(const TSourceLoc& loc, TType& type } } -#endif // GLSLANG_WEB - // Returns true if the first argument to the #line directive is the line number for the next line. // // Desktop, pre-version 3.30: "After processing this directive @@ -4565,7 +4835,6 @@ void TParseContext::nonInitConstCheck(const TSourceLoc& loc, TString& identifier TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TString& identifier, const TQualifier& qualifier, const TShaderQualifiers& publicType) { -#ifndef GLSLANG_WEB if (! builtInName(identifier) || symbolTable.atBuiltInLevel() || ! symbolTable.atGlobalLevel()) return nullptr; @@ -4589,7 +4858,7 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS if (ssoPre150 || (identifier == "gl_FragDepth" && ((nonEsRedecls && version >= 420) || esRedecls)) || - (identifier == "gl_FragCoord" && ((nonEsRedecls && version >= 150) || esRedecls)) || + (identifier == "gl_FragCoord" && ((nonEsRedecls && version >= 140) || esRedecls)) || identifier == "gl_ClipDistance" || identifier == "gl_CullDistance" || identifier == "gl_ShadingRateEXT" || @@ -4605,6 +4874,9 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS identifier == "gl_SampleMask" || identifier == "gl_Layer" || identifier == "gl_PrimitiveIndicesNV" || + identifier == "gl_PrimitivePointIndicesEXT" || + identifier == "gl_PrimitiveLineIndicesEXT" || + identifier == "gl_PrimitiveTriangleIndicesEXT" || identifier == "gl_TexCoord") { // Find the existing symbol, if any. @@ -4658,7 +4930,7 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS symbolQualifier.storage != qualifier.storage) error(loc, "cannot change qualification of", "redeclaration", symbol->getName().c_str()); } else if (identifier == "gl_FragCoord") { - if (intermediate.inIoAccessed("gl_FragCoord")) + if (!intermediate.getTexCoordRedeclared() && intermediate.inIoAccessed("gl_FragCoord")) error(loc, "cannot redeclare after use", "gl_FragCoord", ""); if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat || qualifier.isMemory() || qualifier.isAuxiliary()) @@ -4668,6 +4940,9 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS if (! builtIn && (publicType.pixelCenterInteger != intermediate.getPixelCenterInteger() || publicType.originUpperLeft != intermediate.getOriginUpperLeft())) error(loc, "cannot redeclare with different qualification:", "redeclaration", symbol->getName().c_str()); + + + intermediate.setTexCoordRedeclared(); if (publicType.pixelCenterInteger) intermediate.setPixelCenterInteger(); if (publicType.originUpperLeft) @@ -4684,10 +4959,22 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS if (! intermediate.setDepth(publicType.layoutDepth)) error(loc, "all redeclarations must use the same depth layout on", "redeclaration", symbol->getName().c_str()); } + } else if (identifier == "gl_FragStencilRefARB") { + if (qualifier.nopersp != symbolQualifier.nopersp || qualifier.flat != symbolQualifier.flat || + qualifier.isMemory() || qualifier.isAuxiliary()) + error(loc, "can only change layout qualification of", "redeclaration", symbol->getName().c_str()); + if (qualifier.storage != EvqVaryingOut) + error(loc, "cannot change output storage qualification of", "redeclaration", symbol->getName().c_str()); + if (publicType.layoutStencil != ElsNone) { + if (intermediate.inIoAccessed("gl_FragStencilRefARB")) + error(loc, "cannot redeclare after use", "gl_FragStencilRefARB", ""); + if (!intermediate.setStencil(publicType.layoutStencil)) + error(loc, "all redeclarations must use the same stencil layout on", "redeclaration", + symbol->getName().c_str()); + } } else if ( - identifier == "gl_PrimitiveIndicesNV" || - identifier == "gl_FragStencilRefARB") { + identifier == "gl_PrimitiveIndicesNV") { if (qualifier.hasLayout()) error(loc, "cannot apply layout qualifier to", "redeclaration", symbol->getName().c_str()); if (qualifier.storage != EvqVaryingOut) @@ -4710,7 +4997,6 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS return symbol; } -#endif return nullptr; } @@ -4722,13 +5008,13 @@ TSymbol* TParseContext::redeclareBuiltinVariable(const TSourceLoc& loc, const TS void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newTypeList, const TString& blockName, const TString* instanceName, TArraySizes* arraySizes) { -#ifndef GLSLANG_WEB const char* feature = "built-in block redeclaration"; profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); profileRequires(loc, ~EEsProfile, 410, E_GL_ARB_separate_shader_objects, feature); if (blockName != "gl_PerVertex" && blockName != "gl_PerFragment" && - blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV") { + blockName != "gl_MeshPerVertexNV" && blockName != "gl_MeshPerPrimitiveNV" && + blockName != "gl_MeshPerVertexEXT" && blockName != "gl_MeshPerPrimitiveEXT") { error(loc, "cannot redeclare block: ", "block declaration", blockName.c_str()); return; } @@ -4937,7 +5223,6 @@ void TParseContext::redeclareBuiltinBlock(const TSourceLoc& loc, TTypeList& newT // Save it in the AST for linker use. trackLinkage(*block); -#endif // GLSLANG_WEB } void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQualifier& qualifier, TType& type) @@ -4950,6 +5235,7 @@ void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQu case EvqIn: case EvqOut: case EvqInOut: + case EvqTileImageEXT: type.getQualifier().storage = qualifier; break; case EvqGlobal: @@ -4965,7 +5251,6 @@ void TParseContext::paramCheckFixStorage(const TSourceLoc& loc, const TStorageQu void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& qualifier, TType& type) { -#ifndef GLSLANG_WEB if (qualifier.isMemory()) { type.getQualifier().volatil = qualifier.volatil; type.getQualifier().coherent = qualifier.coherent; @@ -4979,7 +5264,6 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali type.getQualifier().writeonly = qualifier.writeonly; type.getQualifier().restrict = qualifier.restrict; } -#endif if (qualifier.isAuxiliary() || qualifier.isInterpolation()) @@ -4996,7 +5280,6 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali } if (qualifier.isNonUniform()) type.getQualifier().nonUniform = qualifier.nonUniform; -#ifndef GLSLANG_WEB if (qualifier.isSpirvByReference()) type.getQualifier().setSpirvByReference(); if (qualifier.isSpirvLiteral()) { @@ -5005,7 +5288,6 @@ void TParseContext::paramCheckFix(const TSourceLoc& loc, const TQualifier& quali type.getQualifier().setSpirvLiteral(); else error(loc, "cannot use spirv_literal qualifier", type.getBasicTypeString().c_str(), ""); -#endif } paramCheckFixStorage(loc, qualifier.storage, type); @@ -5036,21 +5318,18 @@ void TParseContext::arrayObjectCheck(const TSourceLoc& loc, const TType& type, c void TParseContext::opaqueCheck(const TSourceLoc& loc, const TType& type, const char* op) { - if (containsFieldWithBasicType(type, EbtSampler)) + if (containsFieldWithBasicType(type, EbtSampler) && !extensionTurnedOn(E_GL_ARB_bindless_texture)) error(loc, "can't use with samplers or structs containing samplers", op, ""); } void TParseContext::referenceCheck(const TSourceLoc& loc, const TType& type, const char* op) { -#ifndef GLSLANG_WEB if (containsFieldWithBasicType(type, EbtReference)) error(loc, "can't use with reference types", op, ""); -#endif } void TParseContext::storage16BitAssignmentCheck(const TSourceLoc& loc, const TType& type, const char* op) { -#ifndef GLSLANG_WEB if (type.getBasicType() == EbtStruct && containsFieldWithBasicType(type, EbtFloat16)) requireFloat16Arithmetic(loc, op, "can't use with structs containing float16"); @@ -5080,7 +5359,6 @@ void TParseContext::storage16BitAssignmentCheck(const TSourceLoc& loc, const TTy if (type.isArray() && type.getBasicType() == EbtUint8) requireInt8Arithmetic(loc, op, "can't use with arrays containing uint8"); -#endif } void TParseContext::specializationCheck(const TSourceLoc& loc, const TType& type, const char* op) @@ -5132,12 +5410,11 @@ void TParseContext::structTypeCheck(const TSourceLoc& /*loc*/, TPublicType& publ // void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, TIntermLoop* loop) { -#ifndef GLSLANG_WEB // loop index init must exist and be a declaration, which shows up in the AST as an aggregate of size 1 of the declaration bool badInit = false; if (! init || ! init->getAsAggregate() || init->getAsAggregate()->getSequence().size() != 1) badInit = true; - TIntermBinary* binaryInit = 0; + TIntermBinary* binaryInit = nullptr; if (! badInit) { // get the declaration assignment binaryInit = init->getAsAggregate()->getSequence()[0]->getAsBinaryNode(); @@ -5228,10 +5505,8 @@ void TParseContext::inductiveLoopCheck(const TSourceLoc& loc, TIntermNode* init, // the body inductiveLoopBodyCheck(loop->getBody(), loopIndex, symbolTable); -#endif } -#ifndef GLSLANG_WEB // Do limit checks for built-in arrays. void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identifier, int size) { @@ -5246,7 +5521,6 @@ void TParseContext::arrayLimitCheck(const TSourceLoc& loc, const TString& identi else if (identifier.compare("gl_CullDistancePerViewNV") == 0) limitCheck(loc, size, "gl_MaxCullDistances", "gl_CullDistancePerViewNV array size"); } -#endif // GLSLANG_WEB // See if the provided value is less than or equal to the symbol indicated by limit, // which should be a constant in the symbol table. @@ -5260,8 +5534,6 @@ void TParseContext::limitCheck(const TSourceLoc& loc, int value, const char* lim error(loc, "must be less than or equal to", feature, "%s (%d)", limit, constArray[0].getIConst()); } -#ifndef GLSLANG_WEB - // // Do any additional error checking, etc., once we know the parsing is done. // @@ -5297,11 +5569,11 @@ void TParseContext::finish() if (!isEsProfile() && version < 430) requireExtensions(getCurrentLoc(), 1, &E_GL_ARB_compute_shader, "compute shaders"); break; - case EShLangTaskNV: - requireExtensions(getCurrentLoc(), 1, &E_GL_NV_mesh_shader, "task shaders"); + case EShLangTask: + requireExtensions(getCurrentLoc(), Num_AEP_mesh_shader, AEP_mesh_shader, "task shaders"); break; - case EShLangMeshNV: - requireExtensions(getCurrentLoc(), 1, &E_GL_NV_mesh_shader, "mesh shaders"); + case EShLangMesh: + requireExtensions(getCurrentLoc(), Num_AEP_mesh_shader, AEP_mesh_shader, "mesh shaders"); break; default: break; @@ -5327,7 +5599,6 @@ void TParseContext::finish() } } } -#endif // GLSLANG_WEB // // Layout qualifier stuff. @@ -5371,7 +5642,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.qualifier.layoutPacking = ElpStd140; return; } -#ifndef GLSLANG_WEB if (id == TQualifier::getLayoutPackingString(ElpStd430)) { requireProfile(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, "std430"); profileRequires(loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_shader_storage_buffer_object, "std430"); @@ -5411,12 +5681,34 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi intermediate.setUsePhysicalStorageBuffer(); return; } - if (language == EShLangGeometry || language == EShLangTessEvaluation || language == EShLangMeshNV) { + if (id == "bindless_sampler") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_sampler"); + publicType.qualifier.layoutBindlessSampler = true; + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout); + return; + } + if (id == "bindless_image") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bindless_image"); + publicType.qualifier.layoutBindlessImage = true; + intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout); + return; + } + if (id == "bound_sampler") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_sampler"); + publicType.qualifier.layoutBindlessSampler = false; + return; + } + if (id == "bound_image") { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "bound_image"); + publicType.qualifier.layoutBindlessImage = false; + return; + } + if (language == EShLangGeometry || language == EShLangTessEvaluation || language == EShLangMesh) { if (id == TQualifier::getGeometryString(ElgTriangles)) { publicType.shaderQualifiers.geometry = ElgTriangles; return; } - if (language == EShLangGeometry || language == EShLangMeshNV) { + if (language == EShLangGeometry || language == EShLangMesh) { if (id == TQualifier::getGeometryString(ElgPoints)) { publicType.shaderQualifiers.geometry = ElgPoints; return; @@ -5499,12 +5791,19 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } if (language == EShLangFragment) { if (id == "origin_upper_left") { - requireProfile(loc, ECoreProfile | ECompatibilityProfile, "origin_upper_left"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile | ENoProfile, "origin_upper_left"); + if (profile == ENoProfile) { + profileRequires(loc,ECoreProfile | ECompatibilityProfile, 140, E_GL_ARB_fragment_coord_conventions, "origin_upper_left"); + } + publicType.shaderQualifiers.originUpperLeft = true; return; } if (id == "pixel_center_integer") { - requireProfile(loc, ECoreProfile | ECompatibilityProfile, "pixel_center_integer"); + requireProfile(loc, ECoreProfile | ECompatibilityProfile | ENoProfile, "pixel_center_integer"); + if (profile == ENoProfile) { + profileRequires(loc,ECoreProfile | ECompatibilityProfile, 140, E_GL_ARB_fragment_coord_conventions, "pixel_center_integer"); + } publicType.shaderQualifiers.pixelCenterInteger = true; return; } @@ -5514,6 +5813,12 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.earlyFragmentTests = true; return; } + if (id == "early_and_late_fragment_tests_amd") { + profileRequires(loc, ENoProfile | ECoreProfile | ECompatibilityProfile, 420, E_GL_AMD_shader_early_and_late_fragment_tests, "early_and_late_fragment_tests_amd"); + profileRequires(loc, EEsProfile, 310, nullptr, "early_and_late_fragment_tests_amd"); + publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD = true; + return; + } if (id == "post_depth_coverage") { requireExtensions(loc, Num_post_depth_coverageEXTs, post_depth_coverageEXTs, "post depth coverage"); if (extensionTurnedOn(E_GL_ARB_post_depth_coverage)) { @@ -5522,6 +5827,22 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.postDepthCoverage = true; return; } + /* id is transformed into lower case in the beginning of this function. */ + if (id == "non_coherent_color_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_color_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT = true; + return; + } + if (id == "non_coherent_depth_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_depth_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT = true; + return; + } + if (id == "non_coherent_stencil_attachment_readext") { + requireExtensions(loc, 1, &E_GL_EXT_shader_tile_image, "non_coherent_stencil_attachment_readEXT"); + publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT = true; + return; + } for (TLayoutDepth depth = (TLayoutDepth)(EldNone + 1); depth < EldCount; depth = (TLayoutDepth)(depth+1)) { if (id == TQualifier::getLayoutDepthString(depth)) { requireProfile(loc, ECoreProfile | ECompatibilityProfile, "depth layout qualifier"); @@ -5530,6 +5851,14 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi return; } } + for (TLayoutStencil stencil = (TLayoutStencil)(ElsNone + 1); stencil < ElsCount; stencil = (TLayoutStencil)(stencil+1)) { + if (id == TQualifier::getLayoutStencilString(stencil)) { + requireProfile(loc, ECoreProfile | ECompatibilityProfile, "stencil layout qualifier"); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 420, nullptr, "stencil layout qualifier"); + publicType.shaderQualifiers.layoutStencil = stencil; + return; + } + } for (TInterlockOrdering order = (TInterlockOrdering)(EioNone + 1); order < EioCount; order = (TInterlockOrdering)(order+1)) { if (id == TQualifier::getInterlockOrderingString(order)) { requireProfile(loc, ECoreProfile | ECompatibilityProfile, "fragment shader interlock layout qualifier"); @@ -5562,6 +5891,15 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.layoutOverrideCoverage = true; return; } + if (id == "full_quads") + { + const char* feature = "full_quads qualifier"; + requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, feature); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 140, E_GL_EXT_shader_quad_control, feature); + profileRequires(loc, EEsProfile, 310, E_GL_EXT_shader_quad_control, feature); + publicType.qualifier.layoutFullQuads = true; + return; + } } if (language == EShLangVertex || language == EShLangTessControl || @@ -5584,6 +5922,10 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } publicType.qualifier.layoutShaderRecord = true; return; + } else if (id == "hitobjectshaderrecordnv") { + requireExtensions(loc, 1, &E_GL_NV_shader_invocation_reorder, "hitobject shader record NV"); + publicType.qualifier.layoutHitObjectShaderRecordNV = true; + return; } } @@ -5606,7 +5948,16 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi publicType.shaderQualifiers.layoutPrimitiveCulling = true; return; } -#endif + + if (id == "quad_derivatives") + { + const char* feature = "quad_derivatives qualifier"; + requireProfile(loc, ECompatibilityProfile | ECoreProfile | EEsProfile, feature); + profileRequires(loc, ECoreProfile | ECompatibilityProfile, 140, E_GL_EXT_shader_quad_control, feature); + profileRequires(loc, EEsProfile, 310, E_GL_EXT_shader_quad_control, feature); + publicType.qualifier.layoutQuadDeriv = true; + return; + } error(loc, "unrecognized layout identifier, or qualifier requires assignment (e.g., binding = 4)", id.c_str(), ""); } @@ -5673,7 +6024,7 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi return; } else if (id == "location") { profileRequires(loc, EEsProfile, 300, nullptr, "location"); - const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location }; + const char* exts[2] = { E_GL_ARB_separate_shader_objects, E_GL_ARB_explicit_attrib_location }; // GL_ARB_explicit_uniform_location requires 330 or GL_ARB_explicit_attrib_location we do not need to add it here profileRequires(loc, ~EEsProfile, 330, 2, exts, "location"); if ((unsigned int)value >= TQualifier::layoutLocationEnd) @@ -5694,10 +6045,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi error(loc, "needs a literal integer", "set", ""); return; } else if (id == "binding") { -#ifndef GLSLANG_WEB profileRequires(loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, "binding"); profileRequires(loc, EEsProfile, 310, nullptr, "binding"); -#endif if ((unsigned int)value >= TQualifier::layoutBindingEnd) error(loc, "binding is too large", id.c_str(), ""); else @@ -5720,7 +6069,6 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi error(loc, "needs a literal integer", "constant_id", ""); return; } -#ifndef GLSLANG_WEB if (id == "component") { requireProfile(loc, ECoreProfile | ECompatibilityProfile, "component"); profileRequires(loc, ECoreProfile | ECompatibilityProfile, 440, E_GL_ARB_enhanced_layouts, "component"); @@ -5818,10 +6166,8 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi error(loc, "needs a literal integer", "buffer_reference_align", ""); return; } -#endif switch (language) { -#ifndef GLSLANG_WEB case EShLangTessControl: if (id == "vertices") { if (value == 0) @@ -5883,40 +6229,49 @@ void TParseContext::setLayoutQualifier(const TSourceLoc& loc, TPublicType& publi } break; - case EShLangMeshNV: + case EShLangMesh: if (id == "max_vertices") { - requireExtensions(loc, 1, &E_GL_NV_mesh_shader, "max_vertices"); + requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_vertices"); publicType.shaderQualifiers.vertices = value; - if (value > resources.maxMeshOutputVerticesNV) - error(loc, "too large, must be less than gl_MaxMeshOutputVerticesNV", "max_vertices", ""); + int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputVerticesEXT + : resources.maxMeshOutputVerticesNV; + if (value > max) { + TString maxsErrtring = "too large, must be less than "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputVerticesEXT" + : "gl_MaxMeshOutputVerticesNV"); + error(loc, maxsErrtring.c_str(), "max_vertices", ""); + } if (nonLiteral) error(loc, "needs a literal integer", "max_vertices", ""); return; } if (id == "max_primitives") { - requireExtensions(loc, 1, &E_GL_NV_mesh_shader, "max_primitives"); + requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "max_primitives"); publicType.shaderQualifiers.primitives = value; - if (value > resources.maxMeshOutputPrimitivesNV) - error(loc, "too large, must be less than gl_MaxMeshOutputPrimitivesNV", "max_primitives", ""); + int max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? resources.maxMeshOutputPrimitivesEXT + : resources.maxMeshOutputPrimitivesNV; + if (value > max) { + TString maxsErrtring = "too large, must be less than "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? "gl_MaxMeshOutputPrimitivesEXT" + : "gl_MaxMeshOutputPrimitivesNV"); + error(loc, maxsErrtring.c_str(), "max_primitives", ""); + } if (nonLiteral) error(loc, "needs a literal integer", "max_primitives", ""); return; } - // Fall through + [[fallthrough]]; - case EShLangTaskNV: + case EShLangTask: // Fall through -#endif case EShLangCompute: if (id.compare(0, 11, "local_size_") == 0) { -#ifndef GLSLANG_WEB - if (language == EShLangMeshNV || language == EShLangTaskNV) { - requireExtensions(loc, 1, &E_GL_NV_mesh_shader, "gl_WorkGroupSize"); + if (language == EShLangMesh || language == EShLangTask) { + requireExtensions(loc, Num_AEP_mesh_shader, AEP_mesh_shader, "gl_WorkGroupSize"); } else { - profileRequires(loc, EEsProfile, 310, 0, "gl_WorkGroupSize"); + profileRequires(loc, EEsProfile, 310, nullptr, "gl_WorkGroupSize"); profileRequires(loc, ~EEsProfile, 430, E_GL_ARB_compute_shader, "gl_WorkGroupSize"); } -#endif if (nonLiteral) error(loc, "needs a literal integer", "local_size", ""); if (id.size() == 12 && value == 0) { @@ -5983,7 +6338,6 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie if (src.hasPacking()) dst.layoutPacking = src.layoutPacking; -#ifndef GLSLANG_WEB if (src.hasStream()) dst.layoutStream = src.layoutStream; if (src.hasFormat()) @@ -5992,7 +6346,6 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie dst.layoutXfbBuffer = src.layoutXfbBuffer; if (src.hasBufferReferenceAlign()) dst.layoutBufferReferenceAlign = src.layoutBufferReferenceAlign; -#endif if (src.hasAlign()) dst.layoutAlign = src.layoutAlign; @@ -6010,7 +6363,6 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie if (src.hasSpecConstantId()) dst.layoutSpecConstantId = src.layoutSpecConstantId; -#ifndef GLSLANG_WEB if (src.hasComponent()) dst.layoutComponent = src.layoutComponent; if (src.hasIndex()) @@ -6035,9 +6387,20 @@ void TParseContext::mergeObjectLayoutQualifiers(TQualifier& dst, const TQualifie dst.layoutSecondaryViewportRelativeOffset = src.layoutSecondaryViewportRelativeOffset; if (src.layoutShaderRecord) dst.layoutShaderRecord = true; + if (src.layoutFullQuads) + dst.layoutFullQuads = true; + if (src.layoutQuadDeriv) + dst.layoutQuadDeriv = true; + if (src.layoutBindlessSampler) + dst.layoutBindlessSampler = true; + if (src.layoutBindlessImage) + dst.layoutBindlessImage = true; if (src.pervertexNV) dst.pervertexNV = true; -#endif + if (src.pervertexEXT) + dst.pervertexEXT = true; + if (src.layoutHitObjectShaderRecordNV) + dst.layoutHitObjectShaderRecordNV = true; } } @@ -6073,10 +6436,7 @@ void TParseContext::layoutObjectCheck(const TSourceLoc& loc, const TSymbol& symb switch (qualifier.storage) { case EvqVaryingIn: case EvqVaryingOut: - if (!type.getQualifier().isTaskMemory() && -#ifndef GLSLANG_WEB - !type.getQualifier().hasSprivDecorate() && -#endif + if (!type.getQualifier().isTaskMemory() && !type.getQualifier().hasSpirvDecorate() && (type.getBasicType() != EbtBlock || (!(*type.getStruct())[0].type->getQualifier().hasLocation() && (*type.getStruct())[0].type->getQualifier().builtIn == EbvNone))) @@ -6138,11 +6498,6 @@ void TParseContext::layoutMemberLocationArrayCheck(const TSourceLoc& loc, bool m // Do layout error checking with respect to a type. void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) { -#ifndef GLSLANG_WEB - if (extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) - return; // Skip any check if GL_EXT_spirv_intrinsics is turned on -#endif - const TQualifier& qualifier = type.getQualifier(); // first, intra-layout qualifier-only error checking @@ -6184,15 +6539,22 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) case EvqBuffer: if (type.getBasicType() == EbtBlock) error(loc, "cannot apply to uniform or buffer block", "location", ""); + else if (type.getBasicType() == EbtSampler && type.getSampler().isAttachmentEXT()) + error(loc, "only applies to", "location", "%s with storage tileImageEXT", type.getBasicTypeString().c_str()); + break; + case EvqtaskPayloadSharedEXT: + error(loc, "cannot apply to taskPayloadSharedEXT", "location", ""); break; -#ifndef GLSLANG_WEB case EvqPayload: case EvqPayloadIn: case EvqHitAttr: case EvqCallableData: case EvqCallableDataIn: + case EvqHitObjectAttrNV: + case EvqSpirvStorageClass: + break; + case EvqTileImageEXT: break; -#endif default: error(loc, "can only apply to uniform, buffer, in, or out storage qualifiers", "location", ""); break; @@ -6202,19 +6564,20 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) int repeated = intermediate.addUsedLocation(qualifier, type, typeCollision); if (repeated >= 0 && ! typeCollision) error(loc, "overlapping use of location", "location", "%d", repeated); - // "fragment-shader outputs ... if two variables are placed within the same + // "fragment-shader outputs/tileImageEXT ... if two variables are placed within the same // location, they must have the same underlying type (floating-point or integer)" - if (typeCollision && language == EShLangFragment && qualifier.isPipeOutput()) - error(loc, "fragment outputs sharing the same location must be the same basic type", "location", "%d", repeated); + if (typeCollision && language == EShLangFragment && (qualifier.isPipeOutput() || qualifier.storage == EvqTileImageEXT)) + error(loc, "fragment outputs or tileImageEXTs sharing the same location", "location", "%d must be the same basic type", repeated); } -#ifndef GLSLANG_WEB if (qualifier.hasXfbOffset() && qualifier.hasXfbBuffer()) { - int repeated = intermediate.addXfbBufferOffset(type); - if (repeated >= 0) - error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer); - if (type.isUnsizedArray()) + if (type.isUnsizedArray()) { error(loc, "unsized array", "xfb_offset", "in buffer %d", qualifier.layoutXfbBuffer); + } else { + int repeated = intermediate.addXfbBufferOffset(type); + if (repeated >= 0) + error(loc, "overlapping offsets at", "xfb_offset", "offset %d in buffer %d", repeated, qualifier.layoutXfbBuffer); + } // "The offset must be a multiple of the size of the first component of the first // qualified variable or block member, or a compile-time error results. Further, if applied to an aggregate @@ -6235,7 +6598,6 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (! intermediate.setXfbBufferStride(qualifier.layoutXfbBuffer, qualifier.layoutXfbStride)) error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer); } -#endif if (qualifier.hasBinding()) { // Binding checking, from the spec: @@ -6246,7 +6608,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // an array of size N, all elements of the array from binding through binding + N - 1 must be within this // range." // - if (! type.isOpaque() && type.getBasicType() != EbtBlock) + if (!type.isOpaque() && type.getBasicType() != EbtBlock && type.getBasicType() != EbtSpirvType) error(loc, "requires block, or sampler/image, or atomic-counter type", "binding", ""); if (type.getBasicType() == EbtSampler) { int lastBinding = qualifier.layoutBinding; @@ -6255,16 +6617,12 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) if (type.isSizedArray()) lastBinding += (type.getCumulativeArraySize() - 1); else { -#ifndef GLSLANG_WEB warn(loc, "assuming binding count of one for compile-time checking of binding numbers for unsized array", "[]", ""); -#endif } } } -#ifndef GLSLANG_WEB if (spvVersion.vulkan == 0 && lastBinding >= resources.maxCombinedTextureImageUnits) error(loc, "sampler binding not less than gl_MaxCombinedTextureImageUnits", "binding", type.isArray() ? "(using array)" : ""); -#endif } if (type.isAtomic() && !spvVersion.vulkanRelaxed) { if (qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) { @@ -6287,7 +6645,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) !qualifier.hasAttachment() && !qualifier.hasBufferReference()) error(loc, "uniform/buffer blocks require layout(binding=X)", "binding", ""); - else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler) + else if (spvVersion.vulkan > 0 && type.getBasicType() == EbtSampler && !type.getSampler().isAttachmentEXT()) error(loc, "sampler/texture/image requires layout(binding=X)", "binding", ""); } } @@ -6309,7 +6667,7 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // Image format if (qualifier.hasFormat()) { - if (! type.isImage()) + if (! type.isImage() && !intermediate.getBindlessImageMode()) error(loc, "only apply to images", TQualifier::getLayoutFormatString(qualifier.getFormat()), ""); else { if (type.getSampler().type == EbtFloat && qualifier.getFormat() > ElfFloatGuard) @@ -6328,14 +6686,18 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) } } } - } else if (type.isImage() && ! qualifier.isWriteOnly()) { + } else if (type.isImage() && ! qualifier.isWriteOnly() && !intermediate.getBindlessImageMode()) { const char *explanation = "image variables not declared 'writeonly' and without a format layout qualifier"; requireProfile(loc, ECoreProfile | ECompatibilityProfile, explanation); profileRequires(loc, ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shader_image_load_formatted, explanation); } - if (qualifier.isPushConstant() && type.getBasicType() != EbtBlock) - error(loc, "can only be used with a block", "push_constant", ""); + if (qualifier.isPushConstant()) { + if (type.getBasicType() != EbtBlock) + error(loc, "can only be used with a block", "push_constant", ""); + if (type.isArray()) + error(loc, "Push constants blocks can't be an array", "push_constant", ""); + } if (qualifier.hasBufferReference() && type.getBasicType() != EbtBlock) error(loc, "can only be used with a block", "buffer_reference", ""); @@ -6345,6 +6707,8 @@ void TParseContext::layoutTypeCheck(const TSourceLoc& loc, const TType& type) // input attachment if (type.isSubpass()) { + if (extensionTurnedOn(E_GL_EXT_shader_tile_image)) + error(loc, "can not be used with GL_EXT_shader_tile_image enabled", type.getSampler().getString().c_str(), ""); if (! qualifier.hasAttachment()) error(loc, "requires an input_attachment_index layout qualifier", "subpass", ""); } else { @@ -6414,7 +6778,6 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier // output block declarations, and output block member declarations." switch (qualifier.storage) { -#ifndef GLSLANG_WEB case EvqVaryingIn: { const char* feature = "location qualifier on input"; @@ -6449,7 +6812,6 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier } break; } -#endif case EvqUniform: case EvqBuffer: { @@ -6512,6 +6874,14 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier error(loc, "cannot be used with shaderRecordNV", "set", ""); } + + if (qualifier.storage == EvqTileImageEXT) { + if (qualifier.hasSet()) + error(loc, "cannot be used with tileImageEXT", "set", ""); + if (!qualifier.hasLocation()) + error(loc, "can only be used with an explicit location", "tileImageEXT", ""); + } + if (qualifier.storage == EvqHitAttr && qualifier.hasLayout()) { error(loc, "cannot apply layout qualifiers to hitAttributeNV variable", "hitAttributeNV", ""); } @@ -6520,7 +6890,6 @@ void TParseContext::layoutQualifierCheck(const TSourceLoc& loc, const TQualifier // For places that can't have shader-level layout qualifiers void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQualifiers& shaderQualifiers) { -#ifndef GLSLANG_WEB const char* message = "can only apply to a standalone qualifier"; if (shaderQualifiers.geometry != ElgNone) @@ -6540,7 +6909,7 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "local_size id", ""); } if (shaderQualifiers.vertices != TQualifier::layoutNotSet) { - if (language == EShLangGeometry || language == EShLangMeshNV) + if (language == EShLangGeometry || language == EShLangMesh) error(loc, message, "max_vertices", ""); else if (language == EShLangTessControl) error(loc, message, "vertices", ""); @@ -6551,8 +6920,14 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, "early_fragment_tests", ""); if (shaderQualifiers.postDepthCoverage) error(loc, message, "post_depth_coverage", ""); + if (shaderQualifiers.nonCoherentColorAttachmentReadEXT) + error(loc, message, "non_coherent_color_attachment_readEXT", ""); + if (shaderQualifiers.nonCoherentDepthAttachmentReadEXT) + error(loc, message, "non_coherent_depth_attachment_readEXT", ""); + if (shaderQualifiers.nonCoherentStencilAttachmentReadEXT) + error(loc, message, "non_coherent_stencil_attachment_readEXT", ""); if (shaderQualifiers.primitives != TQualifier::layoutNotSet) { - if (language == EShLangMeshNV) + if (language == EShLangMesh) error(loc, message, "max_primitives", ""); else assert(0); @@ -6565,14 +6940,12 @@ void TParseContext::checkNoShaderLayouts(const TSourceLoc& loc, const TShaderQua error(loc, message, TQualifier::getInterlockOrderingString(shaderQualifiers.interlockOrdering), ""); if (shaderQualifiers.layoutPrimitiveCulling) error(loc, "can only be applied as standalone", "primitive_culling", ""); -#endif } // Correct and/or advance an object's offset layout qualifier. void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol) { const TQualifier& qualifier = symbol.getType().getQualifier(); -#ifndef GLSLANG_WEB if (symbol.getType().isAtomic()) { if (qualifier.hasBinding() && (int)qualifier.layoutBinding < resources.maxAtomicCounterBindings) { @@ -6606,7 +6979,6 @@ void TParseContext::fixOffset(const TSourceLoc& loc, TSymbol& symbol) atomicUintOffsets[qualifier.layoutBinding] = offset + numOffsets; } } -#endif } // @@ -6621,10 +6993,6 @@ const TFunction* TParseContext::findFunction(const TSourceLoc& loc, const TFunct return nullptr; } -#ifdef GLSLANG_WEB - return findFunctionExact(loc, call, builtIn); -#endif - const TFunction* function = nullptr; // debugPrintfEXT has var args and is in the symbol table as "debugPrintfEXT()", @@ -6951,7 +7319,6 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T { TIntermTyped* result = nullptr; -#ifndef GLSLANG_WEB if (function->getBuiltInOp() != EOpNull) { return nullptr; } @@ -6963,12 +7330,14 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T TFunction realFunc(&name, function->getType()); + // Use copyParam to avoid shared ownership of the 'type' field + // of the parameter. for (int i = 0; i < function->getParamCount(); ++i) { - realFunc.addParameter((*function)[i]); + realFunc.addParameter(TParameter().copyParam((*function)[i])); } - TParameter tmpP = { 0, &uintType }; - realFunc.addParameter(tmpP); + TParameter tmpP = { nullptr, &uintType, {} }; + realFunc.addParameter(TParameter().copyParam(tmpP)); arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(1, loc, true)); result = handleFunctionCall(loc, &realFunc, arguments); @@ -6981,11 +7350,11 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T TFunction realFunc(&name, function->getType()); for (int i = 0; i < function->getParamCount(); ++i) { - realFunc.addParameter((*function)[i]); + realFunc.addParameter(TParameter().copyParam((*function)[i])); } - TParameter tmpP = { 0, &uintType }; - realFunc.addParameter(tmpP); + TParameter tmpP = { nullptr, &uintType, {} }; + realFunc.addParameter(TParameter().copyParam(tmpP)); arguments = intermediate.growAggregate(arguments, intermediate.addConstantUnion(-1, loc, true)); result = handleFunctionCall(loc, &realFunc, arguments); @@ -7000,7 +7369,6 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T result = arguments->getAsTyped(); } } -#endif return result; } @@ -7009,7 +7377,6 @@ TIntermTyped* TParseContext::vkRelaxedRemapFunctionCall(const TSourceLoc& loc, T // to establish defaults. void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType& publicType) { -#ifndef GLSLANG_WEB if (publicType.basicType == EbtAtomicUint && publicType.qualifier.hasBinding()) { if (publicType.qualifier.layoutBinding >= (unsigned int)resources.maxAtomicCounterBindings) { error(loc, "atomic_uint binding is too large", "binding", ""); @@ -7026,19 +7393,52 @@ void TParseContext::declareTypeDefaults(const TSourceLoc& loc, const TPublicType if (publicType.qualifier.hasLayout() && !publicType.qualifier.hasBufferReference()) warn(loc, "useless application of layout qualifier", "layout", ""); -#endif } -bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString& identifier, const TPublicType&, +void TParseContext::coopMatTypeParametersCheck(const TSourceLoc& loc, const TPublicType& publicType) +{ + if (parsingBuiltins) + return; + if (publicType.isCoopmatKHR()) { + if (publicType.typeParameters == nullptr) { + error(loc, "coopmat missing type parameters", "", ""); + return; + } + switch (publicType.typeParameters->basicType) { + case EbtFloat: + case EbtFloat16: + case EbtInt: + case EbtInt8: + case EbtInt16: + case EbtUint: + case EbtUint8: + case EbtUint16: + case EbtSpirvType: + break; + default: + error(loc, "coopmat invalid basic type", TType::getBasicString(publicType.typeParameters->basicType), ""); + break; + } + if (publicType.typeParameters->arraySizes->getNumDims() != 4) { + error(loc, "coopmat incorrect number of type parameters", "", ""); + return; + } + int use = publicType.typeParameters->arraySizes->getDimSize(3); + if (use < 0 || use > 2) { + error(loc, "coopmat invalid matrix Use", "", ""); + return; + } + } +} + +bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString& identifier, const TPublicType& publicType, TArraySizes*, TIntermTyped* initializer, TType& type) { + vkRelaxedRemapUniformMembers(loc, publicType, type, identifier); + if (parsingBuiltins || symbolTable.atBuiltInLevel() || !symbolTable.atGlobalLevel() || type.getQualifier().storage != EvqUniform || - !(type.containsNonOpaque() -#ifndef GLSLANG_WEB - || type.getBasicType() == EbtAtomicUint -#endif - )) { + !(type.containsNonOpaque() || type.getBasicType() == EbtAtomicUint || (type.containsSampler() && type.isStruct()))) { return false; } @@ -7067,7 +7467,6 @@ bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString int bufferBinding = TQualifier::layoutBindingEnd; TVariable* updatedBlock = nullptr; -#ifndef GLSLANG_WEB // Convert atomic_uint into members of a buffer block if (type.isAtomic()) { type.setBasicType(EbtUint); @@ -7083,7 +7482,6 @@ bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString growAtomicCounterBlock(bufferBinding, loc, type, identifier, nullptr); updatedBlock = atomicCounterBuffers[bufferBinding]; } -#endif if (!updatedBlock) { growGlobalUniformBlock(loc, type, identifier, nullptr); @@ -7114,6 +7512,263 @@ bool TParseContext::vkRelaxedRemapUniformVariable(const TSourceLoc& loc, TString return true; } +template +static void ForEachOpaque(const TType& type, const TString& path, Function callback) +{ + auto recursion = [&callback](const TType& type, const TString& path, bool skipArray, auto& recursion) -> void { + if (!skipArray && type.isArray()) + { + std::vector indices(type.getArraySizes()->getNumDims()); + for (int flatIndex = 0; + flatIndex < type.getArraySizes()->getCumulativeSize(); + ++flatIndex) + { + TString subscriptPath = path; + for (size_t dimIndex = 0; dimIndex < indices.size(); ++dimIndex) + { + int index = indices[dimIndex]; + subscriptPath.append("["); + subscriptPath.append(String(index)); + subscriptPath.append("]"); + } + + recursion(type, subscriptPath, true, recursion); + + for (size_t dimIndex = 0; dimIndex < indices.size(); ++dimIndex) + { + ++indices[dimIndex]; + if (indices[dimIndex] < type.getArraySizes()->getDimSize(dimIndex)) + break; + else + indices[dimIndex] = 0; + } + } + } + + else if (type.isStruct() && type.containsOpaque()) + { + const TTypeList& types = *type.getStruct(); + for (const TTypeLoc& typeLoc : types) + { + TString nextPath = path; + nextPath.append("."); + nextPath.append(typeLoc.type->getFieldName()); + + recursion(*(typeLoc.type), nextPath, false, recursion); + } + } + + else if (type.isOpaque()) + { + callback(type, path); + } + }; + + recursion(type, path, false, recursion); +} + +void TParseContext::vkRelaxedRemapUniformMembers(const TSourceLoc& loc, const TPublicType& publicType, const TType& type, + const TString& identifier) +{ + if (!type.isStruct() || !type.containsOpaque()) + return; + + ForEachOpaque(type, identifier, + [&publicType, &loc, this](const TType& type, const TString& path) { + TArraySizes arraySizes = {}; + if (type.getArraySizes()) arraySizes = *type.getArraySizes(); + TTypeParameters typeParameters = {}; + if (type.getTypeParameters()) typeParameters = *type.getTypeParameters(); + + TPublicType memberType{}; + memberType.basicType = type.getBasicType(); + memberType.sampler = type.getSampler(); + memberType.qualifier = type.getQualifier(); + memberType.vectorSize = type.getVectorSize(); + memberType.matrixCols = type.getMatrixCols(); + memberType.matrixRows = type.getMatrixRows(); + memberType.coopmatNV = type.isCoopMatNV(); + memberType.coopmatKHR = type.isCoopMatKHR(); + memberType.arraySizes = nullptr; + memberType.userDef = nullptr; + memberType.loc = loc; + memberType.typeParameters = (type.getTypeParameters() ? &typeParameters : nullptr); + memberType.spirvType = nullptr; + + memberType.qualifier.storage = publicType.qualifier.storage; + memberType.shaderQualifiers = publicType.shaderQualifiers; + + TString& structMemberName = *NewPoolTString(path.c_str()); // A copy is required due to declareVariable() signature. + declareVariable(loc, structMemberName, memberType, nullptr, nullptr); + }); +} + +void TParseContext::vkRelaxedRemapFunctionParameter(TFunction* function, TParameter& param, std::vector* newParams) +{ + function->addParameter(param); + + if (!param.type->isStruct() || !param.type->containsOpaque()) + return; + + ForEachOpaque(*param.type, (param.name ? *param.name : param.type->getFieldName()), + [function, param, newParams](const TType& type, const TString& path) { + TString* memberName = NewPoolTString(path.c_str()); + + TType* memberType = new TType(); + memberType->shallowCopy(type); + memberType->getQualifier().storage = param.type->getQualifier().storage; + memberType->clearArraySizes(); + + TParameter memberParam = {}; + memberParam.name = memberName; + memberParam.type = memberType; + memberParam.defaultValue = nullptr; + function->addParameter(memberParam); + if (newParams) + newParams->push_back(function->getParamCount()-1); + }); +} + +// +// Generates a valid GLSL dereferencing string for the input TIntermNode +// +struct AccessChainTraverser : public TIntermTraverser { + AccessChainTraverser() : TIntermTraverser(false, false, true) + {} + + TString path = ""; + TStorageQualifier topLevelStorageQualifier = TStorageQualifier::EvqLast; + + bool visitBinary(TVisit, TIntermBinary* binary) override { + if (binary->getOp() == EOpIndexDirectStruct) + { + const TTypeList& members = *binary->getLeft()->getType().getStruct(); + const TTypeLoc& member = + members[binary->getRight()->getAsConstantUnion()->getConstArray()[0].getIConst()]; + TString memberName = member.type->getFieldName(); + + if (path != "") + path.append("."); + + path.append(memberName); + } + + if (binary->getOp() == EOpIndexDirect) + { + const TConstUnionArray& indices = binary->getRight()->getAsConstantUnion()->getConstArray(); + for (int index = 0; index < indices.size(); ++index) + { + path.append("["); + path.append(String(indices[index].getIConst())); + path.append("]"); + } + } + + return true; + } + + void visitSymbol(TIntermSymbol* symbol) override { + if (symbol->getType().isOpaque()) + topLevelStorageQualifier = symbol->getQualifier().storage; + if (!IsAnonymous(symbol->getName())) + path.append(symbol->getName()); + } +}; + +TIntermNode* TParseContext::vkRelaxedRemapFunctionArgument(const TSourceLoc& loc, TFunction* function, TIntermTyped* intermTyped) +{ + AccessChainTraverser accessChainTraverser{}; + intermTyped->traverse(&accessChainTraverser); + + if (accessChainTraverser.topLevelStorageQualifier == TStorageQualifier::EvqUniform) + { + TParameter param = { 0, new TType, {} }; + param.type->shallowCopy(intermTyped->getType()); + + function->addParameter(param); + return intermTyped; + } + + TParameter param = { NewPoolTString(accessChainTraverser.path.c_str()), new TType, {} }; + param.type->shallowCopy(intermTyped->getType()); + + std::vector newParams = {}; + vkRelaxedRemapFunctionParameter(function, param, &newParams); + + if (intermTyped->getType().isOpaque()) + { + TIntermNode* remappedArgument = intermTyped; + { + TIntermSymbol* intermSymbol = nullptr; + TSymbol* symbol = symbolTable.find(*param.name); + if (symbol && symbol->getAsVariable()) + intermSymbol = intermediate.addSymbol(*symbol->getAsVariable(), loc); + else + { + TVariable* variable = new TVariable(param.name, *param.type); + intermSymbol = intermediate.addSymbol(*variable, loc); + } + + remappedArgument = intermSymbol; + } + + return remappedArgument; + } + else if (!(intermTyped->isStruct() && intermTyped->getType().containsOpaque())) + return intermTyped; + else + { + TIntermNode* remappedArgument = intermTyped; + { + TSymbol* symbol = symbolTable.find(*param.name); + if (symbol && symbol->getAsVariable()) + remappedArgument = intermediate.addSymbol(*symbol->getAsVariable(), loc); + } + + if (!newParams.empty()) + remappedArgument = intermediate.makeAggregate(remappedArgument, loc); + + for (int paramIndex : newParams) + { + TParameter& newParam = function->operator[](paramIndex); + TIntermSymbol* intermSymbol = nullptr; + TSymbol* symbol = symbolTable.find(*newParam.name); + if (symbol && symbol->getAsVariable()) + intermSymbol = intermediate.addSymbol(*symbol->getAsVariable(), loc); + else + { + TVariable* variable = new TVariable(newParam.name, *newParam.type); + intermSymbol = intermediate.addSymbol(*variable, loc); + } + + remappedArgument = intermediate.growAggregate(remappedArgument, intermSymbol); + } + + return remappedArgument; + } +} + +TIntermTyped* TParseContext::vkRelaxedRemapDotDereference(const TSourceLoc&, TIntermTyped& base, const TType& member, + const TString& identifier) +{ + if (!member.isOpaque()) + return &base; + + AccessChainTraverser traverser{}; + base.traverse(&traverser); + if (!traverser.path.empty()) + traverser.path.append("."); + traverser.path.append(identifier); + + const TSymbol* symbol = symbolTable.find(traverser.path); + if (!symbol) + return &base; + + TIntermTyped* result = intermediate.addSymbol(*symbol->getAsVariable()); + result->setType(symbol->getType()); + return result; +} + // // Do everything necessary to handle a variable (non-block) declaration. // Either redeclaring a variable, or making a new one, updating the symbol @@ -7138,32 +7793,50 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden if (initializer) { if (type.getBasicType() == EbtRayQuery) { error(loc, "ray queries can only be initialized by using the rayQueryInitializeEXT intrinsic:", "=", identifier.c_str()); + } else if (type.getBasicType() == EbtHitObjectNV) { + error(loc, "hit objects cannot be initialized using initializers", "=", identifier.c_str()); } + } - if (type.isCoopMat()) { + if (type.isCoopMatKHR()) { intermediate.setUseVulkanMemoryModel(); intermediate.setUseStorageBuffer(); - if (!publicType.typeParameters || publicType.typeParameters->getNumDims() != 4) { + if (!publicType.typeParameters || !publicType.typeParameters->arraySizes || + publicType.typeParameters->arraySizes->getNumDims() != 3) { + error(loc, "unexpected number type parameters", identifier.c_str(), ""); + } + if (publicType.typeParameters) { + if (!isTypeFloat(publicType.typeParameters->basicType) && + !isTypeInt(publicType.typeParameters->basicType) && publicType.typeParameters->basicType != EbtSpirvType) { + error(loc, "expected 8, 16, 32, or 64 bit signed or unsigned integer or 16, 32, or 64 bit float type", identifier.c_str(), ""); + } + } + } + else if (type.isCoopMatNV()) { + intermediate.setUseVulkanMemoryModel(); + intermediate.setUseStorageBuffer(); + + if (!publicType.typeParameters || publicType.typeParameters->arraySizes->getNumDims() != 4) { error(loc, "expected four type parameters", identifier.c_str(), ""); } if (publicType.typeParameters) { if (isTypeFloat(publicType.basicType) && - publicType.typeParameters->getDimSize(0) != 16 && - publicType.typeParameters->getDimSize(0) != 32 && - publicType.typeParameters->getDimSize(0) != 64) { + publicType.typeParameters->arraySizes->getDimSize(0) != 16 && + publicType.typeParameters->arraySizes->getDimSize(0) != 32 && + publicType.typeParameters->arraySizes->getDimSize(0) != 64) { error(loc, "expected 16, 32, or 64 bits for first type parameter", identifier.c_str(), ""); } if (isTypeInt(publicType.basicType) && - publicType.typeParameters->getDimSize(0) != 8 && - publicType.typeParameters->getDimSize(0) != 32) { - error(loc, "expected 8 or 32 bits for first type parameter", identifier.c_str(), ""); + publicType.typeParameters->arraySizes->getDimSize(0) != 8 && + publicType.typeParameters->arraySizes->getDimSize(0) != 16 && + publicType.typeParameters->arraySizes->getDimSize(0) != 32) { + error(loc, "expected 8, 16, or 32 bits for first type parameter", identifier.c_str(), ""); } } - } else { - if (publicType.typeParameters && publicType.typeParameters->getNumDims() != 0) { + if (publicType.typeParameters && publicType.typeParameters->arraySizes->getNumDims() != 0) { error(loc, "unexpected type parameters", identifier.c_str(), ""); } } @@ -7178,11 +7851,9 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden samplerCheck(loc, type, identifier, initializer); transparentOpaqueCheck(loc, type, identifier); -#ifndef GLSLANG_WEB atomicUintCheck(loc, type, identifier); accStructCheck(loc, type, identifier); checkAndResizeMeshViewDim(loc, type, /*isBlockMember*/ false); -#endif if (type.getQualifier().storage == EvqConst && type.containsReference()) { error(loc, "variables with reference type can't have qualifier 'const'", "qualifier", ""); } @@ -7196,6 +7867,8 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden requireInt8Arithmetic(loc, "qualifier", "(u)int8 types can only be in uniform block or buffer storage"); } + if (type.getQualifier().storage == EvqtaskPayloadSharedEXT) + intermediate.addTaskPayloadEXTCount(); if (type.getQualifier().storage == EvqShared && type.containsCoopMat()) error(loc, "qualifier", "Cooperative matrix types must not be used in shared memory", ""); @@ -7219,6 +7892,8 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden error(loc, "can only apply origin_upper_left and pixel_center_origin to gl_FragCoord", "layout qualifier", ""); if (identifier != "gl_FragDepth" && publicType.shaderQualifiers.getDepth() != EldNone) error(loc, "can only apply depth layout to gl_FragDepth", "layout qualifier", ""); + if (identifier != "gl_FragStencilRefARB" && publicType.shaderQualifiers.getStencil() != ElsNone) + error(loc, "can only apply depth layout to gl_FragStencilRefARB", "layout qualifier", ""); // Check for redeclaration of built-ins and/or attempting to declare a reserved name TSymbol* symbol = redeclareBuiltinVariable(loc, identifier, type.getQualifier(), publicType.shaderQualifiers); @@ -7281,14 +7956,12 @@ TIntermNode* TParseContext::declareVariable(const TSourceLoc& loc, TString& iden // Pick up global defaults from the provide global defaults into dst. void TParseContext::inheritGlobalDefaults(TQualifier& dst) const { -#ifndef GLSLANG_WEB if (dst.storage == EvqVaryingOut) { if (! dst.hasStream() && language == EShLangGeometry) dst.layoutStream = globalOutputDefaults.layoutStream; if (! dst.hasXfbBuffer()) dst.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer; } -#endif } // @@ -7317,9 +7990,7 @@ TVariable* TParseContext::declareNonArray(const TSourceLoc& loc, const TString& // make a new variable TVariable* variable = new TVariable(&identifier, type); -#ifndef GLSLANG_WEB ioArrayCheck(loc, type, identifier); -#endif // add variable to symbol table if (symbolTable.insert(*variable)) { @@ -7396,9 +8067,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp TType skeletalType; skeletalType.shallowCopy(variable->getType()); skeletalType.getQualifier().makeTemporary(); -#ifndef GLSLANG_WEB initializer = convertInitializerList(loc, skeletalType, initializer); -#endif if (! initializer) { // error recovery; don't leave const without constant values if (qualifier == EvqConst) @@ -7426,14 +8095,14 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp // Uniforms require a compile-time constant initializer if (qualifier == EvqUniform && ! initializer->getType().getQualifier().isFrontEndConstant()) { error(loc, "uniform initializers must be constant", "=", "'%s'", - variable->getType().getCompleteString().c_str()); + variable->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str()); variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } // Global consts require a constant initializer (specialization constant is okay) if (qualifier == EvqConst && symbolTable.atGlobalLevel() && ! initializer->getType().getQualifier().isConstant()) { error(loc, "global const initializers must be constant", "=", "'%s'", - variable->getType().getCompleteString().c_str()); + variable->getType().getCompleteString(intermediate.getEnhancedMsgs()).c_str()); variable->getWritableType().getQualifier().makeTemporary(); return nullptr; } @@ -7496,7 +8165,7 @@ TIntermNode* TParseContext::executeInitializer(const TSourceLoc& loc, TIntermTyp TIntermSymbol* intermSymbol = intermediate.addSymbol(*variable, loc); TIntermTyped* initNode = intermediate.addAssign(EOpAssign, intermSymbol, initializer, loc); if (! initNode) - assignError(loc, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + assignError(loc, "=", intermSymbol->getCompleteString(intermediate.getEnhancedMsgs()), initializer->getCompleteString(intermediate.getEnhancedMsgs())); return initNode; } @@ -7567,7 +8236,7 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const } } else if (type.isMatrix()) { if (type.getMatrixCols() != (int)initList->getSequence().size()) { - error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString().c_str()); + error(loc, "wrong number of matrix columns:", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str()); return nullptr; } TType vectorType(type, 0); // dereferenced type @@ -7578,20 +8247,20 @@ TIntermTyped* TParseContext::convertInitializerList(const TSourceLoc& loc, const } } else if (type.isVector()) { if (type.getVectorSize() != (int)initList->getSequence().size()) { - error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString().c_str()); + error(loc, "wrong vector size (or rows in a matrix column):", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str()); return nullptr; } TBasicType destType = type.getBasicType(); for (int i = 0; i < type.getVectorSize(); ++i) { TBasicType initType = initList->getSequence()[i]->getAsTyped()->getBasicType(); if (destType != initType && !intermediate.canImplicitlyPromote(initType, destType)) { - error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString().c_str()); + error(loc, "type mismatch in initializer list", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str()); return nullptr; } } } else { - error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString().c_str()); + error(loc, "unexpected initializer-list type:", "initializer list", type.getCompleteString(intermediate.getEnhancedMsgs()).c_str()); return nullptr; } @@ -7626,12 +8295,14 @@ TIntermTyped* TParseContext::addConstructor(const TSourceLoc& loc, TIntermNode* // Combined texture-sampler constructors are completely semantic checked // in constructorTextureSamplerError() if (op == EOpConstructTextureSampler) { - if (aggrNode->getSequence()[1]->getAsTyped()->getType().getSampler().shadow) { - // Transfer depth into the texture (SPIR-V image) type, as a hint - // for tools to know this texture/image is a depth image. - aggrNode->getSequence()[0]->getAsTyped()->getWritableType().getSampler().shadow = true; + if (aggrNode != nullptr) { + if (aggrNode->getSequence()[1]->getAsTyped()->getType().getSampler().shadow) { + // Transfer depth into the texture (SPIR-V image) type, as a hint + // for tools to know this texture/image is a depth image. + aggrNode->getSequence()[0]->getAsTyped()->getWritableType().getSampler().shadow = true; + } + return intermediate.setAggregateOperator(aggrNode, op, type, loc); } - return intermediate.setAggregateOperator(aggrNode, op, type, loc); } TTypeList::const_iterator memberTypes; @@ -7766,7 +8437,18 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUvec2, true, node, type); return newNode; + } else if (node->getType().getBasicType() == EbtSampler) { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "sampler conversion to uvec2"); + // force the basic type of the constructor param to uvec2, otherwise spv builder will + // report some errors + TIntermTyped* newSrcNode = intermediate.createConversion(EbtUint, node); + newSrcNode->getAsTyped()->getWritableType().setVectorSize(2); + + TIntermTyped* newNode = + intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConstructUVec2, false, newSrcNode, type); + return newNode; } + [[fallthrough]]; case EOpConstructUVec3: case EOpConstructUVec4: case EOpConstructUint: @@ -7779,9 +8461,16 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EOpConstructBool: basicOp = EOpConstructBool; break; - -#ifndef GLSLANG_WEB - + case EOpConstructTextureSampler: + if ((node->getType().getBasicType() == EbtUint || node->getType().getBasicType() == EbtInt) && + node->getType().getVectorSize() == 2) { + requireExtensions(loc, 1, &E_GL_ARB_bindless_texture, "ivec2/uvec2 convert to texture handle"); + // No matter ivec2 or uvec2, Set EOpPackUint2x32 just to generate an opBitcast op code + TIntermTyped* newNode = + intermediate.addBuiltInFunctionCall(node->getLoc(), EOpPackUint2x32, true, node, type); + return newNode; + } + [[fallthrough]]; case EOpConstructDVec2: case EOpConstructDVec3: case EOpConstructDVec4: @@ -7934,7 +8623,7 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T TIntermTyped* newNode = intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvPtrToUint64, true, node, type); return newNode; } - // fall through + [[fallthrough]]; case EOpConstructU64Vec2: case EOpConstructU64Vec3: case EOpConstructU64Vec4: @@ -7967,14 +8656,18 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T return nullptr; } - case EOpConstructCooperativeMatrix: + case EOpConstructCooperativeMatrixNV: + case EOpConstructCooperativeMatrixKHR: + if (node->getType() == type) { + return node; + } if (!node->getType().isCoopMat()) { if (type.getBasicType() != node->getType().getBasicType()) { node = intermediate.addConversion(type.getBasicType(), node); if (node == nullptr) return nullptr; } - node = intermediate.setAggregateOperator(node, EOpConstructCooperativeMatrix, type, node->getLoc()); + node = intermediate.setAggregateOperator(node, op, type, node->getLoc()); } else { TOperator op = EOpNull; switch (type.getBasicType()) { @@ -7987,6 +8680,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat16: op = EOpConvFloat16ToInt; break; case EbtUint8: op = EOpConvUint8ToInt; break; case EbtInt8: op = EOpConvInt8ToInt; break; + case EbtUint16: op = EOpConvUint16ToInt; break; + case EbtInt16: op = EOpConvInt16ToInt; break; case EbtUint: op = EOpConvUintToInt; break; default: assert(0); } @@ -7997,8 +8692,33 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat16: op = EOpConvFloat16ToUint; break; case EbtUint8: op = EOpConvUint8ToUint; break; case EbtInt8: op = EOpConvInt8ToUint; break; + case EbtUint16: op = EOpConvUint16ToUint; break; + case EbtInt16: op = EOpConvInt16ToUint; break; case EbtInt: op = EOpConvIntToUint; break; - case EbtUint: op = EOpConvUintToInt8; break; + default: assert(0); + } + break; + case EbtInt16: + switch (node->getType().getBasicType()) { + case EbtFloat: op = EOpConvFloatToInt16; break; + case EbtFloat16: op = EOpConvFloat16ToInt16; break; + case EbtUint8: op = EOpConvUint8ToInt16; break; + case EbtInt8: op = EOpConvInt8ToInt16; break; + case EbtUint16: op = EOpConvUint16ToInt16; break; + case EbtInt: op = EOpConvIntToInt16; break; + case EbtUint: op = EOpConvUintToInt16; break; + default: assert(0); + } + break; + case EbtUint16: + switch (node->getType().getBasicType()) { + case EbtFloat: op = EOpConvFloatToUint16; break; + case EbtFloat16: op = EOpConvFloat16ToUint16; break; + case EbtUint8: op = EOpConvUint8ToUint16; break; + case EbtInt8: op = EOpConvInt8ToUint16; break; + case EbtInt16: op = EOpConvInt16ToUint16; break; + case EbtInt: op = EOpConvIntToUint16; break; + case EbtUint: op = EOpConvUintToUint16; break; default: assert(0); } break; @@ -8007,6 +8727,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat: op = EOpConvFloatToInt8; break; case EbtFloat16: op = EOpConvFloat16ToInt8; break; case EbtUint8: op = EOpConvUint8ToInt8; break; + case EbtInt16: op = EOpConvInt16ToInt8; break; + case EbtUint16: op = EOpConvUint16ToInt8; break; case EbtInt: op = EOpConvIntToInt8; break; case EbtUint: op = EOpConvUintToInt8; break; default: assert(0); @@ -8017,6 +8739,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat: op = EOpConvFloatToUint8; break; case EbtFloat16: op = EOpConvFloat16ToUint8; break; case EbtInt8: op = EOpConvInt8ToUint8; break; + case EbtInt16: op = EOpConvInt16ToUint8; break; + case EbtUint16: op = EOpConvUint16ToUint8; break; case EbtInt: op = EOpConvIntToUint8; break; case EbtUint: op = EOpConvUintToUint8; break; default: assert(0); @@ -8027,6 +8751,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat16: op = EOpConvFloat16ToFloat; break; case EbtInt8: op = EOpConvInt8ToFloat; break; case EbtUint8: op = EOpConvUint8ToFloat; break; + case EbtInt16: op = EOpConvInt16ToFloat; break; + case EbtUint16: op = EOpConvUint16ToFloat; break; case EbtInt: op = EOpConvIntToFloat; break; case EbtUint: op = EOpConvUintToFloat; break; default: assert(0); @@ -8037,6 +8763,8 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EbtFloat: op = EOpConvFloatToFloat16; break; case EbtInt8: op = EOpConvInt8ToFloat16; break; case EbtUint8: op = EOpConvUint8ToFloat16; break; + case EbtInt16: op = EOpConvInt16ToFloat16; break; + case EbtUint16: op = EOpConvUint16ToFloat16; break; case EbtInt: op = EOpConvIntToFloat16; break; case EbtUint: op = EOpConvUintToFloat16; break; default: assert(0); @@ -8055,17 +8783,16 @@ TIntermTyped* TParseContext::constructBuiltIn(const TType& type, TOperator op, T case EOpConstructAccStruct: if ((node->getType().isScalar() && node->getType().getBasicType() == EbtUint64)) { // construct acceleration structure from uint64 - requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "uint64_t conversion to acclerationStructureEXT"); + requireExtensions(loc, Num_ray_tracing_EXTs, ray_tracing_EXTs, "uint64_t conversion to acclerationStructureEXT"); return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUint64ToAccStruct, true, node, type); } else if (node->getType().isVector() && node->getType().getBasicType() == EbtUint && node->getVectorSize() == 2) { // construct acceleration structure from uint64 - requireExtensions(loc, 1, &E_GL_EXT_ray_tracing, "uvec2 conversion to accelerationStructureEXT"); + requireExtensions(loc, Num_ray_tracing_EXTs, ray_tracing_EXTs, "uvec2 conversion to accelerationStructureEXT"); return intermediate.addBuiltInFunctionCall(node->getLoc(), EOpConvUvec2ToAccStruct, true, node, type); } else return nullptr; -#endif // GLSLANG_WEB default: error(loc, "unsupported construction", "", ""); @@ -8099,8 +8826,9 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& { TIntermTyped* converted = intermediate.addConversion(EOpConstructStruct, type, node->getAsTyped()); if (! converted || converted->getType() != type) { + bool enhanced = intermediate.getEnhancedMsgs(); error(loc, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, - node->getAsTyped()->getType().getCompleteString().c_str(), type.getCompleteString().c_str()); + node->getAsTyped()->getType().getCompleteString(enhanced).c_str(), type.getCompleteString(enhanced).c_str()); return nullptr; } @@ -8111,7 +8839,6 @@ TIntermTyped* TParseContext::constructAggregate(TIntermNode* node, const TType& // If a memory qualifier is present in 'to', also make it present in 'from'. void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& to) { -#ifndef GLSLANG_WEB if (from.isReadOnly()) to.readonly = from.readonly; if (from.isWriteOnly()) @@ -8122,7 +8849,30 @@ void TParseContext::inheritMemoryQualifiers(const TQualifier& from, TQualifier& to.volatil = from.volatil; if (from.restrict) to.restrict = from.restrict; -#endif +} + +// +// Update qualifier layoutBindlessImage & layoutBindlessSampler on block member +// +void TParseContext::updateBindlessQualifier(TType& memberType) +{ + if (memberType.containsSampler()) { + if (memberType.isStruct()) { + TTypeList* typeList = memberType.getWritableStruct(); + for (unsigned int member = 0; member < typeList->size(); ++member) { + TType* subMemberType = (*typeList)[member].type; + updateBindlessQualifier(*subMemberType); + } + } + else if (memberType.getSampler().isImage()) { + intermediate.setBindlessImageMode(currentCaller, AstRefTypeLayout); + memberType.getQualifier().layoutBindlessImage = true; + } + else { + intermediate.setBindlessTextureMode(currentCaller, AstRefTypeLayout); + memberType.getQualifier().layoutBindlessSampler = true; + } + } } // @@ -8151,7 +8901,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con error(memberLoc, "member storage qualifier cannot contradict block storage qualifier", memberType.getFieldName().c_str(), ""); memberQualifier.storage = currentBlockQualifier.storage; globalQualifierFixCheck(memberLoc, memberQualifier); -#ifndef GLSLANG_WEB inheritMemoryQualifiers(currentBlockQualifier, memberQualifier); if (currentBlockQualifier.perPrimitiveNV) memberQualifier.perPrimitiveNV = currentBlockQualifier.perPrimitiveNV; @@ -8159,11 +8908,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con memberQualifier.perViewNV = currentBlockQualifier.perViewNV; if (currentBlockQualifier.perTaskNV) memberQualifier.perTaskNV = currentBlockQualifier.perTaskNV; + if (currentBlockQualifier.storage == EvqtaskPayloadSharedEXT) + memberQualifier.storage = EvqtaskPayloadSharedEXT; if (memberQualifier.storage == EvqSpirvStorageClass) error(memberLoc, "member cannot have a spirv_storage_class qualifier", memberType.getFieldName().c_str(), ""); - if (memberQualifier.hasSprivDecorate() && !memberQualifier.getSpirvDecorate().decorateIds.empty()) + if (memberQualifier.hasSpirvDecorate() && !memberQualifier.getSpirvDecorate().decorateIds.empty()) error(memberLoc, "member cannot have a spirv_decorate_id qualifier", memberType.getFieldName().c_str(), ""); -#endif if ((currentBlockQualifier.storage == EvqUniform || currentBlockQualifier.storage == EvqBuffer) && (memberQualifier.isInterpolation() || memberQualifier.isAuxiliary())) error(memberLoc, "member of uniform or buffer block cannot have an auxiliary or interpolation qualifier", memberType.getFieldName().c_str(), ""); if (memberType.isArray()) @@ -8175,8 +8925,13 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con } } - if (memberType.containsOpaque()) - error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), ""); + // For bindless texture, sampler can be declared as uniform/storage block member, + if (memberType.containsOpaque()) { + if (memberType.containsSampler() && extensionTurnedOn(E_GL_ARB_bindless_texture)) + updateBindlessQualifier(memberType); + else + error(memberLoc, "member of block cannot be or contain a sampler, image, or atomic_uint type", typeList[member].type->getFieldName().c_str(), ""); + } if (memberType.containsCoopMat()) error(memberLoc, "member of block cannot be or contain a cooperative matrix type", typeList[member].type->getFieldName().c_str(), ""); @@ -8238,7 +8993,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con for (unsigned int member = 0; member < typeList.size(); ++member) { TQualifier& memberQualifier = typeList[member].type->getQualifier(); const TSourceLoc& memberLoc = typeList[member].loc; -#ifndef GLSLANG_WEB if (memberQualifier.hasStream()) { if (defaultQualification.layoutStream != memberQualifier.layoutStream) error(memberLoc, "member cannot contradict block", "stream", ""); @@ -8252,14 +9006,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con if (defaultQualification.layoutXfbBuffer != memberQualifier.layoutXfbBuffer) error(memberLoc, "member cannot contradict block (or what block inherited from global)", "xfb_buffer", ""); } -#endif if (memberQualifier.hasPacking()) error(memberLoc, "member of block cannot have a packing layout qualifier", typeList[member].type->getFieldName().c_str(), ""); if (memberQualifier.hasLocation()) { const char* feature = "location on block member"; switch (currentBlockQualifier.storage) { -#ifndef GLSLANG_WEB case EvqVaryingIn: case EvqVaryingOut: requireProfile(memberLoc, ECoreProfile | ECompatibilityProfile | EEsProfile, feature); @@ -8267,7 +9019,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con profileRequires(memberLoc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, feature); memberWithLocation = true; break; -#endif default: error(memberLoc, "can only use in an in/out block", feature, ""); break; @@ -8295,7 +9046,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con layoutMemberLocationArrayCheck(loc, memberWithLocation, arraySizes); -#ifndef GLSLANG_WEB // Ensure that the block has an XfbBuffer assigned. This is needed // because if the block has a XfbOffset assigned, then it is // assumed that it has implicitly assigned the current global @@ -8305,7 +9055,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con if (!currentBlockQualifier.hasXfbBuffer() && currentBlockQualifier.hasXfbOffset()) currentBlockQualifier.layoutXfbBuffer = globalOutputDefaults.layoutXfbBuffer; } -#endif // Process the members fixBlockLocations(loc, currentBlockQualifier, typeList, memberWithLocation, memberWithoutLocation); @@ -8316,13 +9065,11 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con for (unsigned int member = 0; member < typeList.size(); ++member) layoutTypeCheck(typeList[member].loc, *typeList[member].type); -#ifndef GLSLANG_WEB if (memberWithPerViewQualifier) { for (unsigned int member = 0; member < typeList.size(); ++member) { checkAndResizeMeshViewDim(typeList[member].loc, *typeList[member].type, /*isBlockMember*/ true); } } -#endif // reverse merge, so that currentBlockQualifier now has all layout information // (can't use defaultQualification directly, it's missing other non-layout-default-class qualifiers) @@ -8336,7 +9083,6 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con if (arraySizes != nullptr) blockType.transferArraySizes(arraySizes); -#ifndef GLSLANG_WEB if (arraySizes == nullptr) ioArrayCheck(loc, blockType, instanceName ? *instanceName : *blockName); if (currentBlockQualifier.hasBufferReference()) { @@ -8363,9 +9109,7 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con if (!instanceName) { return; } - } else -#endif - { + } else { // // Don't make a user-defined type out of block name; that will cause an error // if the same block name gets reused in a different interface. @@ -8413,14 +9157,12 @@ void TParseContext::declareBlock(const TSourceLoc& loc, TTypeList& typeList, con // Check for general layout qualifier errors layoutObjectCheck(loc, variable); -#ifndef GLSLANG_WEB // fix up if (isIoResizeArray(blockType)) { ioArraySymbolResizeList.push_back(&variable); checkIoArraysConsistency(loc, true); } else fixIoArraySize(loc, variable.getWritableType()); -#endif // Save it in the AST for linker use. trackLinkage(variable); @@ -8459,23 +9201,23 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q // It is a compile-time error to have an input block in a vertex shader or an output block in a fragment shader // "Compute shaders do not permit user-defined input variables..." requireStage(loc, (EShLanguageMask)(EShLangTessControlMask|EShLangTessEvaluationMask|EShLangGeometryMask| - EShLangFragmentMask|EShLangMeshNVMask), "input block"); + EShLangFragmentMask|EShLangMeshMask), "input block"); if (language == EShLangFragment) { profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "fragment input block"); - } else if (language == EShLangMeshNV && ! qualifier.isTaskMemory()) { + } else if (language == EShLangMesh && ! qualifier.isTaskMemory()) { error(loc, "input blocks cannot be used in a mesh shader", "out", ""); } break; case EvqVaryingOut: profileRequires(loc, ~EEsProfile, 150, E_GL_ARB_separate_shader_objects, "output block"); requireStage(loc, (EShLanguageMask)(EShLangVertexMask|EShLangTessControlMask|EShLangTessEvaluationMask| - EShLangGeometryMask|EShLangMeshNVMask|EShLangTaskNVMask), "output block"); + EShLangGeometryMask|EShLangMeshMask|EShLangTaskMask), "output block"); // ES 310 can have a block before shader_io is turned on, so skip this test for built-ins if (language == EShLangVertex && ! parsingBuiltins) { profileRequires(loc, EEsProfile, 320, Num_AEP_shader_io_blocks, AEP_shader_io_blocks, "vertex output block"); - } else if (language == EShLangMeshNV && qualifier.isTaskMemory()) { + } else if (language == EShLangMesh && qualifier.isTaskMemory()) { error(loc, "can only use on input blocks in mesh shader", "taskNV", ""); - } else if (language == EShLangTaskNV && ! qualifier.isTaskMemory()) { + } else if (language == EShLangTask && ! qualifier.isTaskMemory()) { error(loc, "output blocks cannot be used in a task shader", "out", ""); } break; @@ -8485,7 +9227,6 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q } profileRequires(loc, EEsProfile | ECoreProfile | ECompatibilityProfile, 0, E_GL_EXT_shared_memory_block, "shared block"); break; -#ifndef GLSLANG_WEB case EvqPayload: profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "rayPayloadNV block"); requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangAnyHitMask | EShLangClosestHitMask | EShLangMissMask), @@ -8509,7 +9250,10 @@ void TParseContext::blockStageIoCheck(const TSourceLoc& loc, const TQualifier& q profileRequires(loc, ~EEsProfile, 460, 2, extsrt, "callableDataInNV block"); requireStage(loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV block"); break; -#endif + case EvqHitObjectAttrNV: + profileRequires(loc, ~EEsProfile, 460, E_GL_NV_shader_invocation_reorder, "hitObjectAttributeNV block"); + requireStage(loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | EShLangMissMask), "hitObjectAttributeNV block"); + break; default: error(loc, "only uniform, buffer, in, or out blocks are supported", blockName->c_str(), ""); break; @@ -8598,7 +9342,6 @@ void TParseContext::fixBlockLocations(const TSourceLoc& loc, TQualifier& qualifi void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList) { -#ifndef GLSLANG_WEB // "If a block is qualified with xfb_offset, all its // members are assigned transform feedback buffer offsets. If a block is not qualified with xfb_offset, any // members of that block not qualified with an xfb_offset will not be assigned transform feedback buffer @@ -8632,7 +9375,6 @@ void TParseContext::fixXfbOffsets(TQualifier& qualifier, TTypeList& typeList) // The above gave all block members an offset, so we can take it off the block now, // which will avoid double counting the offset usage. qualifier.layoutXfbOffset = TQualifier::layoutXfbOffsetEnd; -#endif } // Calculate and save the offset of each block member, using the recursively @@ -8665,7 +9407,8 @@ void TParseContext::fixBlockUniformOffsets(TQualifier& qualifier, TTypeList& typ // "The specified offset must be a multiple // of the base alignment of the type of the block member it qualifies, or a compile-time error results." if (! IsMultipleOfPow2(memberQualifier.layoutOffset, memberAlignment)) - error(memberLoc, "must be a multiple of the member's alignment", "offset", ""); + error(memberLoc, "must be a multiple of the member's alignment", "offset", + "(layout offset = %d | member alignment = %d)", memberQualifier.layoutOffset, memberAlignment); // GLSL: "It is a compile-time error to specify an offset that is smaller than the offset of the previous // member in the block or that lies within the previous member of the block" @@ -8808,7 +9551,7 @@ void TParseContext::addQualifierToExisting(const TSourceLoc& loc, TQualifier qua // TParseContext::declareBlock. if (!symbol && qualifier.hasBufferReference()) { TTypeList typeList; - TType blockType(&typeList, identifier, qualifier);; + TType blockType(&typeList, identifier, qualifier); TType blockNameType(EbtReference, blockType, identifier); TVariable* blockNameVar = new TVariable(&identifier, blockNameType, true); if (! symbolTable.insert(*blockNameVar)) { @@ -8887,9 +9630,8 @@ void TParseContext::invariantCheck(const TSourceLoc& loc, const TQualifier& qual // void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, const TPublicType& publicType) { -#ifndef GLSLANG_WEB if (publicType.shaderQualifiers.vertices != TQualifier::layoutNotSet) { - assert(language == EShLangTessControl || language == EShLangGeometry || language == EShLangMeshNV); + assert(language == EShLangTessControl || language == EShLangGeometry || language == EShLangMesh); const char* id = (language == EShLangTessControl) ? "vertices" : "max_vertices"; if (publicType.qualifier.storage != EvqVaryingOut) @@ -8901,7 +9643,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con checkIoArraysConsistency(loc); } if (publicType.shaderQualifiers.primitives != TQualifier::layoutNotSet) { - assert(language == EShLangMeshNV); + assert(language == EShLangMesh); const char* id = "max_primitives"; if (publicType.qualifier.storage != EvqVaryingOut) @@ -8925,7 +9667,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con case ElgTrianglesAdjacency: case ElgQuads: case ElgIsolines: - if (language == EShLangMeshNV) { + if (language == EShLangMesh) { error(loc, "cannot apply to input", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); break; } @@ -8942,11 +9684,11 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con switch (publicType.shaderQualifiers.geometry) { case ElgLines: case ElgTriangles: - if (language != EShLangMeshNV) { + if (language != EShLangMesh) { error(loc, "cannot apply to 'out'", TQualifier::getGeometryString(publicType.shaderQualifiers.geometry), ""); break; } - // Fall through + [[fallthrough]]; case ElgPoints: case ElgLineStrip: case ElgTriangleStrip: @@ -8979,7 +9721,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con else error(loc, "can only apply to 'in'", "point_mode", ""); } -#endif + for (int i = 0; i < 3; ++i) { if (publicType.shaderQualifiers.localSizeNotDefault[i]) { if (publicType.qualifier.storage == EvqVaryingIn) { @@ -8996,29 +9738,57 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con } if (intermediate.getLocalSize(i) > (unsigned int)max) error(loc, "too large; see gl_MaxComputeWorkGroupSize", "local_size", ""); - } -#ifndef GLSLANG_WEB - else if (language == EShLangMeshNV) { + } else if (language == EShLangMesh) { switch (i) { - case 0: max = resources.maxMeshWorkGroupSizeX_NV; break; - case 1: max = resources.maxMeshWorkGroupSizeY_NV; break; - case 2: max = resources.maxMeshWorkGroupSizeZ_NV; break; + case 0: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxMeshWorkGroupSizeX_EXT : + resources.maxMeshWorkGroupSizeX_NV; + break; + case 1: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxMeshWorkGroupSizeY_EXT : + resources.maxMeshWorkGroupSizeY_NV ; + break; + case 2: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxMeshWorkGroupSizeZ_EXT : + resources.maxMeshWorkGroupSizeZ_NV ; + break; default: break; } - if (intermediate.getLocalSize(i) > (unsigned int)max) - error(loc, "too large; see gl_MaxMeshWorkGroupSizeNV", "local_size", ""); - } else if (language == EShLangTaskNV) { + if (intermediate.getLocalSize(i) > (unsigned int)max) { + TString maxsErrtring = "too large, see "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? + "gl_MaxMeshWorkGroupSizeEXT" : "gl_MaxMeshWorkGroupSizeNV"); + error(loc, maxsErrtring.c_str(), "local_size", ""); + } + } else if (language == EShLangTask) { switch (i) { - case 0: max = resources.maxTaskWorkGroupSizeX_NV; break; - case 1: max = resources.maxTaskWorkGroupSizeY_NV; break; - case 2: max = resources.maxTaskWorkGroupSizeZ_NV; break; + case 0: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxTaskWorkGroupSizeX_EXT : + resources.maxTaskWorkGroupSizeX_NV; + break; + case 1: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxTaskWorkGroupSizeY_EXT: + resources.maxTaskWorkGroupSizeY_NV; + break; + case 2: + max = extensionTurnedOn(E_GL_EXT_mesh_shader) ? + resources.maxTaskWorkGroupSizeZ_EXT: + resources.maxTaskWorkGroupSizeZ_NV; + break; default: break; } - if (intermediate.getLocalSize(i) > (unsigned int)max) - error(loc, "too large; see gl_MaxTaskWorkGroupSizeNV", "local_size", ""); - } -#endif - else { + if (intermediate.getLocalSize(i) > (unsigned int)max) { + TString maxsErrtring = "too large, see "; + maxsErrtring.append(extensionTurnedOn(E_GL_EXT_mesh_shader) ? + "gl_MaxTaskWorkGroupSizeEXT" : "gl_MaxTaskWorkGroupSizeNV"); + error(loc, maxsErrtring.c_str(), "local_size", ""); + } + } else { assert(0); } @@ -9043,19 +9813,42 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con } } -#ifndef GLSLANG_WEB if (publicType.shaderQualifiers.earlyFragmentTests) { if (publicType.qualifier.storage == EvqVaryingIn) intermediate.setEarlyFragmentTests(); else error(loc, "can only apply to 'in'", "early_fragment_tests", ""); } + if (publicType.shaderQualifiers.earlyAndLateFragmentTestsAMD) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setEarlyAndLateFragmentTestsAMD(); + else + error(loc, "can only apply to 'in'", "early_and_late_fragment_tests_amd", ""); + } if (publicType.shaderQualifiers.postDepthCoverage) { if (publicType.qualifier.storage == EvqVaryingIn) intermediate.setPostDepthCoverage(); else error(loc, "can only apply to 'in'", "post_coverage_coverage", ""); } + if (publicType.shaderQualifiers.nonCoherentColorAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentColorAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_color_attachment_readEXT", ""); + } + if (publicType.shaderQualifiers.nonCoherentDepthAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentDepthAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_depth_attachment_readEXT", ""); + } + if (publicType.shaderQualifiers.nonCoherentStencilAttachmentReadEXT) { + if (publicType.qualifier.storage == EvqVaryingIn) + intermediate.setNonCoherentStencilAttachmentReadEXT(); + else + error(loc, "can only apply to 'in'", "non_coherent_stencil_attachment_readEXT", ""); + } if (publicType.shaderQualifiers.hasBlendEquation()) { if (publicType.qualifier.storage != EvqVaryingOut) error(loc, "can only apply to 'out'", "blend equation", ""); @@ -9098,7 +9891,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con error(loc, "can only apply to 'in'", "derivative_group_linearNV", ""); } // Check mesh out array sizes, once all the necessary out qualifiers are defined. - if ((language == EShLangMeshNV) && + if ((language == EShLangMesh) && (intermediate.getVertices() != TQualifier::layoutNotSet) && (intermediate.getPrimitives() != TQualifier::layoutNotSet) && (intermediate.getOutputPrimitive() != ElgNone)) @@ -9115,7 +9908,7 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con // Exit early as further checks are not valid return; } -#endif + const TQualifier& qualifier = publicType.qualifier; if (qualifier.isAuxiliary() || @@ -9148,7 +9941,6 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con case EvqVaryingIn: break; case EvqVaryingOut: -#ifndef GLSLANG_WEB if (qualifier.hasStream()) globalOutputDefaults.layoutStream = qualifier.layoutStream; if (qualifier.hasXfbBuffer()) @@ -9157,7 +9949,6 @@ void TParseContext::updateStandaloneQualifierDefaults(const TSourceLoc& loc, con if (! intermediate.setXfbBufferStride(globalOutputDefaults.layoutXfbBuffer, qualifier.layoutXfbStride)) error(loc, "all stride settings must match for xfb buffer", "xfb_stride", "%d", qualifier.layoutXfbBuffer); } -#endif break; case EvqShared: if (qualifier.hasMatrix()) @@ -9312,5 +10103,38 @@ const TTypeList* TParseContext::recordStructCopy(TStructRecord& record, const TT return originStruct; } -} // end namespace glslang +TLayoutFormat TParseContext::mapLegacyLayoutFormat(TLayoutFormat legacyLayoutFormat, TBasicType imageType) +{ + TLayoutFormat layoutFormat = ElfNone; + if (imageType == EbtFloat) { + switch (legacyLayoutFormat) { + case ElfSize1x16: layoutFormat = ElfR16f; break; + case ElfSize1x32: layoutFormat = ElfR32f; break; + case ElfSize2x32: layoutFormat = ElfRg32f; break; + case ElfSize4x32: layoutFormat = ElfRgba32f; break; + default: break; + } + } else if (imageType == EbtUint) { + switch (legacyLayoutFormat) { + case ElfSize1x8: layoutFormat = ElfR8ui; break; + case ElfSize1x16: layoutFormat = ElfR16ui; break; + case ElfSize1x32: layoutFormat = ElfR32ui; break; + case ElfSize2x32: layoutFormat = ElfRg32ui; break; + case ElfSize4x32: layoutFormat = ElfRgba32ui; break; + default: break; + } + } else if (imageType == EbtInt) { + switch (legacyLayoutFormat) { + case ElfSize1x8: layoutFormat = ElfR8i; break; + case ElfSize1x16: layoutFormat = ElfR16i; break; + case ElfSize1x32: layoutFormat = ElfR32i; break; + case ElfSize2x32: layoutFormat = ElfRg32i; break; + case ElfSize4x32: layoutFormat = ElfRgba32i; break; + default: break; + } + } + return layoutFormat; +} + +} // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h index 885fd9081..16902aefe 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h +++ b/src/libraries/glslang/glslang/MachineIndependent/ParseHelper.h @@ -95,12 +95,15 @@ public: globalUniformSet(TQualifier::layoutSetEnd), atomicCounterBlockSet(TQualifier::layoutSetEnd) { + // use storage buffer on SPIR-V 1.3 and up + if (spvVersion.spv >= EShTargetSpv_1_3) + intermediate.setUseStorageBuffer(); + if (entryPoint != nullptr) sourceEntryPointName = *entryPoint; } virtual ~TParseContextBase() { } -#if !defined(GLSLANG_WEB) || defined(GLSLANG_WEB_DEVEL) virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...); virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, @@ -109,7 +112,6 @@ public: const char* szExtraInfoFormat, ...); virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...); -#endif virtual void setLimits(const TBuiltInResource&) = 0; @@ -178,6 +180,7 @@ public: // Basic parsing state, easily accessible to the grammar TSymbolTable& symbolTable; // symbol table that goes with the current language, version, and profile + TVector relaxedSymbols; int statementNestingLevel; // 0 if outside all flow control or compound statements int loopNestingLevel; // 0 if outside all loops int structNestingLevel; // 0 if outside structures @@ -194,6 +197,7 @@ public: struct TPragma contextPragma; int beginInvocationInterlockCount; int endInvocationInterlockCount; + bool compileOnly = false; protected: TParseContextBase(TParseContextBase&); @@ -327,10 +331,8 @@ public: TIntermTyped* handleBracketDereference(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); void handleIndexLimits(const TSourceLoc&, TIntermTyped* base, TIntermTyped* index); -#ifndef GLSLANG_WEB void makeEditable(TSymbol*&) override; void ioArrayCheck(const TSourceLoc&, const TType&, const TString& identifier); -#endif bool isIoResizeArray(const TType&) const; void fixIoArraySize(const TSourceLoc&, TType&); void handleIoResizeArrayAccess(const TSourceLoc&, TIntermTyped* base); @@ -366,6 +368,10 @@ public: TIntermTyped* vkRelaxedRemapFunctionCall(const TSourceLoc&, TFunction*, TIntermNode*); // returns true if the variable was remapped to something else bool vkRelaxedRemapUniformVariable(const TSourceLoc&, TString&, const TPublicType&, TArraySizes*, TIntermTyped*, TType&); + void vkRelaxedRemapUniformMembers(const TSourceLoc&, const TPublicType&, const TType&, const TString&); + void vkRelaxedRemapFunctionParameter(TFunction*, TParameter&, std::vector* newParams = nullptr); + TIntermNode* vkRelaxedRemapFunctionArgument(const TSourceLoc&, TFunction*, TIntermTyped*); + TIntermTyped* vkRelaxedRemapDotDereference(const TSourceLoc&, TIntermTyped&, const TType&, const TString&); void assignError(const TSourceLoc&, const char* op, TString left, TString right); void unaryOpError(const TSourceLoc&, const char* op, TString operand); @@ -378,7 +384,7 @@ public: void globalCheck(const TSourceLoc&, const char* token); bool constructorError(const TSourceLoc&, TIntermNode*, TFunction&, TOperator, TType&); bool constructorTextureSamplerError(const TSourceLoc&, const TFunction&); - void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType); + void arraySizeCheck(const TSourceLoc&, TIntermTyped* expr, TArraySize&, const char *sizeType, const bool allowZero = false); bool arrayQualifierError(const TSourceLoc&, const TQualifier&); bool arrayError(const TSourceLoc&, const TType&); void arraySizeRequiredCheck(const TSourceLoc&, const TArraySizes&); @@ -393,14 +399,14 @@ public: void accStructCheck(const TSourceLoc & loc, const TType & type, const TString & identifier); void transparentOpaqueCheck(const TSourceLoc&, const TType&, const TString& identifier); void memberQualifierCheck(glslang::TPublicType&); - void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false); + void globalQualifierFixCheck(const TSourceLoc&, TQualifier&, bool isMemberCheck = false, const TPublicType* publicType = nullptr); void globalQualifierTypeCheck(const TSourceLoc&, const TQualifier&, const TPublicType&); bool structQualifierErrorCheck(const TSourceLoc&, const TPublicType& pType); void mergeQualifiers(const TSourceLoc&, TQualifier& dst, const TQualifier& src, bool force); void setDefaultPrecision(const TSourceLoc&, TPublicType&, TPrecisionQualifier); int computeSamplerTypeIndex(TSampler&); TPrecisionQualifier getDefaultPrecision(TPublicType&); - void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&); + void precisionQualifierCheck(const TSourceLoc&, TBasicType, TQualifier&, bool isCoopMat); void parameterTypeCheck(const TSourceLoc&, TStorageQualifier qualifier, const TType& type); bool containsFieldWithBasicType(const TType& type ,TBasicType basicType); TSymbol* redeclareBuiltinVariable(const TSourceLoc&, const TString&, const TQualifier&, const TShaderQualifiers&); @@ -418,6 +424,7 @@ public: void inductiveLoopCheck(const TSourceLoc&, TIntermNode* init, TIntermLoop* loop); void arrayLimitCheck(const TSourceLoc&, const TString&, int size); void limitCheck(const TSourceLoc&, int value, const char* limit, const char* feature); + void coopMatTypeParametersCheck(const TSourceLoc&, const TPublicType&); void inductiveLoopBodyCheck(TIntermNode*, long long loopIndexId, TSymbolTable&); void constantIndexExpressionCheck(TIntermNode*); @@ -438,12 +445,12 @@ public: const TFunction* findFunction400(const TSourceLoc& loc, const TFunction& call, bool& builtIn); const TFunction* findFunctionExplicitTypes(const TSourceLoc& loc, const TFunction& call, bool& builtIn); void declareTypeDefaults(const TSourceLoc&, const TPublicType&); - TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = 0, TIntermTyped* initializer = 0); + TIntermNode* declareVariable(const TSourceLoc&, TString& identifier, const TPublicType&, TArraySizes* typeArray = nullptr, TIntermTyped* initializer = nullptr); TIntermTyped* addConstructor(const TSourceLoc&, TIntermNode*, const TType&); TIntermTyped* constructAggregate(TIntermNode*, const TType&, int, const TSourceLoc&); TIntermTyped* constructBuiltIn(const TType&, TOperator, TIntermTyped*, const TSourceLoc&, bool subset); void inheritMemoryQualifiers(const TQualifier& from, TQualifier& to); - void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = 0, TArraySizes* arraySizes = 0); + void declareBlock(const TSourceLoc&, TTypeList& typeList, const TString* instanceName = nullptr, TArraySizes* arraySizes = nullptr); void blockStorageRemap(const TSourceLoc&, const TString*, TQualifier&); void blockStageIoCheck(const TSourceLoc&, const TQualifier&); void blockQualifierCheck(const TSourceLoc&, const TQualifier&, bool instanceName); @@ -456,11 +463,12 @@ public: void addQualifierToExisting(const TSourceLoc&, TQualifier, TIdentifierList&); void invariantCheck(const TSourceLoc&, const TQualifier&); void updateStandaloneQualifierDefaults(const TSourceLoc&, const TPublicType&); + void updateBindlessQualifier(TType& memberType); void wrapupSwitchSubsequence(TIntermAggregate* statements, TIntermNode* branchNode); TIntermNode* addSwitch(const TSourceLoc&, TIntermTyped* expression, TIntermAggregate* body); const TTypeList* recordStructCopy(TStructRecord&, const TType*, const TType*); + TLayoutFormat mapLegacyLayoutFormat(TLayoutFormat legacyLayoutFormat, TBasicType imageType); -#ifndef GLSLANG_WEB TAttributeType attributeFromName(const TString& name) const; TAttributes* makeAttributes(const TString& identifier) const; TAttributes* makeAttributes(const TString& identifier, TIntermNode* node) const; @@ -480,14 +488,13 @@ public: TSpirvRequirement* mergeSpirvRequirements(const TSourceLoc& loc, TSpirvRequirement* spirvReq1, TSpirvRequirement* spirvReq2); TSpirvTypeParameters* makeSpirvTypeParameters(const TSourceLoc& loc, const TIntermConstantUnion* constant); + TSpirvTypeParameters* makeSpirvTypeParameters(const TSourceLoc& loc, const TPublicType& type); TSpirvTypeParameters* mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2); TSpirvInstruction* makeSpirvInstruction(const TSourceLoc& loc, const TString& name, const TString& value); TSpirvInstruction* makeSpirvInstruction(const TSourceLoc& loc, const TString& name, int value); TSpirvInstruction* mergeSpirvInstruction(const TSourceLoc& loc, TSpirvInstruction* spirvInst1, TSpirvInstruction* spirvInst2); -#endif - void checkAndResizeMeshViewDim(const TSourceLoc&, TType&, bool isBlockMember); protected: @@ -500,9 +507,7 @@ protected: bool isRuntimeLength(const TIntermTyped&) const; TIntermNode* executeInitializer(const TSourceLoc&, TIntermTyped* initializer, TVariable* variable); TIntermTyped* convertInitializerList(const TSourceLoc&, const TType&, TIntermTyped* initializer); -#ifndef GLSLANG_WEB void finish() override; -#endif virtual const char* getGlobalUniformBlockName() const override; virtual void finalizeGlobalUniformBlockLayout(TVariable&) override; @@ -539,7 +544,6 @@ protected: TQualifier globalOutputDefaults; TQualifier globalSharedDefaults; TString currentCaller; // name of last function body entered (not valid when at global scope) -#ifndef GLSLANG_WEB int* atomicUintOffsets; // to become an array of the right size to hold an offset per binding point bool anyIndexLimits; TIdSetType inductiveLoopIds; @@ -580,7 +584,6 @@ protected: // array-sizing declarations // TVector ioArraySymbolResizeList; -#endif }; } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp b/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp index 84c40f4e7..5d7173c9d 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/PoolAlloc.cpp @@ -35,34 +35,28 @@ #include "../Include/Common.h" #include "../Include/PoolAlloc.h" -#include "../Include/InitializeGlobals.h" -#include "../OSDependent/osinclude.h" - namespace glslang { -// Process-wide TLS index -OS_TLSIndex PoolIndex; +namespace { +thread_local TPoolAllocator* threadPoolAllocator = nullptr; + +TPoolAllocator* GetDefaultThreadPoolAllocator() +{ + thread_local TPoolAllocator defaultAllocator; + return &defaultAllocator; +} +} // anonymous namespace // Return the thread-specific current pool. TPoolAllocator& GetThreadPoolAllocator() { - return *static_cast(OS_GetTLSValue(PoolIndex)); + return *(threadPoolAllocator ? threadPoolAllocator : GetDefaultThreadPoolAllocator()); } // Set the thread-specific current pool. void SetThreadPoolAllocator(TPoolAllocator* poolAllocator) { - OS_SetTLSValue(PoolIndex, poolAllocator); -} - -// Process-wide set up of the TLS pool storage. -bool InitializePoolIndex() -{ - // Allocate a TLS index. - if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX) - return false; - - return true; + threadPoolAllocator = poolAllocator; } // @@ -137,16 +131,6 @@ TPoolAllocator::~TPoolAllocator() } } -const unsigned char TAllocation::guardBlockBeginVal = 0xfb; -const unsigned char TAllocation::guardBlockEndVal = 0xfe; -const unsigned char TAllocation::userDataFill = 0xcd; - -# ifdef GUARD_BLOCKS - const size_t TAllocation::guardBlockSize = 16; -# else - const size_t TAllocation::guardBlockSize = 0; -# endif - // // Check a single guard block for damage // @@ -267,8 +251,8 @@ void* TPoolAllocator::allocate(size_t numBytes) // size_t numBytesToAlloc = allocationSize + headerSkip; tHeader* memory = reinterpret_cast(::new char[numBytesToAlloc]); - if (memory == 0) - return 0; + if (memory == nullptr) + return nullptr; // Use placement-new to initialize header new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); @@ -289,8 +273,8 @@ void* TPoolAllocator::allocate(size_t numBytes) freeList = freeList->nextPage; } else { memory = reinterpret_cast(::new char[pageSize]); - if (memory == 0) - return 0; + if (memory == nullptr) + return nullptr; } // Use placement-new to initialize header @@ -308,7 +292,7 @@ void* TPoolAllocator::allocate(size_t numBytes) // void TAllocation::checkAllocList() const { - for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + for (const TAllocation* alloc = this; alloc != nullptr; alloc = alloc->prevAlloc) alloc->check(); } diff --git a/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp b/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp index ce6a6199d..b3f3dc4d4 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Scan.cpp @@ -324,11 +324,9 @@ struct str_hash // A single global usable by all threads, by all versions, by all languages. // After a single process-level initialization, this is read only and thread safe std::unordered_map* KeywordMap = nullptr; -#ifndef GLSLANG_WEB std::unordered_set* ReservedSet = nullptr; -#endif -}; +} namespace glslang { @@ -343,6 +341,7 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["const"] = CONST; (*KeywordMap)["uniform"] = UNIFORM; + (*KeywordMap)["tileImageEXT"] = TILEIMAGEEXT; (*KeywordMap)["buffer"] = BUFFER; (*KeywordMap)["in"] = IN; (*KeywordMap)["out"] = OUT; @@ -408,7 +407,6 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["uvec3"] = UVEC3; (*KeywordMap)["uvec4"] = UVEC4; -#ifndef GLSLANG_WEB (*KeywordMap)["nonuniformEXT"] = NONUNIFORM; (*KeywordMap)["demote"] = DEMOTE; (*KeywordMap)["attribute"] = ATTRIBUTE; @@ -598,7 +596,6 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["spirv_storage_class"] = SPIRV_STORAGE_CLASS; (*KeywordMap)["spirv_by_reference"] = SPIRV_BY_REFERENCE; (*KeywordMap)["spirv_literal"] = SPIRV_LITERAL; -#endif (*KeywordMap)["sampler2D"] = SAMPLER2D; (*KeywordMap)["samplerCube"] = SAMPLERCUBE; @@ -632,7 +629,6 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["sampler"] = SAMPLER; (*KeywordMap)["samplerShadow"] = SAMPLERSHADOW; -#ifndef GLSLANG_WEB (*KeywordMap)["textureCubeArray"] = TEXTURECUBEARRAY; (*KeywordMap)["itextureCubeArray"] = ITEXTURECUBEARRAY; (*KeywordMap)["utextureCubeArray"] = UTEXTURECUBEARRAY; @@ -685,6 +681,10 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["texture2DRect"] = TEXTURE2DRECT; (*KeywordMap)["texture1DArray"] = TEXTURE1DARRAY; + (*KeywordMap)["attachmentEXT"] = ATTACHMENTEXT; + (*KeywordMap)["iattachmentEXT"] = IATTACHMENTEXT; + (*KeywordMap)["uattachmentEXT"] = UATTACHMENTEXT; + (*KeywordMap)["subpassInput"] = SUBPASSINPUT; (*KeywordMap)["subpassInputMS"] = SUBPASSINPUTMS; (*KeywordMap)["isubpassInput"] = ISUBPASSINPUT; @@ -739,6 +739,7 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["f16subpassInputMS"] = F16SUBPASSINPUTMS; (*KeywordMap)["__explicitInterpAMD"] = EXPLICITINTERPAMD; (*KeywordMap)["pervertexNV"] = PERVERTEXNV; + (*KeywordMap)["pervertexEXT"] = PERVERTEXEXT; (*KeywordMap)["precise"] = PRECISE; (*KeywordMap)["rayPayloadNV"] = PAYLOADNV; @@ -757,11 +758,18 @@ void TScanContext::fillInKeywordMap() (*KeywordMap)["perprimitiveNV"] = PERPRIMITIVENV; (*KeywordMap)["perviewNV"] = PERVIEWNV; (*KeywordMap)["taskNV"] = PERTASKNV; + (*KeywordMap)["perprimitiveEXT"] = PERPRIMITIVEEXT; + (*KeywordMap)["taskPayloadSharedEXT"] = TASKPAYLOADWORKGROUPEXT; (*KeywordMap)["fcoopmatNV"] = FCOOPMATNV; (*KeywordMap)["icoopmatNV"] = ICOOPMATNV; (*KeywordMap)["ucoopmatNV"] = UCOOPMATNV; + (*KeywordMap)["coopmat"] = COOPMAT; + + (*KeywordMap)["hitObjectNV"] = HITOBJECTNV; + (*KeywordMap)["hitObjectAttributeNV"] = HITOBJECTATTRNV; + ReservedSet = new std::unordered_set; ReservedSet->insert("common"); @@ -801,17 +809,14 @@ void TScanContext::fillInKeywordMap() ReservedSet->insert("cast"); ReservedSet->insert("namespace"); ReservedSet->insert("using"); -#endif } void TScanContext::deleteKeywordMap() { delete KeywordMap; KeywordMap = nullptr; -#ifndef GLSLANG_WEB delete ReservedSet; ReservedSet = nullptr; -#endif } // Called by yylex to get the next token. @@ -892,14 +897,12 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) case PpAtomConstInt: parserToken->sType.lex.i = ppToken.ival; return INTCONSTANT; case PpAtomConstUint: parserToken->sType.lex.i = ppToken.ival; return UINTCONSTANT; case PpAtomConstFloat: parserToken->sType.lex.d = ppToken.dval; return FLOATCONSTANT; -#ifndef GLSLANG_WEB case PpAtomConstInt16: parserToken->sType.lex.i = ppToken.ival; return INT16CONSTANT; case PpAtomConstUint16: parserToken->sType.lex.i = ppToken.ival; return UINT16CONSTANT; case PpAtomConstInt64: parserToken->sType.lex.i64 = ppToken.i64val; return INT64CONSTANT; case PpAtomConstUint64: parserToken->sType.lex.i64 = ppToken.i64val; return UINT64CONSTANT; case PpAtomConstDouble: parserToken->sType.lex.d = ppToken.dval; return DOUBLECONSTANT; case PpAtomConstFloat16: parserToken->sType.lex.d = ppToken.dval; return FLOAT16CONSTANT; -#endif case PpAtomIdentifier: { int token = tokenizeIdentifier(); @@ -921,10 +924,8 @@ int TScanContext::tokenize(TPpContext* pp, TParserToken& token) int TScanContext::tokenizeIdentifier() { -#ifndef GLSLANG_WEB if (ReservedSet->find(tokenText) != ReservedSet->end()) return reservedWord(); -#endif auto it = KeywordMap->find(tokenText); if (it == KeywordMap->end()) { @@ -936,6 +937,7 @@ int TScanContext::tokenizeIdentifier() switch (keyword) { case CONST: case UNIFORM: + case TILEIMAGEEXT: case IN: case OUT: case INOUT: @@ -1046,7 +1048,6 @@ int TScanContext::tokenizeIdentifier() return identifierOrReserved(reserved); } -#ifndef GLSLANG_WEB case NOPERSPECTIVE: if (parseContext.extensionTurnedOn(E_GL_NV_shader_noperspective_interpolation)) return keyword; @@ -1072,12 +1073,18 @@ int TScanContext::tokenizeIdentifier() parseContext.extensionTurnedOn(E_GL_NV_ray_tracing)) return keyword; return identifierOrType(); + case ACCSTRUCTEXT: + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_ray_tracing) || + parseContext.extensionTurnedOn(E_GL_EXT_ray_query) || + parseContext.extensionTurnedOn(E_GL_NV_displacement_micromap)) + return keyword; + return identifierOrType(); case PAYLOADEXT: case PAYLOADINEXT: case HITATTREXT: case CALLDATAEXT: case CALLDATAINEXT: - case ACCSTRUCTEXT: if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_EXT_ray_tracing) || parseContext.extensionTurnedOn(E_GL_EXT_ray_query)) @@ -1133,7 +1140,7 @@ int TScanContext::tokenizeIdentifier() case SUBROUTINE: return es30ReservedFromGLSL(400); -#endif + case SHARED: if ((parseContext.isEsProfile() && parseContext.version < 300) || (!parseContext.isEsProfile() && parseContext.version < 140)) @@ -1168,7 +1175,6 @@ int TScanContext::tokenizeIdentifier() case MAT4X4: return matNxM(); -#ifndef GLSLANG_WEB case DMAT2: case DMAT3: case DMAT4: @@ -1473,13 +1479,14 @@ int TScanContext::tokenizeIdentifier() return keyword; else return identifierOrType(); -#endif case UINT: case UVEC2: case UVEC3: case UVEC4: case SAMPLERCUBESHADOW: + case SAMPLER2DARRAY: + case SAMPLER2DARRAYSHADOW: case ISAMPLER2D: case ISAMPLER3D: case ISAMPLERCUBE: @@ -1489,6 +1496,12 @@ int TScanContext::tokenizeIdentifier() case USAMPLERCUBE: case USAMPLER2DARRAY: afterType = true; + if (keyword == SAMPLER2DARRAY || keyword == SAMPLER2DARRAYSHADOW) { + if ((keyword == SAMPLER2DARRAY || !parseContext.isEsProfile()) && + (parseContext.extensionTurnedOn(E_GL_EXT_texture_array) || parseContext.symbolTable.atBuiltInLevel())) { + return keyword; + } + } return nonreservedKeyword(300, 130); case SAMPLER3D: @@ -1526,12 +1539,18 @@ int TScanContext::tokenizeIdentifier() else return identifierOrType(); -#ifndef GLSLANG_WEB case ISAMPLER1D: case ISAMPLER1DARRAY: + case SAMPLER1DARRAYSHADOW: case USAMPLER1D: case USAMPLER1DARRAY: afterType = true; + if (keyword == SAMPLER1DARRAYSHADOW) { + if (!parseContext.isEsProfile() && + (parseContext.extensionTurnedOn(E_GL_EXT_texture_array) || parseContext.symbolTable.atBuiltInLevel())) { + return keyword; + } + } return es30ReservedFromGLSL(130); case ISAMPLER2DRECT: case USAMPLER2DRECT: @@ -1583,19 +1602,6 @@ int TScanContext::tokenizeIdentifier() reservedWord(); return keyword; - case SAMPLER2DARRAY: - case SAMPLER2DARRAYSHADOW: - afterType = true; - if (parseContext.symbolTable.atBuiltInLevel()) - return keyword; - else if (parseContext.version < 130 && ((parseContext.isEsProfile() && keyword != SAMPLER2DARRAY) || !parseContext.extensionsTurnedOn(1, &E_GL_EXT_texture_array))) { - if (parseContext.forwardCompatible) - parseContext.warn(loc, "using future keyword", tokenText, ""); - - return identifierOrType(); - } - return keyword; - case SAMPLER2DRECT: case SAMPLER2DRECTSHADOW: afterType = true; @@ -1610,20 +1616,14 @@ int TScanContext::tokenizeIdentifier() return keyword; case SAMPLER1DARRAY: - case SAMPLER1DARRAYSHADOW: afterType = true; - if (parseContext.symbolTable.atBuiltInLevel()) - return keyword; - if (parseContext.isEsProfile()) { - if (parseContext.version >= 300) - reservedWord(); - else - return identifierOrType(); - } else if (parseContext.version < 130 && !parseContext.extensionsTurnedOn(1, &E_GL_EXT_texture_array)) { - if (parseContext.forwardCompatible) - parseContext.warn(loc, "using future keyword", tokenText, ""); - return identifierOrType(); - } + if (parseContext.isEsProfile() && parseContext.version == 300) + reservedWord(); + else if ((parseContext.isEsProfile() && parseContext.version < 300) || + ((!parseContext.isEsProfile() && parseContext.version < 130) && + !parseContext.symbolTable.atBuiltInLevel() && + !parseContext.extensionTurnedOn(E_GL_EXT_texture_array))) + return identifierOrType(); return keyword; case SAMPLEREXTERNALOES: @@ -1670,6 +1670,9 @@ int TScanContext::tokenizeIdentifier() case ISUBPASSINPUTMS: case USUBPASSINPUT: case USUBPASSINPUTMS: + case ATTACHMENTEXT: + case IATTACHMENTEXT: + case UATTACHMENTEXT: if (parseContext.spvVersion.vulkan > 0) return keyword; else @@ -1737,6 +1740,12 @@ int TScanContext::tokenizeIdentifier() return keyword; return identifierOrType(); + case PERVERTEXEXT: + if ((!parseContext.isEsProfile() && parseContext.version >= 450) || + parseContext.extensionTurnedOn(E_GL_EXT_fragment_shader_barycentric)) + return keyword; + return identifierOrType(); + case PRECISE: if ((parseContext.isEsProfile() && (parseContext.version >= 320 || parseContext.extensionsTurnedOn(Num_AEP_gpu_shader5, AEP_gpu_shader5))) || @@ -1751,12 +1760,18 @@ int TScanContext::tokenizeIdentifier() case PERPRIMITIVENV: case PERVIEWNV: case PERTASKNV: - if ((!parseContext.isEsProfile() && parseContext.version >= 450) || - (parseContext.isEsProfile() && parseContext.version >= 320) || + if (parseContext.symbolTable.atBuiltInLevel() || parseContext.extensionTurnedOn(E_GL_NV_mesh_shader)) return keyword; return identifierOrType(); + case PERPRIMITIVEEXT: + case TASKPAYLOADWORKGROUPEXT: + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_EXT_mesh_shader)) + return keyword; + return identifierOrType(); + case FCOOPMATNV: afterType = true; if (parseContext.symbolTable.atBuiltInLevel() || @@ -1772,6 +1787,13 @@ int TScanContext::tokenizeIdentifier() return keyword; return identifierOrType(); + case COOPMAT: + afterType = true; + if (parseContext.symbolTable.atBuiltInLevel() || + parseContext.extensionTurnedOn(E_GL_KHR_cooperative_matrix)) + return keyword; + return identifierOrType(); + case DEMOTE: if (parseContext.extensionTurnedOn(E_GL_EXT_demote_to_helper_invocation)) return keyword; @@ -1792,7 +1814,20 @@ int TScanContext::tokenizeIdentifier() parseContext.extensionTurnedOn(E_GL_EXT_spirv_intrinsics)) return keyword; return identifierOrType(); -#endif + + case HITOBJECTNV: + if (parseContext.symbolTable.atBuiltInLevel() || + (!parseContext.isEsProfile() && parseContext.version >= 460 + && parseContext.extensionTurnedOn(E_GL_NV_shader_invocation_reorder))) + return keyword; + return identifierOrType(); + + case HITOBJECTATTRNV: + if (parseContext.symbolTable.atBuiltInLevel() || + (!parseContext.isEsProfile() && parseContext.version >= 460 + && parseContext.extensionTurnedOn(E_GL_NV_shader_invocation_reorder))) + return keyword; + return identifierOrType(); default: parseContext.infoSink.info.message(EPrefixInternalError, "Unknown glslang keyword", loc); diff --git a/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp b/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp index 7407b4a0c..740ddd648 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/ShaderLang.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include "SymbolTable.h" #include "ParseHelper.h" #include "Scan.h" @@ -57,7 +58,6 @@ #endif #include "../Include/ShHandle.h" -#include "../../OGLCompilersDLL/InitializeDll.h" #include "preprocessor/PpContext.h" @@ -81,6 +81,9 @@ namespace { // anonymous namespace for file-local functions and symbols // Shared global; access should be protected by a global mutex/critical section. int NumberOfClients = 0; +// global initialization lock +std::mutex init_lock; + using namespace glslang; // Create a language specific version of parseables. @@ -295,14 +298,6 @@ void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int versi EShLanguage language, EShSource source, TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables) { -#ifdef GLSLANG_WEB - profile = EEsProfile; - version = 310; -#elif defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif - (*symbolTables[language]).adoptLevels(*commonTable[CommonIndex(profile, language)]); InitializeSymbolTable(builtInParseables.getStageString(language), version, profile, spvVersion, language, source, infoSink, *symbolTables[language]); @@ -319,14 +314,6 @@ void InitializeStageSymbolTable(TBuiltInParseables& builtInParseables, int versi // bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TSymbolTable** symbolTables, int version, EProfile profile, const SpvVersion& spvVersion, EShSource source) { -#ifdef GLSLANG_WEB - profile = EEsProfile; - version = 310; -#elif defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif - std::unique_ptr builtInParseables(CreateBuiltInParseables(infoSink, source)); if (builtInParseables == nullptr) @@ -349,7 +336,6 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangFragment, source, infoSink, commonTable, symbolTables); -#ifndef GLSLANG_WEB // check for tessellation if ((profile != EEsProfile && version >= 150) || (profile == EEsProfile && version >= 310)) { @@ -371,7 +357,6 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangCompute, source, infoSink, commonTable, symbolTables); -#ifndef GLSLANG_ANGLE // check for ray tracing stages if (profile != EEsProfile && version >= 450) { InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangRayGen, source, @@ -391,16 +376,14 @@ bool InitializeSymbolTables(TInfoSink& infoSink, TSymbolTable** commonTable, TS // check for mesh if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMeshNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangMesh, source, infoSink, commonTable, symbolTables); // check for task if ((profile != EEsProfile && version >= 450) || (profile == EEsProfile && version >= 320)) - InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTaskNV, source, + InitializeStageSymbolTable(*builtInParseables, version, profile, spvVersion, EShLangTask, source, infoSink, commonTable, symbolTables); -#endif // !GLSLANG_ANGLE -#endif // !GLSLANG_WEB return true; } @@ -437,18 +420,15 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp TInfoSink infoSink; // Make sure only one thread tries to do this at a time - glslang::GetGlobalLock(); + const std::lock_guard lock(init_lock); // See if it's already been done for this version/profile combination int versionIndex = MapVersionToIndex(version); int spvVersionIndex = MapSpvVersionToIndex(spvVersion); int profileIndex = MapProfileToIndex(profile); int sourceIndex = MapSourceToIndex(source); - if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) { - glslang::ReleaseGlobalLock(); - + if (CommonSymbolTable[versionIndex][spvVersionIndex][profileIndex][sourceIndex][EPcGeneral]) return; - } // Switch to a new pool TPoolAllocator& previousAllocator = GetThreadPoolAllocator(); @@ -495,20 +475,16 @@ void SetupBuiltinSymbolTable(int version, EProfile profile, const SpvVersion& sp delete builtInPoolAllocator; SetThreadPoolAllocator(&previousAllocator); - - glslang::ReleaseGlobalLock(); } // Function to Print all builtins void DumpBuiltinSymbolTable(TInfoSink& infoSink, const TSymbolTable& symbolTable) { -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) infoSink.debug << "BuiltinSymbolTable {\n"; symbolTable.dump(infoSink, true); infoSink.debug << "}\n"; -#endif } // Return true if the shader was correctly specified for version/profile/stage. @@ -606,7 +582,6 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo break; } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Correct for stage type... switch (stage) { case EShLangGeometry: @@ -650,14 +625,15 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo version = 460; } break; - case EShLangMeshNV: - case EShLangTaskNV: + case EShLangMesh: + case EShLangTask: if ((profile == EEsProfile && version < 320) || (profile != EEsProfile && version < 450)) { correct = false; infoSink.info.message(EPrefixError, "#version: mesh/task shaders require es profile with version 320 or above, or non-es profile with version 450 or above"); version = profile == EEsProfile ? 320 : 450; } + break; default: break; } @@ -694,7 +670,6 @@ bool DeduceVersionProfile(TInfoSink& infoSink, EShLanguage stage, bool versionNo break; } } -#endif return correct; } @@ -813,6 +788,7 @@ bool ProcessDeferred( // set version/profile to defaultVersion/defaultProfile regardless of the #version // directive in the source code bool forceDefaultVersionAndProfile, + int overrideVersion, // overrides version specified by #verison or default version bool forwardCompatible, // give errors for use of deprecated features EShMessages messages, // warnings/errors/AST; things to print out TIntermediate& intermediate, // returned tree, etc. @@ -820,7 +796,8 @@ bool ProcessDeferred( bool requireNonempty, TShader::Includer& includer, const std::string sourceEntryPointName = "", - const TEnvironment* environment = nullptr) // optional way of fully setting all versions, overriding the above + const TEnvironment* environment = nullptr, // optional way of fully setting all versions, overriding the above + bool compileOnly = false) { // This must be undone (.pop()) by the caller, after it finishes consuming the created tree. GetThreadPoolAllocator().push(); @@ -883,7 +860,6 @@ bool ProcessDeferred( : userInput.scanVersion(version, profile, versionNotFirstToken); bool versionNotFound = version == 0; if (forceDefaultVersionAndProfile && source == EShSourceGlsl) { -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (! (messages & EShMsgSuppressWarnings) && ! versionNotFound && (version != defaultVersion || profile != defaultProfile)) { compiler->infoSink.info << "Warning, (version, profile) forced to be (" @@ -891,7 +867,7 @@ bool ProcessDeferred( << "), while in source code it is (" << version << ", " << ProfileName(profile) << ")\n"; } -#endif + if (versionNotFound) { versionNotFirstToken = false; versionNotFirst = false; @@ -900,19 +876,13 @@ bool ProcessDeferred( version = defaultVersion; profile = defaultProfile; } + if (source == EShSourceGlsl && overrideVersion != 0) { + version = overrideVersion; + } bool goodVersion = DeduceVersionProfile(compiler->infoSink, stage, versionNotFirst, defaultVersion, source, version, profile, spvVersion); -#ifdef GLSLANG_WEB - profile = EEsProfile; - version = 310; -#elif defined(GLSLANG_ANGLE) - profile = ECoreProfile; - version = 450; -#endif - bool versionWillBeError = (versionNotFound || (profile == EEsProfile && version >= 300 && versionNotFirst)); -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) bool warnVersionNotFirst = false; if (! versionWillBeError && versionNotFirstToken) { if (messages & EShMsgRelaxedErrors) @@ -920,7 +890,6 @@ bool ProcessDeferred( else versionWillBeError = true; } -#endif intermediate.setSource(source); intermediate.setVersion(version); @@ -974,6 +943,7 @@ bool ProcessDeferred( std::unique_ptr parseContext(CreateParseContext(*symbolTable, intermediate, version, profile, source, stage, compiler->infoSink, spvVersion, forwardCompatible, messages, false, sourceEntryPointName)); + parseContext->compileOnly = compileOnly; TPpContext ppContext(*parseContext, names[numPre] ? names[numPre] : "", includer); // only GLSL (bison triggered, really) needs an externally set scan context @@ -985,13 +955,11 @@ bool ProcessDeferred( parseContext->setLimits(*resources); if (! goodVersion) parseContext->addError(); -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) if (warnVersionNotFirst) { TSourceLoc loc; loc.init(); parseContext->warn(loc, "Illegal to have non-comment, non-whitespace tokens before #version", "#version", ""); } -#endif parseContext->initializeExtensionBehavior(); @@ -1023,8 +991,6 @@ bool ProcessDeferred( return success; } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - // Responsible for keeping track of the most recent source string and line in // the preprocessor and outputting newlines appropriately if the source string // or line changes. @@ -1102,8 +1068,8 @@ struct DoPreprocessing { EShOptimizationLevel, EShMessages) { // This is a list of tokens that do not require a space before or after. - static const std::string unNeededSpaceTokens = ";()[]"; - static const std::string noSpaceBeforeTokens = ","; + static const std::string noNeededSpaceBeforeTokens = ";)[].,"; + static const std::string noNeededSpaceAfterTokens = ".(["; glslang::TPpToken ppToken; parseContext.setScanner(&input); @@ -1176,6 +1142,7 @@ struct DoPreprocessing { }); int lastToken = EndOfInput; // lastToken records the last token processed. + std::string lastTokenName; do { int token = ppContext.tokenize(ppToken); if (token == EndOfInput) @@ -1194,12 +1161,23 @@ struct DoPreprocessing { // Output a space in between tokens, but not at the start of a line, // and also not around special tokens. This helps with readability // and consistency. - if (!isNewString && !isNewLine && lastToken != EndOfInput && - (unNeededSpaceTokens.find((char)token) == std::string::npos) && - (unNeededSpaceTokens.find((char)lastToken) == std::string::npos) && - (noSpaceBeforeTokens.find((char)token) == std::string::npos)) { - outputBuffer += ' '; + if (!isNewString && !isNewLine && lastToken != EndOfInput) { + // left parenthesis need a leading space, except it is in a function-call-like context. + // examples: `for (xxx)`, `a * (b + c)`, `vec(2.0)`, `foo(x, y, z)` + if (token == '(') { + if (lastToken != PpAtomIdentifier || + lastTokenName == "if" || + lastTokenName == "for" || + lastTokenName == "while" || + lastTokenName == "switch") + outputBuffer += ' '; + } else if ((noNeededSpaceBeforeTokens.find((char)token) == std::string::npos) && + (noNeededSpaceAfterTokens.find((char)lastToken) == std::string::npos)) { + outputBuffer += ' '; + } } + if (token == PpAtomIdentifier) + lastTokenName = ppToken.name; lastToken = token; if (token == PpAtomConstString) outputBuffer += "\""; @@ -1221,8 +1199,6 @@ struct DoPreprocessing { std::string* outputString; }; -#endif - // DoFullParse is a valid ProcessingConext template argument for fully // parsing the shader. It populates the "intermediate" with the AST. struct DoFullParse{ @@ -1246,16 +1222,13 @@ struct DoFullParse{ parseContext.infoSink.info << parseContext.getNumErrors() << " compilation errors. No code generated.\n\n"; } -#ifndef GLSLANG_ANGLE if (messages & EShMsgAST) intermediate.output(parseContext.infoSink, true); -#endif return success; } }; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Take a single compilation unit, and run the preprocessor on it. // Return: True if there were no issues found in preprocessing, // False if during preprocessing any unknown version, pragmas or @@ -1275,6 +1248,7 @@ bool PreprocessDeferred( int defaultVersion, // use 100 for ES environment, 110 for desktop EProfile defaultProfile, bool forceDefaultVersionAndProfile, + int overrideVersion, // use 0 if not overriding GLSL version bool forwardCompatible, // give errors for use of deprecated features EShMessages messages, // warnings/errors/AST; things to print out TShader::Includer& includer, @@ -1285,11 +1259,10 @@ bool PreprocessDeferred( DoPreprocessing parser(outputString); return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames, preamble, optLevel, resources, defaultVersion, - defaultProfile, forceDefaultVersionAndProfile, + defaultProfile, forceDefaultVersionAndProfile, overrideVersion, forwardCompatible, messages, intermediate, parser, false, includer, "", environment); } -#endif // // do a partial compile on the given strings for a single compilation unit @@ -1314,19 +1287,21 @@ bool CompileDeferred( int defaultVersion, // use 100 for ES environment, 110 for desktop EProfile defaultProfile, bool forceDefaultVersionAndProfile, + int overrideVersion, // use 0 if not overriding GLSL version bool forwardCompatible, // give errors for use of deprecated features EShMessages messages, // warnings/errors/AST; things to print out TIntermediate& intermediate,// returned tree, etc. TShader::Includer& includer, const std::string sourceEntryPointName = "", - TEnvironment* environment = nullptr) + TEnvironment* environment = nullptr, + bool compileOnly = false) { DoFullParse parser; return ProcessDeferred(compiler, shaderStrings, numStrings, inputLengths, stringNames, preamble, optLevel, resources, defaultVersion, - defaultProfile, forceDefaultVersionAndProfile, + defaultProfile, forceDefaultVersionAndProfile, overrideVersion, forwardCompatible, messages, intermediate, parser, - true, includer, sourceEntryPointName, environment); + true, includer, sourceEntryPointName, environment, compileOnly); } } // end anonymous namespace for local functions @@ -1336,12 +1311,7 @@ bool CompileDeferred( // int ShInitialize() { - glslang::InitGlobalLock(); - - if (! InitProcess()) - return 0; - - glslang::GetGlobalLock(); + const std::lock_guard lock(init_lock); ++NumberOfClients; if (PerProcessGPA == nullptr) @@ -1352,7 +1322,6 @@ int ShInitialize() glslang::HlslScanContext::fillInKeywordMap(); #endif - glslang::ReleaseGlobalLock(); return 1; } @@ -1361,31 +1330,22 @@ int ShInitialize() // objects. // -ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions) +ShHandle ShConstructCompiler(const EShLanguage language, int /*debugOptions unused*/) { - if (!InitThread()) - return 0; - - TShHandleBase* base = static_cast(ConstructCompiler(language, debugOptions)); + TShHandleBase* base = static_cast(ConstructCompiler(language, 0)); return reinterpret_cast(base); } -ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions) +ShHandle ShConstructLinker(const EShExecutable executable, int /*debugOptions unused*/) { - if (!InitThread()) - return 0; - - TShHandleBase* base = static_cast(ConstructLinker(executable, debugOptions)); + TShHandleBase* base = static_cast(ConstructLinker(executable, 0)); return reinterpret_cast(base); } ShHandle ShConstructUniformMap() { - if (!InitThread()) - return 0; - TShHandleBase* base = static_cast(ConstructUniformMap()); return reinterpret_cast(base); @@ -1393,7 +1353,7 @@ ShHandle ShConstructUniformMap() void ShDestruct(ShHandle handle) { - if (handle == 0) + if (handle == nullptr) return; TShHandleBase* base = static_cast(handle); @@ -1411,14 +1371,11 @@ void ShDestruct(ShHandle handle) // int ShFinalize() { - glslang::GetGlobalLock(); + const std::lock_guard lock(init_lock); --NumberOfClients; assert(NumberOfClients >= 0); - bool finalize = NumberOfClients == 0; - if (! finalize) { - glslang::ReleaseGlobalLock(); + if (NumberOfClients > 0) return 1; - } for (int version = 0; version < VersionCount; ++version) { for (int spvVersion = 0; spvVersion < SpvVersionCount; ++spvVersion) { @@ -1426,7 +1383,7 @@ int ShFinalize() for (int source = 0; source < SourceCount; ++source) { for (int stage = 0; stage < EShLangCount; ++stage) { delete SharedSymbolTables[version][spvVersion][p][source][stage]; - SharedSymbolTables[version][spvVersion][p][source][stage] = 0; + SharedSymbolTables[version][spvVersion][p][source][stage] = nullptr; } } } @@ -1439,7 +1396,7 @@ int ShFinalize() for (int source = 0; source < SourceCount; ++source) { for (int pc = 0; pc < EPcCount; ++pc) { delete CommonSymbolTable[version][spvVersion][p][source][pc]; - CommonSymbolTable[version][spvVersion][p][source][pc] = 0; + CommonSymbolTable[version][spvVersion][p][source][pc] = nullptr; } } } @@ -1456,7 +1413,6 @@ int ShFinalize() glslang::HlslScanContext::deleteKeywordMap(); #endif - glslang::ReleaseGlobalLock(); return 1; } @@ -1478,27 +1434,31 @@ int ShCompile( int /*debugOptions*/, int defaultVersion, // use 100 for ES environment, 110 for desktop bool forwardCompatible, // give errors for use of deprecated features - EShMessages messages // warnings/errors/AST; things to print out + EShMessages messages, // warnings/errors/AST; things to print out, + const char *shaderFileName // the filename ) { // Map the generic handle to the C++ object - if (handle == 0) + if (handle == nullptr) return 0; TShHandleBase* base = reinterpret_cast(handle); TCompiler* compiler = base->getAsCompiler(); - if (compiler == 0) + if (compiler == nullptr) return 0; SetThreadPoolAllocator(compiler->getPool()); compiler->infoSink.info.erase(); compiler->infoSink.debug.erase(); + compiler->infoSink.info.setShaderFileName(shaderFileName); + compiler->infoSink.debug.setShaderFileName(shaderFileName); + TIntermediate intermediate(compiler->getLanguage()); TShader::ForbidIncluder includer; bool success = CompileDeferred(compiler, shaderStrings, numStrings, inputLengths, nullptr, - "", optLevel, resources, defaultVersion, ENoProfile, false, + "", optLevel, resources, defaultVersion, ENoProfile, false, 0, forwardCompatible, messages, intermediate, includer); // @@ -1527,13 +1487,13 @@ int ShLinkExt( const ShHandle compHandles[], const int numHandles) { - if (linkHandle == 0 || numHandles == 0) + if (linkHandle == nullptr || numHandles == 0) return 0; THandleList cObjects; for (int i = 0; i < numHandles; ++i) { - if (compHandles[i] == 0) + if (compHandles[i] == nullptr) return 0; TShHandleBase* base = reinterpret_cast(compHandles[i]); if (base->getAsLinker()) { @@ -1542,18 +1502,17 @@ int ShLinkExt( if (base->getAsCompiler()) cObjects.push_back(base->getAsCompiler()); - if (cObjects[i] == 0) + if (cObjects[i] == nullptr) return 0; } TShHandleBase* base = reinterpret_cast(linkHandle); TLinker* linker = static_cast(base->getAsLinker()); - SetThreadPoolAllocator(linker->getPool()); - - if (linker == 0) + if (linker == nullptr) return 0; - + + SetThreadPoolAllocator(linker->getPool()); linker->infoSink.info.erase(); for (int i = 0; i < numHandles; ++i) { @@ -1576,7 +1535,7 @@ int ShLinkExt( // void ShSetEncryptionMethod(ShHandle handle) { - if (handle == 0) + if (handle == nullptr) return; } @@ -1585,8 +1544,8 @@ void ShSetEncryptionMethod(ShHandle handle) // const char* ShGetInfoLog(const ShHandle handle) { - if (handle == 0) - return 0; + if (handle == nullptr) + return nullptr; TShHandleBase* base = static_cast(handle); TInfoSink* infoSink; @@ -1596,7 +1555,7 @@ const char* ShGetInfoLog(const ShHandle handle) else if (base->getAsLinker()) infoSink = &(base->getAsLinker()->getInfoSink()); else - return 0; + return nullptr; infoSink->info << infoSink->debug.c_str(); return infoSink->info.c_str(); @@ -1608,14 +1567,14 @@ const char* ShGetInfoLog(const ShHandle handle) // const void* ShGetExecutable(const ShHandle handle) { - if (handle == 0) - return 0; + if (handle == nullptr) + return nullptr; TShHandleBase* base = reinterpret_cast(handle); TLinker* linker = static_cast(base->getAsLinker()); - if (linker == 0) - return 0; + if (linker == nullptr) + return nullptr; return linker->getObjectCode(); } @@ -1630,13 +1589,13 @@ const void* ShGetExecutable(const ShHandle handle) // int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table) { - if (handle == 0) + if (handle == nullptr) return 0; TShHandleBase* base = reinterpret_cast(handle); TLinker* linker = static_cast(base->getAsLinker()); - if (linker == 0) + if (linker == nullptr) return 0; linker->setAppAttributeBindings(table); @@ -1649,13 +1608,13 @@ int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* t // int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table) { - if (handle == 0) + if (handle == nullptr) return 0; TShHandleBase* base = reinterpret_cast(handle); TLinker* linker = static_cast(base->getAsLinker()); - if (linker == 0) + if (linker == nullptr) return 0; linker->setFixedAttributeBindings(table); @@ -1667,12 +1626,12 @@ int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* tab // int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) { - if (handle == 0) + if (handle == nullptr) return 0; TShHandleBase* base = reinterpret_cast(handle); TLinker* linker = static_cast(base->getAsLinker()); - if (linker == 0) + if (linker == nullptr) return 0; linker->setExcludedAttributes(attributes, count); @@ -1688,12 +1647,12 @@ int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) // int ShGetUniformLocation(const ShHandle handle, const char* name) { - if (handle == 0) + if (handle == nullptr) return -1; TShHandleBase* base = reinterpret_cast(handle); TUniformMap* uniformMap= base->getAsUniformMap(); - if (uniformMap == 0) + if (uniformMap == nullptr) return -1; return uniformMap->getLocation(name); @@ -1759,7 +1718,7 @@ public: }; TShader::TShader(EShLanguage s) - : stage(s), lengths(nullptr), stringNames(nullptr), preamble("") + : stage(s), lengths(nullptr), stringNames(nullptr), preamble(""), overrideVersion(0) { pool = new TPoolAllocator; infoSink = new TInfoSink; @@ -1828,12 +1787,17 @@ void TShader::setUniqueId(unsigned long long id) intermediate->setUniqueId(id); } +void TShader::setOverrideVersion(int version) +{ + overrideVersion = version; +} + +void TShader::setDebugInfo(bool debugInfo) { intermediate->setDebugInfo(debugInfo); } void TShader::setInvertY(bool invert) { intermediate->setInvertY(invert); } void TShader::setDxPositionW(bool invert) { intermediate->setDxPositionW(invert); } +void TShader::setEnhancedMsgs() { intermediate->setEnhancedMsgs(); } void TShader::setNanMinMaxClamp(bool useNonNan) { intermediate->setNanMinMaxClamp(useNonNan); } -#ifndef GLSLANG_WEB - // Set binding base for given resource type void TShader::setShiftBinding(TResourceType res, unsigned int base) { intermediate->setShiftBinding(res, base); @@ -1875,7 +1839,6 @@ void TShader::setUniformLocationBase(int base) void TShader::setNoStorageFormat(bool useUnknownFormat) { intermediate->setNoStorageFormat(useUnknownFormat); } void TShader::setResourceSetBinding(const std::vector& base) { intermediate->setResourceSetBinding(base); } void TShader::setTextureSamplerTransformMode(EShTextureSamplerTransformMode mode) { intermediate->setTextureSamplerTransformMode(mode); } -#endif void TShader::addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) { intermediate->addBlockStorageOverride(nameStr, backing); } @@ -1900,8 +1863,6 @@ void TShader::setFlattenUniformArrays(bool flatten) { intermediate->setFlatt bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion, EProfile defaultProfile, bool forceDefaultVersionAndProfile, bool forwardCompatible, EShMessages messages, Includer& includer) { - if (! InitThread()) - return false; SetThreadPoolAllocator(pool); if (! preamble) @@ -1909,12 +1870,11 @@ bool TShader::parse(const TBuiltInResource* builtInResources, int defaultVersion return CompileDeferred(compiler, strings, numStrings, lengths, stringNames, preamble, EShOptNone, builtInResources, defaultVersion, - defaultProfile, forceDefaultVersionAndProfile, + defaultProfile, forceDefaultVersionAndProfile, overrideVersion, forwardCompatible, messages, *intermediate, includer, sourceEntryPointName, - &environment); + &environment, compileOnly); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) // Fill in a string with the result of preprocessing ShaderStrings // Returns true if all extensions, pragmas and version strings were valid. // @@ -1927,8 +1887,6 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources, std::string* output_string, Includer& includer) { - if (! InitThread()) - return false; SetThreadPoolAllocator(pool); if (! preamble) @@ -1936,11 +1894,10 @@ bool TShader::preprocess(const TBuiltInResource* builtInResources, return PreprocessDeferred(compiler, strings, numStrings, lengths, stringNames, preamble, EShOptNone, builtInResources, defaultVersion, - defaultProfile, forceDefaultVersionAndProfile, + defaultProfile, forceDefaultVersionAndProfile, overrideVersion, forwardCompatible, message, includer, *intermediate, output_string, &environment); } -#endif const char* TShader::getInfoLog() { @@ -1952,16 +1909,12 @@ const char* TShader::getInfoDebugLog() return infoSink->debug.c_str(); } -TProgram::TProgram() : -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - reflection(0), -#endif - linked(false) +TProgram::TProgram() : reflection(nullptr), linked(false) { pool = new TPoolAllocator; infoSink = new TInfoSink; for (int s = 0; s < EShLangCount; ++s) { - intermediate[s] = 0; + intermediate[s] = nullptr; newedIntermediate[s] = false; } } @@ -1969,9 +1922,7 @@ TProgram::TProgram() : TProgram::~TProgram() { delete infoSink; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) delete reflection; -#endif for (int s = 0; s < EShLangCount; ++s) if (newedIntermediate[s]) @@ -2019,7 +1970,6 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) if (stages[stage].size() == 0) return true; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) int numEsShaders = 0, numNonEsShaders = 0; for (auto it = stages[stage].begin(); it != stages[stage].end(); ++it) { if ((*it)->intermediate->getProfile() == EEsProfile) { @@ -2049,6 +1999,8 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) firstIntermediate->getVersion(), firstIntermediate->getProfile()); intermediate[stage]->setLimits(firstIntermediate->getLimits()); + if (firstIntermediate->getEnhancedMsgs()) + intermediate[stage]->setEnhancedMsgs(); // The new TIntermediate must use the same origin as the original TIntermediates. // Otherwise linking will fail due to different coordinate systems. @@ -2068,15 +2020,10 @@ bool TProgram::linkStage(EShLanguage stage, EShMessages messages) for (it = stages[stage].begin(); it != stages[stage].end(); ++it) intermediate[stage]->merge(*infoSink, *(*it)->intermediate); } -#else - intermediate[stage] = stages[stage].front()->intermediate; -#endif intermediate[stage]->finalCheck(*infoSink, (messages & EShMsgKeepUncalled) != 0); -#ifndef GLSLANG_ANGLE if (messages & EShMsgAST) intermediate[stage]->output(*infoSink, true); -#endif return intermediate[stage]->getNumErrors() == 0; } @@ -2154,8 +2101,6 @@ const char* TProgram::getInfoDebugLog() return infoSink->debug.c_str(); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - // // Reflection implementation. // @@ -2236,6 +2181,4 @@ bool TProgram::mapIO(TIoMapResolver* pResolver, TIoMapper* pIoMapper) return ioMapper->doMap(pResolver, *infoSink); } -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE - } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp b/src/libraries/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp index 6650f7d9e..1d08797ac 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/SpirvIntrinsics.cpp @@ -33,8 +33,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB - // // GL_EXT_spirv_intrinsics // @@ -45,6 +43,15 @@ namespace glslang { +bool TSpirvTypeParameter::operator==(const TSpirvTypeParameter& rhs) const +{ + if (getAsConstant() != nullptr) + return getAsConstant()->getConstArray() == rhs.getAsConstant()->getConstArray(); + + assert(getAsType() != nullptr); + return *getAsType() == *rhs.getAsType(); +} + // // Handle SPIR-V requirements // @@ -67,7 +74,7 @@ TSpirvRequirement* TParseContext::makeSpirvRequirement(const TSourceLoc& loc, co spirvReq->capabilities.insert(capability->getAsConstantUnion()->getConstArray()[0].getIConst()); } } else - error(loc, "unknow SPIR-V requirement", name.c_str(), ""); + error(loc, "unknown SPIR-V requirement", name.c_str(), ""); return spirvReq; } @@ -168,7 +175,7 @@ void TQualifier::setSpirvDecorateId(int decoration, const TIntermAggregate* args TVector extraOperands; for (auto arg : args->getSequence()) { auto extraOperand = arg->getAsTyped(); - assert(extraOperand != nullptr && extraOperand->getQualifier().isConstant()); + assert(extraOperand != nullptr); extraOperands.push_back(extraOperand); } spirvDecorate->decorateIds[decoration] = extraOperands; @@ -202,30 +209,29 @@ TString TQualifier::getSpirvDecorateQualifierString() const const auto appendStr = [&](const char* s) { qualifierString.append(s); }; const auto appendDecorate = [&](const TIntermTyped* constant) { - auto& constArray = constant->getAsConstantUnion() != nullptr ? constant->getAsConstantUnion()->getConstArray() - : constant->getAsSymbolNode()->getConstArray(); - if (constant->getBasicType() == EbtFloat) { - float value = static_cast(constArray[0].getDConst()); - appendFloat(value); + if (constant->getAsConstantUnion()) { + auto& constArray = constant->getAsConstantUnion()->getConstArray(); + if (constant->getBasicType() == EbtFloat) { + float value = static_cast(constArray[0].getDConst()); + appendFloat(value); + } else if (constant->getBasicType() == EbtInt) { + int value = constArray[0].getIConst(); + appendInt(value); + } else if (constant->getBasicType() == EbtUint) { + unsigned value = constArray[0].getUConst(); + appendUint(value); + } else if (constant->getBasicType() == EbtBool) { + bool value = constArray[0].getBConst(); + appendBool(value); + } else if (constant->getBasicType() == EbtString) { + const TString* value = constArray[0].getSConst(); + appendStr(value->c_str()); + } else + assert(0); + } else { + assert(constant->getAsSymbolNode()); + appendStr(constant->getAsSymbolNode()->getName().c_str()); } - else if (constant->getBasicType() == EbtInt) { - int value = constArray[0].getIConst(); - appendInt(value); - } - else if (constant->getBasicType() == EbtUint) { - unsigned value = constArray[0].getUConst(); - appendUint(value); - } - else if (constant->getBasicType() == EbtBool) { - bool value = constArray[0].getBConst(); - appendBool(value); - } - else if (constant->getBasicType() == EbtString) { - const TString* value = constArray[0].getSConst(); - appendStr(value->c_str()); - } - else - assert(0); }; for (auto& decorate : spirvDecorate->decorates) { @@ -284,14 +290,20 @@ TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& l constant->getBasicType() != EbtBool && constant->getBasicType() != EbtString) error(loc, "this type not allowed", constant->getType().getBasicString(), ""); - else { - assert(constant); + else spirvTypeParams->push_back(TSpirvTypeParameter(constant)); - } return spirvTypeParams; } +TSpirvTypeParameters* TParseContext::makeSpirvTypeParameters(const TSourceLoc& /* loc */, + const TPublicType& type) +{ + TSpirvTypeParameters* spirvTypeParams = new TSpirvTypeParameters; + spirvTypeParams->push_back(TSpirvTypeParameter(new TType(type))); + return spirvTypeParams; +} + TSpirvTypeParameters* TParseContext::mergeSpirvTypeParameters(TSpirvTypeParameters* spirvTypeParams1, TSpirvTypeParameters* spirvTypeParams2) { // Merge SPIR-V type parameters of the second one to the first one @@ -346,5 +358,3 @@ TSpirvInstruction* TParseContext::mergeSpirvInstruction(const TSourceLoc& loc, T } } // end namespace glslang - -#endif // GLSLANG_WEB diff --git a/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp b/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp index a3ffa0c46..3b56e414b 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.cpp @@ -65,7 +65,6 @@ void TType::buildMangledName(TString& mangledName) const case EbtInt: mangledName += 'i'; break; case EbtUint: mangledName += 'u'; break; case EbtBool: mangledName += 'b'; break; -#ifndef GLSLANG_WEB case EbtDouble: mangledName += 'd'; break; case EbtFloat16: mangledName += "f16"; break; case EbtInt8: mangledName += "i8"; break; @@ -78,12 +77,10 @@ void TType::buildMangledName(TString& mangledName) const case EbtAccStruct: mangledName += "as"; break; case EbtRayQuery: mangledName += "rq"; break; case EbtSpirvType: mangledName += "spv-t"; break; -#endif + case EbtHitObjectNV: mangledName += "ho"; break; case EbtSampler: switch (sampler.type) { -#ifndef GLSLANG_WEB case EbtFloat16: mangledName += "f16"; break; -#endif case EbtInt: mangledName += "i"; break; case EbtUint: mangledName += "u"; break; case EbtInt64: mangledName += "i64"; break; @@ -110,12 +107,10 @@ void TType::buildMangledName(TString& mangledName) const case Esd2D: mangledName += "2"; break; case Esd3D: mangledName += "3"; break; case EsdCube: mangledName += "C"; break; -#ifndef GLSLANG_WEB case Esd1D: mangledName += "1"; break; case EsdRect: mangledName += "R2"; break; case EsdBuffer: mangledName += "B"; break; case EsdSubpass: mangledName += "P"; break; -#endif default: break; // some compilers want this } @@ -154,6 +149,7 @@ void TType::buildMangledName(TString& mangledName) const mangledName += '-'; (*structure)[i].type->buildMangledName(mangledName); } + break; default: break; } @@ -183,8 +179,6 @@ void TType::buildMangledName(TString& mangledName) const } } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - // // Dump functions. // @@ -263,8 +257,6 @@ void TSymbolTable::dump(TInfoSink& infoSink, bool complete) const } } -#endif - // // Functions have buried pointers to delete. // @@ -327,6 +319,16 @@ void TSymbolTableLevel::setFunctionExtensions(const char* name, int num, const c } } +// Make a single function require an extension(s). i.e., this will only set the extensions for the symbol that matches 'name' exactly. +// This is different from setFunctionExtensions, which uses std::map::lower_bound to effectively set all symbols that start with 'name'. +// Should only be used for a version/profile that actually needs the extension(s). +void TSymbolTableLevel::setSingleFunctionExtensions(const char* name, int num, const char* const extensions[]) +{ + if (auto candidate = level.find(name); candidate != level.end()) { + candidate->second->setExtensions(num, extensions); + } +} + // // Make all symbols in this table level read only. // @@ -381,9 +383,9 @@ TVariable* TVariable::clone() const TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) { for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) { - TParameter param; + TParameter param{}; parameters.push_back(param); - parameters.back().copyParam(copyOf.parameters[i]); + (void)parameters.back().copyParam(copyOf.parameters[i]); } extensions = nullptr; @@ -397,9 +399,7 @@ TFunction::TFunction(const TFunction& copyOf) : TSymbol(copyOf) implicitThis = copyOf.implicitThis; illegalImplicitThis = copyOf.illegalImplicitThis; defaultParamCount = copyOf.defaultParamCount; -#ifndef GLSLANG_WEB spirvInst = copyOf.spirvInst; -#endif } TFunction* TFunction::clone() const @@ -416,7 +416,7 @@ TAnonMember* TAnonMember::clone() const // copy of the original container. assert(0); - return 0; + return nullptr; } TSymbolTableLevel* TSymbolTableLevel::clone() const diff --git a/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h b/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h index 31312ecba..94c3929da 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h +++ b/src/libraries/glslang/glslang/MachineIndependent/SymbolTable.h @@ -84,7 +84,7 @@ typedef TVector TExtensionList; class TSymbol { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - explicit TSymbol(const TString *n) : name(n), uniqueId(0), extensions(0), writable(true) { } + explicit TSymbol(const TString *n) : name(n), uniqueId(0), extensions(nullptr), writable(true) { } virtual TSymbol* clone() const = 0; virtual ~TSymbol() { } // rely on all symbol owned memory coming from the pool @@ -97,18 +97,18 @@ public: changeName(NewPoolTString(newName.c_str())); } virtual const TString& getMangledName() const { return getName(); } - virtual TFunction* getAsFunction() { return 0; } - virtual const TFunction* getAsFunction() const { return 0; } - virtual TVariable* getAsVariable() { return 0; } - virtual const TVariable* getAsVariable() const { return 0; } - virtual const TAnonMember* getAsAnonMember() const { return 0; } + virtual TFunction* getAsFunction() { return nullptr; } + virtual const TFunction* getAsFunction() const { return nullptr; } + virtual TVariable* getAsVariable() { return nullptr; } + virtual const TVariable* getAsVariable() const { return nullptr; } + virtual const TAnonMember* getAsAnonMember() const { return nullptr; } virtual const TType& getType() const = 0; virtual TType& getWritableType() = 0; virtual void setUniqueId(long long id) { uniqueId = id; } virtual long long getUniqueId() const { return uniqueId; } virtual void setExtensions(int numExts, const char* const exts[]) { - assert(extensions == 0); + assert(extensions == nullptr); assert(numExts > 0); extensions = NewPoolObject(extensions); for (int e = 0; e < numExts; ++e) @@ -117,10 +117,8 @@ public: virtual int getNumExtensions() const { return extensions == nullptr ? 0 : (int)extensions->size(); } virtual const char** getExtensions() const { return extensions->data(); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const = 0; void dumpExtensions(TInfoSink& infoSink) const; -#endif virtual bool isReadOnly() const { return ! writable; } virtual void makeReadOnly() { writable = false; } @@ -196,9 +194,7 @@ public: } virtual const char** getMemberExtensions(int member) const { return (*memberExtensions)[member].data(); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const; -#endif protected: explicit TVariable(const TVariable&); @@ -224,14 +220,15 @@ struct TParameter { TString *name; TType* type; TIntermTyped* defaultValue; - void copyParam(const TParameter& param) + TParameter& copyParam(const TParameter& param) { if (param.name) name = NewPoolTString(param.name->c_str()); else - name = 0; + name = nullptr; type = param.type->clone(); defaultValue = param.defaultValue; + return *this; } TBuiltInVariable getDeclaredBuiltIn() const { return type->getQualifier().declaredBuiltIn; } }; @@ -242,14 +239,15 @@ struct TParameter { class TFunction : public TSymbol { public: explicit TFunction(TOperator o) : - TSymbol(0), + TSymbol(nullptr), op(o), defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) { } TFunction(const TString *name, const TType& retType, TOperator tOp = EOpNull) : TSymbol(name), mangledName(*name + '('), op(tOp), - defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0) + defined(false), prototyped(false), implicitThis(false), illegalImplicitThis(false), defaultParamCount(0), + linkType(ELinkNone) { returnType.shallowCopy(retType); declaredBuiltIn = retType.getQualifier().builtIn; @@ -318,19 +316,19 @@ public: virtual TParameter& operator[](int i) { assert(writable); return parameters[i]; } virtual const TParameter& operator[](int i) const { return parameters[i]; } + const TQualifier& getQualifier() const { return returnType.getQualifier(); } -#ifndef GLSLANG_WEB virtual void setSpirvInstruction(const TSpirvInstruction& inst) { relateToOperator(EOpSpirvInst); spirvInst = inst; } virtual const TSpirvInstruction& getSpirvInstruction() const { return spirvInst; } -#endif -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const override; -#endif + + void setExport() { linkType = ELinkExport; } + TLinkType getLinkType() const { return linkType; } protected: explicit TFunction(const TFunction&); @@ -352,9 +350,8 @@ protected: // but is not allowed to use them, or see hidden symbols instead. int defaultParamCount; -#ifndef GLSLANG_WEB TSpirvInstruction spirvInst; // SPIR-V instruction qualifiers -#endif + TLinkType linkType; }; // @@ -394,9 +391,7 @@ public: virtual const char** getExtensions() const override { return anonContainer.getMemberExtensions(memberNumber); } virtual int getAnonId() const { return anonId; } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) virtual void dump(TInfoSink& infoSink, bool complete = false) const override; -#endif protected: explicit TAnonMember(const TAnonMember&); @@ -410,7 +405,7 @@ protected: class TSymbolTableLevel { public: POOL_ALLOCATOR_NEW_DELETE(GetThreadPoolAllocator()) - TSymbolTableLevel() : defaultPrecision(0), anonId(0), thisLevel(false) { } + TSymbolTableLevel() : defaultPrecision(nullptr), anonId(0), thisLevel(false) { } ~TSymbolTableLevel(); bool insert(const TString& name, TSymbol* symbol) { @@ -492,7 +487,7 @@ public: { tLevel::const_iterator it = level.find(name); if (it == level.end()) - return 0; + return nullptr; else return (*it).second; } @@ -560,7 +555,7 @@ public: { // can call multiple times at one scope, will only latch on first call, // as we're tracking the previous scope's values, not the current values - if (defaultPrecision != 0) + if (defaultPrecision != nullptr) return; defaultPrecision = new TPrecisionQualifier[EbtNumTypes]; @@ -572,7 +567,7 @@ public: { // can be called for table level pops that didn't set the // defaults - if (defaultPrecision == 0 || p == 0) + if (defaultPrecision == nullptr || p == nullptr) return; for (int t = 0; t < EbtNumTypes; ++t) @@ -581,9 +576,8 @@ public: void relateToOperator(const char* name, TOperator op); void setFunctionExtensions(const char* name, int num, const char* const extensions[]); -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) + void setSingleFunctionExtensions(const char* name, int num, const char* const extensions[]); void dump(TInfoSink& infoSink, bool complete = false) const; -#endif TSymbolTableLevel* clone() const; void readOnly(); @@ -621,7 +615,7 @@ public: // don't deallocate levels passed in from elsewhere while (table.size() > adoptedLevels) - pop(0); + pop(nullptr); } void adoptLevels(TSymbolTable& symTable) @@ -782,7 +776,7 @@ public: // Normal find of a symbol, that can optionally say whether the symbol was found // at a built-in level or the current top-scope level. - TSymbol* find(const TString& name, bool* builtIn = 0, bool* currentScope = 0, int* thisDepthP = 0) + TSymbol* find(const TString& name, bool* builtIn = nullptr, bool* currentScope = nullptr, int* thisDepthP = nullptr) { int level = currentLevel(); TSymbol* symbol; @@ -826,7 +820,7 @@ public: ++thisDepth; symbol = table[level]->find(name); --level; - } while (symbol == 0 && level >= 0); + } while (symbol == nullptr && level >= 0); if (! table[level + 1]->isThisLevel()) thisDepth = 0; @@ -884,6 +878,12 @@ public: table[level]->setFunctionExtensions(name, num, extensions); } + void setSingleFunctionExtensions(const char* name, int num, const char* const extensions[]) + { + for (unsigned int level = 0; level < table.size(); ++level) + table[level]->setSingleFunctionExtensions(name, num, extensions); + } + void setVariableExtensions(const char* name, int numExts, const char* const extensions[]) { TSymbol* symbol = find(TString(name)); @@ -911,9 +911,7 @@ public: } long long getMaxSymbolId() { return uniqueId; } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) void dump(TInfoSink& infoSink, bool complete = false) const; -#endif void copyTable(const TSymbolTable& copyOf); void setPreviousDefaultPrecisions(TPrecisionQualifier *p) { table[currentLevel()]->setPreviousDefaultPrecisions(p); } diff --git a/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp b/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp index 4a2b833f3..0d13fafa1 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/Versions.cpp @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Copyright (C) 2015-2020 Google, Inc. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // @@ -151,8 +151,6 @@ namespace glslang { -#ifndef GLSLANG_WEB - // // Initialize all extensions, almost always to 'disable', as once their features // are incorporated into a core version, their features are supported through allowing that @@ -166,7 +164,8 @@ void TParseVersions::initializeExtensionBehavior() } extensionData; const extensionData exts[] = { {E_GL_EXT_ray_tracing, EShTargetSpv_1_4}, - {E_GL_NV_ray_tracing_motion_blur, EShTargetSpv_1_4} + {E_GL_NV_ray_tracing_motion_blur, EShTargetSpv_1_4}, + {E_GL_EXT_mesh_shader, EShTargetSpv_1_4} }; for (size_t ii = 0; ii < sizeof(exts) / sizeof(exts[0]); ii++) { @@ -183,7 +182,6 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_OES_EGL_image_external_essl3] = EBhDisable; extensionBehavior[E_GL_EXT_YUV_target] = EBhDisable; extensionBehavior[E_GL_EXT_shader_texture_lod] = EBhDisable; - extensionBehavior[E_GL_EXT_texture_array] = EBhDisable; extensionBehavior[E_GL_EXT_shadow_samplers] = EBhDisable; extensionBehavior[E_GL_ARB_texture_rectangle] = EBhDisable; extensionBehavior[E_GL_3DL_array_objects] = EBhDisable; @@ -227,6 +225,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_ARB_texture_query_lod] = EBhDisable; extensionBehavior[E_GL_ARB_vertex_attrib_64bit] = EBhDisable; extensionBehavior[E_GL_ARB_draw_instanced] = EBhDisable; + extensionBehavior[E_GL_ARB_bindless_texture] = EBhDisable; extensionBehavior[E_GL_ARB_fragment_coord_conventions] = EBhDisable; @@ -236,6 +235,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_KHR_shader_subgroup_ballot] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_shuffle] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_shuffle_relative] = EBhDisable; + extensionBehavior[E_GL_KHR_shader_subgroup_rotate] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_clustered] = EBhDisable; extensionBehavior[E_GL_KHR_shader_subgroup_quad] = EBhDisable; extensionBehavior[E_GL_KHR_memory_scope_semantics] = EBhDisable; @@ -259,10 +259,19 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_shader_16bit_storage] = EBhDisable; extensionBehavior[E_GL_EXT_shader_8bit_storage] = EBhDisable; extensionBehavior[E_GL_EXT_subgroup_uniform_control_flow] = EBhDisable; + extensionBehavior[E_GL_EXT_maximal_reconvergence] = EBhDisable; + + extensionBehavior[E_GL_EXT_fragment_shader_barycentric] = EBhDisable; + extensionBehavior[E_GL_EXT_expect_assume] = EBhDisable; + + extensionBehavior[E_GL_EXT_control_flow_attributes2] = EBhDisable; + + extensionBehavior[E_GL_KHR_cooperative_matrix] = EBhDisable; // #line and #include extensionBehavior[E_GL_GOOGLE_cpp_style_line_directive] = EBhDisable; extensionBehavior[E_GL_GOOGLE_include_directive] = EBhDisable; + extensionBehavior[E_GL_ARB_shading_language_include] = EBhDisable; extensionBehavior[E_GL_AMD_shader_ballot] = EBhDisable; extensionBehavior[E_GL_AMD_shader_trinary_minmax] = EBhDisable; @@ -274,6 +283,7 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_AMD_shader_image_load_store_lod] = EBhDisable; extensionBehavior[E_GL_AMD_shader_fragment_mask] = EBhDisable; extensionBehavior[E_GL_AMD_gpu_shader_half_float_fetch] = EBhDisable; + extensionBehavior[E_GL_AMD_shader_early_and_late_fragment_tests] = EBhDisable; extensionBehavior[E_GL_INTEL_shader_integer_functions2] = EBhDisable; @@ -293,10 +303,19 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_NV_compute_shader_derivatives] = EBhDisable; extensionBehavior[E_GL_NV_shader_texture_footprint] = EBhDisable; extensionBehavior[E_GL_NV_mesh_shader] = EBhDisable; - extensionBehavior[E_GL_NV_cooperative_matrix] = EBhDisable; extensionBehavior[E_GL_NV_shader_sm_builtins] = EBhDisable; extensionBehavior[E_GL_NV_integer_cooperative_matrix] = EBhDisable; + extensionBehavior[E_GL_NV_shader_invocation_reorder] = EBhDisable; + extensionBehavior[E_GL_NV_displacement_micromap] = EBhDisable; + extensionBehavior[E_GL_NV_shader_atomic_fp16_vector] = EBhDisable; + + // ARM + extensionBehavior[E_GL_ARM_shader_core_builtins] = EBhDisable; + + // QCOM + extensionBehavior[E_GL_QCOM_image_processing] = EBhDisable; + extensionBehavior[E_GL_QCOM_image_processing2] = EBhDisable; // AEP extensionBehavior[E_GL_ANDROID_extension_pack_es31a] = EBhDisable; @@ -335,13 +354,22 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_ray_tracing] = EBhDisable; extensionBehavior[E_GL_EXT_ray_query] = EBhDisable; extensionBehavior[E_GL_EXT_ray_flags_primitive_culling] = EBhDisable; + extensionBehavior[E_GL_EXT_ray_cull_mask] = EBhDisable; extensionBehavior[E_GL_EXT_blend_func_extended] = EBhDisable; extensionBehavior[E_GL_EXT_shader_implicit_conversions] = EBhDisable; extensionBehavior[E_GL_EXT_fragment_shading_rate] = EBhDisable; - extensionBehavior[E_GL_EXT_shader_image_int64] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_image_int64] = EBhDisable; extensionBehavior[E_GL_EXT_terminate_invocation] = EBhDisable; extensionBehavior[E_GL_EXT_shared_memory_block] = EBhDisable; extensionBehavior[E_GL_EXT_spirv_intrinsics] = EBhDisable; + extensionBehavior[E_GL_EXT_mesh_shader] = EBhDisable; + extensionBehavior[E_GL_EXT_opacity_micromap] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_quad_control] = EBhDisable; + extensionBehavior[E_GL_EXT_ray_tracing_position_fetch] = EBhDisable; + extensionBehavior[E_GL_EXT_shader_tile_image] = EBhDisable; + extensionBehavior[E_GL_EXT_texture_shadow_lod] = EBhDisable; + extensionBehavior[E_GL_EXT_draw_instanced] = EBhDisable; + extensionBehavior[E_GL_EXT_texture_array] = EBhDisable; // OVR extensions extensionBehavior[E_GL_OVR_multiview] = EBhDisable; @@ -364,9 +392,10 @@ void TParseVersions::initializeExtensionBehavior() extensionBehavior[E_GL_EXT_shader_subgroup_extended_types_float16] = EBhDisable; extensionBehavior[E_GL_EXT_shader_atomic_float] = EBhDisable; extensionBehavior[E_GL_EXT_shader_atomic_float2] = EBhDisable; -} -#endif // GLSLANG_WEB + // Record extensions not for spv. + spvUnsupportedExt.push_back(E_GL_ARB_bindless_texture); +} // Get code that is not part of a shared symbol table, is specific to this shader, // or needed by the preprocessor (which does not use a shared symbol table). @@ -376,10 +405,6 @@ void TParseVersions::getPreamble(std::string& preamble) preamble = "#define GL_ES 1\n" "#define GL_FRAGMENT_PRECISION_HIGH 1\n" -#ifdef GLSLANG_WEB - ; -#else - "#define GL_EXT_texture_array 1\n" "#define GL_OES_texture_3D 1\n" "#define GL_OES_standard_derivatives 1\n" "#define GL_EXT_frag_depth 1\n" @@ -389,6 +414,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_texture_lod 1\n" "#define GL_EXT_shadow_samplers 1\n" "#define GL_EXT_fragment_shading_rate 1\n" + "#define GL_EXT_texture_array 1\n" // AEP "#define GL_ANDROID_extension_pack_es31a 1\n" @@ -420,6 +446,9 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_OES_texture_buffer 1\n" "#define GL_OES_texture_cube_map_array 1\n" "#define GL_EXT_shader_non_constant_global_initializers 1\n" + + "#define GL_QCOM_image_processing 1\n" + "#define GL_QCOM_image_processing2 1\n" ; if (version >= 300) { @@ -428,12 +457,11 @@ void TParseVersions::getPreamble(std::string& preamble) if (version >= 310) { preamble += "#define GL_EXT_null_initializer 1\n"; preamble += "#define GL_EXT_subgroup_uniform_control_flow 1\n"; + preamble += "#define GL_EXT_maximal_reconvergence 1\n"; } } else { // !isEsProfile() preamble = - "#define GL_FRAGMENT_PRECISION_HIGH 1\n" - "#define GL_EXT_texture_array 1\n" "#define GL_ARB_texture_rectangle 1\n" "#define GL_ARB_shading_language_420pack 1\n" "#define GL_ARB_texture_gather 1\n" @@ -473,6 +501,7 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_ARB_vertex_attrib_64bit 1\n" "#define GL_ARB_draw_instanced 1\n" "#define GL_ARB_fragment_coord_conventions 1\n" + "#define GL_EXT_shader_non_constant_global_initializers 1\n" "#define GL_EXT_shader_image_load_formatted 1\n" "#define GL_EXT_post_depth_coverage 1\n" @@ -502,13 +531,18 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_KHR_shader_subgroup_clustered 1\n" "#define GL_KHR_shader_subgroup_quad 1\n" + "#define GL_KHR_cooperative_matrix 1\n" + "#define GL_EXT_shader_image_int64 1\n" "#define GL_EXT_shader_atomic_int64 1\n" "#define GL_EXT_shader_realtime_clock 1\n" "#define GL_EXT_ray_tracing 1\n" "#define GL_EXT_ray_query 1\n" "#define GL_EXT_ray_flags_primitive_culling 1\n" + "#define GL_EXT_ray_cull_mask 1\n" + "#define GL_EXT_ray_tracing_position_fetch 1\n" "#define GL_EXT_spirv_intrinsics 1\n" + "#define GL_EXT_mesh_shader 1\n" "#define GL_AMD_shader_ballot 1\n" "#define GL_AMD_shader_trinary_minmax 1\n" @@ -538,6 +572,10 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_NV_mesh_shader 1\n" "#define GL_NV_cooperative_matrix 1\n" "#define GL_NV_integer_cooperative_matrix 1\n" + "#define GL_NV_shader_invocation_reorder 1\n" + + "#define GL_QCOM_image_processing 1\n" + "#define GL_QCOM_image_processing2 1\n" "#define GL_EXT_shader_explicit_arithmetic_types 1\n" "#define GL_EXT_shader_explicit_arithmetic_types_int8 1\n" @@ -555,8 +593,18 @@ void TParseVersions::getPreamble(std::string& preamble) "#define GL_EXT_shader_atomic_float 1\n" "#define GL_EXT_shader_atomic_float2 1\n" + + "#define GL_EXT_fragment_shader_barycentric 1\n" + "#define GL_EXT_shader_quad_control 1\n" + "#define GL_EXT_texture_array 1\n" + + "#define GL_EXT_control_flow_attributes2 1\n" ; + if (spvVersion.spv == 0) { + preamble += "#define GL_ARB_bindless_texture 1\n"; + } + if (version >= 150) { // define GL_core_profile and GL_compatibility_profile preamble += "#define GL_core_profile 1\n"; @@ -567,11 +615,13 @@ void TParseVersions::getPreamble(std::string& preamble) if (version >= 140) { preamble += "#define GL_EXT_null_initializer 1\n"; preamble += "#define GL_EXT_subgroup_uniform_control_flow 1\n"; + preamble += "#define GL_EXT_maximal_reconvergence 1\n"; + } + if (version >= 130) { + preamble +="#define GL_FRAGMENT_PRECISION_HIGH 1\n"; } -#endif // GLSLANG_WEB } -#ifndef GLSLANG_WEB if ((!isEsProfile() && version >= 140) || (isEsProfile() && version >= 310)) { preamble += @@ -599,7 +649,6 @@ void TParseVersions::getPreamble(std::string& preamble) preamble += "#define GL_EXT_terminate_invocation 1\n" ; -#endif // #define VULKAN XXXX const int numberBufSize = 12; @@ -611,7 +660,6 @@ void TParseVersions::getPreamble(std::string& preamble) preamble += "\n"; } -#ifndef GLSLANG_WEB // #define GL_SPIRV XXXX if (spvVersion.openGl > 0) { preamble += "#define GL_SPIRV "; @@ -619,9 +667,7 @@ void TParseVersions::getPreamble(std::string& preamble) preamble += numberBuf; preamble += "\n"; } -#endif -#ifndef GLSLANG_WEB // GL_EXT_spirv_intrinsics if (!isEsProfile()) { switch (language) { @@ -637,12 +683,11 @@ void TParseVersions::getPreamble(std::string& preamble) case EShLangClosestHit: preamble += "#define GL_CLOSEST_HIT_SHADER_EXT 1 \n"; break; case EShLangMiss: preamble += "#define GL_MISS_SHADER_EXT 1 \n"; break; case EShLangCallable: preamble += "#define GL_CALLABLE_SHADER_EXT 1 \n"; break; - case EShLangTaskNV: preamble += "#define GL_TASK_SHADER_NV 1 \n"; break; - case EShLangMeshNV: preamble += "#define GL_MESH_SHADER_NV 1 \n"; break; + case EShLangTask: preamble += "#define GL_TASK_SHADER_NV 1 \n"; break; + case EShLangMesh: preamble += "#define GL_MESH_SHADER_NV 1 \n"; break; default: break; } } -#endif } // @@ -654,7 +699,6 @@ const char* StageName(EShLanguage stage) case EShLangVertex: return "vertex"; case EShLangFragment: return "fragment"; case EShLangCompute: return "compute"; -#ifndef GLSLANG_WEB case EShLangTessControl: return "tessellation control"; case EShLangTessEvaluation: return "tessellation evaluation"; case EShLangGeometry: return "geometry"; @@ -664,9 +708,8 @@ const char* StageName(EShLanguage stage) case EShLangClosestHit: return "closest-hit"; case EShLangMiss: return "miss"; case EShLangCallable: return "callable"; - case EShLangMeshNV: return "mesh"; - case EShLangTaskNV: return "task"; -#endif + case EShLangMesh: return "mesh"; + case EShLangTask: return "task"; default: return "unknown stage"; } } @@ -691,7 +734,6 @@ void TParseVersions::requireStage(const TSourceLoc& loc, EShLanguage stage, cons requireStage(loc, static_cast(1 << stage), featureDesc); } -#ifndef GLSLANG_WEB // // When to use requireProfile(): // @@ -729,12 +771,11 @@ void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int { if (profile & profileMask) { bool okay = minVersion > 0 && version >= minVersion; -#ifndef GLSLANG_WEB for (int i = 0; i < numExtensions; ++i) { switch (getExtensionBehavior(extensions[i])) { case EBhWarn: infoSink.info.message(EPrefixWarning, ("extension " + TString(extensions[i]) + " is being used for " + featureDesc).c_str(), loc); - // fall through + [[fallthrough]]; case EBhRequire: case EBhEnable: okay = true; @@ -742,7 +783,6 @@ void TParseVersions::profileRequires(const TSourceLoc& loc, int profileMask, int default: break; // some compilers want this } } -#endif if (! okay) error(loc, "not supported for this version or the enabled extensions", featureDesc, ""); } @@ -952,6 +992,8 @@ void TParseVersions::updateExtensionBehavior(int line, const char* extension, co updateExtensionBehavior(line, "GL_OES_shader_io_blocks", behaviorString); else if (strcmp(extension, "GL_GOOGLE_include_directive") == 0) updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString); + else if (strcmp(extension, "GL_ARB_shading_language_include") == 0) + updateExtensionBehavior(line, "GL_GOOGLE_cpp_style_line_directive", behaviorString); // subgroup_* to subgroup_basic else if (strcmp(extension, "GL_KHR_shader_subgroup_vote") == 0) updateExtensionBehavior(line, "GL_KHR_shader_subgroup_basic", behaviorString); @@ -1056,10 +1098,22 @@ void TParseVersions::checkExtensionStage(const TSourceLoc& loc, const char * con { // GL_NV_mesh_shader extension is only allowed in task/mesh shaders if (strcmp(extension, "GL_NV_mesh_shader") == 0) { - requireStage(loc, (EShLanguageMask)(EShLangTaskNVMask | EShLangMeshNVMask | EShLangFragmentMask), + requireStage(loc, (EShLanguageMask)(EShLangTaskMask | EShLangMeshMask | EShLangFragmentMask), "#extension GL_NV_mesh_shader"); - profileRequires(loc, ECoreProfile, 450, 0, "#extension GL_NV_mesh_shader"); - profileRequires(loc, EEsProfile, 320, 0, "#extension GL_NV_mesh_shader"); + profileRequires(loc, ECoreProfile, 450, nullptr, "#extension GL_NV_mesh_shader"); + profileRequires(loc, EEsProfile, 320, nullptr, "#extension GL_NV_mesh_shader"); + if (extensionTurnedOn(E_GL_EXT_mesh_shader)) { + error(loc, "GL_EXT_mesh_shader is already turned on, and not allowed with", "#extension", extension); + } + } + else if (strcmp(extension, "GL_EXT_mesh_shader") == 0) { + requireStage(loc, (EShLanguageMask)(EShLangTaskMask | EShLangMeshMask | EShLangFragmentMask), + "#extension GL_EXT_mesh_shader"); + profileRequires(loc, ECoreProfile, 450, nullptr, "#extension GL_EXT_mesh_shader"); + profileRequires(loc, EEsProfile, 320, nullptr, "#extension GL_EXT_mesh_shader"); + if (extensionTurnedOn(E_GL_NV_mesh_shader)) { + error(loc, "GL_NV_mesh_shader is already turned on, and not allowed with", "#extension", extension); + } } } @@ -1079,6 +1133,13 @@ void TParseVersions::extensionRequires(const TSourceLoc &loc, const char * const minSpvVersion = iter->second; requireSpv(loc, extension, minSpvVersion); } + + if (spvVersion.spv != 0){ + for (auto ext : spvUnsupportedExt){ + if (strcmp(extension, ext.c_str()) == 0) + error(loc, "not allowed when using generating SPIR-V codes", extension, ""); + } + } } // Call for any operation needing full GLSL integer data-type support. @@ -1291,7 +1352,7 @@ void TParseVersions::int64Check(const TSourceLoc& loc, const char* op, bool buil } } -void TParseVersions::fcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn) +void TParseVersions::fcoopmatCheckNV(const TSourceLoc& loc, const char* op, bool builtIn) { if (!builtIn) { const char* const extensions[] = {E_GL_NV_cooperative_matrix}; @@ -1299,14 +1360,22 @@ void TParseVersions::fcoopmatCheck(const TSourceLoc& loc, const char* op, bool b } } -void TParseVersions::intcoopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn) +void TParseVersions::intcoopmatCheckNV(const TSourceLoc& loc, const char* op, bool builtIn) { if (!builtIn) { const char* const extensions[] = {E_GL_NV_integer_cooperative_matrix}; requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op); } } -#endif // GLSLANG_WEB + +void TParseVersions::coopmatCheck(const TSourceLoc& loc, const char* op, bool builtIn) +{ + if (!builtIn) { + const char* const extensions[] = {E_GL_KHR_cooperative_matrix}; + requireExtensions(loc, sizeof(extensions)/sizeof(extensions[0]), extensions, op); + } +} + // Call for any operation removed because SPIR-V is in use. void TParseVersions::spvRemoved(const TSourceLoc& loc, const char* op) { @@ -1324,26 +1393,20 @@ void TParseVersions::vulkanRemoved(const TSourceLoc& loc, const char* op) // Call for any operation that requires Vulkan. void TParseVersions::requireVulkan(const TSourceLoc& loc, const char* op) { -#ifndef GLSLANG_WEB if (spvVersion.vulkan == 0) error(loc, "only allowed when using GLSL for Vulkan", op, ""); -#endif } // Call for any operation that requires SPIR-V. void TParseVersions::requireSpv(const TSourceLoc& loc, const char* op) { -#ifndef GLSLANG_WEB if (spvVersion.spv == 0) error(loc, "only allowed when generating SPIR-V", op, ""); -#endif } void TParseVersions::requireSpv(const TSourceLoc& loc, const char *op, unsigned int version) { -#ifndef GLSLANG_WEB if (spvVersion.spv < version) error(loc, "not supported for current targeted SPIR-V version", op, ""); -#endif } } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/Versions.h b/src/libraries/glslang/glslang/MachineIndependent/Versions.h old mode 100644 new mode 100755 index 35e1f9aa6..cfaeb1ff1 --- a/src/libraries/glslang/glslang/MachineIndependent/Versions.h +++ b/src/libraries/glslang/glslang/MachineIndependent/Versions.h @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2013 LunarG, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Copyright (C) 2015-2018 Google, Inc. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // @@ -120,7 +120,6 @@ const char* const E_GL_EXT_YUV_target = "GL_EXT_YUV_target"; const char* const E_GL_EXT_shader_texture_lod = "GL_EXT_shader_texture_lod"; const char* const E_GL_EXT_shadow_samplers = "GL_EXT_shadow_samplers"; -const char* const E_GL_EXT_texture_array = "GL_EXT_texture_array"; const char* const E_GL_ARB_texture_rectangle = "GL_ARB_texture_rectangle"; const char* const E_GL_3DL_array_objects = "GL_3DL_array_objects"; const char* const E_GL_ARB_shading_language_420pack = "GL_ARB_shading_language_420pack"; @@ -164,6 +163,7 @@ const char* const E_GL_ARB_texture_query_lod = "GL_ARB_texture_query_ const char* const E_GL_ARB_vertex_attrib_64bit = "GL_ARB_vertex_attrib_64bit"; const char* const E_GL_ARB_draw_instanced = "GL_ARB_draw_instanced"; const char* const E_GL_ARB_fragment_coord_conventions = "GL_ARB_fragment_coord_conventions"; +const char* const E_GL_ARB_bindless_texture = "GL_ARB_bindless_texture"; const char* const E_GL_KHR_shader_subgroup_basic = "GL_KHR_shader_subgroup_basic"; const char* const E_GL_KHR_shader_subgroup_vote = "GL_KHR_shader_subgroup_vote"; @@ -171,9 +171,11 @@ const char* const E_GL_KHR_shader_subgroup_arithmetic = "GL_KHR_shader_sub const char* const E_GL_KHR_shader_subgroup_ballot = "GL_KHR_shader_subgroup_ballot"; const char* const E_GL_KHR_shader_subgroup_shuffle = "GL_KHR_shader_subgroup_shuffle"; const char* const E_GL_KHR_shader_subgroup_shuffle_relative = "GL_KHR_shader_subgroup_shuffle_relative"; +const char* const E_GL_KHR_shader_subgroup_rotate = "GL_KHR_shader_subgroup_rotate"; const char* const E_GL_KHR_shader_subgroup_clustered = "GL_KHR_shader_subgroup_clustered"; const char* const E_GL_KHR_shader_subgroup_quad = "GL_KHR_shader_subgroup_quad"; const char* const E_GL_KHR_memory_scope_semantics = "GL_KHR_memory_scope_semantics"; +const char* const E_GL_KHR_cooperative_matrix = "GL_KHR_cooperative_matrix"; const char* const E_GL_EXT_shader_atomic_int64 = "GL_EXT_shader_atomic_int64"; @@ -202,6 +204,7 @@ const char* const E_GL_EXT_debug_printf = "GL_EXT_debug_prin const char* const E_GL_EXT_ray_tracing = "GL_EXT_ray_tracing"; const char* const E_GL_EXT_ray_query = "GL_EXT_ray_query"; const char* const E_GL_EXT_ray_flags_primitive_culling = "GL_EXT_ray_flags_primitive_culling"; +const char* const E_GL_EXT_ray_cull_mask = "GL_EXT_ray_cull_mask"; const char* const E_GL_EXT_blend_func_extended = "GL_EXT_blend_func_extended"; const char* const E_GL_EXT_shader_implicit_conversions = "GL_EXT_shader_implicit_conversions"; const char* const E_GL_EXT_fragment_shading_rate = "GL_EXT_fragment_shading_rate"; @@ -210,12 +213,25 @@ const char* const E_GL_EXT_null_initializer = "GL_EXT_null_initi const char* const E_GL_EXT_shared_memory_block = "GL_EXT_shared_memory_block"; const char* const E_GL_EXT_subgroup_uniform_control_flow = "GL_EXT_subgroup_uniform_control_flow"; const char* const E_GL_EXT_spirv_intrinsics = "GL_EXT_spirv_intrinsics"; +const char* const E_GL_EXT_fragment_shader_barycentric = "GL_EXT_fragment_shader_barycentric"; +const char* const E_GL_EXT_mesh_shader = "GL_EXT_mesh_shader"; +const char* const E_GL_EXT_opacity_micromap = "GL_EXT_opacity_micromap"; +const char* const E_GL_EXT_shader_quad_control = "GL_EXT_shader_quad_control"; +const char* const E_GL_EXT_draw_instanced = "GL_EXT_draw_instanced"; +const char* const E_GL_EXT_texture_array = "GL_EXT_texture_array"; +const char* const E_GL_EXT_maximal_reconvergence = "GL_EXT_maximal_reconvergence"; +const char* const E_GL_EXT_expect_assume = "GL_EXT_expect_assume"; +const char* const E_GL_EXT_control_flow_attributes2 = "GL_EXT_control_flow_attributes2"; // Arrays of extensions for the above viewportEXTs duplications const char* const post_depth_coverageEXTs[] = { E_GL_ARB_post_depth_coverage, E_GL_EXT_post_depth_coverage }; const int Num_post_depth_coverageEXTs = sizeof(post_depth_coverageEXTs) / sizeof(post_depth_coverageEXTs[0]); +// Array of extensions to cover both extensions providing ray tracing capabilities. +const char* const ray_tracing_EXTs[] = { E_GL_EXT_ray_query, E_GL_EXT_ray_tracing }; +const int Num_ray_tracing_EXTs = sizeof(ray_tracing_EXTs) / sizeof(ray_tracing_EXTs[0]); + // OVR extensions const char* const E_GL_OVR_multiview = "GL_OVR_multiview"; const char* const E_GL_OVR_multiview2 = "GL_OVR_multiview2"; @@ -226,6 +242,7 @@ const int Num_OVR_multiview_EXTs = sizeof(OVR_multiview_EXTs) / sizeof(OVR_multi // #line and #include const char* const E_GL_GOOGLE_cpp_style_line_directive = "GL_GOOGLE_cpp_style_line_directive"; const char* const E_GL_GOOGLE_include_directive = "GL_GOOGLE_include_directive"; +const char* const E_GL_ARB_shading_language_include = "GL_ARB_shading_language_include"; const char* const E_GL_AMD_shader_ballot = "GL_AMD_shader_ballot"; const char* const E_GL_AMD_shader_trinary_minmax = "GL_AMD_shader_trinary_minmax"; @@ -237,6 +254,7 @@ const char* const E_GL_AMD_gpu_shader_int16 = "GL_AMD_gpu_sh const char* const E_GL_AMD_shader_image_load_store_lod = "GL_AMD_shader_image_load_store_lod"; const char* const E_GL_AMD_shader_fragment_mask = "GL_AMD_shader_fragment_mask"; const char* const E_GL_AMD_gpu_shader_half_float_fetch = "GL_AMD_gpu_shader_half_float_fetch"; +const char* const E_GL_AMD_shader_early_and_late_fragment_tests = "GL_AMD_shader_early_and_late_fragment_tests"; const char* const E_GL_INTEL_shader_integer_functions2 = "GL_INTEL_shader_integer_functions2"; @@ -256,15 +274,25 @@ const char* const E_GL_NV_fragment_shader_barycentric = "GL_NV_fragmen const char* const E_GL_NV_compute_shader_derivatives = "GL_NV_compute_shader_derivatives"; const char* const E_GL_NV_shader_texture_footprint = "GL_NV_shader_texture_footprint"; const char* const E_GL_NV_mesh_shader = "GL_NV_mesh_shader"; +const char* const E_GL_NV_cooperative_matrix = "GL_NV_cooperative_matrix"; +const char* const E_GL_NV_shader_sm_builtins = "GL_NV_shader_sm_builtins"; +const char* const E_GL_NV_integer_cooperative_matrix = "GL_NV_integer_cooperative_matrix"; +const char* const E_GL_NV_shader_invocation_reorder = "GL_NV_shader_invocation_reorder"; +const char* const E_GL_EXT_ray_tracing_position_fetch = "GL_EXT_ray_tracing_position_fetch"; +const char* const E_GL_NV_displacement_micromap = "GL_NV_displacement_micromap"; +const char* const E_GL_NV_shader_atomic_fp16_vector = "GL_NV_shader_atomic_fp16_vector"; + +// ARM +const char* const E_GL_ARM_shader_core_builtins = "GL_ARM_shader_core_builtins"; // Arrays of extensions for the above viewportEXTs duplications const char* const viewportEXTs[] = { E_GL_ARB_shader_viewport_layer_array, E_GL_NV_viewport_array2 }; const int Num_viewportEXTs = sizeof(viewportEXTs) / sizeof(viewportEXTs[0]); -const char* const E_GL_NV_cooperative_matrix = "GL_NV_cooperative_matrix"; -const char* const E_GL_NV_shader_sm_builtins = "GL_NV_shader_sm_builtins"; -const char* const E_GL_NV_integer_cooperative_matrix = "GL_NV_integer_cooperative_matrix"; + +const char* const E_GL_QCOM_image_processing = "GL_QCOM_image_processing"; +const char* const E_GL_QCOM_image_processing2 = "GL_QCOM_image_processing2"; // AEP const char* const E_GL_ANDROID_extension_pack_es31a = "GL_ANDROID_extension_pack_es31a"; @@ -282,7 +310,7 @@ const char* const E_GL_EXT_tessellation_shader = "GL_EXT_tessel const char* const E_GL_EXT_tessellation_point_size = "GL_EXT_tessellation_point_size"; const char* const E_GL_EXT_texture_buffer = "GL_EXT_texture_buffer"; const char* const E_GL_EXT_texture_cube_map_array = "GL_EXT_texture_cube_map_array"; -const char* const E_GL_EXT_shader_integer_mix = "GL_EXT_shader_integer_mix"; +const char* const E_GL_EXT_shader_integer_mix = "GL_EXT_shader_integer_mix"; // OES matching AEP const char* const E_GL_OES_geometry_shader = "GL_OES_geometry_shader"; @@ -314,6 +342,10 @@ const char* const E_GL_EXT_terminate_invocation = "GL_EXT_terminate_invocation"; const char* const E_GL_EXT_shader_atomic_float = "GL_EXT_shader_atomic_float"; const char* const E_GL_EXT_shader_atomic_float2 = "GL_EXT_shader_atomic_float2"; +const char* const E_GL_EXT_shader_tile_image = "GL_EXT_shader_tile_image"; + +const char* const E_GL_EXT_texture_shadow_lod = "GL_EXT_texture_shadow_lod"; + // Arrays of extensions for the above AEP duplications const char* const AEP_geometry_shader[] = { E_GL_EXT_geometry_shader, E_GL_OES_geometry_shader }; @@ -343,6 +375,9 @@ const int Num_AEP_texture_buffer = sizeof(AEP_texture_buffer)/sizeof(AEP_texture const char* const AEP_texture_cube_map_array[] = { E_GL_EXT_texture_cube_map_array, E_GL_OES_texture_cube_map_array }; const int Num_AEP_texture_cube_map_array = sizeof(AEP_texture_cube_map_array)/sizeof(AEP_texture_cube_map_array[0]); +const char* const AEP_mesh_shader[] = { E_GL_NV_mesh_shader, E_GL_EXT_mesh_shader }; +const int Num_AEP_mesh_shader = sizeof(AEP_mesh_shader)/sizeof(AEP_mesh_shader[0]); + } // end namespace glslang #endif // _VERSIONS_INCLUDED_ diff --git a/src/libraries/glslang/glslang/MachineIndependent/attribute.cpp b/src/libraries/glslang/glslang/MachineIndependent/attribute.cpp index df7fdc2a6..19e8faac3 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/attribute.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/attribute.cpp @@ -34,8 +34,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#ifndef GLSLANG_WEB - #include "attribute.h" #include "../Include/intermediate.h" #include "ParseHelper.h" @@ -125,6 +123,10 @@ TAttributeType TParseContext::attributeFromName(const TString& name) const return EatPartialCount; else if (name == "subgroup_uniform_control_flow") return EatSubgroupUniformControlFlow; + else if (name == "export") + return EatExport; + else if (name == "maximally_reconverges") + return EatMaximallyReconverges; else return EatNone; } @@ -357,8 +359,13 @@ void TParseContext::handleFunctionAttributes(const TSourceLoc& loc, const TAttri switch (it->name) { case EatSubgroupUniformControlFlow: + requireExtensions(loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); intermediate.setSubgroupUniformControlFlow(); break; + case EatMaximallyReconverges: + requireExtensions(loc, 1, &E_GL_EXT_maximal_reconvergence, "attribute"); + intermediate.setMaximallyReconverges(); + break; default: warn(loc, "attribute does not apply to a function", "", ""); break; @@ -367,5 +374,3 @@ void TParseContext::handleFunctionAttributes(const TSourceLoc& loc, const TAttri } } // end namespace glslang - -#endif // GLSLANG_WEB diff --git a/src/libraries/glslang/glslang/MachineIndependent/attribute.h b/src/libraries/glslang/glslang/MachineIndependent/attribute.h index c5b29176c..3b480c6f0 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/attribute.h +++ b/src/libraries/glslang/glslang/MachineIndependent/attribute.h @@ -120,6 +120,8 @@ namespace glslang { EatNonWritable, EatNonReadable, EatSubgroupUniformControlFlow, + EatExport, + EatMaximallyReconverges, }; class TIntermAggregate; diff --git a/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp b/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp index 5ba6a6d49..5764d3929 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.7.4. */ +/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison implementation for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -46,10 +46,10 @@ USER NAME SPACE" below. */ /* Identify Bison output, and Bison version. */ -#define YYBISON 30704 +#define YYBISON 30802 /* Bison version string. */ -#define YYBISON_VERSION "3.7.4" +#define YYBISON_VERSION "3.8.2" /* Skeleton name. */ #define YYSKELETON_NAME "yacc.c" @@ -67,7 +67,7 @@ /* First part of user prologue. */ -#line 69 "MachineIndependent/glslang.y" +#line 44 "MachineIndependent/glslang.y" /* Based on: @@ -287,448 +287,452 @@ enum yysymbol_kind_t YYSYMBOL_FCOOPMATNV = 163, /* FCOOPMATNV */ YYSYMBOL_ICOOPMATNV = 164, /* ICOOPMATNV */ YYSYMBOL_UCOOPMATNV = 165, /* UCOOPMATNV */ - YYSYMBOL_SAMPLERCUBEARRAY = 166, /* SAMPLERCUBEARRAY */ - YYSYMBOL_SAMPLERCUBEARRAYSHADOW = 167, /* SAMPLERCUBEARRAYSHADOW */ - YYSYMBOL_ISAMPLERCUBEARRAY = 168, /* ISAMPLERCUBEARRAY */ - YYSYMBOL_USAMPLERCUBEARRAY = 169, /* USAMPLERCUBEARRAY */ - YYSYMBOL_SAMPLER1D = 170, /* SAMPLER1D */ - YYSYMBOL_SAMPLER1DARRAY = 171, /* SAMPLER1DARRAY */ - YYSYMBOL_SAMPLER1DARRAYSHADOW = 172, /* SAMPLER1DARRAYSHADOW */ - YYSYMBOL_ISAMPLER1D = 173, /* ISAMPLER1D */ - YYSYMBOL_SAMPLER1DSHADOW = 174, /* SAMPLER1DSHADOW */ - YYSYMBOL_SAMPLER2DRECT = 175, /* SAMPLER2DRECT */ - YYSYMBOL_SAMPLER2DRECTSHADOW = 176, /* SAMPLER2DRECTSHADOW */ - YYSYMBOL_ISAMPLER2DRECT = 177, /* ISAMPLER2DRECT */ - YYSYMBOL_USAMPLER2DRECT = 178, /* USAMPLER2DRECT */ - YYSYMBOL_SAMPLERBUFFER = 179, /* SAMPLERBUFFER */ - YYSYMBOL_ISAMPLERBUFFER = 180, /* ISAMPLERBUFFER */ - YYSYMBOL_USAMPLERBUFFER = 181, /* USAMPLERBUFFER */ - YYSYMBOL_SAMPLER2DMS = 182, /* SAMPLER2DMS */ - YYSYMBOL_ISAMPLER2DMS = 183, /* ISAMPLER2DMS */ - YYSYMBOL_USAMPLER2DMS = 184, /* USAMPLER2DMS */ - YYSYMBOL_SAMPLER2DMSARRAY = 185, /* SAMPLER2DMSARRAY */ - YYSYMBOL_ISAMPLER2DMSARRAY = 186, /* ISAMPLER2DMSARRAY */ - YYSYMBOL_USAMPLER2DMSARRAY = 187, /* USAMPLER2DMSARRAY */ - YYSYMBOL_SAMPLEREXTERNALOES = 188, /* SAMPLEREXTERNALOES */ - YYSYMBOL_SAMPLEREXTERNAL2DY2YEXT = 189, /* SAMPLEREXTERNAL2DY2YEXT */ - YYSYMBOL_ISAMPLER1DARRAY = 190, /* ISAMPLER1DARRAY */ - YYSYMBOL_USAMPLER1D = 191, /* USAMPLER1D */ - YYSYMBOL_USAMPLER1DARRAY = 192, /* USAMPLER1DARRAY */ - YYSYMBOL_F16SAMPLER1D = 193, /* F16SAMPLER1D */ - YYSYMBOL_F16SAMPLER2D = 194, /* F16SAMPLER2D */ - YYSYMBOL_F16SAMPLER3D = 195, /* F16SAMPLER3D */ - YYSYMBOL_F16SAMPLER2DRECT = 196, /* F16SAMPLER2DRECT */ - YYSYMBOL_F16SAMPLERCUBE = 197, /* F16SAMPLERCUBE */ - YYSYMBOL_F16SAMPLER1DARRAY = 198, /* F16SAMPLER1DARRAY */ - YYSYMBOL_F16SAMPLER2DARRAY = 199, /* F16SAMPLER2DARRAY */ - YYSYMBOL_F16SAMPLERCUBEARRAY = 200, /* F16SAMPLERCUBEARRAY */ - YYSYMBOL_F16SAMPLERBUFFER = 201, /* F16SAMPLERBUFFER */ - YYSYMBOL_F16SAMPLER2DMS = 202, /* F16SAMPLER2DMS */ - YYSYMBOL_F16SAMPLER2DMSARRAY = 203, /* F16SAMPLER2DMSARRAY */ - YYSYMBOL_F16SAMPLER1DSHADOW = 204, /* F16SAMPLER1DSHADOW */ - YYSYMBOL_F16SAMPLER2DSHADOW = 205, /* F16SAMPLER2DSHADOW */ - YYSYMBOL_F16SAMPLER1DARRAYSHADOW = 206, /* F16SAMPLER1DARRAYSHADOW */ - YYSYMBOL_F16SAMPLER2DARRAYSHADOW = 207, /* F16SAMPLER2DARRAYSHADOW */ - YYSYMBOL_F16SAMPLER2DRECTSHADOW = 208, /* F16SAMPLER2DRECTSHADOW */ - YYSYMBOL_F16SAMPLERCUBESHADOW = 209, /* F16SAMPLERCUBESHADOW */ - YYSYMBOL_F16SAMPLERCUBEARRAYSHADOW = 210, /* F16SAMPLERCUBEARRAYSHADOW */ - YYSYMBOL_IMAGE1D = 211, /* IMAGE1D */ - YYSYMBOL_IIMAGE1D = 212, /* IIMAGE1D */ - YYSYMBOL_UIMAGE1D = 213, /* UIMAGE1D */ - YYSYMBOL_IMAGE2D = 214, /* IMAGE2D */ - YYSYMBOL_IIMAGE2D = 215, /* IIMAGE2D */ - YYSYMBOL_UIMAGE2D = 216, /* UIMAGE2D */ - YYSYMBOL_IMAGE3D = 217, /* IMAGE3D */ - YYSYMBOL_IIMAGE3D = 218, /* IIMAGE3D */ - YYSYMBOL_UIMAGE3D = 219, /* UIMAGE3D */ - YYSYMBOL_IMAGE2DRECT = 220, /* IMAGE2DRECT */ - YYSYMBOL_IIMAGE2DRECT = 221, /* IIMAGE2DRECT */ - YYSYMBOL_UIMAGE2DRECT = 222, /* UIMAGE2DRECT */ - YYSYMBOL_IMAGECUBE = 223, /* IMAGECUBE */ - YYSYMBOL_IIMAGECUBE = 224, /* IIMAGECUBE */ - YYSYMBOL_UIMAGECUBE = 225, /* UIMAGECUBE */ - YYSYMBOL_IMAGEBUFFER = 226, /* IMAGEBUFFER */ - YYSYMBOL_IIMAGEBUFFER = 227, /* IIMAGEBUFFER */ - YYSYMBOL_UIMAGEBUFFER = 228, /* UIMAGEBUFFER */ - YYSYMBOL_IMAGE1DARRAY = 229, /* IMAGE1DARRAY */ - YYSYMBOL_IIMAGE1DARRAY = 230, /* IIMAGE1DARRAY */ - YYSYMBOL_UIMAGE1DARRAY = 231, /* UIMAGE1DARRAY */ - YYSYMBOL_IMAGE2DARRAY = 232, /* IMAGE2DARRAY */ - YYSYMBOL_IIMAGE2DARRAY = 233, /* IIMAGE2DARRAY */ - YYSYMBOL_UIMAGE2DARRAY = 234, /* UIMAGE2DARRAY */ - YYSYMBOL_IMAGECUBEARRAY = 235, /* IMAGECUBEARRAY */ - YYSYMBOL_IIMAGECUBEARRAY = 236, /* IIMAGECUBEARRAY */ - YYSYMBOL_UIMAGECUBEARRAY = 237, /* UIMAGECUBEARRAY */ - YYSYMBOL_IMAGE2DMS = 238, /* IMAGE2DMS */ - YYSYMBOL_IIMAGE2DMS = 239, /* IIMAGE2DMS */ - YYSYMBOL_UIMAGE2DMS = 240, /* UIMAGE2DMS */ - YYSYMBOL_IMAGE2DMSARRAY = 241, /* IMAGE2DMSARRAY */ - YYSYMBOL_IIMAGE2DMSARRAY = 242, /* IIMAGE2DMSARRAY */ - YYSYMBOL_UIMAGE2DMSARRAY = 243, /* UIMAGE2DMSARRAY */ - YYSYMBOL_F16IMAGE1D = 244, /* F16IMAGE1D */ - YYSYMBOL_F16IMAGE2D = 245, /* F16IMAGE2D */ - YYSYMBOL_F16IMAGE3D = 246, /* F16IMAGE3D */ - YYSYMBOL_F16IMAGE2DRECT = 247, /* F16IMAGE2DRECT */ - YYSYMBOL_F16IMAGECUBE = 248, /* F16IMAGECUBE */ - YYSYMBOL_F16IMAGE1DARRAY = 249, /* F16IMAGE1DARRAY */ - YYSYMBOL_F16IMAGE2DARRAY = 250, /* F16IMAGE2DARRAY */ - YYSYMBOL_F16IMAGECUBEARRAY = 251, /* F16IMAGECUBEARRAY */ - YYSYMBOL_F16IMAGEBUFFER = 252, /* F16IMAGEBUFFER */ - YYSYMBOL_F16IMAGE2DMS = 253, /* F16IMAGE2DMS */ - YYSYMBOL_F16IMAGE2DMSARRAY = 254, /* F16IMAGE2DMSARRAY */ - YYSYMBOL_I64IMAGE1D = 255, /* I64IMAGE1D */ - YYSYMBOL_U64IMAGE1D = 256, /* U64IMAGE1D */ - YYSYMBOL_I64IMAGE2D = 257, /* I64IMAGE2D */ - YYSYMBOL_U64IMAGE2D = 258, /* U64IMAGE2D */ - YYSYMBOL_I64IMAGE3D = 259, /* I64IMAGE3D */ - YYSYMBOL_U64IMAGE3D = 260, /* U64IMAGE3D */ - YYSYMBOL_I64IMAGE2DRECT = 261, /* I64IMAGE2DRECT */ - YYSYMBOL_U64IMAGE2DRECT = 262, /* U64IMAGE2DRECT */ - YYSYMBOL_I64IMAGECUBE = 263, /* I64IMAGECUBE */ - YYSYMBOL_U64IMAGECUBE = 264, /* U64IMAGECUBE */ - YYSYMBOL_I64IMAGEBUFFER = 265, /* I64IMAGEBUFFER */ - YYSYMBOL_U64IMAGEBUFFER = 266, /* U64IMAGEBUFFER */ - YYSYMBOL_I64IMAGE1DARRAY = 267, /* I64IMAGE1DARRAY */ - YYSYMBOL_U64IMAGE1DARRAY = 268, /* U64IMAGE1DARRAY */ - YYSYMBOL_I64IMAGE2DARRAY = 269, /* I64IMAGE2DARRAY */ - YYSYMBOL_U64IMAGE2DARRAY = 270, /* U64IMAGE2DARRAY */ - YYSYMBOL_I64IMAGECUBEARRAY = 271, /* I64IMAGECUBEARRAY */ - YYSYMBOL_U64IMAGECUBEARRAY = 272, /* U64IMAGECUBEARRAY */ - YYSYMBOL_I64IMAGE2DMS = 273, /* I64IMAGE2DMS */ - YYSYMBOL_U64IMAGE2DMS = 274, /* U64IMAGE2DMS */ - YYSYMBOL_I64IMAGE2DMSARRAY = 275, /* I64IMAGE2DMSARRAY */ - YYSYMBOL_U64IMAGE2DMSARRAY = 276, /* U64IMAGE2DMSARRAY */ - YYSYMBOL_TEXTURECUBEARRAY = 277, /* TEXTURECUBEARRAY */ - YYSYMBOL_ITEXTURECUBEARRAY = 278, /* ITEXTURECUBEARRAY */ - YYSYMBOL_UTEXTURECUBEARRAY = 279, /* UTEXTURECUBEARRAY */ - YYSYMBOL_TEXTURE1D = 280, /* TEXTURE1D */ - YYSYMBOL_ITEXTURE1D = 281, /* ITEXTURE1D */ - YYSYMBOL_UTEXTURE1D = 282, /* UTEXTURE1D */ - YYSYMBOL_TEXTURE1DARRAY = 283, /* TEXTURE1DARRAY */ - YYSYMBOL_ITEXTURE1DARRAY = 284, /* ITEXTURE1DARRAY */ - YYSYMBOL_UTEXTURE1DARRAY = 285, /* UTEXTURE1DARRAY */ - YYSYMBOL_TEXTURE2DRECT = 286, /* TEXTURE2DRECT */ - YYSYMBOL_ITEXTURE2DRECT = 287, /* ITEXTURE2DRECT */ - YYSYMBOL_UTEXTURE2DRECT = 288, /* UTEXTURE2DRECT */ - YYSYMBOL_TEXTUREBUFFER = 289, /* TEXTUREBUFFER */ - YYSYMBOL_ITEXTUREBUFFER = 290, /* ITEXTUREBUFFER */ - YYSYMBOL_UTEXTUREBUFFER = 291, /* UTEXTUREBUFFER */ - YYSYMBOL_TEXTURE2DMS = 292, /* TEXTURE2DMS */ - YYSYMBOL_ITEXTURE2DMS = 293, /* ITEXTURE2DMS */ - YYSYMBOL_UTEXTURE2DMS = 294, /* UTEXTURE2DMS */ - YYSYMBOL_TEXTURE2DMSARRAY = 295, /* TEXTURE2DMSARRAY */ - YYSYMBOL_ITEXTURE2DMSARRAY = 296, /* ITEXTURE2DMSARRAY */ - YYSYMBOL_UTEXTURE2DMSARRAY = 297, /* UTEXTURE2DMSARRAY */ - YYSYMBOL_F16TEXTURE1D = 298, /* F16TEXTURE1D */ - YYSYMBOL_F16TEXTURE2D = 299, /* F16TEXTURE2D */ - YYSYMBOL_F16TEXTURE3D = 300, /* F16TEXTURE3D */ - YYSYMBOL_F16TEXTURE2DRECT = 301, /* F16TEXTURE2DRECT */ - YYSYMBOL_F16TEXTURECUBE = 302, /* F16TEXTURECUBE */ - YYSYMBOL_F16TEXTURE1DARRAY = 303, /* F16TEXTURE1DARRAY */ - YYSYMBOL_F16TEXTURE2DARRAY = 304, /* F16TEXTURE2DARRAY */ - YYSYMBOL_F16TEXTURECUBEARRAY = 305, /* F16TEXTURECUBEARRAY */ - YYSYMBOL_F16TEXTUREBUFFER = 306, /* F16TEXTUREBUFFER */ - YYSYMBOL_F16TEXTURE2DMS = 307, /* F16TEXTURE2DMS */ - YYSYMBOL_F16TEXTURE2DMSARRAY = 308, /* F16TEXTURE2DMSARRAY */ - YYSYMBOL_SUBPASSINPUT = 309, /* SUBPASSINPUT */ - YYSYMBOL_SUBPASSINPUTMS = 310, /* SUBPASSINPUTMS */ - YYSYMBOL_ISUBPASSINPUT = 311, /* ISUBPASSINPUT */ - YYSYMBOL_ISUBPASSINPUTMS = 312, /* ISUBPASSINPUTMS */ - YYSYMBOL_USUBPASSINPUT = 313, /* USUBPASSINPUT */ - YYSYMBOL_USUBPASSINPUTMS = 314, /* USUBPASSINPUTMS */ - YYSYMBOL_F16SUBPASSINPUT = 315, /* F16SUBPASSINPUT */ - YYSYMBOL_F16SUBPASSINPUTMS = 316, /* F16SUBPASSINPUTMS */ - YYSYMBOL_SPIRV_INSTRUCTION = 317, /* SPIRV_INSTRUCTION */ - YYSYMBOL_SPIRV_EXECUTION_MODE = 318, /* SPIRV_EXECUTION_MODE */ - YYSYMBOL_SPIRV_EXECUTION_MODE_ID = 319, /* SPIRV_EXECUTION_MODE_ID */ - YYSYMBOL_SPIRV_DECORATE = 320, /* SPIRV_DECORATE */ - YYSYMBOL_SPIRV_DECORATE_ID = 321, /* SPIRV_DECORATE_ID */ - YYSYMBOL_SPIRV_DECORATE_STRING = 322, /* SPIRV_DECORATE_STRING */ - YYSYMBOL_SPIRV_TYPE = 323, /* SPIRV_TYPE */ - YYSYMBOL_SPIRV_STORAGE_CLASS = 324, /* SPIRV_STORAGE_CLASS */ - YYSYMBOL_SPIRV_BY_REFERENCE = 325, /* SPIRV_BY_REFERENCE */ - YYSYMBOL_SPIRV_LITERAL = 326, /* SPIRV_LITERAL */ - YYSYMBOL_LEFT_OP = 327, /* LEFT_OP */ - YYSYMBOL_RIGHT_OP = 328, /* RIGHT_OP */ - YYSYMBOL_INC_OP = 329, /* INC_OP */ - YYSYMBOL_DEC_OP = 330, /* DEC_OP */ - YYSYMBOL_LE_OP = 331, /* LE_OP */ - YYSYMBOL_GE_OP = 332, /* GE_OP */ - YYSYMBOL_EQ_OP = 333, /* EQ_OP */ - YYSYMBOL_NE_OP = 334, /* NE_OP */ - YYSYMBOL_AND_OP = 335, /* AND_OP */ - YYSYMBOL_OR_OP = 336, /* OR_OP */ - YYSYMBOL_XOR_OP = 337, /* XOR_OP */ - YYSYMBOL_MUL_ASSIGN = 338, /* MUL_ASSIGN */ - YYSYMBOL_DIV_ASSIGN = 339, /* DIV_ASSIGN */ - YYSYMBOL_ADD_ASSIGN = 340, /* ADD_ASSIGN */ - YYSYMBOL_MOD_ASSIGN = 341, /* MOD_ASSIGN */ - YYSYMBOL_LEFT_ASSIGN = 342, /* LEFT_ASSIGN */ - YYSYMBOL_RIGHT_ASSIGN = 343, /* RIGHT_ASSIGN */ - YYSYMBOL_AND_ASSIGN = 344, /* AND_ASSIGN */ - YYSYMBOL_XOR_ASSIGN = 345, /* XOR_ASSIGN */ - YYSYMBOL_OR_ASSIGN = 346, /* OR_ASSIGN */ - YYSYMBOL_SUB_ASSIGN = 347, /* SUB_ASSIGN */ - YYSYMBOL_STRING_LITERAL = 348, /* STRING_LITERAL */ - YYSYMBOL_LEFT_PAREN = 349, /* LEFT_PAREN */ - YYSYMBOL_RIGHT_PAREN = 350, /* RIGHT_PAREN */ - YYSYMBOL_LEFT_BRACKET = 351, /* LEFT_BRACKET */ - YYSYMBOL_RIGHT_BRACKET = 352, /* RIGHT_BRACKET */ - YYSYMBOL_LEFT_BRACE = 353, /* LEFT_BRACE */ - YYSYMBOL_RIGHT_BRACE = 354, /* RIGHT_BRACE */ - YYSYMBOL_DOT = 355, /* DOT */ - YYSYMBOL_COMMA = 356, /* COMMA */ - YYSYMBOL_COLON = 357, /* COLON */ - YYSYMBOL_EQUAL = 358, /* EQUAL */ - YYSYMBOL_SEMICOLON = 359, /* SEMICOLON */ - YYSYMBOL_BANG = 360, /* BANG */ - YYSYMBOL_DASH = 361, /* DASH */ - YYSYMBOL_TILDE = 362, /* TILDE */ - YYSYMBOL_PLUS = 363, /* PLUS */ - YYSYMBOL_STAR = 364, /* STAR */ - YYSYMBOL_SLASH = 365, /* SLASH */ - YYSYMBOL_PERCENT = 366, /* PERCENT */ - YYSYMBOL_LEFT_ANGLE = 367, /* LEFT_ANGLE */ - YYSYMBOL_RIGHT_ANGLE = 368, /* RIGHT_ANGLE */ - YYSYMBOL_VERTICAL_BAR = 369, /* VERTICAL_BAR */ - YYSYMBOL_CARET = 370, /* CARET */ - YYSYMBOL_AMPERSAND = 371, /* AMPERSAND */ - YYSYMBOL_QUESTION = 372, /* QUESTION */ - YYSYMBOL_INVARIANT = 373, /* INVARIANT */ - YYSYMBOL_HIGH_PRECISION = 374, /* HIGH_PRECISION */ - YYSYMBOL_MEDIUM_PRECISION = 375, /* MEDIUM_PRECISION */ - YYSYMBOL_LOW_PRECISION = 376, /* LOW_PRECISION */ - YYSYMBOL_PRECISION = 377, /* PRECISION */ - YYSYMBOL_PACKED = 378, /* PACKED */ - YYSYMBOL_RESOURCE = 379, /* RESOURCE */ - YYSYMBOL_SUPERP = 380, /* SUPERP */ - YYSYMBOL_FLOATCONSTANT = 381, /* FLOATCONSTANT */ - YYSYMBOL_INTCONSTANT = 382, /* INTCONSTANT */ - YYSYMBOL_UINTCONSTANT = 383, /* UINTCONSTANT */ - YYSYMBOL_BOOLCONSTANT = 384, /* BOOLCONSTANT */ - YYSYMBOL_IDENTIFIER = 385, /* IDENTIFIER */ - YYSYMBOL_TYPE_NAME = 386, /* TYPE_NAME */ - YYSYMBOL_CENTROID = 387, /* CENTROID */ - YYSYMBOL_IN = 388, /* IN */ - YYSYMBOL_OUT = 389, /* OUT */ - YYSYMBOL_INOUT = 390, /* INOUT */ - YYSYMBOL_STRUCT = 391, /* STRUCT */ - YYSYMBOL_VOID = 392, /* VOID */ - YYSYMBOL_WHILE = 393, /* WHILE */ - YYSYMBOL_BREAK = 394, /* BREAK */ - YYSYMBOL_CONTINUE = 395, /* CONTINUE */ - YYSYMBOL_DO = 396, /* DO */ - YYSYMBOL_ELSE = 397, /* ELSE */ - YYSYMBOL_FOR = 398, /* FOR */ - YYSYMBOL_IF = 399, /* IF */ - YYSYMBOL_DISCARD = 400, /* DISCARD */ - YYSYMBOL_RETURN = 401, /* RETURN */ - YYSYMBOL_SWITCH = 402, /* SWITCH */ - YYSYMBOL_CASE = 403, /* CASE */ - YYSYMBOL_DEFAULT = 404, /* DEFAULT */ - YYSYMBOL_TERMINATE_INVOCATION = 405, /* TERMINATE_INVOCATION */ - YYSYMBOL_TERMINATE_RAY = 406, /* TERMINATE_RAY */ - YYSYMBOL_IGNORE_INTERSECTION = 407, /* IGNORE_INTERSECTION */ - YYSYMBOL_UNIFORM = 408, /* UNIFORM */ - YYSYMBOL_SHARED = 409, /* SHARED */ - YYSYMBOL_BUFFER = 410, /* BUFFER */ - YYSYMBOL_FLAT = 411, /* FLAT */ - YYSYMBOL_SMOOTH = 412, /* SMOOTH */ - YYSYMBOL_LAYOUT = 413, /* LAYOUT */ - YYSYMBOL_DOUBLECONSTANT = 414, /* DOUBLECONSTANT */ - YYSYMBOL_INT16CONSTANT = 415, /* INT16CONSTANT */ - YYSYMBOL_UINT16CONSTANT = 416, /* UINT16CONSTANT */ - YYSYMBOL_FLOAT16CONSTANT = 417, /* FLOAT16CONSTANT */ - YYSYMBOL_INT32CONSTANT = 418, /* INT32CONSTANT */ - YYSYMBOL_UINT32CONSTANT = 419, /* UINT32CONSTANT */ - YYSYMBOL_INT64CONSTANT = 420, /* INT64CONSTANT */ - YYSYMBOL_UINT64CONSTANT = 421, /* UINT64CONSTANT */ - YYSYMBOL_SUBROUTINE = 422, /* SUBROUTINE */ - YYSYMBOL_DEMOTE = 423, /* DEMOTE */ - YYSYMBOL_PAYLOADNV = 424, /* PAYLOADNV */ - YYSYMBOL_PAYLOADINNV = 425, /* PAYLOADINNV */ - YYSYMBOL_HITATTRNV = 426, /* HITATTRNV */ - YYSYMBOL_CALLDATANV = 427, /* CALLDATANV */ - YYSYMBOL_CALLDATAINNV = 428, /* CALLDATAINNV */ - YYSYMBOL_PAYLOADEXT = 429, /* PAYLOADEXT */ - YYSYMBOL_PAYLOADINEXT = 430, /* PAYLOADINEXT */ - YYSYMBOL_HITATTREXT = 431, /* HITATTREXT */ - YYSYMBOL_CALLDATAEXT = 432, /* CALLDATAEXT */ - YYSYMBOL_CALLDATAINEXT = 433, /* CALLDATAINEXT */ - YYSYMBOL_PATCH = 434, /* PATCH */ - YYSYMBOL_SAMPLE = 435, /* SAMPLE */ - YYSYMBOL_NONUNIFORM = 436, /* NONUNIFORM */ - YYSYMBOL_COHERENT = 437, /* COHERENT */ - YYSYMBOL_VOLATILE = 438, /* VOLATILE */ - YYSYMBOL_RESTRICT = 439, /* RESTRICT */ - YYSYMBOL_READONLY = 440, /* READONLY */ - YYSYMBOL_WRITEONLY = 441, /* WRITEONLY */ - YYSYMBOL_DEVICECOHERENT = 442, /* DEVICECOHERENT */ - YYSYMBOL_QUEUEFAMILYCOHERENT = 443, /* QUEUEFAMILYCOHERENT */ - YYSYMBOL_WORKGROUPCOHERENT = 444, /* WORKGROUPCOHERENT */ - YYSYMBOL_SUBGROUPCOHERENT = 445, /* SUBGROUPCOHERENT */ - YYSYMBOL_NONPRIVATE = 446, /* NONPRIVATE */ - YYSYMBOL_SHADERCALLCOHERENT = 447, /* SHADERCALLCOHERENT */ - YYSYMBOL_NOPERSPECTIVE = 448, /* NOPERSPECTIVE */ - YYSYMBOL_EXPLICITINTERPAMD = 449, /* EXPLICITINTERPAMD */ - YYSYMBOL_PERVERTEXNV = 450, /* PERVERTEXNV */ - YYSYMBOL_PERPRIMITIVENV = 451, /* PERPRIMITIVENV */ - YYSYMBOL_PERVIEWNV = 452, /* PERVIEWNV */ - YYSYMBOL_PERTASKNV = 453, /* PERTASKNV */ - YYSYMBOL_PRECISE = 454, /* PRECISE */ - YYSYMBOL_YYACCEPT = 455, /* $accept */ - YYSYMBOL_variable_identifier = 456, /* variable_identifier */ - YYSYMBOL_primary_expression = 457, /* primary_expression */ - YYSYMBOL_postfix_expression = 458, /* postfix_expression */ - YYSYMBOL_integer_expression = 459, /* integer_expression */ - YYSYMBOL_function_call = 460, /* function_call */ - YYSYMBOL_function_call_or_method = 461, /* function_call_or_method */ - YYSYMBOL_function_call_generic = 462, /* function_call_generic */ - YYSYMBOL_function_call_header_no_parameters = 463, /* function_call_header_no_parameters */ - YYSYMBOL_function_call_header_with_parameters = 464, /* function_call_header_with_parameters */ - YYSYMBOL_function_call_header = 465, /* function_call_header */ - YYSYMBOL_function_identifier = 466, /* function_identifier */ - YYSYMBOL_unary_expression = 467, /* unary_expression */ - YYSYMBOL_unary_operator = 468, /* unary_operator */ - YYSYMBOL_multiplicative_expression = 469, /* multiplicative_expression */ - YYSYMBOL_additive_expression = 470, /* additive_expression */ - YYSYMBOL_shift_expression = 471, /* shift_expression */ - YYSYMBOL_relational_expression = 472, /* relational_expression */ - YYSYMBOL_equality_expression = 473, /* equality_expression */ - YYSYMBOL_and_expression = 474, /* and_expression */ - YYSYMBOL_exclusive_or_expression = 475, /* exclusive_or_expression */ - YYSYMBOL_inclusive_or_expression = 476, /* inclusive_or_expression */ - YYSYMBOL_logical_and_expression = 477, /* logical_and_expression */ - YYSYMBOL_logical_xor_expression = 478, /* logical_xor_expression */ - YYSYMBOL_logical_or_expression = 479, /* logical_or_expression */ - YYSYMBOL_conditional_expression = 480, /* conditional_expression */ - YYSYMBOL_481_1 = 481, /* $@1 */ - YYSYMBOL_assignment_expression = 482, /* assignment_expression */ - YYSYMBOL_assignment_operator = 483, /* assignment_operator */ - YYSYMBOL_expression = 484, /* expression */ - YYSYMBOL_constant_expression = 485, /* constant_expression */ - YYSYMBOL_declaration = 486, /* declaration */ - YYSYMBOL_block_structure = 487, /* block_structure */ - YYSYMBOL_488_2 = 488, /* $@2 */ - YYSYMBOL_identifier_list = 489, /* identifier_list */ - YYSYMBOL_function_prototype = 490, /* function_prototype */ - YYSYMBOL_function_declarator = 491, /* function_declarator */ - YYSYMBOL_function_header_with_parameters = 492, /* function_header_with_parameters */ - YYSYMBOL_function_header = 493, /* function_header */ - YYSYMBOL_parameter_declarator = 494, /* parameter_declarator */ - YYSYMBOL_parameter_declaration = 495, /* parameter_declaration */ - YYSYMBOL_parameter_type_specifier = 496, /* parameter_type_specifier */ - YYSYMBOL_init_declarator_list = 497, /* init_declarator_list */ - YYSYMBOL_single_declaration = 498, /* single_declaration */ - YYSYMBOL_fully_specified_type = 499, /* fully_specified_type */ - YYSYMBOL_invariant_qualifier = 500, /* invariant_qualifier */ - YYSYMBOL_interpolation_qualifier = 501, /* interpolation_qualifier */ - YYSYMBOL_layout_qualifier = 502, /* layout_qualifier */ - YYSYMBOL_layout_qualifier_id_list = 503, /* layout_qualifier_id_list */ - YYSYMBOL_layout_qualifier_id = 504, /* layout_qualifier_id */ - YYSYMBOL_precise_qualifier = 505, /* precise_qualifier */ - YYSYMBOL_type_qualifier = 506, /* type_qualifier */ - YYSYMBOL_single_type_qualifier = 507, /* single_type_qualifier */ - YYSYMBOL_storage_qualifier = 508, /* storage_qualifier */ - YYSYMBOL_non_uniform_qualifier = 509, /* non_uniform_qualifier */ - YYSYMBOL_type_name_list = 510, /* type_name_list */ - YYSYMBOL_type_specifier = 511, /* type_specifier */ - YYSYMBOL_array_specifier = 512, /* array_specifier */ - YYSYMBOL_type_parameter_specifier_opt = 513, /* type_parameter_specifier_opt */ - YYSYMBOL_type_parameter_specifier = 514, /* type_parameter_specifier */ - YYSYMBOL_type_parameter_specifier_list = 515, /* type_parameter_specifier_list */ - YYSYMBOL_type_specifier_nonarray = 516, /* type_specifier_nonarray */ - YYSYMBOL_precision_qualifier = 517, /* precision_qualifier */ - YYSYMBOL_struct_specifier = 518, /* struct_specifier */ - YYSYMBOL_519_3 = 519, /* $@3 */ - YYSYMBOL_520_4 = 520, /* $@4 */ - YYSYMBOL_struct_declaration_list = 521, /* struct_declaration_list */ - YYSYMBOL_struct_declaration = 522, /* struct_declaration */ - YYSYMBOL_struct_declarator_list = 523, /* struct_declarator_list */ - YYSYMBOL_struct_declarator = 524, /* struct_declarator */ - YYSYMBOL_initializer = 525, /* initializer */ - YYSYMBOL_initializer_list = 526, /* initializer_list */ - YYSYMBOL_declaration_statement = 527, /* declaration_statement */ - YYSYMBOL_statement = 528, /* statement */ - YYSYMBOL_simple_statement = 529, /* simple_statement */ - YYSYMBOL_demote_statement = 530, /* demote_statement */ - YYSYMBOL_compound_statement = 531, /* compound_statement */ - YYSYMBOL_532_5 = 532, /* $@5 */ - YYSYMBOL_533_6 = 533, /* $@6 */ - YYSYMBOL_statement_no_new_scope = 534, /* statement_no_new_scope */ - YYSYMBOL_statement_scoped = 535, /* statement_scoped */ - YYSYMBOL_536_7 = 536, /* $@7 */ - YYSYMBOL_537_8 = 537, /* $@8 */ - YYSYMBOL_compound_statement_no_new_scope = 538, /* compound_statement_no_new_scope */ - YYSYMBOL_statement_list = 539, /* statement_list */ - YYSYMBOL_expression_statement = 540, /* expression_statement */ - YYSYMBOL_selection_statement = 541, /* selection_statement */ - YYSYMBOL_selection_statement_nonattributed = 542, /* selection_statement_nonattributed */ - YYSYMBOL_selection_rest_statement = 543, /* selection_rest_statement */ - YYSYMBOL_condition = 544, /* condition */ - YYSYMBOL_switch_statement = 545, /* switch_statement */ - YYSYMBOL_switch_statement_nonattributed = 546, /* switch_statement_nonattributed */ - YYSYMBOL_547_9 = 547, /* $@9 */ - YYSYMBOL_switch_statement_list = 548, /* switch_statement_list */ - YYSYMBOL_case_label = 549, /* case_label */ - YYSYMBOL_iteration_statement = 550, /* iteration_statement */ - YYSYMBOL_iteration_statement_nonattributed = 551, /* iteration_statement_nonattributed */ - YYSYMBOL_552_10 = 552, /* $@10 */ - YYSYMBOL_553_11 = 553, /* $@11 */ - YYSYMBOL_554_12 = 554, /* $@12 */ - YYSYMBOL_for_init_statement = 555, /* for_init_statement */ - YYSYMBOL_conditionopt = 556, /* conditionopt */ - YYSYMBOL_for_rest_statement = 557, /* for_rest_statement */ - YYSYMBOL_jump_statement = 558, /* jump_statement */ - YYSYMBOL_translation_unit = 559, /* translation_unit */ - YYSYMBOL_external_declaration = 560, /* external_declaration */ - YYSYMBOL_function_definition = 561, /* function_definition */ - YYSYMBOL_562_13 = 562, /* $@13 */ - YYSYMBOL_attribute = 563, /* attribute */ - YYSYMBOL_attribute_list = 564, /* attribute_list */ - YYSYMBOL_single_attribute = 565, /* single_attribute */ - YYSYMBOL_spirv_requirements_list = 566, /* spirv_requirements_list */ - YYSYMBOL_spirv_requirements_parameter = 567, /* spirv_requirements_parameter */ - YYSYMBOL_spirv_extension_list = 568, /* spirv_extension_list */ - YYSYMBOL_spirv_capability_list = 569, /* spirv_capability_list */ - YYSYMBOL_spirv_execution_mode_qualifier = 570, /* spirv_execution_mode_qualifier */ - YYSYMBOL_spirv_execution_mode_parameter_list = 571, /* spirv_execution_mode_parameter_list */ - YYSYMBOL_spirv_execution_mode_parameter = 572, /* spirv_execution_mode_parameter */ - YYSYMBOL_spirv_execution_mode_id_parameter_list = 573, /* spirv_execution_mode_id_parameter_list */ - YYSYMBOL_spirv_storage_class_qualifier = 574, /* spirv_storage_class_qualifier */ - YYSYMBOL_spirv_decorate_qualifier = 575, /* spirv_decorate_qualifier */ - YYSYMBOL_spirv_decorate_parameter_list = 576, /* spirv_decorate_parameter_list */ - YYSYMBOL_spirv_decorate_parameter = 577, /* spirv_decorate_parameter */ - YYSYMBOL_spirv_decorate_id_parameter_list = 578, /* spirv_decorate_id_parameter_list */ - YYSYMBOL_spirv_decorate_string_parameter_list = 579, /* spirv_decorate_string_parameter_list */ - YYSYMBOL_spirv_type_specifier = 580, /* spirv_type_specifier */ - YYSYMBOL_spirv_type_parameter_list = 581, /* spirv_type_parameter_list */ - YYSYMBOL_spirv_type_parameter = 582, /* spirv_type_parameter */ - YYSYMBOL_spirv_instruction_qualifier = 583, /* spirv_instruction_qualifier */ - YYSYMBOL_spirv_instruction_qualifier_list = 584, /* spirv_instruction_qualifier_list */ - YYSYMBOL_spirv_instruction_qualifier_id = 585 /* spirv_instruction_qualifier_id */ + YYSYMBOL_COOPMAT = 166, /* COOPMAT */ + YYSYMBOL_HITOBJECTNV = 167, /* HITOBJECTNV */ + YYSYMBOL_HITOBJECTATTRNV = 168, /* HITOBJECTATTRNV */ + YYSYMBOL_SAMPLERCUBEARRAY = 169, /* SAMPLERCUBEARRAY */ + YYSYMBOL_SAMPLERCUBEARRAYSHADOW = 170, /* SAMPLERCUBEARRAYSHADOW */ + YYSYMBOL_ISAMPLERCUBEARRAY = 171, /* ISAMPLERCUBEARRAY */ + YYSYMBOL_USAMPLERCUBEARRAY = 172, /* USAMPLERCUBEARRAY */ + YYSYMBOL_SAMPLER1D = 173, /* SAMPLER1D */ + YYSYMBOL_SAMPLER1DARRAY = 174, /* SAMPLER1DARRAY */ + YYSYMBOL_SAMPLER1DARRAYSHADOW = 175, /* SAMPLER1DARRAYSHADOW */ + YYSYMBOL_ISAMPLER1D = 176, /* ISAMPLER1D */ + YYSYMBOL_SAMPLER1DSHADOW = 177, /* SAMPLER1DSHADOW */ + YYSYMBOL_SAMPLER2DRECT = 178, /* SAMPLER2DRECT */ + YYSYMBOL_SAMPLER2DRECTSHADOW = 179, /* SAMPLER2DRECTSHADOW */ + YYSYMBOL_ISAMPLER2DRECT = 180, /* ISAMPLER2DRECT */ + YYSYMBOL_USAMPLER2DRECT = 181, /* USAMPLER2DRECT */ + YYSYMBOL_SAMPLERBUFFER = 182, /* SAMPLERBUFFER */ + YYSYMBOL_ISAMPLERBUFFER = 183, /* ISAMPLERBUFFER */ + YYSYMBOL_USAMPLERBUFFER = 184, /* USAMPLERBUFFER */ + YYSYMBOL_SAMPLER2DMS = 185, /* SAMPLER2DMS */ + YYSYMBOL_ISAMPLER2DMS = 186, /* ISAMPLER2DMS */ + YYSYMBOL_USAMPLER2DMS = 187, /* USAMPLER2DMS */ + YYSYMBOL_SAMPLER2DMSARRAY = 188, /* SAMPLER2DMSARRAY */ + YYSYMBOL_ISAMPLER2DMSARRAY = 189, /* ISAMPLER2DMSARRAY */ + YYSYMBOL_USAMPLER2DMSARRAY = 190, /* USAMPLER2DMSARRAY */ + YYSYMBOL_SAMPLEREXTERNALOES = 191, /* SAMPLEREXTERNALOES */ + YYSYMBOL_SAMPLEREXTERNAL2DY2YEXT = 192, /* SAMPLEREXTERNAL2DY2YEXT */ + YYSYMBOL_ISAMPLER1DARRAY = 193, /* ISAMPLER1DARRAY */ + YYSYMBOL_USAMPLER1D = 194, /* USAMPLER1D */ + YYSYMBOL_USAMPLER1DARRAY = 195, /* USAMPLER1DARRAY */ + YYSYMBOL_F16SAMPLER1D = 196, /* F16SAMPLER1D */ + YYSYMBOL_F16SAMPLER2D = 197, /* F16SAMPLER2D */ + YYSYMBOL_F16SAMPLER3D = 198, /* F16SAMPLER3D */ + YYSYMBOL_F16SAMPLER2DRECT = 199, /* F16SAMPLER2DRECT */ + YYSYMBOL_F16SAMPLERCUBE = 200, /* F16SAMPLERCUBE */ + YYSYMBOL_F16SAMPLER1DARRAY = 201, /* F16SAMPLER1DARRAY */ + YYSYMBOL_F16SAMPLER2DARRAY = 202, /* F16SAMPLER2DARRAY */ + YYSYMBOL_F16SAMPLERCUBEARRAY = 203, /* F16SAMPLERCUBEARRAY */ + YYSYMBOL_F16SAMPLERBUFFER = 204, /* F16SAMPLERBUFFER */ + YYSYMBOL_F16SAMPLER2DMS = 205, /* F16SAMPLER2DMS */ + YYSYMBOL_F16SAMPLER2DMSARRAY = 206, /* F16SAMPLER2DMSARRAY */ + YYSYMBOL_F16SAMPLER1DSHADOW = 207, /* F16SAMPLER1DSHADOW */ + YYSYMBOL_F16SAMPLER2DSHADOW = 208, /* F16SAMPLER2DSHADOW */ + YYSYMBOL_F16SAMPLER1DARRAYSHADOW = 209, /* F16SAMPLER1DARRAYSHADOW */ + YYSYMBOL_F16SAMPLER2DARRAYSHADOW = 210, /* F16SAMPLER2DARRAYSHADOW */ + YYSYMBOL_F16SAMPLER2DRECTSHADOW = 211, /* F16SAMPLER2DRECTSHADOW */ + YYSYMBOL_F16SAMPLERCUBESHADOW = 212, /* F16SAMPLERCUBESHADOW */ + YYSYMBOL_F16SAMPLERCUBEARRAYSHADOW = 213, /* F16SAMPLERCUBEARRAYSHADOW */ + YYSYMBOL_IMAGE1D = 214, /* IMAGE1D */ + YYSYMBOL_IIMAGE1D = 215, /* IIMAGE1D */ + YYSYMBOL_UIMAGE1D = 216, /* UIMAGE1D */ + YYSYMBOL_IMAGE2D = 217, /* IMAGE2D */ + YYSYMBOL_IIMAGE2D = 218, /* IIMAGE2D */ + YYSYMBOL_UIMAGE2D = 219, /* UIMAGE2D */ + YYSYMBOL_IMAGE3D = 220, /* IMAGE3D */ + YYSYMBOL_IIMAGE3D = 221, /* IIMAGE3D */ + YYSYMBOL_UIMAGE3D = 222, /* UIMAGE3D */ + YYSYMBOL_IMAGE2DRECT = 223, /* IMAGE2DRECT */ + YYSYMBOL_IIMAGE2DRECT = 224, /* IIMAGE2DRECT */ + YYSYMBOL_UIMAGE2DRECT = 225, /* UIMAGE2DRECT */ + YYSYMBOL_IMAGECUBE = 226, /* IMAGECUBE */ + YYSYMBOL_IIMAGECUBE = 227, /* IIMAGECUBE */ + YYSYMBOL_UIMAGECUBE = 228, /* UIMAGECUBE */ + YYSYMBOL_IMAGEBUFFER = 229, /* IMAGEBUFFER */ + YYSYMBOL_IIMAGEBUFFER = 230, /* IIMAGEBUFFER */ + YYSYMBOL_UIMAGEBUFFER = 231, /* UIMAGEBUFFER */ + YYSYMBOL_IMAGE1DARRAY = 232, /* IMAGE1DARRAY */ + YYSYMBOL_IIMAGE1DARRAY = 233, /* IIMAGE1DARRAY */ + YYSYMBOL_UIMAGE1DARRAY = 234, /* UIMAGE1DARRAY */ + YYSYMBOL_IMAGE2DARRAY = 235, /* IMAGE2DARRAY */ + YYSYMBOL_IIMAGE2DARRAY = 236, /* IIMAGE2DARRAY */ + YYSYMBOL_UIMAGE2DARRAY = 237, /* UIMAGE2DARRAY */ + YYSYMBOL_IMAGECUBEARRAY = 238, /* IMAGECUBEARRAY */ + YYSYMBOL_IIMAGECUBEARRAY = 239, /* IIMAGECUBEARRAY */ + YYSYMBOL_UIMAGECUBEARRAY = 240, /* UIMAGECUBEARRAY */ + YYSYMBOL_IMAGE2DMS = 241, /* IMAGE2DMS */ + YYSYMBOL_IIMAGE2DMS = 242, /* IIMAGE2DMS */ + YYSYMBOL_UIMAGE2DMS = 243, /* UIMAGE2DMS */ + YYSYMBOL_IMAGE2DMSARRAY = 244, /* IMAGE2DMSARRAY */ + YYSYMBOL_IIMAGE2DMSARRAY = 245, /* IIMAGE2DMSARRAY */ + YYSYMBOL_UIMAGE2DMSARRAY = 246, /* UIMAGE2DMSARRAY */ + YYSYMBOL_F16IMAGE1D = 247, /* F16IMAGE1D */ + YYSYMBOL_F16IMAGE2D = 248, /* F16IMAGE2D */ + YYSYMBOL_F16IMAGE3D = 249, /* F16IMAGE3D */ + YYSYMBOL_F16IMAGE2DRECT = 250, /* F16IMAGE2DRECT */ + YYSYMBOL_F16IMAGECUBE = 251, /* F16IMAGECUBE */ + YYSYMBOL_F16IMAGE1DARRAY = 252, /* F16IMAGE1DARRAY */ + YYSYMBOL_F16IMAGE2DARRAY = 253, /* F16IMAGE2DARRAY */ + YYSYMBOL_F16IMAGECUBEARRAY = 254, /* F16IMAGECUBEARRAY */ + YYSYMBOL_F16IMAGEBUFFER = 255, /* F16IMAGEBUFFER */ + YYSYMBOL_F16IMAGE2DMS = 256, /* F16IMAGE2DMS */ + YYSYMBOL_F16IMAGE2DMSARRAY = 257, /* F16IMAGE2DMSARRAY */ + YYSYMBOL_I64IMAGE1D = 258, /* I64IMAGE1D */ + YYSYMBOL_U64IMAGE1D = 259, /* U64IMAGE1D */ + YYSYMBOL_I64IMAGE2D = 260, /* I64IMAGE2D */ + YYSYMBOL_U64IMAGE2D = 261, /* U64IMAGE2D */ + YYSYMBOL_I64IMAGE3D = 262, /* I64IMAGE3D */ + YYSYMBOL_U64IMAGE3D = 263, /* U64IMAGE3D */ + YYSYMBOL_I64IMAGE2DRECT = 264, /* I64IMAGE2DRECT */ + YYSYMBOL_U64IMAGE2DRECT = 265, /* U64IMAGE2DRECT */ + YYSYMBOL_I64IMAGECUBE = 266, /* I64IMAGECUBE */ + YYSYMBOL_U64IMAGECUBE = 267, /* U64IMAGECUBE */ + YYSYMBOL_I64IMAGEBUFFER = 268, /* I64IMAGEBUFFER */ + YYSYMBOL_U64IMAGEBUFFER = 269, /* U64IMAGEBUFFER */ + YYSYMBOL_I64IMAGE1DARRAY = 270, /* I64IMAGE1DARRAY */ + YYSYMBOL_U64IMAGE1DARRAY = 271, /* U64IMAGE1DARRAY */ + YYSYMBOL_I64IMAGE2DARRAY = 272, /* I64IMAGE2DARRAY */ + YYSYMBOL_U64IMAGE2DARRAY = 273, /* U64IMAGE2DARRAY */ + YYSYMBOL_I64IMAGECUBEARRAY = 274, /* I64IMAGECUBEARRAY */ + YYSYMBOL_U64IMAGECUBEARRAY = 275, /* U64IMAGECUBEARRAY */ + YYSYMBOL_I64IMAGE2DMS = 276, /* I64IMAGE2DMS */ + YYSYMBOL_U64IMAGE2DMS = 277, /* U64IMAGE2DMS */ + YYSYMBOL_I64IMAGE2DMSARRAY = 278, /* I64IMAGE2DMSARRAY */ + YYSYMBOL_U64IMAGE2DMSARRAY = 279, /* U64IMAGE2DMSARRAY */ + YYSYMBOL_TEXTURECUBEARRAY = 280, /* TEXTURECUBEARRAY */ + YYSYMBOL_ITEXTURECUBEARRAY = 281, /* ITEXTURECUBEARRAY */ + YYSYMBOL_UTEXTURECUBEARRAY = 282, /* UTEXTURECUBEARRAY */ + YYSYMBOL_TEXTURE1D = 283, /* TEXTURE1D */ + YYSYMBOL_ITEXTURE1D = 284, /* ITEXTURE1D */ + YYSYMBOL_UTEXTURE1D = 285, /* UTEXTURE1D */ + YYSYMBOL_TEXTURE1DARRAY = 286, /* TEXTURE1DARRAY */ + YYSYMBOL_ITEXTURE1DARRAY = 287, /* ITEXTURE1DARRAY */ + YYSYMBOL_UTEXTURE1DARRAY = 288, /* UTEXTURE1DARRAY */ + YYSYMBOL_TEXTURE2DRECT = 289, /* TEXTURE2DRECT */ + YYSYMBOL_ITEXTURE2DRECT = 290, /* ITEXTURE2DRECT */ + YYSYMBOL_UTEXTURE2DRECT = 291, /* UTEXTURE2DRECT */ + YYSYMBOL_TEXTUREBUFFER = 292, /* TEXTUREBUFFER */ + YYSYMBOL_ITEXTUREBUFFER = 293, /* ITEXTUREBUFFER */ + YYSYMBOL_UTEXTUREBUFFER = 294, /* UTEXTUREBUFFER */ + YYSYMBOL_TEXTURE2DMS = 295, /* TEXTURE2DMS */ + YYSYMBOL_ITEXTURE2DMS = 296, /* ITEXTURE2DMS */ + YYSYMBOL_UTEXTURE2DMS = 297, /* UTEXTURE2DMS */ + YYSYMBOL_TEXTURE2DMSARRAY = 298, /* TEXTURE2DMSARRAY */ + YYSYMBOL_ITEXTURE2DMSARRAY = 299, /* ITEXTURE2DMSARRAY */ + YYSYMBOL_UTEXTURE2DMSARRAY = 300, /* UTEXTURE2DMSARRAY */ + YYSYMBOL_F16TEXTURE1D = 301, /* F16TEXTURE1D */ + YYSYMBOL_F16TEXTURE2D = 302, /* F16TEXTURE2D */ + YYSYMBOL_F16TEXTURE3D = 303, /* F16TEXTURE3D */ + YYSYMBOL_F16TEXTURE2DRECT = 304, /* F16TEXTURE2DRECT */ + YYSYMBOL_F16TEXTURECUBE = 305, /* F16TEXTURECUBE */ + YYSYMBOL_F16TEXTURE1DARRAY = 306, /* F16TEXTURE1DARRAY */ + YYSYMBOL_F16TEXTURE2DARRAY = 307, /* F16TEXTURE2DARRAY */ + YYSYMBOL_F16TEXTURECUBEARRAY = 308, /* F16TEXTURECUBEARRAY */ + YYSYMBOL_F16TEXTUREBUFFER = 309, /* F16TEXTUREBUFFER */ + YYSYMBOL_F16TEXTURE2DMS = 310, /* F16TEXTURE2DMS */ + YYSYMBOL_F16TEXTURE2DMSARRAY = 311, /* F16TEXTURE2DMSARRAY */ + YYSYMBOL_SUBPASSINPUT = 312, /* SUBPASSINPUT */ + YYSYMBOL_SUBPASSINPUTMS = 313, /* SUBPASSINPUTMS */ + YYSYMBOL_ISUBPASSINPUT = 314, /* ISUBPASSINPUT */ + YYSYMBOL_ISUBPASSINPUTMS = 315, /* ISUBPASSINPUTMS */ + YYSYMBOL_USUBPASSINPUT = 316, /* USUBPASSINPUT */ + YYSYMBOL_USUBPASSINPUTMS = 317, /* USUBPASSINPUTMS */ + YYSYMBOL_F16SUBPASSINPUT = 318, /* F16SUBPASSINPUT */ + YYSYMBOL_F16SUBPASSINPUTMS = 319, /* F16SUBPASSINPUTMS */ + YYSYMBOL_SPIRV_INSTRUCTION = 320, /* SPIRV_INSTRUCTION */ + YYSYMBOL_SPIRV_EXECUTION_MODE = 321, /* SPIRV_EXECUTION_MODE */ + YYSYMBOL_SPIRV_EXECUTION_MODE_ID = 322, /* SPIRV_EXECUTION_MODE_ID */ + YYSYMBOL_SPIRV_DECORATE = 323, /* SPIRV_DECORATE */ + YYSYMBOL_SPIRV_DECORATE_ID = 324, /* SPIRV_DECORATE_ID */ + YYSYMBOL_SPIRV_DECORATE_STRING = 325, /* SPIRV_DECORATE_STRING */ + YYSYMBOL_SPIRV_TYPE = 326, /* SPIRV_TYPE */ + YYSYMBOL_SPIRV_STORAGE_CLASS = 327, /* SPIRV_STORAGE_CLASS */ + YYSYMBOL_SPIRV_BY_REFERENCE = 328, /* SPIRV_BY_REFERENCE */ + YYSYMBOL_SPIRV_LITERAL = 329, /* SPIRV_LITERAL */ + YYSYMBOL_ATTACHMENTEXT = 330, /* ATTACHMENTEXT */ + YYSYMBOL_IATTACHMENTEXT = 331, /* IATTACHMENTEXT */ + YYSYMBOL_UATTACHMENTEXT = 332, /* UATTACHMENTEXT */ + YYSYMBOL_LEFT_OP = 333, /* LEFT_OP */ + YYSYMBOL_RIGHT_OP = 334, /* RIGHT_OP */ + YYSYMBOL_INC_OP = 335, /* INC_OP */ + YYSYMBOL_DEC_OP = 336, /* DEC_OP */ + YYSYMBOL_LE_OP = 337, /* LE_OP */ + YYSYMBOL_GE_OP = 338, /* GE_OP */ + YYSYMBOL_EQ_OP = 339, /* EQ_OP */ + YYSYMBOL_NE_OP = 340, /* NE_OP */ + YYSYMBOL_AND_OP = 341, /* AND_OP */ + YYSYMBOL_OR_OP = 342, /* OR_OP */ + YYSYMBOL_XOR_OP = 343, /* XOR_OP */ + YYSYMBOL_MUL_ASSIGN = 344, /* MUL_ASSIGN */ + YYSYMBOL_DIV_ASSIGN = 345, /* DIV_ASSIGN */ + YYSYMBOL_ADD_ASSIGN = 346, /* ADD_ASSIGN */ + YYSYMBOL_MOD_ASSIGN = 347, /* MOD_ASSIGN */ + YYSYMBOL_LEFT_ASSIGN = 348, /* LEFT_ASSIGN */ + YYSYMBOL_RIGHT_ASSIGN = 349, /* RIGHT_ASSIGN */ + YYSYMBOL_AND_ASSIGN = 350, /* AND_ASSIGN */ + YYSYMBOL_XOR_ASSIGN = 351, /* XOR_ASSIGN */ + YYSYMBOL_OR_ASSIGN = 352, /* OR_ASSIGN */ + YYSYMBOL_SUB_ASSIGN = 353, /* SUB_ASSIGN */ + YYSYMBOL_STRING_LITERAL = 354, /* STRING_LITERAL */ + YYSYMBOL_LEFT_PAREN = 355, /* LEFT_PAREN */ + YYSYMBOL_RIGHT_PAREN = 356, /* RIGHT_PAREN */ + YYSYMBOL_LEFT_BRACKET = 357, /* LEFT_BRACKET */ + YYSYMBOL_RIGHT_BRACKET = 358, /* RIGHT_BRACKET */ + YYSYMBOL_LEFT_BRACE = 359, /* LEFT_BRACE */ + YYSYMBOL_RIGHT_BRACE = 360, /* RIGHT_BRACE */ + YYSYMBOL_DOT = 361, /* DOT */ + YYSYMBOL_COMMA = 362, /* COMMA */ + YYSYMBOL_COLON = 363, /* COLON */ + YYSYMBOL_EQUAL = 364, /* EQUAL */ + YYSYMBOL_SEMICOLON = 365, /* SEMICOLON */ + YYSYMBOL_BANG = 366, /* BANG */ + YYSYMBOL_DASH = 367, /* DASH */ + YYSYMBOL_TILDE = 368, /* TILDE */ + YYSYMBOL_PLUS = 369, /* PLUS */ + YYSYMBOL_STAR = 370, /* STAR */ + YYSYMBOL_SLASH = 371, /* SLASH */ + YYSYMBOL_PERCENT = 372, /* PERCENT */ + YYSYMBOL_LEFT_ANGLE = 373, /* LEFT_ANGLE */ + YYSYMBOL_RIGHT_ANGLE = 374, /* RIGHT_ANGLE */ + YYSYMBOL_VERTICAL_BAR = 375, /* VERTICAL_BAR */ + YYSYMBOL_CARET = 376, /* CARET */ + YYSYMBOL_AMPERSAND = 377, /* AMPERSAND */ + YYSYMBOL_QUESTION = 378, /* QUESTION */ + YYSYMBOL_INVARIANT = 379, /* INVARIANT */ + YYSYMBOL_HIGH_PRECISION = 380, /* HIGH_PRECISION */ + YYSYMBOL_MEDIUM_PRECISION = 381, /* MEDIUM_PRECISION */ + YYSYMBOL_LOW_PRECISION = 382, /* LOW_PRECISION */ + YYSYMBOL_PRECISION = 383, /* PRECISION */ + YYSYMBOL_PACKED = 384, /* PACKED */ + YYSYMBOL_RESOURCE = 385, /* RESOURCE */ + YYSYMBOL_SUPERP = 386, /* SUPERP */ + YYSYMBOL_FLOATCONSTANT = 387, /* FLOATCONSTANT */ + YYSYMBOL_INTCONSTANT = 388, /* INTCONSTANT */ + YYSYMBOL_UINTCONSTANT = 389, /* UINTCONSTANT */ + YYSYMBOL_BOOLCONSTANT = 390, /* BOOLCONSTANT */ + YYSYMBOL_IDENTIFIER = 391, /* IDENTIFIER */ + YYSYMBOL_TYPE_NAME = 392, /* TYPE_NAME */ + YYSYMBOL_CENTROID = 393, /* CENTROID */ + YYSYMBOL_IN = 394, /* IN */ + YYSYMBOL_OUT = 395, /* OUT */ + YYSYMBOL_INOUT = 396, /* INOUT */ + YYSYMBOL_STRUCT = 397, /* STRUCT */ + YYSYMBOL_VOID = 398, /* VOID */ + YYSYMBOL_WHILE = 399, /* WHILE */ + YYSYMBOL_BREAK = 400, /* BREAK */ + YYSYMBOL_CONTINUE = 401, /* CONTINUE */ + YYSYMBOL_DO = 402, /* DO */ + YYSYMBOL_ELSE = 403, /* ELSE */ + YYSYMBOL_FOR = 404, /* FOR */ + YYSYMBOL_IF = 405, /* IF */ + YYSYMBOL_DISCARD = 406, /* DISCARD */ + YYSYMBOL_RETURN = 407, /* RETURN */ + YYSYMBOL_SWITCH = 408, /* SWITCH */ + YYSYMBOL_CASE = 409, /* CASE */ + YYSYMBOL_DEFAULT = 410, /* DEFAULT */ + YYSYMBOL_TERMINATE_INVOCATION = 411, /* TERMINATE_INVOCATION */ + YYSYMBOL_TERMINATE_RAY = 412, /* TERMINATE_RAY */ + YYSYMBOL_IGNORE_INTERSECTION = 413, /* IGNORE_INTERSECTION */ + YYSYMBOL_UNIFORM = 414, /* UNIFORM */ + YYSYMBOL_SHARED = 415, /* SHARED */ + YYSYMBOL_BUFFER = 416, /* BUFFER */ + YYSYMBOL_TILEIMAGEEXT = 417, /* TILEIMAGEEXT */ + YYSYMBOL_FLAT = 418, /* FLAT */ + YYSYMBOL_SMOOTH = 419, /* SMOOTH */ + YYSYMBOL_LAYOUT = 420, /* LAYOUT */ + YYSYMBOL_DOUBLECONSTANT = 421, /* DOUBLECONSTANT */ + YYSYMBOL_INT16CONSTANT = 422, /* INT16CONSTANT */ + YYSYMBOL_UINT16CONSTANT = 423, /* UINT16CONSTANT */ + YYSYMBOL_FLOAT16CONSTANT = 424, /* FLOAT16CONSTANT */ + YYSYMBOL_INT32CONSTANT = 425, /* INT32CONSTANT */ + YYSYMBOL_UINT32CONSTANT = 426, /* UINT32CONSTANT */ + YYSYMBOL_INT64CONSTANT = 427, /* INT64CONSTANT */ + YYSYMBOL_UINT64CONSTANT = 428, /* UINT64CONSTANT */ + YYSYMBOL_SUBROUTINE = 429, /* SUBROUTINE */ + YYSYMBOL_DEMOTE = 430, /* DEMOTE */ + YYSYMBOL_PAYLOADNV = 431, /* PAYLOADNV */ + YYSYMBOL_PAYLOADINNV = 432, /* PAYLOADINNV */ + YYSYMBOL_HITATTRNV = 433, /* HITATTRNV */ + YYSYMBOL_CALLDATANV = 434, /* CALLDATANV */ + YYSYMBOL_CALLDATAINNV = 435, /* CALLDATAINNV */ + YYSYMBOL_PAYLOADEXT = 436, /* PAYLOADEXT */ + YYSYMBOL_PAYLOADINEXT = 437, /* PAYLOADINEXT */ + YYSYMBOL_HITATTREXT = 438, /* HITATTREXT */ + YYSYMBOL_CALLDATAEXT = 439, /* CALLDATAEXT */ + YYSYMBOL_CALLDATAINEXT = 440, /* CALLDATAINEXT */ + YYSYMBOL_PATCH = 441, /* PATCH */ + YYSYMBOL_SAMPLE = 442, /* SAMPLE */ + YYSYMBOL_NONUNIFORM = 443, /* NONUNIFORM */ + YYSYMBOL_COHERENT = 444, /* COHERENT */ + YYSYMBOL_VOLATILE = 445, /* VOLATILE */ + YYSYMBOL_RESTRICT = 446, /* RESTRICT */ + YYSYMBOL_READONLY = 447, /* READONLY */ + YYSYMBOL_WRITEONLY = 448, /* WRITEONLY */ + YYSYMBOL_DEVICECOHERENT = 449, /* DEVICECOHERENT */ + YYSYMBOL_QUEUEFAMILYCOHERENT = 450, /* QUEUEFAMILYCOHERENT */ + YYSYMBOL_WORKGROUPCOHERENT = 451, /* WORKGROUPCOHERENT */ + YYSYMBOL_SUBGROUPCOHERENT = 452, /* SUBGROUPCOHERENT */ + YYSYMBOL_NONPRIVATE = 453, /* NONPRIVATE */ + YYSYMBOL_SHADERCALLCOHERENT = 454, /* SHADERCALLCOHERENT */ + YYSYMBOL_NOPERSPECTIVE = 455, /* NOPERSPECTIVE */ + YYSYMBOL_EXPLICITINTERPAMD = 456, /* EXPLICITINTERPAMD */ + YYSYMBOL_PERVERTEXEXT = 457, /* PERVERTEXEXT */ + YYSYMBOL_PERVERTEXNV = 458, /* PERVERTEXNV */ + YYSYMBOL_PERPRIMITIVENV = 459, /* PERPRIMITIVENV */ + YYSYMBOL_PERVIEWNV = 460, /* PERVIEWNV */ + YYSYMBOL_PERTASKNV = 461, /* PERTASKNV */ + YYSYMBOL_PERPRIMITIVEEXT = 462, /* PERPRIMITIVEEXT */ + YYSYMBOL_TASKPAYLOADWORKGROUPEXT = 463, /* TASKPAYLOADWORKGROUPEXT */ + YYSYMBOL_PRECISE = 464, /* PRECISE */ + YYSYMBOL_YYACCEPT = 465, /* $accept */ + YYSYMBOL_variable_identifier = 466, /* variable_identifier */ + YYSYMBOL_primary_expression = 467, /* primary_expression */ + YYSYMBOL_postfix_expression = 468, /* postfix_expression */ + YYSYMBOL_integer_expression = 469, /* integer_expression */ + YYSYMBOL_function_call = 470, /* function_call */ + YYSYMBOL_function_call_or_method = 471, /* function_call_or_method */ + YYSYMBOL_function_call_generic = 472, /* function_call_generic */ + YYSYMBOL_function_call_header_no_parameters = 473, /* function_call_header_no_parameters */ + YYSYMBOL_function_call_header_with_parameters = 474, /* function_call_header_with_parameters */ + YYSYMBOL_function_call_header = 475, /* function_call_header */ + YYSYMBOL_function_identifier = 476, /* function_identifier */ + YYSYMBOL_unary_expression = 477, /* unary_expression */ + YYSYMBOL_unary_operator = 478, /* unary_operator */ + YYSYMBOL_multiplicative_expression = 479, /* multiplicative_expression */ + YYSYMBOL_additive_expression = 480, /* additive_expression */ + YYSYMBOL_shift_expression = 481, /* shift_expression */ + YYSYMBOL_relational_expression = 482, /* relational_expression */ + YYSYMBOL_equality_expression = 483, /* equality_expression */ + YYSYMBOL_and_expression = 484, /* and_expression */ + YYSYMBOL_exclusive_or_expression = 485, /* exclusive_or_expression */ + YYSYMBOL_inclusive_or_expression = 486, /* inclusive_or_expression */ + YYSYMBOL_logical_and_expression = 487, /* logical_and_expression */ + YYSYMBOL_logical_xor_expression = 488, /* logical_xor_expression */ + YYSYMBOL_logical_or_expression = 489, /* logical_or_expression */ + YYSYMBOL_conditional_expression = 490, /* conditional_expression */ + YYSYMBOL_491_1 = 491, /* $@1 */ + YYSYMBOL_assignment_expression = 492, /* assignment_expression */ + YYSYMBOL_assignment_operator = 493, /* assignment_operator */ + YYSYMBOL_expression = 494, /* expression */ + YYSYMBOL_constant_expression = 495, /* constant_expression */ + YYSYMBOL_declaration = 496, /* declaration */ + YYSYMBOL_block_structure = 497, /* block_structure */ + YYSYMBOL_498_2 = 498, /* $@2 */ + YYSYMBOL_identifier_list = 499, /* identifier_list */ + YYSYMBOL_function_prototype = 500, /* function_prototype */ + YYSYMBOL_function_declarator = 501, /* function_declarator */ + YYSYMBOL_function_header_with_parameters = 502, /* function_header_with_parameters */ + YYSYMBOL_function_header = 503, /* function_header */ + YYSYMBOL_parameter_declarator = 504, /* parameter_declarator */ + YYSYMBOL_parameter_declaration = 505, /* parameter_declaration */ + YYSYMBOL_parameter_type_specifier = 506, /* parameter_type_specifier */ + YYSYMBOL_init_declarator_list = 507, /* init_declarator_list */ + YYSYMBOL_single_declaration = 508, /* single_declaration */ + YYSYMBOL_fully_specified_type = 509, /* fully_specified_type */ + YYSYMBOL_invariant_qualifier = 510, /* invariant_qualifier */ + YYSYMBOL_interpolation_qualifier = 511, /* interpolation_qualifier */ + YYSYMBOL_layout_qualifier = 512, /* layout_qualifier */ + YYSYMBOL_layout_qualifier_id_list = 513, /* layout_qualifier_id_list */ + YYSYMBOL_layout_qualifier_id = 514, /* layout_qualifier_id */ + YYSYMBOL_precise_qualifier = 515, /* precise_qualifier */ + YYSYMBOL_type_qualifier = 516, /* type_qualifier */ + YYSYMBOL_single_type_qualifier = 517, /* single_type_qualifier */ + YYSYMBOL_storage_qualifier = 518, /* storage_qualifier */ + YYSYMBOL_non_uniform_qualifier = 519, /* non_uniform_qualifier */ + YYSYMBOL_type_name_list = 520, /* type_name_list */ + YYSYMBOL_type_specifier = 521, /* type_specifier */ + YYSYMBOL_array_specifier = 522, /* array_specifier */ + YYSYMBOL_type_parameter_specifier_opt = 523, /* type_parameter_specifier_opt */ + YYSYMBOL_type_parameter_specifier = 524, /* type_parameter_specifier */ + YYSYMBOL_type_parameter_specifier_list = 525, /* type_parameter_specifier_list */ + YYSYMBOL_type_specifier_nonarray = 526, /* type_specifier_nonarray */ + YYSYMBOL_precision_qualifier = 527, /* precision_qualifier */ + YYSYMBOL_struct_specifier = 528, /* struct_specifier */ + YYSYMBOL_529_3 = 529, /* $@3 */ + YYSYMBOL_530_4 = 530, /* $@4 */ + YYSYMBOL_struct_declaration_list = 531, /* struct_declaration_list */ + YYSYMBOL_struct_declaration = 532, /* struct_declaration */ + YYSYMBOL_struct_declarator_list = 533, /* struct_declarator_list */ + YYSYMBOL_struct_declarator = 534, /* struct_declarator */ + YYSYMBOL_initializer = 535, /* initializer */ + YYSYMBOL_initializer_list = 536, /* initializer_list */ + YYSYMBOL_declaration_statement = 537, /* declaration_statement */ + YYSYMBOL_statement = 538, /* statement */ + YYSYMBOL_simple_statement = 539, /* simple_statement */ + YYSYMBOL_demote_statement = 540, /* demote_statement */ + YYSYMBOL_compound_statement = 541, /* compound_statement */ + YYSYMBOL_542_5 = 542, /* $@5 */ + YYSYMBOL_543_6 = 543, /* $@6 */ + YYSYMBOL_statement_no_new_scope = 544, /* statement_no_new_scope */ + YYSYMBOL_statement_scoped = 545, /* statement_scoped */ + YYSYMBOL_546_7 = 546, /* $@7 */ + YYSYMBOL_547_8 = 547, /* $@8 */ + YYSYMBOL_compound_statement_no_new_scope = 548, /* compound_statement_no_new_scope */ + YYSYMBOL_statement_list = 549, /* statement_list */ + YYSYMBOL_expression_statement = 550, /* expression_statement */ + YYSYMBOL_selection_statement = 551, /* selection_statement */ + YYSYMBOL_selection_statement_nonattributed = 552, /* selection_statement_nonattributed */ + YYSYMBOL_selection_rest_statement = 553, /* selection_rest_statement */ + YYSYMBOL_condition = 554, /* condition */ + YYSYMBOL_switch_statement = 555, /* switch_statement */ + YYSYMBOL_switch_statement_nonattributed = 556, /* switch_statement_nonattributed */ + YYSYMBOL_557_9 = 557, /* $@9 */ + YYSYMBOL_switch_statement_list = 558, /* switch_statement_list */ + YYSYMBOL_case_label = 559, /* case_label */ + YYSYMBOL_iteration_statement = 560, /* iteration_statement */ + YYSYMBOL_iteration_statement_nonattributed = 561, /* iteration_statement_nonattributed */ + YYSYMBOL_562_10 = 562, /* $@10 */ + YYSYMBOL_563_11 = 563, /* $@11 */ + YYSYMBOL_564_12 = 564, /* $@12 */ + YYSYMBOL_for_init_statement = 565, /* for_init_statement */ + YYSYMBOL_conditionopt = 566, /* conditionopt */ + YYSYMBOL_for_rest_statement = 567, /* for_rest_statement */ + YYSYMBOL_jump_statement = 568, /* jump_statement */ + YYSYMBOL_translation_unit = 569, /* translation_unit */ + YYSYMBOL_external_declaration = 570, /* external_declaration */ + YYSYMBOL_function_definition = 571, /* function_definition */ + YYSYMBOL_572_13 = 572, /* $@13 */ + YYSYMBOL_attribute = 573, /* attribute */ + YYSYMBOL_attribute_list = 574, /* attribute_list */ + YYSYMBOL_single_attribute = 575, /* single_attribute */ + YYSYMBOL_spirv_requirements_list = 576, /* spirv_requirements_list */ + YYSYMBOL_spirv_requirements_parameter = 577, /* spirv_requirements_parameter */ + YYSYMBOL_spirv_extension_list = 578, /* spirv_extension_list */ + YYSYMBOL_spirv_capability_list = 579, /* spirv_capability_list */ + YYSYMBOL_spirv_execution_mode_qualifier = 580, /* spirv_execution_mode_qualifier */ + YYSYMBOL_spirv_execution_mode_parameter_list = 581, /* spirv_execution_mode_parameter_list */ + YYSYMBOL_spirv_execution_mode_parameter = 582, /* spirv_execution_mode_parameter */ + YYSYMBOL_spirv_execution_mode_id_parameter_list = 583, /* spirv_execution_mode_id_parameter_list */ + YYSYMBOL_spirv_storage_class_qualifier = 584, /* spirv_storage_class_qualifier */ + YYSYMBOL_spirv_decorate_qualifier = 585, /* spirv_decorate_qualifier */ + YYSYMBOL_spirv_decorate_parameter_list = 586, /* spirv_decorate_parameter_list */ + YYSYMBOL_spirv_decorate_parameter = 587, /* spirv_decorate_parameter */ + YYSYMBOL_spirv_decorate_id_parameter_list = 588, /* spirv_decorate_id_parameter_list */ + YYSYMBOL_spirv_decorate_id_parameter = 589, /* spirv_decorate_id_parameter */ + YYSYMBOL_spirv_decorate_string_parameter_list = 590, /* spirv_decorate_string_parameter_list */ + YYSYMBOL_spirv_type_specifier = 591, /* spirv_type_specifier */ + YYSYMBOL_spirv_type_parameter_list = 592, /* spirv_type_parameter_list */ + YYSYMBOL_spirv_type_parameter = 593, /* spirv_type_parameter */ + YYSYMBOL_spirv_instruction_qualifier = 594, /* spirv_instruction_qualifier */ + YYSYMBOL_spirv_instruction_qualifier_list = 595, /* spirv_instruction_qualifier_list */ + YYSYMBOL_spirv_instruction_qualifier_id = 596 /* spirv_instruction_qualifier_id */ }; typedef enum yysymbol_kind_t yysymbol_kind_t; /* Second part of user prologue. */ -#line 136 "MachineIndependent/glslang.y" +#line 111 "MachineIndependent/glslang.y" -/* windows only pragma */ -#ifdef _MSC_VER - #pragma warning(disable : 4065) - #pragma warning(disable : 4127) - #pragma warning(disable : 4244) -#endif - #define parseContext (*pParseContext) #define yyerror(context, msg) context->parserError(msg) extern int yylex(YYSTYPE*, TParseContext&); -#line 732 "MachineIndependent/glslang_tab.cpp" +#line 736 "MachineIndependent/glslang_tab.cpp" #ifdef short @@ -768,6 +772,18 @@ typedef int_least16_t yytype_int16; typedef short yytype_int16; #endif +/* Work around bug in HP-UX 11.23, which defines these macros + incorrectly for preprocessor constants. This workaround can likely + be removed in 2023, as HPE has promised support for HP-UX 11.23 + (aka HP-UX 11i v2) only through the end of 2022; see Table 2 of + . */ +#ifdef __hpux +# undef UINT_LEAST8_MAX +# undef UINT_LEAST16_MAX +# define UINT_LEAST8_MAX 255 +# define UINT_LEAST16_MAX 65535 +#endif + #if defined __UINT_LEAST8_MAX__ && __UINT_LEAST8_MAX__ <= __INT_MAX__ typedef __UINT_LEAST8_TYPE__ yytype_uint8; #elif (!defined __UINT_LEAST8_MAX__ && defined YY_STDINT_H \ @@ -865,17 +881,23 @@ typedef int yy_state_fast_t; /* Suppress unused-variable warnings by "using" E. */ #if ! defined lint || defined __GNUC__ -# define YYUSE(E) ((void) (E)) +# define YY_USE(E) ((void) (E)) #else -# define YYUSE(E) /* empty */ +# define YY_USE(E) /* empty */ #endif -#if defined __GNUC__ && ! defined __ICC && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ /* Suppress an incorrect diagnostic about yylval being uninitialized. */ -# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ +#if defined __GNUC__ && ! defined __ICC && 406 <= __GNUC__ * 100 + __GNUC_MINOR__ +# if __GNUC__ * 100 + __GNUC_MINOR__ < 407 +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") +# else +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ _Pragma ("GCC diagnostic push") \ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"") \ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# endif # define YY_IGNORE_MAYBE_UNINITIALIZED_END \ _Pragma ("GCC diagnostic pop") #else @@ -1032,21 +1054,21 @@ union yyalloc #endif /* !YYCOPY_NEEDED */ /* YYFINAL -- State number of the termination state. */ -#define YYFINAL 442 +#define YYFINAL 452 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 12452 +#define YYLAST 12701 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 455 +#define YYNTOKENS 465 /* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 131 +#define YYNNTS 132 /* YYNRULES -- Number of rules. */ -#define YYNRULES 683 +#define YYNRULES 700 /* YYNSTATES -- Number of states. */ -#define YYNSTATES 929 +#define YYNSTATES 946 /* YYMAXUTOK -- Last valid token kind. */ -#define YYMAXUTOK 709 +#define YYMAXUTOK 719 /* YYTRANSLATE(TOKEN-NUM) -- Symbol number corresponding to TOKEN-NUM @@ -1130,82 +1152,85 @@ static const yytype_int16 yytranslate[] = 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454 + 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, + 455, 456, 457, 458, 459, 460, 461, 462, 463, 464 }; #if YYDEBUG - /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +/* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 392, 392, 398, 401, 406, 409, 412, 416, 420, - 423, 427, 431, 435, 439, 443, 447, 453, 461, 464, - 467, 470, 473, 478, 486, 493, 500, 506, 510, 517, - 520, 526, 533, 543, 551, 556, 584, 593, 599, 603, - 607, 627, 628, 629, 630, 636, 637, 642, 647, 656, - 657, 662, 670, 671, 677, 686, 687, 692, 697, 702, - 710, 711, 720, 732, 733, 742, 743, 752, 753, 762, - 763, 771, 772, 780, 781, 789, 790, 790, 808, 809, - 825, 829, 833, 837, 842, 846, 850, 854, 858, 862, - 866, 873, 876, 887, 894, 900, 907, 913, 918, 925, - 929, 933, 937, 942, 947, 956, 956, 967, 971, 978, - 982, 988, 994, 1004, 1007, 1014, 1022, 1042, 1065, 1080, - 1105, 1116, 1126, 1136, 1146, 1155, 1158, 1162, 1166, 1171, - 1179, 1186, 1191, 1196, 1201, 1210, 1220, 1247, 1256, 1263, - 1271, 1278, 1285, 1293, 1303, 1310, 1321, 1327, 1330, 1337, - 1341, 1345, 1354, 1364, 1367, 1378, 1381, 1384, 1388, 1392, - 1397, 1401, 1404, 1409, 1413, 1418, 1427, 1431, 1436, 1442, - 1448, 1455, 1460, 1468, 1474, 1486, 1500, 1506, 1511, 1519, - 1527, 1535, 1543, 1551, 1559, 1567, 1575, 1582, 1589, 1593, - 1598, 1603, 1608, 1613, 1618, 1623, 1627, 1631, 1635, 1639, - 1645, 1656, 1663, 1666, 1675, 1680, 1690, 1695, 1703, 1707, - 1717, 1720, 1726, 1732, 1739, 1749, 1753, 1757, 1761, 1766, - 1770, 1775, 1780, 1785, 1790, 1795, 1800, 1805, 1810, 1815, - 1821, 1827, 1833, 1838, 1843, 1848, 1853, 1858, 1863, 1868, - 1873, 1878, 1883, 1888, 1894, 1901, 1906, 1911, 1916, 1921, - 1926, 1931, 1936, 1941, 1946, 1951, 1956, 1964, 1972, 1980, - 1986, 1992, 1998, 2004, 2010, 2016, 2022, 2028, 2034, 2040, - 2046, 2052, 2058, 2064, 2070, 2076, 2082, 2088, 2094, 2100, - 2106, 2112, 2118, 2124, 2130, 2136, 2142, 2148, 2154, 2160, - 2166, 2172, 2178, 2186, 2194, 2202, 2210, 2218, 2226, 2234, - 2242, 2250, 2258, 2266, 2274, 2280, 2286, 2292, 2298, 2304, - 2310, 2316, 2322, 2328, 2334, 2340, 2346, 2352, 2358, 2364, - 2370, 2376, 2382, 2388, 2394, 2400, 2406, 2412, 2418, 2424, - 2430, 2436, 2442, 2448, 2454, 2460, 2466, 2472, 2478, 2484, - 2490, 2494, 2498, 2502, 2507, 2513, 2518, 2523, 2528, 2533, - 2538, 2543, 2549, 2554, 2559, 2564, 2569, 2574, 2580, 2586, - 2592, 2598, 2604, 2610, 2616, 2622, 2628, 2634, 2640, 2646, - 2652, 2658, 2663, 2668, 2673, 2678, 2683, 2688, 2694, 2699, - 2704, 2709, 2714, 2719, 2724, 2729, 2735, 2740, 2745, 2750, - 2755, 2760, 2765, 2770, 2775, 2780, 2785, 2790, 2795, 2800, - 2805, 2811, 2816, 2821, 2827, 2833, 2838, 2843, 2848, 2854, - 2859, 2864, 2869, 2875, 2880, 2885, 2890, 2896, 2901, 2906, - 2911, 2917, 2923, 2929, 2935, 2940, 2946, 2952, 2958, 2963, - 2968, 2973, 2978, 2983, 2989, 2994, 2999, 3004, 3010, 3015, - 3020, 3025, 3031, 3036, 3041, 3046, 3052, 3057, 3062, 3067, - 3073, 3078, 3083, 3088, 3094, 3099, 3104, 3109, 3115, 3120, - 3125, 3130, 3136, 3141, 3146, 3151, 3157, 3162, 3167, 3172, - 3178, 3183, 3188, 3193, 3199, 3204, 3209, 3214, 3220, 3225, - 3230, 3235, 3241, 3246, 3251, 3256, 3262, 3267, 3272, 3277, - 3283, 3288, 3293, 3298, 3303, 3308, 3313, 3318, 3323, 3328, - 3333, 3338, 3343, 3348, 3353, 3358, 3363, 3368, 3373, 3378, - 3383, 3388, 3393, 3398, 3403, 3409, 3415, 3421, 3427, 3434, - 3441, 3447, 3453, 3459, 3465, 3471, 3477, 3483, 3488, 3493, - 3509, 3514, 3519, 3527, 3527, 3538, 3538, 3548, 3551, 3564, - 3586, 3613, 3617, 3623, 3628, 3639, 3643, 3649, 3655, 3666, - 3669, 3676, 3680, 3681, 3687, 3688, 3689, 3690, 3691, 3692, - 3693, 3695, 3701, 3710, 3711, 3715, 3711, 3727, 3728, 3732, - 3732, 3739, 3739, 3753, 3756, 3764, 3772, 3783, 3784, 3788, - 3792, 3800, 3807, 3811, 3819, 3823, 3836, 3840, 3848, 3848, - 3868, 3871, 3877, 3889, 3901, 3905, 3913, 3913, 3928, 3928, - 3946, 3946, 3967, 3970, 3976, 3979, 3985, 3989, 3996, 4001, - 4006, 4013, 4016, 4020, 4025, 4029, 4039, 4043, 4052, 4055, - 4059, 4068, 4068, 4110, 4115, 4118, 4123, 4126, 4133, 4136, - 4141, 4144, 4149, 4152, 4157, 4160, 4165, 4169, 4174, 4178, - 4183, 4187, 4194, 4197, 4202, 4205, 4208, 4211, 4214, 4219, - 4228, 4239, 4244, 4252, 4256, 4261, 4265, 4270, 4274, 4279, - 4283, 4290, 4293, 4298, 4301, 4304, 4307, 4312, 4320, 4330, - 4334, 4339, 4343, 4348, 4352, 4359, 4362, 4367, 4372, 4375, - 4381, 4384, 4389, 4392 + 0, 355, 355, 361, 364, 369, 372, 375, 379, 382, + 385, 389, 393, 397, 401, 405, 409, 415, 422, 425, + 428, 431, 434, 439, 447, 454, 461, 467, 471, 478, + 481, 487, 505, 530, 538, 543, 570, 578, 584, 588, + 592, 612, 613, 614, 615, 621, 622, 627, 632, 641, + 642, 647, 655, 656, 662, 671, 672, 677, 682, 687, + 695, 696, 705, 717, 718, 727, 728, 737, 738, 747, + 748, 756, 757, 765, 766, 774, 775, 775, 793, 794, + 810, 814, 818, 822, 827, 831, 835, 839, 843, 847, + 851, 858, 861, 872, 879, 884, 891, 896, 901, 908, + 912, 916, 920, 925, 930, 939, 939, 950, 954, 961, + 966, 974, 982, 994, 997, 1004, 1017, 1040, 1063, 1078, + 1103, 1114, 1124, 1134, 1144, 1153, 1156, 1160, 1164, 1169, + 1177, 1182, 1187, 1192, 1197, 1206, 1216, 1243, 1252, 1259, + 1266, 1273, 1280, 1288, 1296, 1306, 1316, 1323, 1333, 1339, + 1342, 1349, 1353, 1357, 1365, 1374, 1377, 1388, 1391, 1394, + 1398, 1402, 1406, 1410, 1413, 1418, 1422, 1427, 1435, 1439, + 1444, 1450, 1456, 1463, 1468, 1473, 1481, 1486, 1498, 1512, + 1518, 1523, 1531, 1539, 1547, 1555, 1563, 1571, 1579, 1587, + 1595, 1602, 1609, 1613, 1618, 1623, 1628, 1633, 1638, 1643, + 1647, 1651, 1655, 1659, 1665, 1671, 1681, 1688, 1691, 1699, + 1706, 1717, 1722, 1730, 1734, 1744, 1747, 1753, 1759, 1765, + 1773, 1783, 1787, 1791, 1795, 1800, 1804, 1809, 1814, 1819, + 1824, 1829, 1834, 1839, 1844, 1849, 1855, 1861, 1867, 1872, + 1877, 1882, 1887, 1892, 1897, 1902, 1907, 1912, 1917, 1922, + 1927, 1934, 1939, 1944, 1949, 1954, 1959, 1964, 1969, 1974, + 1979, 1984, 1989, 1997, 2005, 2013, 2019, 2025, 2031, 2037, + 2043, 2049, 2055, 2061, 2067, 2073, 2079, 2085, 2091, 2097, + 2103, 2109, 2115, 2121, 2127, 2133, 2139, 2145, 2151, 2157, + 2163, 2169, 2175, 2181, 2187, 2193, 2199, 2205, 2211, 2219, + 2227, 2235, 2243, 2251, 2259, 2267, 2275, 2283, 2291, 2299, + 2307, 2313, 2319, 2325, 2331, 2337, 2343, 2349, 2355, 2361, + 2367, 2373, 2379, 2385, 2391, 2397, 2403, 2409, 2415, 2421, + 2427, 2433, 2439, 2445, 2451, 2457, 2463, 2469, 2475, 2481, + 2487, 2493, 2499, 2505, 2511, 2517, 2523, 2527, 2531, 2535, + 2540, 2545, 2550, 2555, 2560, 2565, 2570, 2575, 2580, 2585, + 2590, 2595, 2600, 2605, 2611, 2617, 2623, 2629, 2635, 2641, + 2647, 2653, 2659, 2665, 2671, 2677, 2683, 2688, 2693, 2698, + 2703, 2708, 2713, 2718, 2723, 2728, 2733, 2738, 2743, 2748, + 2753, 2758, 2763, 2768, 2773, 2778, 2783, 2788, 2793, 2798, + 2803, 2808, 2813, 2818, 2823, 2828, 2833, 2838, 2843, 2848, + 2854, 2860, 2865, 2870, 2875, 2881, 2886, 2891, 2896, 2902, + 2907, 2912, 2917, 2923, 2928, 2933, 2938, 2944, 2950, 2956, + 2962, 2967, 2973, 2979, 2985, 2990, 2995, 3000, 3005, 3010, + 3016, 3021, 3026, 3031, 3037, 3042, 3047, 3052, 3058, 3063, + 3068, 3073, 3079, 3084, 3089, 3094, 3100, 3105, 3110, 3115, + 3121, 3126, 3131, 3136, 3142, 3147, 3152, 3157, 3163, 3168, + 3173, 3178, 3184, 3189, 3194, 3199, 3205, 3210, 3215, 3220, + 3226, 3231, 3236, 3241, 3247, 3252, 3257, 3262, 3268, 3273, + 3278, 3283, 3289, 3294, 3299, 3304, 3310, 3315, 3320, 3325, + 3330, 3335, 3340, 3345, 3350, 3355, 3360, 3365, 3370, 3375, + 3380, 3385, 3390, 3395, 3400, 3405, 3410, 3415, 3420, 3425, + 3430, 3436, 3442, 3448, 3454, 3460, 3466, 3472, 3479, 3486, + 3492, 3498, 3504, 3510, 3517, 3524, 3531, 3538, 3542, 3546, + 3551, 3567, 3572, 3577, 3585, 3585, 3602, 3602, 3612, 3615, + 3628, 3650, 3677, 3681, 3687, 3692, 3703, 3706, 3712, 3718, + 3727, 3730, 3736, 3740, 3741, 3747, 3748, 3749, 3750, 3751, + 3752, 3753, 3754, 3758, 3766, 3767, 3771, 3767, 3783, 3784, + 3788, 3788, 3795, 3795, 3809, 3812, 3820, 3828, 3839, 3840, + 3844, 3847, 3854, 3861, 3865, 3873, 3877, 3890, 3893, 3900, + 3900, 3920, 3923, 3929, 3941, 3953, 3956, 3964, 3964, 3979, + 3979, 3997, 3997, 4018, 4021, 4027, 4030, 4036, 4040, 4047, + 4052, 4057, 4064, 4067, 4071, 4075, 4079, 4088, 4092, 4101, + 4104, 4107, 4115, 4115, 4157, 4162, 4165, 4170, 4173, 4178, + 4181, 4186, 4189, 4194, 4197, 4202, 4205, 4210, 4214, 4219, + 4223, 4228, 4232, 4239, 4242, 4247, 4250, 4253, 4256, 4259, + 4264, 4273, 4284, 4289, 4297, 4301, 4306, 4310, 4315, 4319, + 4324, 4328, 4335, 4338, 4343, 4346, 4349, 4352, 4357, 4360, + 4365, 4371, 4374, 4377, 4380, 4385, 4389, 4394, 4398, 4403, + 4407, 4414, 4417, 4422, 4425, 4430, 4433, 4439, 4442, 4447, + 4450 }; #endif @@ -1250,16 +1275,17 @@ static const char *const yytname[] = "F32MAT4X2", "F32MAT4X3", "F32MAT4X4", "F64MAT2X2", "F64MAT2X3", "F64MAT2X4", "F64MAT3X2", "F64MAT3X3", "F64MAT3X4", "F64MAT4X2", "F64MAT4X3", "F64MAT4X4", "ATOMIC_UINT", "ACCSTRUCTNV", "ACCSTRUCTEXT", - "RAYQUERYEXT", "FCOOPMATNV", "ICOOPMATNV", "UCOOPMATNV", - "SAMPLERCUBEARRAY", "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", - "USAMPLERCUBEARRAY", "SAMPLER1D", "SAMPLER1DARRAY", - "SAMPLER1DARRAYSHADOW", "ISAMPLER1D", "SAMPLER1DSHADOW", "SAMPLER2DRECT", - "SAMPLER2DRECTSHADOW", "ISAMPLER2DRECT", "USAMPLER2DRECT", - "SAMPLERBUFFER", "ISAMPLERBUFFER", "USAMPLERBUFFER", "SAMPLER2DMS", - "ISAMPLER2DMS", "USAMPLER2DMS", "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", - "USAMPLER2DMSARRAY", "SAMPLEREXTERNALOES", "SAMPLEREXTERNAL2DY2YEXT", - "ISAMPLER1DARRAY", "USAMPLER1D", "USAMPLER1DARRAY", "F16SAMPLER1D", - "F16SAMPLER2D", "F16SAMPLER3D", "F16SAMPLER2DRECT", "F16SAMPLERCUBE", + "RAYQUERYEXT", "FCOOPMATNV", "ICOOPMATNV", "UCOOPMATNV", "COOPMAT", + "HITOBJECTNV", "HITOBJECTATTRNV", "SAMPLERCUBEARRAY", + "SAMPLERCUBEARRAYSHADOW", "ISAMPLERCUBEARRAY", "USAMPLERCUBEARRAY", + "SAMPLER1D", "SAMPLER1DARRAY", "SAMPLER1DARRAYSHADOW", "ISAMPLER1D", + "SAMPLER1DSHADOW", "SAMPLER2DRECT", "SAMPLER2DRECTSHADOW", + "ISAMPLER2DRECT", "USAMPLER2DRECT", "SAMPLERBUFFER", "ISAMPLERBUFFER", + "USAMPLERBUFFER", "SAMPLER2DMS", "ISAMPLER2DMS", "USAMPLER2DMS", + "SAMPLER2DMSARRAY", "ISAMPLER2DMSARRAY", "USAMPLER2DMSARRAY", + "SAMPLEREXTERNALOES", "SAMPLEREXTERNAL2DY2YEXT", "ISAMPLER1DARRAY", + "USAMPLER1D", "USAMPLER1DARRAY", "F16SAMPLER1D", "F16SAMPLER2D", + "F16SAMPLER3D", "F16SAMPLER2DRECT", "F16SAMPLERCUBE", "F16SAMPLER1DARRAY", "F16SAMPLER2DARRAY", "F16SAMPLERCUBEARRAY", "F16SAMPLERBUFFER", "F16SAMPLER2DMS", "F16SAMPLER2DMSARRAY", "F16SAMPLER1DSHADOW", "F16SAMPLER2DSHADOW", "F16SAMPLER1DARRAYSHADOW", @@ -1295,32 +1321,34 @@ static const char *const yytname[] = "F16SUBPASSINPUTMS", "SPIRV_INSTRUCTION", "SPIRV_EXECUTION_MODE", "SPIRV_EXECUTION_MODE_ID", "SPIRV_DECORATE", "SPIRV_DECORATE_ID", "SPIRV_DECORATE_STRING", "SPIRV_TYPE", "SPIRV_STORAGE_CLASS", - "SPIRV_BY_REFERENCE", "SPIRV_LITERAL", "LEFT_OP", "RIGHT_OP", "INC_OP", - "DEC_OP", "LE_OP", "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", - "XOR_OP", "MUL_ASSIGN", "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", - "LEFT_ASSIGN", "RIGHT_ASSIGN", "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", - "SUB_ASSIGN", "STRING_LITERAL", "LEFT_PAREN", "RIGHT_PAREN", - "LEFT_BRACKET", "RIGHT_BRACKET", "LEFT_BRACE", "RIGHT_BRACE", "DOT", - "COMMA", "COLON", "EQUAL", "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", - "STAR", "SLASH", "PERCENT", "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", - "CARET", "AMPERSAND", "QUESTION", "INVARIANT", "HIGH_PRECISION", - "MEDIUM_PRECISION", "LOW_PRECISION", "PRECISION", "PACKED", "RESOURCE", - "SUPERP", "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", + "SPIRV_BY_REFERENCE", "SPIRV_LITERAL", "ATTACHMENTEXT", "IATTACHMENTEXT", + "UATTACHMENTEXT", "LEFT_OP", "RIGHT_OP", "INC_OP", "DEC_OP", "LE_OP", + "GE_OP", "EQ_OP", "NE_OP", "AND_OP", "OR_OP", "XOR_OP", "MUL_ASSIGN", + "DIV_ASSIGN", "ADD_ASSIGN", "MOD_ASSIGN", "LEFT_ASSIGN", "RIGHT_ASSIGN", + "AND_ASSIGN", "XOR_ASSIGN", "OR_ASSIGN", "SUB_ASSIGN", "STRING_LITERAL", + "LEFT_PAREN", "RIGHT_PAREN", "LEFT_BRACKET", "RIGHT_BRACKET", + "LEFT_BRACE", "RIGHT_BRACE", "DOT", "COMMA", "COLON", "EQUAL", + "SEMICOLON", "BANG", "DASH", "TILDE", "PLUS", "STAR", "SLASH", "PERCENT", + "LEFT_ANGLE", "RIGHT_ANGLE", "VERTICAL_BAR", "CARET", "AMPERSAND", + "QUESTION", "INVARIANT", "HIGH_PRECISION", "MEDIUM_PRECISION", + "LOW_PRECISION", "PRECISION", "PACKED", "RESOURCE", "SUPERP", + "FLOATCONSTANT", "INTCONSTANT", "UINTCONSTANT", "BOOLCONSTANT", "IDENTIFIER", "TYPE_NAME", "CENTROID", "IN", "OUT", "INOUT", "STRUCT", "VOID", "WHILE", "BREAK", "CONTINUE", "DO", "ELSE", "FOR", "IF", "DISCARD", "RETURN", "SWITCH", "CASE", "DEFAULT", "TERMINATE_INVOCATION", "TERMINATE_RAY", "IGNORE_INTERSECTION", "UNIFORM", "SHARED", "BUFFER", - "FLAT", "SMOOTH", "LAYOUT", "DOUBLECONSTANT", "INT16CONSTANT", - "UINT16CONSTANT", "FLOAT16CONSTANT", "INT32CONSTANT", "UINT32CONSTANT", - "INT64CONSTANT", "UINT64CONSTANT", "SUBROUTINE", "DEMOTE", "PAYLOADNV", - "PAYLOADINNV", "HITATTRNV", "CALLDATANV", "CALLDATAINNV", "PAYLOADEXT", - "PAYLOADINEXT", "HITATTREXT", "CALLDATAEXT", "CALLDATAINEXT", "PATCH", - "SAMPLE", "NONUNIFORM", "COHERENT", "VOLATILE", "RESTRICT", "READONLY", - "WRITEONLY", "DEVICECOHERENT", "QUEUEFAMILYCOHERENT", - "WORKGROUPCOHERENT", "SUBGROUPCOHERENT", "NONPRIVATE", - "SHADERCALLCOHERENT", "NOPERSPECTIVE", "EXPLICITINTERPAMD", - "PERVERTEXNV", "PERPRIMITIVENV", "PERVIEWNV", "PERTASKNV", "PRECISE", - "$accept", "variable_identifier", "primary_expression", + "TILEIMAGEEXT", "FLAT", "SMOOTH", "LAYOUT", "DOUBLECONSTANT", + "INT16CONSTANT", "UINT16CONSTANT", "FLOAT16CONSTANT", "INT32CONSTANT", + "UINT32CONSTANT", "INT64CONSTANT", "UINT64CONSTANT", "SUBROUTINE", + "DEMOTE", "PAYLOADNV", "PAYLOADINNV", "HITATTRNV", "CALLDATANV", + "CALLDATAINNV", "PAYLOADEXT", "PAYLOADINEXT", "HITATTREXT", + "CALLDATAEXT", "CALLDATAINEXT", "PATCH", "SAMPLE", "NONUNIFORM", + "COHERENT", "VOLATILE", "RESTRICT", "READONLY", "WRITEONLY", + "DEVICECOHERENT", "QUEUEFAMILYCOHERENT", "WORKGROUPCOHERENT", + "SUBGROUPCOHERENT", "NONPRIVATE", "SHADERCALLCOHERENT", "NOPERSPECTIVE", + "EXPLICITINTERPAMD", "PERVERTEXEXT", "PERVERTEXNV", "PERPRIMITIVENV", + "PERVIEWNV", "PERTASKNV", "PERPRIMITIVEEXT", "TASKPAYLOADWORKGROUPEXT", + "PRECISE", "$accept", "variable_identifier", "primary_expression", "postfix_expression", "integer_expression", "function_call", "function_call_or_method", "function_call_generic", "function_call_header_no_parameters", @@ -1365,7 +1393,7 @@ static const char *const yytname[] = "spirv_execution_mode_id_parameter_list", "spirv_storage_class_qualifier", "spirv_decorate_qualifier", "spirv_decorate_parameter_list", "spirv_decorate_parameter", - "spirv_decorate_id_parameter_list", + "spirv_decorate_id_parameter_list", "spirv_decorate_id_parameter", "spirv_decorate_string_parameter_list", "spirv_type_specifier", "spirv_type_parameter_list", "spirv_type_parameter", "spirv_instruction_qualifier", "spirv_instruction_qualifier_list", @@ -1379,406 +1407,358 @@ yysymbol_name (yysymbol_kind_t yysymbol) } #endif -#ifdef YYPRINT -/* YYTOKNUM[NUM] -- (External) token number corresponding to the - (internal) symbol number NUM (which must be that of a token). */ -static const yytype_int16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, - 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, - 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, - 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, - 375, 376, 377, 378, 379, 380, 381, 382, 383, 384, - 385, 386, 387, 388, 389, 390, 391, 392, 393, 394, - 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, - 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, - 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, - 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, - 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, - 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, - 475, 476, 477, 478, 479, 480, 481, 482, 483, 484, - 485, 486, 487, 488, 489, 490, 491, 492, 493, 494, - 495, 496, 497, 498, 499, 500, 501, 502, 503, 504, - 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, - 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, - 525, 526, 527, 528, 529, 530, 531, 532, 533, 534, - 535, 536, 537, 538, 539, 540, 541, 542, 543, 544, - 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, - 555, 556, 557, 558, 559, 560, 561, 562, 563, 564, - 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, - 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, - 585, 586, 587, 588, 589, 590, 591, 592, 593, 594, - 595, 596, 597, 598, 599, 600, 601, 602, 603, 604, - 605, 606, 607, 608, 609, 610, 611, 612, 613, 614, - 615, 616, 617, 618, 619, 620, 621, 622, 623, 624, - 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, - 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, - 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, - 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, - 665, 666, 667, 668, 669, 670, 671, 672, 673, 674, - 675, 676, 677, 678, 679, 680, 681, 682, 683, 684, - 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, - 695, 696, 697, 698, 699, 700, 701, 702, 703, 704, - 705, 706, 707, 708, 709 -}; -#endif - -#define YYPACT_NINF (-859) +#define YYPACT_NINF (-872) #define yypact_value_is_default(Yyn) \ ((Yyn) == YYPACT_NINF) -#define YYTABLE_NINF (-570) +#define YYTABLE_NINF (-695) #define yytable_value_is_error(Yyn) \ 0 - /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ static const yytype_int16 yypact[] = { - 4548, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -312, -274, -244, -212, -208, - -201, -181, -169, -859, -859, -194, -859, -859, -859, -859, - -859, -285, -859, -859, -859, -859, -859, -317, -859, -859, - -859, -859, -859, -859, -132, -73, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -329, -70, - -158, -145, 7712, -221, -859, -164, -859, -859, -859, -859, - 5452, -859, -859, -859, -859, -68, -859, -859, 932, -859, - -859, 7712, -55, -859, -859, -859, 5904, -80, -154, -150, - -142, -135, -130, -80, -129, -79, 12060, -859, -45, -354, - -76, -859, -308, -859, -43, -40, 7712, -859, -859, -859, - 7712, -72, -71, -859, -265, -859, -257, -859, -859, 10761, - -39, -859, -859, -859, -35, -69, 7712, -859, -42, -38, - -37, -859, -302, -859, -235, -32, -33, -28, -27, -217, - -26, -23, -22, -21, -20, -16, -216, -29, -15, -31, - -303, -859, -13, 7712, -859, -14, -859, -214, -859, -859, - -205, 9029, -859, -279, 1384, -859, -859, -859, -859, -859, - -39, -299, -859, 9462, -275, -859, -34, -859, -137, 10761, - 10761, -859, 10761, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -248, -859, -859, -859, -3, -203, 11194, -1, - -859, 10761, -859, -859, -310, 3, -40, 1, -859, -309, - -80, -859, -30, -859, -319, 5, -128, 10761, -124, -859, - -157, -122, 10761, -120, 10, -118, -80, -859, 11627, -859, - -116, 10761, 7, -79, -859, 7712, -25, 6356, -859, 7712, - 10761, -859, -354, -859, -19, -859, -859, -78, -263, -94, - -298, -52, -18, -8, -12, 29, 28, -301, 15, 9895, - -859, 16, -859, -859, 19, 12, 17, -859, 20, 23, - 18, 10328, 24, 10761, 21, 22, 25, 27, 30, -215, - -859, -859, -117, -859, -70, 26, 34, -859, -859, -859, - -859, -859, 1836, -859, -859, -859, -859, -859, -859, -859, - -859, -859, 5000, 3, 9462, -264, 8163, -859, -859, 9462, - 7712, -859, -11, -859, -859, -859, -195, -859, -859, 10761, - -6, -859, -859, 10761, 37, -859, -859, -859, 10761, -859, - -859, -859, -322, -859, -859, -192, 35, -859, -859, -859, - -859, -859, -859, -179, -859, -178, -859, -859, -177, 32, - -859, -859, -859, -859, -175, -859, -174, -859, -167, 36, - -859, -166, 38, -165, 35, -859, -163, -859, 45, 46, - -859, -859, -25, -39, -115, -859, -859, -859, 6808, -859, - -859, -859, 10761, 10761, 10761, 10761, 10761, 10761, 10761, 10761, - 10761, 10761, 10761, 10761, 10761, 10761, 10761, 10761, 10761, 10761, - 10761, -859, -859, -859, 51, -859, 2288, -859, -859, -859, - 2288, -859, 10761, -859, -859, -88, 10761, -63, -859, -859, - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, 10761, 10761, -859, -859, -859, -859, - -859, -859, -859, 9462, -859, -859, -108, -859, 7260, -859, - -859, 52, 53, -859, -859, -859, -859, -859, -138, -136, - -859, -304, -859, -319, -859, -319, -859, 10761, 10761, -859, - -157, -859, -157, -859, 10761, 10761, -859, 65, 10, -859, - 11627, -859, 10761, -859, -859, -86, 3, -25, -859, -859, - -859, -859, -859, -78, -78, -263, -263, -94, -94, -94, - -94, -298, -298, -52, -18, -8, -12, 29, 28, 10761, - -859, 2288, 4096, 31, 3644, -156, -859, -155, -859, -859, - -859, -859, -859, 8596, -859, -859, -859, 66, -859, 39, - -859, -153, -859, -151, -859, -148, -859, -146, -859, -144, - -143, -859, -859, -859, -61, 64, 53, 40, 72, 74, - -859, -859, 4096, 75, -859, -859, -859, -859, -859, -859, - -859, -859, -859, -859, -859, 10761, -859, 71, 2740, 10761, - -859, 73, 81, 41, 80, 3192, -859, 83, -859, 9462, - -859, -859, -859, -141, 10761, 2740, 75, -859, -859, 2288, - -859, 78, 53, -859, -859, 2288, 86, -859, -859 + 4648, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -305, -301, + -289, -276, -246, -238, -227, -182, -872, -872, -872, -872, + -872, -168, -872, -872, -872, -872, -872, -55, -872, -872, + -872, -872, -872, -319, -872, -872, -872, -872, -872, -872, + -872, -135, -120, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -327, -114, + -81, -124, 7882, -313, -872, -101, -872, -872, -872, -872, + 5572, -872, -872, -872, -872, -94, -872, -872, 952, -872, + -872, 7882, -73, -872, -872, -872, 6034, -78, -252, -250, + -216, -197, -136, -78, -127, -49, 12303, -872, -13, -346, + -39, -872, -309, -872, -10, -9, 7882, -872, -872, -872, + 7882, -38, -37, -872, -267, -872, -236, -872, -872, 10983, + -2, -872, -872, -872, 3, -35, 7882, -872, -8, -6, + -1, -872, -256, -872, -255, -4, 4, 7, 8, -237, + 10, 11, 13, 14, 15, 18, -232, 9, 19, 27, + -188, -872, -3, 7882, -872, 20, -872, -229, -872, -872, + -219, 9223, -872, -272, 1414, -872, -872, -872, -872, -872, + -2, -277, -872, 9663, -265, -872, -23, -872, -112, 10983, + 10983, -872, 10983, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -253, -872, -872, -872, 29, -204, 11423, 28, + -872, 10983, -872, 31, -321, 17, -9, 32, -872, -325, + -78, -872, 5, -872, -330, 33, -125, 10983, -123, -872, + -130, -119, -146, -118, 34, -103, -78, -872, 11863, -872, + -74, 10983, 36, -49, -872, 7882, 24, 6496, -872, 7882, + 10983, -872, -346, -872, 30, -872, -872, -33, -133, -105, + -303, -11, -14, 21, 23, 48, 52, -316, 41, -872, + 10103, -872, 42, -872, -872, 46, 38, 40, -872, 64, + 67, 60, 10543, 74, 10983, 68, 65, 69, 70, 73, + -167, -872, -872, -47, -872, -114, 77, 31, -872, -872, + -872, -872, -872, 1876, -872, -872, -872, -872, -872, -872, + -872, -872, -872, 5110, 17, 9663, -261, 8343, -872, -872, + 9663, 7882, -872, 50, -872, -872, -872, -203, -872, -872, + 10983, 51, -872, -872, 10983, 87, -872, -872, -872, 10983, + -872, -872, -872, -312, -872, -872, -200, 80, -872, -872, + -872, -872, -872, -872, -199, -872, -196, -872, -872, -195, + 71, -872, -872, -872, -872, -169, -872, -164, -872, -872, + -872, -872, -872, -161, -872, 83, -872, -160, 84, -153, + 80, -872, -278, -152, -872, 91, 94, -872, -872, 24, + -2, -43, -872, -872, -872, 6958, -872, -872, -872, 10983, + 10983, 10983, 10983, 10983, 10983, 10983, 10983, 10983, 10983, 10983, + 10983, 10983, 10983, 10983, 10983, 10983, 10983, 10983, -872, -872, + -872, 93, -872, 2338, -872, -872, -872, 2338, -872, 10983, + -872, -872, -42, 10983, -32, -872, -872, -872, -872, -872, + -872, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, 10983, 10983, -872, -872, -872, -872, -872, -872, -872, + 9663, -872, -872, -76, -872, 7420, -872, -872, 96, 95, + -872, -872, -872, -872, -872, -132, -131, -872, -311, -872, + -330, -872, -330, -872, 10983, 10983, -872, -130, -872, -130, + -872, -146, -146, -872, 101, 34, -872, 11863, -872, 10983, + -872, -872, -41, 17, 24, -872, -872, -872, -872, -872, + -33, -33, -133, -133, -105, -105, -105, -105, -303, -303, + -11, -14, 21, 23, 48, 52, 10983, -872, 2338, 4186, + 59, 3724, -151, -872, -150, -872, -872, -872, -872, -872, + 8783, -872, -872, -872, 105, -872, 72, -872, -149, -872, + -148, -872, -141, -872, -140, -872, -139, -138, -872, -872, + -872, -28, 102, 95, 75, 107, 106, -872, -872, 4186, + 108, -872, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, 10983, -872, 100, 2800, 10983, -872, 104, 109, + 76, 112, 3262, -872, 113, -872, 9663, -872, -872, -872, + -137, 10983, 2800, 108, -872, -872, 2338, -872, 110, 95, + -872, -872, 2338, 114, -872, -872 }; - /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE does not specify something else to do. Zero - means the default is an error. */ +/* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ static const yytype_int16 yydefact[] = { - 0, 166, 219, 217, 218, 216, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 220, 221, 222, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 345, 346, 347, 348, 349, 350, 351, 371, 372, 373, - 374, 375, 376, 377, 386, 399, 400, 387, 388, 390, - 389, 391, 392, 393, 394, 395, 396, 397, 398, 174, - 175, 245, 246, 244, 247, 254, 255, 252, 253, 250, - 251, 248, 249, 277, 278, 279, 289, 290, 291, 274, - 275, 276, 286, 287, 288, 271, 272, 273, 283, 284, - 285, 268, 269, 270, 280, 281, 282, 256, 257, 258, - 292, 293, 294, 259, 260, 261, 304, 305, 306, 262, - 263, 264, 316, 317, 318, 265, 266, 267, 328, 329, - 330, 295, 296, 297, 298, 299, 300, 301, 302, 303, - 307, 308, 309, 310, 311, 312, 313, 314, 315, 319, - 320, 321, 322, 323, 324, 325, 326, 327, 331, 332, - 333, 334, 335, 336, 337, 338, 339, 343, 340, 341, - 342, 524, 525, 526, 355, 356, 379, 382, 344, 353, - 354, 370, 352, 401, 402, 405, 406, 407, 409, 410, - 411, 413, 414, 415, 417, 418, 514, 515, 378, 380, - 381, 357, 358, 359, 403, 360, 364, 365, 368, 408, - 412, 416, 361, 362, 366, 367, 404, 363, 369, 448, - 450, 451, 452, 454, 455, 456, 458, 459, 460, 462, - 463, 464, 466, 467, 468, 470, 471, 472, 474, 475, - 476, 478, 479, 480, 482, 483, 484, 486, 487, 488, - 490, 491, 449, 453, 457, 461, 465, 473, 477, 481, - 469, 485, 489, 492, 493, 494, 495, 496, 497, 498, - 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, - 509, 510, 511, 512, 513, 383, 384, 385, 419, 428, - 430, 424, 429, 431, 432, 434, 435, 436, 438, 439, - 440, 442, 443, 444, 446, 447, 420, 421, 422, 433, - 423, 425, 426, 427, 437, 441, 445, 516, 517, 520, - 521, 522, 523, 518, 519, 0, 0, 0, 0, 0, - 0, 0, 0, 164, 165, 0, 620, 137, 530, 531, - 532, 0, 529, 170, 168, 169, 167, 0, 215, 171, - 172, 173, 139, 138, 0, 199, 180, 182, 178, 184, - 186, 181, 183, 179, 185, 187, 176, 177, 201, 188, - 195, 196, 197, 198, 189, 190, 191, 192, 193, 194, - 140, 141, 142, 143, 144, 145, 152, 619, 0, 621, - 0, 114, 113, 0, 125, 130, 159, 158, 156, 160, - 0, 153, 155, 161, 135, 211, 157, 528, 0, 616, - 618, 0, 0, 162, 163, 527, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, + 0, 168, 225, 223, 224, 222, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 226, 227, 228, 238, 239, + 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, + 351, 352, 353, 354, 355, 356, 357, 377, 378, 379, + 380, 381, 382, 383, 392, 405, 406, 393, 394, 396, + 395, 397, 398, 399, 400, 401, 402, 403, 404, 177, + 178, 251, 252, 250, 253, 260, 261, 258, 259, 256, + 257, 254, 255, 283, 284, 285, 295, 296, 297, 280, + 281, 282, 292, 293, 294, 277, 278, 279, 289, 290, + 291, 274, 275, 276, 286, 287, 288, 262, 263, 264, + 298, 299, 300, 265, 266, 267, 310, 311, 312, 268, + 269, 270, 322, 323, 324, 271, 272, 273, 334, 335, + 336, 301, 302, 303, 304, 305, 306, 307, 308, 309, + 313, 314, 315, 316, 317, 318, 319, 320, 321, 325, + 326, 327, 328, 329, 330, 331, 332, 333, 337, 338, + 339, 340, 341, 342, 343, 344, 345, 349, 346, 347, + 348, 533, 534, 535, 536, 538, 182, 361, 362, 385, + 388, 350, 359, 360, 376, 358, 407, 408, 411, 412, + 413, 415, 416, 417, 419, 420, 421, 423, 424, 520, + 521, 384, 386, 387, 363, 364, 365, 409, 366, 370, + 371, 374, 414, 418, 422, 367, 368, 372, 373, 410, + 369, 375, 454, 456, 457, 458, 460, 461, 462, 464, + 465, 466, 468, 469, 470, 472, 473, 474, 476, 477, + 478, 480, 481, 482, 484, 485, 486, 488, 489, 490, + 492, 493, 494, 496, 497, 455, 459, 463, 467, 471, + 479, 483, 487, 475, 491, 495, 498, 499, 500, 501, + 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, + 512, 513, 514, 515, 516, 517, 518, 519, 389, 390, + 391, 425, 434, 436, 430, 435, 437, 438, 440, 441, + 442, 444, 445, 446, 448, 449, 450, 452, 453, 426, + 427, 428, 439, 429, 431, 432, 433, 443, 447, 451, + 525, 526, 529, 530, 531, 532, 527, 528, 0, 0, + 0, 0, 0, 0, 0, 0, 166, 167, 522, 523, + 524, 0, 631, 137, 541, 542, 543, 0, 540, 172, + 170, 171, 169, 0, 221, 173, 175, 176, 174, 139, + 138, 0, 203, 184, 186, 181, 188, 190, 185, 187, + 183, 189, 191, 179, 180, 206, 192, 199, 200, 201, + 202, 193, 194, 195, 196, 197, 198, 140, 141, 143, + 142, 144, 146, 147, 145, 205, 154, 630, 0, 632, + 0, 114, 113, 0, 125, 130, 161, 160, 158, 162, + 0, 155, 157, 163, 135, 216, 159, 539, 0, 627, + 629, 0, 0, 164, 165, 537, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 546, 0, 0, 0, 99, 0, 94, 0, 109, 0, 121, 115, 123, - 0, 124, 0, 97, 131, 102, 0, 154, 136, 0, - 204, 210, 1, 617, 0, 0, 0, 96, 0, 0, - 0, 628, 0, 680, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 626, - 0, 624, 0, 0, 533, 149, 151, 0, 147, 202, - 0, 0, 100, 0, 0, 622, 110, 116, 120, 122, + 0, 124, 0, 97, 131, 102, 0, 156, 136, 0, + 209, 215, 1, 628, 0, 0, 0, 96, 0, 0, + 0, 639, 0, 697, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 637, + 0, 635, 0, 0, 544, 151, 153, 0, 149, 207, + 0, 0, 100, 0, 0, 633, 110, 116, 120, 122, 118, 126, 117, 0, 132, 105, 0, 103, 0, 0, 0, 9, 0, 43, 42, 44, 41, 5, 6, 7, 8, 2, 16, 14, 15, 17, 10, 11, 12, 13, 3, 18, 37, 20, 25, 26, 0, 0, 30, 0, - 213, 0, 36, 34, 0, 205, 111, 0, 95, 0, - 0, 678, 0, 636, 0, 0, 0, 0, 0, 653, - 0, 0, 0, 0, 0, 0, 0, 673, 0, 651, - 0, 0, 0, 0, 98, 0, 0, 0, 537, 0, - 0, 146, 0, 200, 0, 206, 45, 49, 52, 55, - 60, 63, 65, 67, 69, 71, 73, 75, 0, 0, - 101, 564, 573, 577, 0, 0, 0, 598, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 45, - 78, 91, 0, 551, 0, 161, 135, 554, 575, 553, - 561, 552, 0, 555, 556, 579, 557, 586, 558, 559, - 594, 560, 0, 119, 0, 127, 0, 545, 134, 0, - 0, 107, 0, 104, 38, 39, 0, 22, 23, 0, - 0, 28, 27, 0, 215, 31, 33, 40, 0, 212, - 112, 682, 0, 683, 629, 0, 0, 681, 648, 644, - 645, 646, 647, 0, 642, 0, 93, 649, 0, 0, - 663, 664, 665, 666, 0, 661, 0, 667, 0, 0, - 669, 0, 0, 0, 2, 677, 0, 675, 0, 0, - 623, 625, 0, 543, 0, 541, 536, 538, 0, 150, - 148, 203, 0, 0, 0, 0, 0, 0, 0, 0, + 219, 0, 36, 218, 0, 210, 111, 0, 95, 0, + 0, 695, 0, 647, 0, 0, 0, 0, 0, 664, + 0, 0, 0, 0, 0, 0, 0, 689, 0, 662, + 0, 0, 0, 0, 98, 0, 0, 0, 548, 0, + 0, 148, 0, 204, 0, 211, 45, 49, 52, 55, + 60, 63, 65, 67, 69, 71, 73, 75, 0, 34, + 0, 101, 575, 584, 588, 0, 0, 0, 609, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 76, 207, 208, 0, 563, 0, 596, 609, 608, - 0, 600, 0, 612, 610, 0, 0, 0, 593, 613, - 614, 615, 562, 81, 82, 84, 83, 86, 87, 88, - 89, 90, 85, 80, 0, 0, 578, 574, 576, 580, - 587, 595, 129, 0, 548, 549, 0, 133, 0, 108, - 4, 0, 24, 21, 32, 214, 632, 634, 0, 0, - 679, 0, 638, 0, 637, 0, 640, 0, 0, 655, - 0, 654, 0, 657, 0, 0, 659, 0, 0, 674, - 0, 671, 0, 652, 627, 0, 544, 0, 539, 534, - 46, 47, 48, 51, 50, 53, 54, 58, 59, 56, - 57, 61, 62, 64, 66, 68, 70, 72, 74, 0, - 209, 565, 0, 0, 0, 0, 611, 0, 592, 79, - 92, 128, 546, 0, 106, 19, 630, 0, 631, 0, - 643, 0, 650, 0, 662, 0, 668, 0, 670, 0, - 0, 676, 540, 542, 0, 0, 584, 0, 0, 0, - 603, 602, 605, 571, 588, 547, 550, 633, 635, 639, - 641, 656, 658, 660, 672, 0, 566, 0, 0, 0, - 604, 0, 0, 583, 0, 0, 581, 0, 77, 0, - 568, 597, 567, 0, 606, 0, 571, 570, 572, 590, - 585, 0, 607, 601, 582, 591, 0, 599, 589 + 45, 78, 91, 0, 562, 0, 163, 135, 565, 586, + 564, 572, 563, 0, 566, 567, 590, 568, 597, 569, + 570, 605, 571, 0, 119, 0, 127, 0, 556, 134, + 0, 0, 107, 0, 104, 38, 39, 0, 22, 23, + 0, 0, 28, 27, 0, 221, 31, 33, 40, 0, + 217, 112, 699, 0, 700, 640, 0, 0, 698, 659, + 655, 656, 657, 658, 0, 653, 0, 93, 660, 0, + 0, 674, 675, 676, 677, 0, 672, 0, 681, 682, + 683, 684, 680, 0, 678, 0, 685, 0, 0, 0, + 2, 693, 216, 0, 691, 0, 0, 634, 636, 0, + 554, 0, 552, 547, 549, 0, 152, 150, 208, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 76, 212, + 213, 0, 574, 0, 607, 620, 619, 0, 611, 0, + 623, 621, 0, 0, 0, 604, 624, 625, 626, 573, + 81, 82, 84, 83, 86, 87, 88, 89, 90, 85, + 80, 0, 0, 589, 585, 587, 591, 598, 606, 129, + 0, 559, 560, 0, 133, 0, 108, 4, 0, 24, + 21, 32, 220, 643, 645, 0, 0, 696, 0, 649, + 0, 648, 0, 651, 0, 0, 666, 0, 665, 0, + 668, 0, 0, 670, 0, 0, 690, 0, 687, 0, + 663, 638, 0, 555, 0, 550, 545, 46, 47, 48, + 51, 50, 53, 54, 58, 59, 56, 57, 61, 62, + 64, 66, 68, 70, 72, 74, 0, 214, 576, 0, + 0, 0, 0, 622, 0, 603, 79, 92, 128, 557, + 0, 106, 19, 641, 0, 642, 0, 654, 0, 661, + 0, 673, 0, 679, 0, 686, 0, 0, 692, 551, + 553, 0, 0, 595, 0, 0, 0, 614, 613, 616, + 582, 599, 558, 561, 644, 646, 650, 652, 667, 669, + 671, 688, 0, 577, 0, 0, 0, 615, 0, 0, + 594, 0, 0, 592, 0, 77, 0, 579, 608, 578, + 0, 617, 0, 582, 581, 583, 601, 596, 0, 618, + 612, 593, 602, 0, 610, 600 }; - /* YYPGOTO[NTERM-NUM]. */ +/* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -859, -859, -859, -859, -859, -859, -859, -859, -859, -859, - -859, -859, -209, -859, -418, -417, -602, -421, -291, -284, - -286, -283, -281, -287, -859, -473, -859, -490, -859, -497, - -520, 13, -859, -859, -859, 14, -394, -859, -859, 33, - 42, 44, -859, -859, -395, -859, -859, -859, -859, -121, - -859, -381, -369, -859, 9, -859, 0, -424, -859, -859, - -859, -859, 113, -859, -859, -859, -545, -549, -252, -365, - -617, -859, -391, -618, -858, -859, -450, -859, -859, -459, - -458, -859, -859, 43, -721, -387, -859, -173, -859, -422, - -859, -170, -859, -859, -859, -859, -168, -859, -859, -859, - -859, -859, -859, -859, -859, 67, -859, -859, 2, -859, - -97, -300, -386, -859, -859, -859, -326, -323, -327, -859, - -859, -330, -325, -328, -332, -859, -331, -334, -859, -390, - -530 + -872, -544, -872, -872, -872, -872, -872, -872, -872, -872, + -872, -872, -436, -872, -392, -391, -490, -390, -269, -266, + -268, -264, -262, -260, -872, -482, -872, -499, -872, -492, + -534, 6, -872, -872, -872, 1, -403, -872, -872, 45, + 44, 49, -872, -872, -406, -872, -872, -872, -872, -104, + -872, -389, -375, -872, 12, -872, 0, -433, -872, -872, + -872, -553, 145, -872, -872, -872, -560, -556, -233, -344, + -614, -872, -373, -626, -871, -872, -430, -872, -872, -440, + -437, -872, -872, 63, -737, -363, -872, -144, -872, -399, + -872, -142, -872, -872, -872, -872, -134, -872, -872, -872, + -872, -872, -872, -872, -872, 97, -872, -872, 2, -872, + -71, -308, -416, -872, -872, -872, -304, -307, -302, -872, + -872, -315, -310, -306, -300, -314, -872, -299, -317, -872, + -395, -538 }; - /* YYDEFGOTO[NTERM-NUM]. */ +/* YYDEFGOTO[NTERM-NUM]. */ static const yytype_int16 yydefgoto[] = { - -1, 520, 521, 522, 781, 523, 524, 525, 526, 527, - 528, 529, 609, 531, 577, 578, 579, 580, 581, 582, - 583, 584, 585, 586, 587, 610, 839, 611, 764, 612, - 695, 613, 378, 640, 498, 614, 380, 381, 382, 427, - 428, 429, 383, 384, 385, 386, 387, 388, 477, 478, - 389, 390, 391, 392, 532, 480, 533, 483, 440, 441, - 534, 395, 396, 397, 569, 473, 567, 568, 704, 705, - 638, 776, 617, 618, 619, 620, 621, 736, 875, 911, - 903, 904, 905, 912, 622, 623, 624, 625, 906, 878, - 626, 627, 907, 926, 628, 629, 630, 842, 740, 844, - 882, 901, 902, 631, 398, 399, 400, 424, 632, 470, - 471, 450, 451, 788, 789, 402, 673, 674, 678, 403, - 404, 684, 685, 688, 691, 405, 696, 697, 406, 452, - 453 + 0, 530, 531, 532, 798, 533, 534, 535, 536, 537, + 538, 539, 620, 541, 587, 588, 589, 590, 591, 592, + 593, 594, 595, 596, 597, 621, 856, 622, 781, 623, + 711, 624, 388, 651, 508, 625, 390, 391, 392, 437, + 438, 439, 393, 394, 395, 396, 397, 398, 487, 488, + 399, 400, 401, 402, 542, 490, 599, 493, 450, 451, + 544, 405, 406, 407, 579, 483, 577, 578, 721, 722, + 649, 793, 628, 629, 630, 631, 632, 753, 892, 928, + 920, 921, 922, 929, 633, 634, 635, 636, 923, 895, + 637, 638, 924, 943, 639, 640, 641, 859, 757, 861, + 899, 918, 919, 642, 408, 409, 410, 434, 643, 480, + 481, 460, 461, 805, 806, 412, 684, 685, 689, 413, + 414, 695, 696, 703, 704, 707, 415, 713, 714, 416, + 462, 463 }; - /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule whose - number is the opposite. If YYTABLE_NINF, syntax error. */ +/* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ static const yytype_int16 yytable[] = { - 394, 430, 401, 637, 768, 646, 445, 444, 588, 393, - 494, 445, 667, 377, 379, 841, 535, 772, 707, 775, - 446, 437, 777, 466, 708, 446, 786, 677, 667, 668, - 421, 475, 687, 719, 720, 730, 417, 407, 655, 661, - 910, 699, 662, 481, 661, 430, 658, 918, 541, 562, - 709, 482, 481, 563, 542, 476, 422, 910, 659, 634, - 787, 437, 669, 670, 671, 672, 633, 635, 418, 721, - 722, 731, 589, 663, 676, 408, 589, 437, 663, 676, - 590, 647, 648, 639, 492, 676, 481, 589, 676, 328, - 329, 330, 565, 493, 773, 778, 495, 676, 715, 496, - 716, -35, 497, 649, 745, 409, 747, 650, 456, 458, - 460, 462, 464, 465, 468, 543, 734, 827, 828, 829, - 830, 544, 843, 753, 754, 755, 756, 757, 758, 759, - 760, 761, 762, 549, 557, 432, 571, 410, 433, 550, - 558, 411, 572, 763, 637, 573, 637, 652, 412, 637, - 665, 574, 782, 653, 664, 780, 851, 415, 790, 707, - 664, 765, 664, 784, 542, 664, 693, 664, 413, 664, - 664, 792, 794, 796, 664, 799, 801, 793, 795, 797, - 414, 800, 802, 803, 806, 809, 565, 811, 565, 804, - 807, 810, 425, 812, 883, 884, 437, 889, 925, 890, - 765, 765, 891, 793, 892, 797, 893, 894, 800, 921, - 804, 426, 807, 812, 856, 765, 858, 419, 857, 642, - 859, 434, 643, 768, 680, 681, 682, 683, 454, 707, - 530, 455, 457, 717, 718, 455, 886, 445, 444, 765, - 459, 817, 766, 455, 818, 845, 852, 461, 853, 847, - 455, 446, 463, 467, 675, 455, 455, 455, 679, 565, - 686, 455, 689, 455, 692, 455, 698, 455, 765, 455, - 817, 846, 576, 872, 849, 850, 420, 862, 677, 816, - 667, 723, 724, 637, 866, 687, 712, 713, 714, 423, - 644, 645, 920, 765, 848, 765, 895, 823, 824, 439, - 825, 826, 831, 832, 447, 449, 469, 768, 474, 479, - 484, 325, 481, 490, 491, 536, 537, 538, 561, 540, - 539, 559, 657, 546, 676, 676, 545, 565, 547, 548, - 551, 676, 676, 552, 553, 554, 555, 676, 576, 676, - 556, 560, 874, 576, 570, 876, 564, 651, 656, 576, - 492, 641, 576, 725, 589, 666, 662, 727, 690, 700, - 703, 576, 726, 637, 728, 729, 711, 732, 737, 741, - 735, 738, 742, 746, 779, -36, 739, 743, 748, 783, - 576, 749, 431, -34, 750, 876, 751, -29, 798, 752, - 438, 393, 805, 791, 808, 813, 814, 565, 394, 393, - 401, 394, 913, 840, 855, 908, 394, 393, 401, 765, - 393, 377, 379, 868, 887, 393, 472, 922, 896, 637, - 448, 888, 898, 899, 879, 897, 431, 486, -569, 909, - 431, 915, 914, 591, 833, 393, 919, 927, 916, 393, - 928, 835, 834, 838, 416, 836, 438, 877, 837, 785, - 815, 710, 873, 880, 917, 393, 923, 881, 924, 769, - 900, 446, 770, 488, 771, 443, 701, 485, 487, 861, - 860, 863, 865, 566, 489, 864, 869, 867, 871, 870, - 0, 0, 393, 0, 616, 0, 0, 877, 0, 0, - 0, 0, 0, 615, 0, 0, 0, 0, 0, 0, - 0, 446, 0, 820, 821, 822, 576, 576, 576, 576, - 576, 576, 576, 576, 576, 576, 576, 576, 576, 576, - 576, 576, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 660, 0, + 404, 389, 411, 440, 648, 455, 387, 785, 454, 598, + 455, 504, 403, 540, 678, 712, 858, 545, 702, 725, + 657, 724, 456, 688, 679, 447, 747, 456, 476, 672, + 678, 789, 673, 792, 736, 737, 794, 716, 431, 666, + 427, 669, 803, 672, 927, 485, 726, 440, 491, 442, + 417, 935, 443, 670, 418, 586, 492, 680, 681, 682, + 683, 927, 748, 674, 432, 447, 419, 644, 646, 486, + 738, 739, 428, 655, 656, 687, 804, 674, -694, 420, + 491, 447, 658, 659, -694, 600, 687, 645, 502, 687, + 491, 795, 600, 601, 575, 449, 600, 503, 687, 650, + 551, 553, -35, 790, 660, 668, 552, 554, 661, 421, + 466, 468, 470, 472, 474, 475, 478, 422, 751, 559, + 762, 586, 764, 505, 567, 560, 506, 581, 423, 507, + 568, 860, 586, 582, 675, 586, 464, 583, 467, 465, + 675, 465, 675, 584, 586, 675, 648, 675, 648, 675, + 675, 648, 663, 797, 675, 676, 807, 809, 664, 782, + 811, 813, 552, 810, 586, 801, 812, 814, 799, 724, + 572, 709, 469, 424, 573, 465, 868, 770, 771, 772, + 773, 774, 775, 776, 777, 778, 779, 816, 575, 425, + 575, 471, 818, 817, 465, 820, 823, 780, 819, 942, + 447, 821, 824, 826, 828, 900, 901, 906, 907, 827, + 829, 782, 782, 810, 814, 908, 909, 910, 911, 938, + 429, 817, 821, 824, 829, 782, 873, 875, 734, 735, + 874, 876, 785, 802, 732, 430, 733, 455, 436, 724, + 454, 698, 699, 700, 701, 521, 844, 845, 846, 847, + 653, 433, 473, 654, 456, 465, 903, 691, 692, 693, + 694, 477, 575, 686, 465, 690, 465, 862, 465, 697, + 705, 864, 465, 465, 712, 435, 712, 702, 702, 449, + 879, 688, 866, 867, 869, 708, 870, 833, 465, 678, + 444, 648, 457, 837, 838, 839, 586, 586, 586, 586, + 586, 586, 586, 586, 586, 586, 586, 586, 586, 586, + 586, 586, 937, 459, 715, 782, 785, 465, 783, 834, + 782, 834, 835, 863, 889, 334, 335, 336, 740, 741, + 782, 865, 687, 687, 782, 912, 575, 729, 730, 731, + 840, 841, 479, 842, 843, 687, 484, 687, 331, 494, + 848, 849, 489, 500, 501, 491, 547, 548, 549, 546, + 555, 550, 574, 742, 891, 569, 556, 893, 652, 557, + 558, 648, 561, 562, 600, 563, 564, 565, 586, 586, + 566, 570, 571, 667, 580, 662, -34, 502, 706, 745, + 673, 586, 441, 586, 717, 746, 677, 743, 744, 749, + 448, 754, 752, 755, 403, 756, 575, 893, 404, 389, + 411, 404, 403, 925, 387, 720, 404, 458, 411, 758, + 403, 728, 759, 403, 930, 760, 482, 648, 403, 763, + 766, 765, -36, 815, 767, 768, 441, 496, 769, 939, + 441, 796, 800, -29, 808, 822, 825, 830, 403, 543, + 831, 857, 403, 894, 872, 885, 448, 782, 896, 904, + 905, 916, 913, 915, 926, 932, 914, -580, 403, 931, + 456, 602, 936, 850, 945, 944, 852, 851, 727, 933, + 497, 853, 426, 576, 854, 498, 832, 855, 897, 499, + 890, 934, 940, 894, 627, 403, 941, 495, 898, 786, + 917, 787, 718, 877, 882, 453, 626, 881, 878, 788, + 456, 886, 888, 880, 0, 0, 884, 0, 0, 0, + 0, 883, 0, 0, 0, 0, 0, 0, 887, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 702, 0, 566, 0, 566, - 0, 0, 0, 0, 393, 0, 393, 0, 393, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 576, 576, - 0, 0, 0, 0, 0, 576, 576, 0, 0, 0, - 0, 576, 0, 576, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 719, 0, 576, 0, 576, + 0, 0, 0, 0, 0, 0, 0, 403, 0, 403, + 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 616, 0, 0, 0, 0, 0, 0, 0, - 0, 615, 394, 0, 0, 0, 0, 0, 0, 0, - 566, 393, 0, 0, 0, 0, 0, 0, 0, 393, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 627, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 404, 0, 626, 0, 0, 0, 0, + 0, 576, 0, 0, 0, 403, 0, 0, 0, 0, + 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 566, 0, - 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, + 0, 0, 0, 0, 0, 576, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 616, 0, 0, 0, - 616, 0, 0, 0, 0, 615, 0, 0, 0, 615, + 0, 0, 0, 627, 0, 0, 0, 627, 0, 0, + 0, 0, 0, 0, 0, 626, 0, 0, 0, 626, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 566, 0, - 0, 0, 0, 0, 0, 0, 0, 393, 0, 0, + 0, 0, 0, 0, 0, 576, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 403, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 627, 627, + 0, 627, 0, 411, 0, 0, 0, 0, 0, 0, + 626, 626, 0, 626, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 616, 616, 0, 616, 0, 401, 0, 0, 0, - 615, 615, 0, 615, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 627, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 616, 0, 0, 0, 0, 0, 0, 0, - 0, 615, 0, 0, 0, 0, 0, 0, 616, 0, - 0, 0, 0, 0, 0, 616, 0, 615, 0, 0, - 0, 0, 0, 0, 615, 616, 0, 0, 0, 616, - 0, 0, 0, 0, 615, 616, 0, 0, 615, 0, - 0, 0, 442, 0, 615, 1, 2, 3, 4, 5, + 0, 626, 0, 0, 0, 627, 0, 0, 0, 0, + 0, 0, 627, 0, 0, 0, 0, 626, 0, 0, + 0, 0, 627, 0, 626, 0, 627, 0, 0, 0, + 0, 0, 627, 0, 626, 0, 0, 0, 626, 0, + 0, 0, 452, 0, 626, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -1810,20 +1790,21 @@ static const yytype_int16 yytable[] = 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 323, 324, 0, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 331, + 0, 0, 0, 0, 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, - 0, 326, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 327, 328, 329, 330, 331, - 0, 0, 0, 0, 0, 0, 0, 0, 332, 333, - 334, 335, 336, 337, 338, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, - 0, 0, 0, 0, 345, 0, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 0, 333, 334, 335, 336, 337, 0, 0, 0, 0, + 0, 0, 0, 0, 338, 339, 340, 341, 342, 343, + 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 345, 346, 347, 348, + 349, 350, 351, 0, 0, 0, 0, 0, 0, 0, + 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 1, 2, 3, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -1856,19 +1837,20 @@ static const yytype_int16 yytable[] = 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 0, 0, 499, 500, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 501, 502, 0, 325, 0, 591, 592, 0, - 0, 0, 0, 593, 503, 504, 505, 506, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 327, 328, 329, - 330, 331, 0, 0, 0, 507, 508, 509, 510, 511, - 332, 333, 334, 335, 336, 337, 338, 594, 595, 596, - 597, 0, 598, 599, 600, 601, 602, 603, 604, 605, - 606, 607, 339, 340, 341, 342, 343, 344, 512, 513, - 514, 515, 516, 517, 518, 519, 345, 608, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 324, 325, 326, 327, 328, 329, 330, 0, 0, 509, + 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 511, 512, + 0, 331, 0, 602, 603, 0, 0, 0, 0, 604, + 513, 514, 515, 516, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 333, 334, 335, 336, 337, 0, 0, + 0, 517, 518, 519, 520, 521, 338, 339, 340, 341, + 342, 343, 344, 605, 606, 607, 608, 0, 609, 610, + 611, 612, 613, 614, 615, 616, 617, 618, 345, 346, + 347, 348, 349, 350, 351, 522, 523, 524, 525, 526, + 527, 528, 529, 352, 619, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 1, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -1901,20 +1883,21 @@ static const yytype_int16 yytable[] = 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 0, 0, 499, 500, 0, 0, 0, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 0, + 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 501, 502, 0, 325, 0, 591, - 767, 0, 0, 0, 0, 593, 503, 504, 505, 506, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 327, - 328, 329, 330, 331, 0, 0, 0, 507, 508, 509, - 510, 511, 332, 333, 334, 335, 336, 337, 338, 594, - 595, 596, 597, 0, 598, 599, 600, 601, 602, 603, - 604, 605, 606, 607, 339, 340, 341, 342, 343, 344, - 512, 513, 514, 515, 516, 517, 518, 519, 345, 608, - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, + 511, 512, 0, 331, 0, 602, 784, 0, 0, 0, + 0, 604, 513, 514, 515, 516, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 333, 334, 335, 336, 337, + 0, 0, 0, 517, 518, 519, 520, 521, 338, 339, + 340, 341, 342, 343, 344, 605, 606, 607, 608, 0, + 609, 610, 611, 612, 613, 614, 615, 616, 617, 618, + 345, 346, 347, 348, 349, 350, 351, 522, 523, 524, + 525, 526, 527, 528, 529, 352, 619, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -1946,20 +1929,21 @@ static const yytype_int16 yytable[] = 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 323, 324, 0, 0, 499, 500, 0, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 501, 502, 0, 325, - 0, 591, 0, 0, 0, 0, 0, 593, 503, 504, - 505, 506, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 327, 328, 329, 330, 331, 0, 0, 0, 507, - 508, 509, 510, 511, 332, 333, 334, 335, 336, 337, - 338, 594, 595, 596, 597, 0, 598, 599, 600, 601, - 602, 603, 604, 605, 606, 607, 339, 340, 341, 342, - 343, 344, 512, 513, 514, 515, 516, 517, 518, 519, - 345, 608, 346, 347, 348, 349, 350, 351, 352, 353, + 0, 0, 511, 512, 0, 331, 0, 602, 0, 0, + 0, 0, 0, 604, 513, 514, 515, 516, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 333, 334, 335, + 336, 337, 0, 0, 0, 517, 518, 519, 520, 521, + 338, 339, 340, 341, 342, 343, 344, 605, 606, 607, + 608, 0, 609, 610, 611, 612, 613, 614, 615, 616, + 617, 618, 345, 346, 347, 348, 349, 350, 351, 522, + 523, 524, 525, 526, 527, 528, 529, 352, 619, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 1, 2, 3, 4, 5, 6, 7, + 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -1991,20 +1975,21 @@ static const yytype_int16 yytable[] = 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 0, 0, 499, - 500, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 501, 502, - 0, 325, 0, 484, 0, 0, 0, 0, 0, 593, - 503, 504, 505, 506, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 327, 328, 329, 330, 331, 0, 0, - 0, 507, 508, 509, 510, 511, 332, 333, 334, 335, - 336, 337, 338, 594, 595, 596, 597, 0, 598, 599, - 600, 601, 602, 603, 604, 605, 606, 607, 339, 340, - 341, 342, 343, 344, 512, 513, 514, 515, 516, 517, - 518, 519, 345, 608, 346, 347, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 511, 512, 0, 331, 0, 494, + 0, 0, 0, 0, 0, 604, 513, 514, 515, 516, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, + 334, 335, 336, 337, 0, 0, 0, 517, 518, 519, + 520, 521, 338, 339, 340, 341, 342, 343, 344, 605, + 606, 607, 608, 0, 609, 610, 611, 612, 613, 614, + 615, 616, 617, 618, 345, 346, 347, 348, 349, 350, + 351, 522, 523, 524, 525, 526, 527, 528, 529, 352, + 619, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 1, 2, 3, 4, 5, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -2036,20 +2021,21 @@ static const yytype_int16 yytable[] = 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, 317, 318, 319, 320, 321, 322, 323, 324, 0, - 0, 499, 500, 0, 0, 0, 0, 0, 0, 0, + 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, + 326, 327, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 501, 502, 0, 325, 0, 0, 0, 0, 0, 0, - 0, 593, 503, 504, 505, 506, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 327, 328, 329, 330, 331, - 0, 0, 0, 507, 508, 509, 510, 511, 332, 333, - 334, 335, 336, 337, 338, 594, 595, 596, 597, 0, - 598, 599, 600, 601, 602, 603, 604, 605, 606, 607, - 339, 340, 341, 342, 343, 344, 512, 513, 514, 515, - 516, 517, 518, 519, 345, 608, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 0, 0, 0, 0, 0, 0, 511, 512, 0, 331, + 0, 0, 0, 0, 0, 0, 0, 604, 513, 514, + 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 333, 334, 335, 336, 337, 0, 0, 0, 517, + 518, 519, 520, 521, 338, 339, 340, 341, 342, 343, + 344, 605, 606, 607, 608, 0, 609, 610, 611, 612, + 613, 614, 615, 616, 617, 618, 345, 346, 347, 348, + 349, 350, 351, 522, 523, 524, 525, 526, 527, 528, + 529, 352, 619, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 1, 2, 3, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -2082,19 +2068,20 @@ static const yytype_int16 yytable[] = 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 0, 0, 499, 500, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 501, 502, 0, 325, 0, 0, 0, 0, - 0, 0, 0, 593, 503, 504, 505, 506, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 327, 328, 329, - 330, 331, 0, 0, 0, 507, 508, 509, 510, 511, - 332, 333, 334, 335, 336, 337, 338, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 339, 340, 341, 342, 343, 344, 512, 513, - 514, 515, 516, 517, 518, 519, 345, 0, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 324, 325, 326, 327, 328, 329, 330, 0, 0, 509, + 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 511, 512, + 0, 331, 0, 0, 0, 0, 0, 0, 0, 604, + 513, 514, 515, 516, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 333, 334, 335, 336, 337, 0, 0, + 0, 517, 518, 519, 520, 521, 338, 339, 340, 341, + 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, + 347, 348, 349, 350, 351, 522, 523, 524, 525, 526, + 527, 528, 529, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 1, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -2126,21 +2113,22 @@ static const yytype_int16 yytable[] = 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 0, 0, 0, 318, 319, 320, 321, - 322, 323, 324, 0, 0, 499, 500, 0, 0, 0, + 312, 313, 314, 315, 316, 317, 0, 0, 0, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 0, + 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 501, 502, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 503, 504, 505, 506, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 327, - 328, 329, 330, 0, 0, 0, 0, 507, 508, 509, - 510, 511, 332, 333, 334, 335, 336, 337, 338, 0, + 511, 512, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 513, 514, 515, 516, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 333, 334, 335, 336, 0, + 0, 0, 0, 517, 518, 519, 520, 521, 338, 339, + 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 339, 340, 341, 342, 343, 344, - 512, 513, 514, 515, 516, 517, 518, 519, 345, 0, - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, + 345, 346, 347, 348, 349, 350, 351, 522, 523, 524, + 525, 526, 527, 528, 529, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -2172,20 +2160,21 @@ static const yytype_int16 yytable[] = 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 323, 324, 0, 0, 0, 0, 0, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 325, - 0, 0, 0, 0, 0, 0, 0, 326, 0, 0, + 0, 0, 0, 0, 0, 331, 0, 0, 0, 0, + 0, 0, 0, 332, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 333, 334, 335, + 336, 337, 0, 0, 0, 0, 0, 0, 0, 0, + 338, 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 327, 328, 329, 330, 331, 0, 0, 0, 0, - 0, 0, 0, 0, 332, 333, 334, 335, 336, 337, - 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 339, 340, 341, 342, - 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, - 345, 0, 346, 347, 348, 349, 350, 351, 352, 353, + 0, 0, 345, 346, 347, 348, 349, 350, 351, 0, + 0, 0, 0, 0, 0, 0, 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 1, 2, 3, 4, 5, 6, 7, + 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -2216,21 +2205,22 @@ static const yytype_int16 yytable[] = 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 0, 0, 0, - 318, 319, 320, 321, 322, 323, 324, 0, 0, 0, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 0, 0, 0, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 327, 328, 329, 330, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 332, 333, 334, 335, - 336, 337, 338, 594, 0, 0, 597, 0, 598, 599, - 0, 0, 602, 0, 0, 0, 0, 0, 339, 340, - 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, - 0, 0, 345, 0, 346, 347, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, + 334, 335, 336, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 338, 339, 340, 341, 342, 343, 344, 605, + 0, 0, 608, 0, 609, 610, 0, 0, 613, 0, + 0, 0, 0, 0, 345, 346, 347, 348, 349, 350, + 351, 0, 0, 0, 0, 0, 0, 0, 0, 352, + 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 1, 2, 3, 4, 5, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -2261,21 +2251,22 @@ static const yytype_int16 yytable[] = 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 0, - 0, 0, 318, 319, 320, 321, 322, 323, 324, 0, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 0, 0, 0, 321, 322, 323, 324, 325, + 326, 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 445, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 435, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 327, 328, 329, 330, 0, - 0, 0, 0, 0, 0, 0, 0, 436, 332, 333, - 334, 335, 336, 337, 338, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, - 0, 0, 0, 0, 345, 0, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 0, 333, 334, 335, 336, 0, 0, 0, 0, 0, + 0, 0, 0, 446, 338, 339, 340, 341, 342, 343, + 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 345, 346, 347, 348, + 349, 350, 351, 0, 0, 0, 0, 0, 0, 0, + 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 1, 2, 3, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -2307,20 +2298,21 @@ static const yytype_int16 yytable[] = 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 0, 0, 0, 318, 319, 320, 321, 322, 323, - 324, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 314, 315, 316, 317, 0, 0, 0, 321, 322, 323, + 324, 325, 326, 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 325, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 327, 328, 329, - 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 332, 333, 334, 335, 336, 337, 338, 0, 0, 0, + 0, 331, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 339, 340, 341, 342, 343, 344, 0, 0, - 0, 0, 0, 0, 0, 0, 345, 0, 346, 347, - 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, + 0, 0, 0, 333, 334, 335, 336, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 338, 339, 340, 341, + 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 345, 346, + 347, 348, 349, 350, 351, 0, 0, 0, 0, 0, + 0, 0, 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, - 368, 369, 370, 371, 372, 373, 374, 375, 376, 1, + 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -2352,21 +2344,22 @@ static const yytype_int16 yytable[] = 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 0, 0, 0, 318, 319, 320, 321, - 322, 323, 324, 0, 0, 0, 0, 0, 0, 0, + 312, 313, 314, 315, 316, 317, 0, 0, 0, 321, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 706, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 327, - 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 332, 333, 334, 335, 336, 337, 338, 0, + 0, 0, 0, 0, 0, 0, 723, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 339, 340, 341, 342, 343, 344, - 0, 0, 0, 0, 0, 0, 0, 0, 345, 0, - 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, + 0, 0, 0, 0, 0, 333, 334, 335, 336, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 338, 339, + 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 345, 346, 347, 348, 349, 350, 351, 0, 0, 0, + 0, 0, 0, 0, 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, - 376, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 376, 377, 378, 379, 380, 381, 382, 383, 384, 385, + 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -2397,21 +2390,22 @@ static const yytype_int16 yytable[] = 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 0, 0, 0, 318, 319, - 320, 321, 322, 323, 324, 0, 0, 0, 0, 0, + 310, 311, 312, 313, 314, 315, 316, 317, 0, 0, + 0, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 836, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 819, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 333, 334, 335, + 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 338, 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 327, 328, 329, 330, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 332, 333, 334, 335, 336, 337, - 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 339, 340, 341, 342, - 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, - 345, 0, 346, 347, 348, 349, 350, 351, 352, 353, + 0, 0, 345, 346, 347, 348, 349, 350, 351, 0, + 0, 0, 0, 0, 0, 0, 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, - 374, 375, 376, 1, 2, 3, 4, 5, 6, 7, + 374, 375, 376, 377, 378, 379, 380, 381, 382, 383, + 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -2442,21 +2436,22 @@ static const yytype_int16 yytable[] = 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 0, 0, 0, - 318, 319, 320, 321, 322, 323, 324, 0, 0, 0, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 0, 0, 0, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 854, 0, 0, 0, 0, 0, + 871, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 333, + 334, 335, 336, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 338, 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 327, 328, 329, 330, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 332, 333, 334, 335, - 336, 337, 338, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 339, 340, - 341, 342, 343, 344, 0, 0, 0, 0, 0, 0, - 0, 0, 345, 0, 346, 347, 348, 349, 350, 351, - 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, + 0, 0, 0, 0, 345, 346, 347, 348, 349, 350, + 351, 0, 0, 0, 0, 0, 0, 0, 0, 352, + 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, - 372, 373, 374, 375, 376, 1, 2, 3, 4, 5, + 372, 373, 374, 375, 376, 377, 378, 379, 380, 381, + 382, 383, 384, 385, 386, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -2487,21 +2482,22 @@ static const yytype_int16 yytable[] = 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 0, - 0, 0, 318, 319, 320, 321, 322, 323, 324, 0, + 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, + 316, 317, 0, 0, 0, 321, 322, 323, 324, 325, + 326, 327, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 327, 328, 329, 330, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 332, 333, - 334, 335, 336, 337, 338, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 339, 340, 341, 342, 343, 344, 0, 0, 0, 0, - 0, 0, 0, 0, 345, 0, 346, 347, 348, 349, - 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, + 0, 333, 334, 335, 336, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 338, 339, 340, 341, 342, 343, + 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 345, 346, 347, 348, + 349, 350, 351, 0, 0, 0, 0, 0, 0, 0, + 0, 352, 0, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, - 370, 371, 372, 373, 374, 375, 376, 2, 3, 4, + 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, + 380, 381, 382, 383, 384, 385, 386, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, @@ -2518,7 +2514,7 @@ static const yytype_int16 yytable[] = 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, @@ -2533,502 +2529,511 @@ static const yytype_int16 yytable[] = 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 0, 0, 0, 0, 0, 0, 321, 0, 0, 0, - 0, 0, 499, 500, 0, 0, 0, 0, 0, 0, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 501, 502, 0, 0, 0, 636, 774, 0, 0, - 0, 0, 0, 503, 504, 505, 506, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 647, 791, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 507, 508, 509, 510, 511, 332, - 0, 0, 0, 0, 337, 338, 0, 0, 0, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 512, 513, 514, - 515, 516, 517, 518, 519, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 358, - 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 0, 0, 61, - 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 0, 0, 0, 0, 0, 0, 321, - 0, 0, 0, 0, 0, 499, 500, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 501, 502, 0, 0, 0, 636, - 885, 0, 0, 0, 0, 0, 503, 504, 505, 506, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 647, 902, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 507, 508, 509, - 510, 511, 332, 0, 0, 0, 0, 337, 338, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 512, 513, 514, 515, 516, 517, 518, 519, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 585, 0, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 358, 2, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 0, 0, 61, 62, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 0, 0, 0, 0, - 0, 0, 321, 0, 0, 0, 0, 0, 499, 500, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 501, 502, 0, - 0, 575, 0, 0, 0, 0, 0, 0, 0, 503, - 504, 505, 506, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 507, 508, 509, 510, 511, 332, 0, 0, 0, 0, - 337, 338, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 647, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 512, 513, 514, 515, 516, 517, 518, - 519, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 358, 2, 3, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 0, 0, 61, 62, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 0, - 0, 0, 0, 0, 0, 321, 0, 0, 0, 0, - 0, 499, 500, 0, 0, 0, 0, 0, 0, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 501, 502, 0, 0, 0, 636, 0, 0, 0, 0, - 0, 0, 503, 504, 505, 506, 0, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 507, 508, 509, 510, 511, 332, 0, - 0, 0, 0, 337, 338, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 750, 0, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 512, 513, 514, 515, - 516, 517, 518, 519, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 358, 2, - 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 0, 0, 61, 62, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, - 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, - 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 0, 0, 0, 0, 0, 0, 321, 0, - 0, 0, 0, 0, 499, 500, 0, 0, 0, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 501, 502, 0, 0, 733, 0, 0, - 0, 0, 0, 0, 0, 503, 504, 505, 506, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 507, 508, 509, 510, - 511, 332, 0, 0, 0, 0, 337, 338, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 761, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 512, - 513, 514, 515, 516, 517, 518, 519, 0, 0, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 358, 2, 3, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 0, - 0, 61, 62, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 0, 0, 0, 0, 0, - 0, 321, 0, 0, 0, 0, 0, 499, 500, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 501, 502, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 744, 503, 504, - 505, 506, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 507, - 508, 509, 510, 511, 332, 0, 0, 0, 0, 337, - 338, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 512, 513, 514, 515, 516, 517, 518, 519, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 358, 2, 3, 4, 5, 6, - 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, - 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 0, 0, 61, 62, 63, 64, 65, 66, - 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, - 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, - 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, - 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, - 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, - 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, - 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, - 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, - 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, - 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, - 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, - 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, - 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, - 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, - 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, - 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, - 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, - 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, - 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, - 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, - 307, 308, 309, 310, 311, 312, 313, 314, 0, 0, - 0, 0, 0, 0, 321, 0, 0, 0, 0, 0, - 499, 500, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 501, - 502, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 503, 504, 505, 506, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 507, 508, 509, 510, 511, 332, 0, 0, - 0, 0, 337, 338, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 512, 513, 514, 515, 516, - 517, 518, 519, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 358, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 0, 0, 61, 62, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, - 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 0, 0, 0, 0, 0, 0, 321, 0, 0, - 0, 0, 0, 499, 500, 0, 0, 0, 0, 0, + 517, 518, 519, 520, 521, 338, 0, 0, 0, 0, + 343, 665, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 501, 502, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 503, 504, 505, 506, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 509, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 507, 508, 509, 510, 511, - 332, 0, 0, 0, 0, 337, 654, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 511, 512, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 513, + 514, 515, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 512, 513, - 514, 515, 516, 517, 518, 519, 0, 0, 0, 0, + 517, 518, 519, 520, 710, 338, 0, 0, 0, 0, + 343, 344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 358, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 0, 0, - 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 0, 0, 0, 0, 0, 0, - 321, 0, 0, 0, 0, 0, 499, 500, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 501, 502, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 503, 504, 505, - 506, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 507, 508, - 509, 510, 694, 332, 0, 0, 0, 0, 337, 338, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 512, 513, 514, 515, 516, 517, 518, 519, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 358, 2, 3, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 0, 0, 61, 62, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 0, 0, 0, - 0, 0, 0, 321, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 522, 523, 524, 525, 526, 527, + 528, 529, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 365, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, + 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, + 55, 56, 57, 58, 0, 0, 61, 62, 63, 64, + 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, + 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, + 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, + 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, + 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, + 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, + 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, + 165, 0, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, + 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, + 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, + 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, + 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, + 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, + 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 0, 0, 0, 0, 0, 0, 324, + 0, 0, 0, 328, 329, 330, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 332, 0, 0, 0, - 0, 337, 338 + 0, 0, 0, 0, 0, 338, 0, 0, 0, 0, + 343, 344 }; static const yytype_int16 yycheck[] = { - 0, 382, 0, 493, 622, 502, 401, 401, 481, 0, - 434, 406, 542, 0, 0, 736, 440, 634, 567, 636, - 401, 390, 639, 413, 569, 406, 348, 547, 558, 348, - 359, 385, 552, 331, 332, 336, 353, 349, 528, 348, - 898, 561, 351, 351, 348, 426, 356, 905, 350, 352, - 570, 359, 351, 356, 356, 409, 385, 915, 368, 358, - 382, 430, 381, 382, 383, 384, 490, 491, 385, 367, - 368, 372, 351, 382, 547, 349, 351, 446, 382, 552, - 359, 329, 330, 358, 349, 558, 351, 351, 561, 374, - 375, 376, 473, 358, 358, 640, 353, 570, 361, 356, - 363, 349, 359, 351, 601, 349, 603, 355, 408, 409, - 410, 411, 412, 413, 414, 350, 589, 719, 720, 721, - 722, 356, 740, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 350, 350, 356, 350, 349, 359, 356, - 356, 349, 356, 358, 634, 350, 636, 350, 349, 639, - 540, 356, 649, 356, 540, 350, 773, 351, 350, 708, - 546, 356, 548, 653, 356, 551, 556, 553, 349, 555, - 556, 350, 350, 350, 560, 350, 350, 356, 356, 356, - 349, 356, 356, 350, 350, 350, 567, 350, 569, 356, - 356, 356, 350, 356, 350, 350, 565, 350, 919, 350, - 356, 356, 350, 356, 350, 356, 350, 350, 356, 350, - 356, 356, 356, 356, 352, 356, 352, 349, 356, 356, - 356, 385, 359, 841, 381, 382, 383, 384, 382, 778, - 439, 385, 382, 327, 328, 385, 853, 632, 632, 356, - 382, 356, 359, 385, 359, 742, 354, 382, 356, 746, - 385, 632, 382, 382, 382, 385, 385, 385, 382, 640, - 382, 385, 382, 385, 382, 385, 382, 385, 356, 385, - 356, 359, 481, 359, 764, 765, 349, 797, 798, 703, - 810, 333, 334, 773, 804, 805, 364, 365, 366, 359, - 499, 500, 909, 356, 357, 356, 357, 715, 716, 367, - 717, 718, 723, 724, 359, 385, 385, 925, 353, 385, - 353, 351, 351, 385, 385, 350, 385, 359, 349, 356, - 358, 350, 531, 356, 797, 798, 358, 708, 356, 356, - 356, 804, 805, 356, 356, 356, 356, 810, 547, 812, - 356, 356, 839, 552, 358, 842, 359, 350, 349, 558, - 349, 385, 561, 371, 351, 385, 351, 369, 348, 352, - 385, 570, 370, 853, 335, 337, 385, 352, 349, 349, - 354, 359, 349, 349, 385, 349, 359, 359, 357, 385, - 589, 359, 382, 349, 359, 882, 359, 350, 356, 359, - 390, 382, 356, 358, 356, 350, 350, 778, 398, 390, - 398, 401, 899, 352, 352, 895, 406, 398, 406, 356, - 401, 398, 398, 348, 348, 406, 416, 914, 354, 909, - 406, 382, 350, 349, 393, 385, 426, 425, 353, 358, - 430, 350, 359, 353, 725, 426, 353, 359, 397, 430, - 354, 727, 726, 730, 331, 728, 446, 842, 729, 658, - 702, 572, 817, 844, 904, 446, 915, 844, 916, 632, - 882, 842, 632, 430, 632, 398, 563, 424, 426, 795, - 793, 798, 802, 473, 430, 800, 808, 805, 812, 810, - -1, -1, 473, -1, 484, -1, -1, 882, -1, -1, - -1, -1, -1, 484, -1, -1, -1, -1, -1, -1, - -1, 882, -1, 712, 713, 714, 715, 716, 717, 718, - 719, 720, 721, 722, 723, 724, 725, 726, 727, 728, - 729, 730, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 536, -1, + 0, 0, 0, 392, 503, 411, 0, 633, 411, 491, + 416, 444, 0, 449, 552, 568, 753, 450, 562, 579, + 512, 577, 411, 557, 354, 400, 342, 416, 423, 354, + 568, 645, 357, 647, 337, 338, 650, 571, 365, 538, + 359, 362, 354, 354, 915, 391, 580, 436, 357, 362, + 355, 922, 365, 374, 355, 491, 365, 387, 388, 389, + 390, 932, 378, 388, 391, 440, 355, 500, 501, 415, + 373, 374, 391, 509, 510, 557, 388, 388, 356, 355, + 357, 456, 335, 336, 362, 357, 568, 364, 355, 571, + 357, 651, 357, 365, 483, 373, 357, 364, 580, 364, + 356, 356, 355, 364, 357, 541, 362, 362, 361, 355, + 418, 419, 420, 421, 422, 423, 424, 355, 600, 356, + 612, 557, 614, 359, 356, 362, 362, 356, 355, 365, + 362, 757, 568, 362, 550, 571, 388, 356, 388, 391, + 556, 391, 558, 362, 580, 561, 645, 563, 647, 565, + 566, 650, 356, 356, 570, 550, 356, 356, 362, 362, + 356, 356, 362, 362, 600, 664, 362, 362, 660, 725, + 358, 566, 388, 355, 362, 391, 790, 344, 345, 346, + 347, 348, 349, 350, 351, 352, 353, 356, 577, 357, + 579, 388, 356, 362, 391, 356, 356, 364, 362, 936, + 575, 362, 362, 356, 356, 356, 356, 356, 356, 362, + 362, 362, 362, 362, 362, 356, 356, 356, 356, 356, + 355, 362, 362, 362, 362, 362, 358, 358, 333, 334, + 362, 362, 858, 669, 367, 355, 369, 643, 362, 795, + 643, 387, 388, 389, 390, 391, 736, 737, 738, 739, + 362, 365, 388, 365, 643, 391, 870, 387, 388, 389, + 390, 388, 651, 388, 391, 388, 391, 759, 391, 388, + 388, 763, 391, 391, 827, 356, 829, 821, 822, 373, + 814, 815, 781, 782, 360, 388, 362, 720, 391, 827, + 391, 790, 365, 729, 730, 731, 732, 733, 734, 735, + 736, 737, 738, 739, 740, 741, 742, 743, 744, 745, + 746, 747, 926, 391, 388, 362, 942, 391, 365, 362, + 362, 362, 365, 365, 365, 380, 381, 382, 339, 340, + 362, 363, 814, 815, 362, 363, 725, 370, 371, 372, + 732, 733, 391, 734, 735, 827, 359, 829, 357, 359, + 740, 741, 391, 391, 391, 357, 391, 365, 364, 356, + 364, 362, 365, 377, 856, 356, 362, 859, 391, 362, + 362, 870, 362, 362, 357, 362, 362, 362, 814, 815, + 362, 362, 355, 355, 364, 356, 355, 355, 354, 341, + 357, 827, 392, 829, 358, 343, 391, 376, 375, 358, + 400, 355, 360, 365, 392, 365, 795, 899, 408, 408, + 408, 411, 400, 912, 408, 391, 416, 416, 416, 355, + 408, 391, 355, 411, 916, 365, 426, 926, 416, 355, + 365, 363, 355, 362, 365, 365, 436, 435, 365, 931, + 440, 391, 391, 356, 364, 362, 362, 356, 436, 449, + 356, 358, 440, 859, 358, 354, 456, 362, 399, 354, + 388, 355, 360, 356, 364, 356, 391, 359, 456, 365, + 859, 359, 359, 742, 360, 365, 744, 743, 582, 403, + 436, 745, 337, 483, 746, 440, 719, 747, 861, 440, + 834, 921, 932, 899, 494, 483, 933, 434, 861, 643, + 899, 643, 573, 810, 819, 408, 494, 817, 812, 643, + 899, 825, 829, 815, -1, -1, 822, -1, -1, -1, + -1, 821, -1, -1, -1, -1, -1, -1, 827, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 546, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 565, -1, 567, -1, 569, - -1, -1, -1, -1, 565, -1, 567, -1, 569, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 797, 798, - -1, -1, -1, -1, -1, 804, 805, -1, -1, -1, - -1, 810, -1, 812, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 575, -1, 577, -1, 579, + -1, -1, -1, -1, -1, -1, -1, 575, -1, 577, + -1, 579, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 622, -1, -1, -1, -1, -1, -1, -1, - -1, 622, 632, -1, -1, -1, -1, -1, -1, -1, - 640, 632, -1, -1, -1, -1, -1, -1, -1, 640, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 633, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 643, -1, 633, -1, -1, -1, -1, + -1, 651, -1, -1, -1, 643, -1, -1, -1, -1, + -1, -1, -1, 651, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 708, -1, - -1, -1, -1, -1, -1, -1, -1, 708, -1, -1, + -1, -1, -1, -1, -1, 725, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 725, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 736, -1, -1, -1, - 740, -1, -1, -1, -1, 736, -1, -1, -1, 740, + -1, -1, -1, 753, -1, -1, -1, 757, -1, -1, + -1, -1, -1, -1, -1, 753, -1, -1, -1, 757, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 778, -1, - -1, -1, -1, -1, -1, -1, -1, 778, -1, -1, + -1, -1, -1, -1, -1, 795, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 795, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 858, 859, + -1, 861, -1, 861, -1, -1, -1, -1, -1, -1, + 858, 859, -1, 861, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 841, 842, -1, 844, -1, 844, -1, -1, -1, - 841, 842, -1, 844, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 899, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 882, -1, -1, -1, -1, -1, -1, -1, - -1, 882, -1, -1, -1, -1, -1, -1, 898, -1, - -1, -1, -1, -1, -1, 905, -1, 898, -1, -1, - -1, -1, -1, -1, 905, 915, -1, -1, -1, 919, - -1, -1, -1, -1, 915, 925, -1, -1, 919, -1, - -1, -1, 0, -1, 925, 3, 4, 5, 6, 7, + -1, 899, -1, -1, -1, 915, -1, -1, -1, -1, + -1, -1, 922, -1, -1, -1, -1, 915, -1, -1, + -1, -1, 932, -1, 922, -1, 936, -1, -1, -1, + -1, -1, 942, -1, 932, -1, -1, -1, 936, -1, + -1, -1, 0, -1, 942, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -3060,20 +3065,21 @@ static const yytype_int16 yycheck[] = 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 326, -1, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 357, + -1, -1, -1, -1, -1, -1, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 351, -1, -1, -1, -1, -1, -1, - -1, 359, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 373, 374, 375, 376, 377, - -1, -1, -1, -1, -1, -1, -1, -1, 386, 387, - 388, 389, 390, 391, 392, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 408, 409, 410, 411, 412, 413, -1, -1, -1, -1, - -1, -1, -1, -1, 422, -1, 424, 425, 426, 427, - 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + -1, 379, 380, 381, 382, 383, -1, -1, -1, -1, + -1, -1, -1, -1, 392, 393, 394, 395, 396, 397, + 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 414, 415, 416, 417, + 418, 419, 420, -1, -1, -1, -1, -1, -1, -1, + -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 3, 4, 5, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -3106,19 +3112,20 @@ static const yytype_int16 yycheck[] = 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, - 326, -1, -1, 329, 330, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 348, 349, -1, 351, -1, 353, 354, -1, - -1, -1, -1, 359, 360, 361, 362, 363, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 373, 374, 375, - 376, 377, -1, -1, -1, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, 393, 394, 395, - 396, -1, 398, 399, 400, 401, 402, 403, 404, 405, + 326, 327, 328, 329, 330, 331, 332, -1, -1, 335, + 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 354, 355, + -1, 357, -1, 359, 360, -1, -1, -1, -1, 365, + 366, 367, 368, 369, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 379, 380, 381, 382, 383, -1, -1, + -1, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, 399, 400, 401, 402, -1, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 3, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -3151,20 +3158,21 @@ static const yytype_int16 yycheck[] = 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, - 324, 325, 326, -1, -1, 329, 330, -1, -1, -1, + 324, 325, 326, 327, 328, 329, 330, 331, 332, -1, + -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 348, 349, -1, 351, -1, 353, - 354, -1, -1, -1, -1, 359, 360, 361, 362, 363, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 373, - 374, 375, 376, 377, -1, -1, -1, 381, 382, 383, - 384, 385, 386, 387, 388, 389, 390, 391, 392, 393, - 394, 395, 396, -1, 398, 399, 400, 401, 402, 403, + 354, 355, -1, 357, -1, 359, 360, -1, -1, -1, + -1, 365, 366, 367, 368, 369, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 379, 380, 381, 382, 383, + -1, -1, -1, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, 402, -1, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, + 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, @@ -3196,20 +3204,21 @@ static const yytype_int16 yycheck[] = 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, -1, -1, 329, 330, -1, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 348, 349, -1, 351, - -1, 353, -1, -1, -1, -1, -1, 359, 360, 361, - 362, 363, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 373, 374, 375, 376, 377, -1, -1, -1, 381, - 382, 383, 384, 385, 386, 387, 388, 389, 390, 391, - 392, 393, 394, 395, 396, -1, 398, 399, 400, 401, - 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, + -1, -1, 354, 355, -1, 357, -1, 359, -1, -1, + -1, -1, -1, 365, 366, 367, 368, 369, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 379, 380, 381, + 382, 383, -1, -1, -1, 387, 388, 389, 390, 391, + 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, + 402, -1, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 3, 4, 5, 6, 7, 8, 9, + 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -3241,20 +3250,21 @@ static const yytype_int16 yycheck[] = 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, - 320, 321, 322, 323, 324, 325, 326, -1, -1, 329, - 330, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 348, 349, - -1, 351, -1, 353, -1, -1, -1, -1, -1, 359, - 360, 361, 362, 363, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 373, 374, 375, 376, 377, -1, -1, - -1, 381, 382, 383, 384, 385, 386, 387, 388, 389, - 390, 391, 392, 393, 394, 395, 396, -1, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, + 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 354, 355, -1, 357, -1, 359, + -1, -1, -1, -1, -1, 365, 366, 367, 368, 369, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 379, + 380, 381, 382, 383, -1, -1, -1, 387, 388, 389, + 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, + 400, 401, 402, -1, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 453, 454, 3, 4, 5, 6, 7, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -3286,20 +3296,21 @@ static const yytype_int16 yycheck[] = 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, - 318, 319, 320, 321, 322, 323, 324, 325, 326, -1, - -1, 329, 330, -1, -1, -1, -1, -1, -1, -1, + 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 348, 349, -1, 351, -1, -1, -1, -1, -1, -1, - -1, 359, 360, 361, 362, 363, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 373, 374, 375, 376, 377, - -1, -1, -1, 381, 382, 383, 384, 385, 386, 387, - 388, 389, 390, 391, 392, 393, 394, 395, 396, -1, - 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, + -1, -1, -1, -1, -1, -1, 354, 355, -1, 357, + -1, -1, -1, -1, -1, -1, -1, 365, 366, 367, + 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 379, 380, 381, 382, 383, -1, -1, -1, 387, + 388, 389, 390, 391, 392, 393, 394, 395, 396, 397, + 398, 399, 400, 401, 402, -1, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 3, 4, 5, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -3332,19 +3343,20 @@ static const yytype_int16 yycheck[] = 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, - 326, -1, -1, 329, 330, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 348, 349, -1, 351, -1, -1, -1, -1, - -1, -1, -1, 359, 360, 361, 362, 363, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 373, 374, 375, - 376, 377, -1, -1, -1, 381, 382, 383, 384, 385, - 386, 387, 388, 389, 390, 391, 392, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 408, 409, 410, 411, 412, 413, 414, 415, - 416, 417, 418, 419, 420, 421, 422, -1, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, + 326, 327, 328, 329, 330, 331, 332, -1, -1, 335, + 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 354, 355, + -1, 357, -1, -1, -1, -1, -1, -1, -1, 365, + 366, 367, 368, 369, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 379, 380, 381, 382, 383, -1, -1, + -1, 387, 388, 389, 390, 391, 392, 393, 394, 395, + 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 414, 415, + 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, + 426, 427, 428, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 3, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -3376,21 +3388,22 @@ static const yytype_int16 yycheck[] = 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, -1, -1, -1, 320, 321, 322, 323, - 324, 325, 326, -1, -1, 329, 330, -1, -1, -1, + 314, 315, 316, 317, 318, 319, -1, -1, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, -1, + -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 348, 349, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 360, 361, 362, 363, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 373, - 374, 375, 376, -1, -1, -1, -1, 381, 382, 383, - 384, 385, 386, 387, 388, 389, 390, 391, 392, -1, + 354, 355, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 366, 367, 368, 369, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 379, 380, 381, 382, -1, + -1, -1, -1, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 408, 409, 410, 411, 412, 413, - 414, 415, 416, 417, 418, 419, 420, 421, 422, -1, - 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, + 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, + 424, 425, 426, 427, 428, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, + 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, @@ -3422,20 +3435,21 @@ static const yytype_int16 yycheck[] = 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, -1, -1, -1, -1, -1, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 351, - -1, -1, -1, -1, -1, -1, -1, 359, -1, -1, + -1, -1, -1, -1, -1, 357, -1, -1, -1, -1, + -1, -1, -1, 365, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 379, 380, 381, + 382, 383, -1, -1, -1, -1, -1, -1, -1, -1, + 392, 393, 394, 395, 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 373, 374, 375, 376, 377, -1, -1, -1, -1, - -1, -1, -1, -1, 386, 387, 388, 389, 390, 391, - 392, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 408, 409, 410, 411, - 412, 413, -1, -1, -1, -1, -1, -1, -1, -1, - 422, -1, 424, 425, 426, 427, 428, 429, 430, 431, + -1, -1, 414, 415, 416, 417, 418, 419, 420, -1, + -1, -1, -1, -1, -1, -1, -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 3, 4, 5, 6, 7, 8, 9, + 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -3466,21 +3480,22 @@ static const yytype_int16 yycheck[] = 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, -1, -1, -1, - 320, 321, 322, 323, 324, 325, 326, -1, -1, -1, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + -1, -1, -1, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 373, 374, 375, 376, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 386, 387, 388, 389, - 390, 391, 392, 393, -1, -1, 396, -1, 398, 399, - -1, -1, 402, -1, -1, -1, -1, -1, 408, 409, - 410, 411, 412, 413, -1, -1, -1, -1, -1, -1, - -1, -1, 422, -1, 424, 425, 426, 427, 428, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 379, + 380, 381, 382, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 392, 393, 394, 395, 396, 397, 398, 399, + -1, -1, 402, -1, 404, 405, -1, -1, 408, -1, + -1, -1, -1, -1, 414, 415, 416, 417, 418, 419, + 420, -1, -1, -1, -1, -1, -1, -1, -1, 429, + -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 453, 454, 3, 4, 5, 6, 7, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -3511,21 +3526,22 @@ static const yytype_int16 yycheck[] = 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, -1, - -1, -1, 320, 321, 322, 323, 324, 325, 326, -1, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, -1, -1, -1, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 365, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 359, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 373, 374, 375, 376, -1, - -1, -1, -1, -1, -1, -1, -1, 385, 386, 387, - 388, 389, 390, 391, 392, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 408, 409, 410, 411, 412, 413, -1, -1, -1, -1, - -1, -1, -1, -1, 422, -1, 424, 425, 426, 427, - 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + -1, 379, 380, 381, 382, -1, -1, -1, -1, -1, + -1, -1, -1, 391, 392, 393, 394, 395, 396, 397, + 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 414, 415, 416, 417, + 418, 419, 420, -1, -1, -1, -1, -1, -1, -1, + -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 3, 4, 5, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, @@ -3557,20 +3573,21 @@ static const yytype_int16 yycheck[] = 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, -1, -1, -1, 320, 321, 322, 323, 324, 325, - 326, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 316, 317, 318, 319, -1, -1, -1, 323, 324, 325, + 326, 327, 328, 329, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 351, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 373, 374, 375, - 376, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 386, 387, 388, 389, 390, 391, 392, -1, -1, -1, + -1, 357, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 408, 409, 410, 411, 412, 413, -1, -1, - -1, -1, -1, -1, -1, -1, 422, -1, 424, 425, - 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, + -1, -1, -1, 379, 380, 381, 382, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 392, 393, 394, 395, + 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 414, 415, + 416, 417, 418, 419, 420, -1, -1, -1, -1, -1, + -1, -1, -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, - 446, 447, 448, 449, 450, 451, 452, 453, 454, 3, + 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, + 456, 457, 458, 459, 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, @@ -3602,21 +3619,22 @@ static const yytype_int16 yycheck[] = 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, -1, -1, -1, 320, 321, 322, 323, - 324, 325, 326, -1, -1, -1, -1, -1, -1, -1, + 314, 315, 316, 317, 318, 319, -1, -1, -1, 323, + 324, 325, 326, 327, 328, 329, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 354, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 373, - 374, 375, 376, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 386, 387, 388, 389, 390, 391, 392, -1, + -1, -1, -1, -1, -1, -1, 360, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 408, 409, 410, 411, 412, 413, - -1, -1, -1, -1, -1, -1, -1, -1, 422, -1, - 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, + -1, -1, -1, -1, -1, 379, 380, 381, 382, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 392, 393, + 394, 395, 396, 397, 398, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 414, 415, 416, 417, 418, 419, 420, -1, -1, -1, + -1, -1, -1, -1, -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, - 454, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, + 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, @@ -3647,21 +3665,22 @@ static const yytype_int16 yycheck[] = 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, -1, -1, -1, 320, 321, - 322, 323, 324, 325, 326, -1, -1, -1, -1, -1, + 312, 313, 314, 315, 316, 317, 318, 319, -1, -1, + -1, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 360, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 354, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 379, 380, 381, + 382, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 392, 393, 394, 395, 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 373, 374, 375, 376, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 386, 387, 388, 389, 390, 391, - 392, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 408, 409, 410, 411, - 412, 413, -1, -1, -1, -1, -1, -1, -1, -1, - 422, -1, 424, 425, 426, 427, 428, 429, 430, 431, + -1, -1, 414, 415, 416, 417, 418, 419, 420, -1, + -1, -1, -1, -1, -1, -1, -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, - 452, 453, 454, 3, 4, 5, 6, 7, 8, 9, + 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, + 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, @@ -3692,21 +3711,22 @@ static const yytype_int16 yycheck[] = 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, -1, -1, -1, - 320, 321, 322, 323, 324, 325, 326, -1, -1, -1, + 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, + -1, -1, -1, 323, 324, 325, 326, 327, 328, 329, + 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 354, -1, -1, -1, -1, -1, + 360, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 379, + 380, 381, 382, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 392, 393, 394, 395, 396, 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 373, 374, 375, 376, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 386, 387, 388, 389, - 390, 391, 392, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 408, 409, - 410, 411, 412, 413, -1, -1, -1, -1, -1, -1, - -1, -1, 422, -1, 424, 425, 426, 427, 428, 429, - 430, 431, 432, 433, 434, 435, 436, 437, 438, 439, + -1, -1, -1, -1, 414, 415, 416, 417, 418, 419, + 420, -1, -1, -1, -1, -1, -1, -1, -1, 429, + -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, - 450, 451, 452, 453, 454, 3, 4, 5, 6, 7, + 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, + 460, 461, 462, 463, 464, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, @@ -3737,21 +3757,22 @@ static const yytype_int16 yycheck[] = 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, -1, - -1, -1, 320, 321, 322, 323, 324, 325, 326, -1, + 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, + 318, 319, -1, -1, -1, 323, 324, 325, 326, 327, + 328, 329, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 373, 374, 375, 376, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 386, 387, - 388, 389, 390, 391, 392, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 408, 409, 410, 411, 412, 413, -1, -1, -1, -1, - -1, -1, -1, -1, 422, -1, 424, 425, 426, 427, - 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + -1, 379, 380, 381, 382, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 392, 393, 394, 395, 396, 397, + 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 414, 415, 416, 417, + 418, 419, 420, -1, -1, -1, -1, -1, -1, -1, + -1, 429, -1, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 4, 5, 6, + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, @@ -3768,7 +3789,7 @@ static const yytype_int16 yycheck[] = 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, - 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, @@ -3783,408 +3804,415 @@ static const yytype_int16 yycheck[] = 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, - -1, -1, -1, -1, -1, -1, 323, -1, -1, -1, - -1, -1, 329, 330, -1, -1, -1, -1, -1, -1, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 348, 349, -1, -1, -1, 353, 354, -1, -1, - -1, -1, -1, 360, 361, 362, 363, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, 359, 360, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 381, 382, 383, 384, 385, 386, - -1, -1, -1, -1, 391, 392, -1, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 414, 415, 416, - 417, 418, 419, 420, 421, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 436, - 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, -1, -1, 63, - 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, - 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, - 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, - 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, - 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, - 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, - 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, - 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, - 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, - 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, - 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, - 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, - 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, - 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, - 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, - 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, - 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, - 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, - 314, 315, 316, -1, -1, -1, -1, -1, -1, 323, - -1, -1, -1, -1, -1, 329, 330, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 348, 349, -1, -1, -1, 353, - 354, -1, -1, -1, -1, -1, 360, 361, 362, 363, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, 359, 360, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 381, 382, 383, - 384, 385, 386, -1, -1, -1, -1, 391, 392, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 414, 415, 416, 417, 418, 419, 420, 421, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, 358, -1, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 436, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - -1, -1, 63, 64, 65, 66, 67, 68, 69, 70, - 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, - 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, - 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, - 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, - 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, - 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, - 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, - 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, - 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, - 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, - 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, - 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, - 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, - 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, - 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, - 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, - 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, - 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, - 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, - 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, - 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, - 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, - 311, 312, 313, 314, 315, 316, -1, -1, -1, -1, - -1, -1, 323, -1, -1, -1, -1, -1, 329, 330, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 348, 349, -1, - -1, 352, -1, -1, -1, -1, -1, -1, -1, 360, - 361, 362, 363, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 381, 382, 383, 384, 385, 386, -1, -1, -1, -1, - 391, 392, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, 359, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 414, 415, 416, 417, 418, 419, 420, - 421, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 436, 4, 5, 6, 7, - 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, - 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, - 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, -1, -1, 63, 64, 65, 66, 67, - 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, - 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, - 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, - 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, - 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, - 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, - 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, - 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, - 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, - 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, - 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, - 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, - 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, - 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, - 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, - 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, - 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, - 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, - 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, - 308, 309, 310, 311, 312, 313, 314, 315, 316, -1, - -1, -1, -1, -1, -1, 323, -1, -1, -1, -1, - -1, 329, 330, -1, -1, -1, -1, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 348, 349, -1, -1, -1, 353, -1, -1, -1, -1, - -1, -1, 360, 361, 362, 363, -1, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 381, 382, 383, 384, 385, 386, -1, - -1, -1, -1, 391, 392, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, 358, -1, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 414, 415, 416, 417, - 418, 419, 420, 421, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 436, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, -1, -1, 63, 64, - 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, - 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, - 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, - 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, - 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, - 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, - 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, - 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, - 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, - 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, - 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, - 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, - 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, - 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, - 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, - 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, - 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, -1, -1, -1, -1, -1, -1, 323, -1, - -1, -1, -1, -1, 329, 330, -1, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 348, 349, -1, -1, 352, -1, -1, - -1, -1, -1, -1, -1, 360, 361, 362, 363, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 381, 382, 383, 384, - 385, 386, -1, -1, -1, -1, 391, 392, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, -1, -1, -1, -1, -1, -1, 365, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 414, - 415, 416, 417, 418, 419, 420, 421, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 436, 4, 5, 6, 7, 8, 9, 10, 11, - 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, - 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, - 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, - 52, 53, 54, 55, 56, 57, 58, 59, 60, -1, - -1, 63, 64, 65, 66, 67, 68, 69, 70, 71, - 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, - 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, - 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, - 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, - 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, - 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, - 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, - 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, - 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, - 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, - 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, - 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, - 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, - 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, - 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, - 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, - 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, - 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, - 312, 313, 314, 315, 316, -1, -1, -1, -1, -1, - -1, 323, -1, -1, -1, -1, -1, 329, 330, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 348, 349, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 359, 360, 361, - 362, 363, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 381, - 382, 383, 384, 385, 386, -1, -1, -1, -1, 391, - 392, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 414, 415, 416, 417, 418, 419, 420, 421, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 436, 4, 5, 6, 7, 8, - 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, - 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, - 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, - 59, 60, -1, -1, 63, 64, 65, 66, 67, 68, - 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, - 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, - 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, - 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, - 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, - 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, - 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, - 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, - 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, - 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, - 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, - 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, - 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, - 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, - 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, - 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, - 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, - 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, - 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, - 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, - 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, - 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, - 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, - 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, - 309, 310, 311, 312, 313, 314, 315, 316, -1, -1, - -1, -1, -1, -1, 323, -1, -1, -1, -1, -1, - 329, 330, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 348, - 349, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 360, 361, 362, 363, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 381, 382, 383, 384, 385, 386, -1, -1, - -1, -1, 391, 392, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 414, 415, 416, 417, 418, - 419, 420, 421, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 436, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, - 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, - 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, - 56, 57, 58, 59, 60, -1, -1, 63, 64, 65, - 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, - 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, - 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, - 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, - 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, - 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, - 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, - 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, - 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, - 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, - 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, - 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, - 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, - 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, - 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, - 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, - 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, - 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, - 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, - 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, - 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, - 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, - 316, -1, -1, -1, -1, -1, -1, 323, -1, -1, - -1, -1, -1, 329, 330, -1, -1, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, 348, 349, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, 360, 361, 362, 363, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, 335, 336, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 381, 382, 383, 384, 385, - 386, -1, -1, -1, -1, 391, 392, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, 355, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 366, + 367, 368, 369, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 414, 415, - 416, 417, 418, 419, 420, 421, -1, -1, -1, -1, + 387, 388, 389, 390, 391, 392, -1, -1, -1, -1, + 397, 398, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 436, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, - 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, - 53, 54, 55, 56, 57, 58, 59, 60, -1, -1, - 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, - 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, - 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, - 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, - 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, - 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, - 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, - 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, - 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, - 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, - 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, - 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, - 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, - 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, - 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, - 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, - 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, - 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, - 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, - 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, - 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, - 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, - 313, 314, 315, 316, -1, -1, -1, -1, -1, -1, - 323, -1, -1, -1, -1, -1, 329, 330, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, 348, 349, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, 360, 361, 362, - 363, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 381, 382, - 383, 384, 385, 386, -1, -1, -1, -1, 391, 392, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 414, 415, 416, 417, 418, 419, 420, 421, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 436, 4, 5, 6, 7, 8, 9, - 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, - 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, - 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, -1, -1, 63, 64, 65, 66, 67, 68, 69, - 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, - 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, - 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, - 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, - 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, - 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, - 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, - 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, - 310, 311, 312, 313, 314, 315, 316, -1, -1, -1, - -1, -1, -1, 323, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 421, 422, 423, 424, 425, 426, + 427, 428, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 443, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, + 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, -1, -1, 63, 64, 65, 66, + 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, + 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, + 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, + 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, + 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, + 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, + 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, + 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, -1, 169, 170, 171, 172, 173, 174, 175, 176, + 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, + 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, + 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, + 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, + 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, + 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, + 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, + 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, + 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, + 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, + 317, 318, 319, -1, -1, -1, -1, -1, -1, 326, + -1, -1, -1, 330, 331, 332, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, 386, -1, -1, -1, - -1, 391, 392 + -1, -1, -1, -1, -1, 392, -1, -1, -1, -1, + 397, 398 }; - /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ +/* YYSTOS[STATE-NUM] -- The symbol kind of the accessing symbol of + state STATE-NUM. */ static const yytype_int16 yystos[] = { 0, 3, 4, 5, 6, 7, 8, 9, 10, 11, @@ -4219,144 +4247,148 @@ static const yytype_int16 yystos[] = 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, - 322, 323, 324, 325, 326, 351, 359, 373, 374, 375, - 376, 377, 386, 387, 388, 389, 390, 391, 392, 408, - 409, 410, 411, 412, 413, 422, 424, 425, 426, 427, - 428, 429, 430, 431, 432, 433, 434, 435, 436, 437, + 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, + 332, 357, 365, 379, 380, 381, 382, 383, 392, 393, + 394, 395, 396, 397, 398, 414, 415, 416, 417, 418, + 419, 420, 429, 431, 432, 433, 434, 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, - 448, 449, 450, 451, 452, 453, 454, 486, 487, 490, - 491, 492, 493, 497, 498, 499, 500, 501, 502, 505, - 506, 507, 508, 509, 511, 516, 517, 518, 559, 560, - 561, 563, 570, 574, 575, 580, 583, 349, 349, 349, - 349, 349, 349, 349, 349, 351, 517, 353, 385, 349, - 349, 359, 385, 359, 562, 350, 356, 494, 495, 496, - 506, 511, 356, 359, 385, 359, 385, 507, 511, 367, - 513, 514, 0, 560, 491, 499, 506, 359, 490, 385, - 566, 567, 584, 585, 382, 385, 566, 382, 566, 382, - 566, 382, 566, 382, 566, 566, 584, 382, 566, 385, - 564, 565, 511, 520, 353, 385, 409, 503, 504, 385, - 510, 351, 359, 512, 353, 538, 563, 495, 494, 496, - 385, 385, 349, 358, 512, 353, 356, 359, 489, 329, - 330, 348, 349, 360, 361, 362, 363, 381, 382, 383, - 384, 385, 414, 415, 416, 417, 418, 419, 420, 421, - 456, 457, 458, 460, 461, 462, 463, 464, 465, 466, - 467, 468, 509, 511, 515, 512, 350, 385, 359, 358, - 356, 350, 356, 350, 356, 358, 356, 356, 356, 350, - 356, 356, 356, 356, 356, 356, 356, 350, 356, 350, - 356, 349, 352, 356, 359, 506, 511, 521, 522, 519, - 358, 350, 356, 350, 356, 352, 467, 469, 470, 471, - 472, 473, 474, 475, 476, 477, 478, 479, 480, 351, - 359, 353, 354, 359, 393, 394, 395, 396, 398, 399, - 400, 401, 402, 403, 404, 405, 406, 407, 423, 467, - 480, 482, 484, 486, 490, 509, 511, 527, 528, 529, - 530, 531, 539, 540, 541, 542, 545, 546, 549, 550, - 551, 558, 563, 512, 358, 512, 353, 482, 525, 358, - 488, 385, 356, 359, 467, 467, 484, 329, 330, 351, - 355, 350, 350, 356, 392, 482, 349, 467, 356, 368, - 563, 348, 351, 382, 567, 584, 385, 585, 348, 381, - 382, 383, 384, 571, 572, 382, 480, 485, 573, 382, - 381, 382, 383, 384, 576, 577, 382, 485, 578, 382, - 348, 579, 382, 584, 385, 485, 581, 582, 382, 485, - 352, 565, 511, 385, 523, 524, 354, 522, 521, 485, - 504, 385, 364, 365, 366, 361, 363, 327, 328, 331, - 332, 367, 368, 333, 334, 371, 370, 369, 335, 337, - 336, 372, 352, 352, 480, 354, 532, 349, 359, 359, - 553, 349, 349, 359, 359, 484, 349, 484, 357, 359, - 359, 359, 359, 338, 339, 340, 341, 342, 343, 344, - 345, 346, 347, 358, 483, 356, 359, 354, 528, 542, - 546, 551, 525, 358, 354, 525, 526, 525, 521, 385, - 350, 459, 484, 385, 482, 467, 348, 382, 568, 569, - 350, 358, 350, 356, 350, 356, 350, 356, 356, 350, - 356, 350, 356, 350, 356, 356, 350, 356, 356, 350, - 356, 350, 356, 350, 350, 523, 512, 356, 359, 354, - 467, 467, 467, 469, 469, 470, 470, 471, 471, 471, - 471, 472, 472, 473, 474, 475, 476, 477, 478, 481, - 352, 539, 552, 528, 554, 484, 359, 484, 357, 482, - 482, 525, 354, 356, 354, 352, 352, 356, 352, 356, - 572, 571, 485, 573, 577, 576, 485, 578, 348, 579, - 581, 582, 359, 524, 484, 533, 484, 499, 544, 393, - 527, 540, 555, 350, 350, 354, 525, 348, 382, 350, - 350, 350, 350, 350, 350, 357, 354, 385, 350, 349, - 544, 556, 557, 535, 536, 537, 543, 547, 482, 358, - 529, 534, 538, 484, 359, 350, 397, 531, 529, 353, - 525, 350, 484, 534, 535, 539, 548, 359, 354 + 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, + 458, 459, 460, 461, 462, 463, 464, 496, 497, 500, + 501, 502, 503, 507, 508, 509, 510, 511, 512, 515, + 516, 517, 518, 519, 521, 526, 527, 528, 569, 570, + 571, 573, 580, 584, 585, 591, 594, 355, 355, 355, + 355, 355, 355, 355, 355, 357, 527, 359, 391, 355, + 355, 365, 391, 365, 572, 356, 362, 504, 505, 506, + 516, 521, 362, 365, 391, 365, 391, 517, 521, 373, + 523, 524, 0, 570, 501, 509, 516, 365, 500, 391, + 576, 577, 595, 596, 388, 391, 576, 388, 576, 388, + 576, 388, 576, 388, 576, 576, 595, 388, 576, 391, + 574, 575, 521, 530, 359, 391, 415, 513, 514, 391, + 520, 357, 365, 522, 359, 548, 573, 505, 504, 506, + 391, 391, 355, 364, 522, 359, 362, 365, 499, 335, + 336, 354, 355, 366, 367, 368, 369, 387, 388, 389, + 390, 391, 421, 422, 423, 424, 425, 426, 427, 428, + 466, 467, 468, 470, 471, 472, 473, 474, 475, 476, + 477, 478, 519, 521, 525, 522, 356, 391, 365, 364, + 362, 356, 362, 356, 362, 364, 362, 362, 362, 356, + 362, 362, 362, 362, 362, 362, 362, 356, 362, 356, + 362, 355, 358, 362, 365, 516, 521, 531, 532, 529, + 364, 356, 362, 356, 362, 358, 477, 479, 480, 481, + 482, 483, 484, 485, 486, 487, 488, 489, 490, 521, + 357, 365, 359, 360, 365, 399, 400, 401, 402, 404, + 405, 406, 407, 408, 409, 410, 411, 412, 413, 430, + 477, 490, 492, 494, 496, 500, 519, 521, 537, 538, + 539, 540, 541, 549, 550, 551, 552, 555, 556, 559, + 560, 561, 568, 573, 522, 364, 522, 359, 492, 535, + 364, 498, 391, 362, 365, 477, 477, 494, 335, 336, + 357, 361, 356, 356, 362, 398, 492, 355, 477, 362, + 374, 573, 354, 357, 388, 577, 595, 391, 596, 354, + 387, 388, 389, 390, 581, 582, 388, 490, 495, 583, + 388, 387, 388, 389, 390, 586, 587, 388, 387, 388, + 389, 390, 466, 588, 589, 388, 354, 590, 388, 595, + 391, 495, 526, 592, 593, 388, 495, 358, 575, 521, + 391, 533, 534, 360, 532, 531, 495, 514, 391, 370, + 371, 372, 367, 369, 333, 334, 337, 338, 373, 374, + 339, 340, 377, 376, 375, 341, 343, 342, 378, 358, + 358, 490, 360, 542, 355, 365, 365, 563, 355, 355, + 365, 365, 494, 355, 494, 363, 365, 365, 365, 365, + 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, + 364, 493, 362, 365, 360, 538, 552, 556, 561, 535, + 364, 360, 535, 536, 535, 531, 391, 356, 469, 494, + 391, 492, 477, 354, 388, 578, 579, 356, 364, 356, + 362, 356, 362, 356, 362, 362, 356, 362, 356, 362, + 356, 362, 362, 356, 362, 362, 356, 362, 356, 362, + 356, 356, 533, 522, 362, 365, 360, 477, 477, 477, + 479, 479, 480, 480, 481, 481, 481, 481, 482, 482, + 483, 484, 485, 486, 487, 488, 491, 358, 549, 562, + 538, 564, 494, 365, 494, 363, 492, 492, 535, 360, + 362, 360, 358, 358, 362, 358, 362, 582, 581, 495, + 583, 587, 586, 589, 588, 354, 590, 592, 593, 365, + 534, 494, 543, 494, 509, 554, 399, 537, 550, 565, + 356, 356, 360, 535, 354, 388, 356, 356, 356, 356, + 356, 356, 363, 360, 391, 356, 355, 554, 566, 567, + 545, 546, 547, 553, 557, 492, 364, 539, 544, 548, + 494, 365, 356, 403, 541, 539, 359, 535, 356, 494, + 544, 545, 549, 558, 365, 360 }; - /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +/* YYR1[RULE-NUM] -- Symbol kind of the left-hand side of rule RULE-NUM. */ static const yytype_int16 yyr1[] = { - 0, 455, 456, 457, 457, 457, 457, 457, 457, 457, - 457, 457, 457, 457, 457, 457, 457, 457, 458, 458, - 458, 458, 458, 458, 459, 460, 461, 462, 462, 463, - 463, 464, 464, 465, 466, 466, 466, 467, 467, 467, - 467, 468, 468, 468, 468, 469, 469, 469, 469, 470, - 470, 470, 471, 471, 471, 472, 472, 472, 472, 472, - 473, 473, 473, 474, 474, 475, 475, 476, 476, 477, - 477, 478, 478, 479, 479, 480, 481, 480, 482, 482, - 483, 483, 483, 483, 483, 483, 483, 483, 483, 483, - 483, 484, 484, 485, 486, 486, 486, 486, 486, 486, - 486, 486, 486, 486, 486, 488, 487, 489, 489, 490, - 490, 490, 490, 491, 491, 492, 492, 493, 494, 494, - 495, 495, 495, 495, 496, 497, 497, 497, 497, 497, - 498, 498, 498, 498, 498, 499, 499, 500, 501, 501, - 501, 501, 501, 501, 501, 501, 502, 503, 503, 504, - 504, 504, 505, 506, 506, 507, 507, 507, 507, 507, - 507, 507, 507, 507, 507, 507, 508, 508, 508, 508, - 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 508, 508, 508, 508, 508, 508, 508, 508, 508, - 508, 509, 510, 510, 511, 511, 512, 512, 512, 512, - 513, 513, 514, 515, 515, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 516, 516, 516, 516, 516, 516, 516, 516, 516, 516, - 517, 517, 517, 519, 518, 520, 518, 521, 521, 522, - 522, 523, 523, 524, 524, 525, 525, 525, 525, 526, - 526, 527, 528, 528, 529, 529, 529, 529, 529, 529, - 529, 529, 530, 531, 532, 533, 531, 534, 534, 536, - 535, 537, 535, 538, 538, 539, 539, 540, 540, 541, - 541, 542, 543, 543, 544, 544, 545, 545, 547, 546, - 548, 548, 549, 549, 550, 550, 552, 551, 553, 551, - 554, 551, 555, 555, 556, 556, 557, 557, 558, 558, - 558, 558, 558, 558, 558, 558, 559, 559, 560, 560, - 560, 562, 561, 563, 564, 564, 565, 565, 566, 566, - 567, 567, 568, 568, 569, 569, 570, 570, 570, 570, - 570, 570, 571, 571, 572, 572, 572, 572, 572, 573, - 573, 574, 574, 575, 575, 575, 575, 575, 575, 575, - 575, 576, 576, 577, 577, 577, 577, 578, 578, 579, - 579, 580, 580, 580, 580, 581, 581, 582, 583, 583, - 584, 584, 585, 585 + 0, 465, 466, 467, 467, 467, 467, 467, 467, 467, + 467, 467, 467, 467, 467, 467, 467, 467, 468, 468, + 468, 468, 468, 468, 469, 470, 471, 472, 472, 473, + 473, 474, 474, 475, 476, 476, 476, 477, 477, 477, + 477, 478, 478, 478, 478, 479, 479, 479, 479, 480, + 480, 480, 481, 481, 481, 482, 482, 482, 482, 482, + 483, 483, 483, 484, 484, 485, 485, 486, 486, 487, + 487, 488, 488, 489, 489, 490, 491, 490, 492, 492, + 493, 493, 493, 493, 493, 493, 493, 493, 493, 493, + 493, 494, 494, 495, 496, 496, 496, 496, 496, 496, + 496, 496, 496, 496, 496, 498, 497, 499, 499, 500, + 500, 500, 500, 501, 501, 502, 502, 503, 504, 504, + 505, 505, 505, 505, 506, 507, 507, 507, 507, 507, + 508, 508, 508, 508, 508, 509, 509, 510, 511, 511, + 511, 511, 511, 511, 511, 511, 511, 511, 512, 513, + 513, 514, 514, 514, 515, 516, 516, 517, 517, 517, + 517, 517, 517, 517, 517, 517, 517, 517, 518, 518, + 518, 518, 518, 518, 518, 518, 518, 518, 518, 518, + 518, 518, 518, 518, 518, 518, 518, 518, 518, 518, + 518, 518, 518, 518, 518, 518, 518, 518, 518, 518, + 518, 518, 518, 518, 518, 518, 519, 520, 520, 521, + 521, 522, 522, 522, 522, 523, 523, 524, 525, 525, + 525, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 526, 526, 526, 526, 526, 526, 526, 526, 526, + 526, 527, 527, 527, 529, 528, 530, 528, 531, 531, + 532, 532, 533, 533, 534, 534, 535, 535, 535, 535, + 536, 536, 537, 538, 538, 539, 539, 539, 539, 539, + 539, 539, 539, 540, 541, 542, 543, 541, 544, 544, + 546, 545, 547, 545, 548, 548, 549, 549, 550, 550, + 551, 551, 552, 553, 553, 554, 554, 555, 555, 557, + 556, 558, 558, 559, 559, 560, 560, 562, 561, 563, + 561, 564, 561, 565, 565, 566, 566, 567, 567, 568, + 568, 568, 568, 568, 568, 568, 568, 569, 569, 570, + 570, 570, 572, 571, 573, 574, 574, 575, 575, 576, + 576, 577, 577, 578, 578, 579, 579, 580, 580, 580, + 580, 580, 580, 581, 581, 582, 582, 582, 582, 582, + 583, 583, 584, 584, 585, 585, 585, 585, 585, 585, + 585, 585, 586, 586, 587, 587, 587, 587, 588, 588, + 589, 589, 589, 589, 589, 590, 590, 591, 591, 591, + 591, 592, 592, 593, 593, 594, 594, 595, 595, 596, + 596 }; - /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +/* YYR2[RULE-NUM] -- Number of symbols on the right-hand side of rule RULE-NUM. */ static const yytype_int8 yyr2[] = { 0, 2, 1, 1, 3, 1, 1, 1, 1, 1, @@ -4373,61 +4405,63 @@ static const yytype_int8 yyr2[] = 3, 3, 4, 1, 1, 2, 3, 3, 2, 3, 2, 1, 2, 1, 1, 1, 3, 4, 6, 5, 1, 2, 3, 5, 4, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 4, 1, 3, 1, - 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, + 3, 1, 3, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 4, 1, 1, 3, 2, 3, 2, 3, 3, 4, - 1, 0, 3, 1, 3, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 0, 6, 0, 5, 1, 2, 3, - 4, 1, 3, 1, 2, 1, 3, 4, 2, 1, + 1, 1, 1, 1, 4, 1, 1, 1, 3, 2, + 3, 2, 3, 3, 4, 1, 0, 3, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 0, 0, 5, 1, 1, 0, - 2, 0, 2, 2, 3, 1, 2, 1, 2, 1, - 2, 5, 3, 1, 1, 4, 1, 2, 0, 8, - 0, 1, 3, 2, 1, 2, 0, 6, 0, 8, - 0, 7, 1, 1, 1, 0, 2, 3, 2, 2, - 2, 3, 2, 2, 2, 2, 1, 2, 1, 1, - 1, 0, 3, 5, 1, 3, 1, 4, 1, 3, - 5, 5, 1, 3, 1, 3, 4, 6, 6, 8, - 6, 8, 1, 3, 1, 1, 1, 1, 1, 1, - 3, 4, 6, 4, 6, 6, 8, 6, 8, 6, - 8, 1, 3, 1, 1, 1, 1, 1, 3, 1, - 3, 6, 8, 4, 6, 1, 3, 1, 4, 6, - 1, 3, 3, 3 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 6, 0, 5, 1, 2, + 3, 4, 1, 3, 1, 2, 1, 3, 4, 2, + 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 2, 2, 0, 0, 5, 1, 1, + 0, 2, 0, 2, 2, 3, 1, 2, 1, 2, + 1, 2, 5, 3, 1, 1, 4, 1, 2, 0, + 8, 0, 1, 3, 2, 1, 2, 0, 6, 0, + 8, 0, 7, 1, 1, 1, 0, 2, 3, 2, + 2, 2, 3, 2, 2, 2, 2, 1, 2, 1, + 1, 1, 0, 3, 5, 1, 3, 1, 4, 1, + 3, 5, 5, 1, 3, 1, 3, 4, 6, 6, + 8, 6, 8, 1, 3, 1, 1, 1, 1, 1, + 1, 3, 4, 6, 4, 6, 6, 8, 6, 8, + 6, 8, 1, 3, 1, 1, 1, 1, 1, 3, + 1, 1, 1, 1, 1, 1, 3, 6, 8, 4, + 6, 1, 3, 1, 1, 4, 6, 1, 3, 3, + 3 }; @@ -4439,6 +4473,7 @@ enum { YYENOMEM = -2 }; #define YYACCEPT goto yyacceptlab #define YYABORT goto yyabortlab #define YYERROR goto yyerrorlab +#define YYNOMEM goto yyexhaustedlab #define YYRECOVERING() (!!yyerrstatus) @@ -4479,10 +4514,7 @@ do { \ YYFPRINTF Args; \ } while (0) -/* This macro is provided for backward compatibility. */ -# ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -# endif + # define YY_SYMBOL_PRINT(Title, Kind, Value, Location) \ @@ -4506,16 +4538,12 @@ yy_symbol_value_print (FILE *yyo, yysymbol_kind_t yykind, YYSTYPE const * const yyvaluep, glslang::TParseContext* pParseContext) { FILE *yyoutput = yyo; - YYUSE (yyoutput); - YYUSE (pParseContext); + YY_USE (yyoutput); + YY_USE (pParseContext); if (!yyvaluep) return; -# ifdef YYPRINT - if (yykind < YYNTOKENS) - YYPRINT (yyo, yytoknum[yykind], *yyvaluep); -# endif YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yykind); + YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -4896,14 +4924,14 @@ static void yydestruct (const char *yymsg, yysymbol_kind_t yykind, YYSTYPE *yyvaluep, glslang::TParseContext* pParseContext) { - YYUSE (yyvaluep); - YYUSE (pParseContext); + YY_USE (yyvaluep); + YY_USE (pParseContext); if (!yymsg) yymsg = "Deleting"; YY_SYMBOL_PRINT (yymsg, yykind, yyvaluep, yylocationp); YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN - YYUSE (yykind); + YY_USE (yykind); YY_IGNORE_MAYBE_UNINITIALIZED_END } @@ -4975,6 +5003,7 @@ YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); YYDPRINTF ((stderr, "Starting parse\n")); yychar = YYEMPTY; /* Cause a token to be read. */ + goto yysetstate; @@ -5000,7 +5029,7 @@ yysetstate: if (yyss + yystacksize - 1 <= yyssp) #if !defined yyoverflow && !defined YYSTACK_RELOCATE - goto yyexhaustedlab; + YYNOMEM; #else { /* Get the current used size of the three stacks, in elements. */ @@ -5028,7 +5057,7 @@ yysetstate: # else /* defined YYSTACK_RELOCATE */ /* Extend the stack our own way. */ if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; + YYNOMEM; yystacksize *= 2; if (YYMAXDEPTH < yystacksize) yystacksize = YYMAXDEPTH; @@ -5039,7 +5068,7 @@ yysetstate: YY_CAST (union yyalloc *, YYSTACK_ALLOC (YY_CAST (YYSIZE_T, YYSTACK_BYTES (yystacksize)))); if (! yyptr) - goto yyexhaustedlab; + YYNOMEM; YYSTACK_RELOCATE (yyss_alloc, yyss); YYSTACK_RELOCATE (yyvs_alloc, yyvs); # undef YYSTACK_RELOCATE @@ -5061,6 +5090,7 @@ yysetstate: } #endif /* !defined yyoverflow && !defined YYSTACK_RELOCATE */ + if (yystate == YYFINAL) YYACCEPT; @@ -5173,302 +5203,328 @@ yyreduce: switch (yyn) { case 2: /* variable_identifier: IDENTIFIER */ -#line 392 "MachineIndependent/glslang.y" +#line 355 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleVariable((yyvsp[0].lex).loc, (yyvsp[0].lex).symbol, (yyvsp[0].lex).string); } -#line 5181 "MachineIndependent/glslang_tab.cpp" +#line 5211 "MachineIndependent/glslang_tab.cpp" break; case 3: /* primary_expression: variable_identifier */ -#line 398 "MachineIndependent/glslang.y" +#line 361 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5189 "MachineIndependent/glslang_tab.cpp" +#line 5219 "MachineIndependent/glslang_tab.cpp" break; case 4: /* primary_expression: LEFT_PAREN expression RIGHT_PAREN */ -#line 401 "MachineIndependent/glslang.y" +#line 364 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); if ((yyval.interm.intermTypedNode)->getAsConstantUnion()) (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); } -#line 5199 "MachineIndependent/glslang_tab.cpp" +#line 5229 "MachineIndependent/glslang_tab.cpp" break; case 5: /* primary_expression: FLOATCONSTANT */ -#line 406 "MachineIndependent/glslang.y" +#line 369 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); } -#line 5207 "MachineIndependent/glslang_tab.cpp" +#line 5237 "MachineIndependent/glslang_tab.cpp" break; case 6: /* primary_expression: INTCONSTANT */ -#line 409 "MachineIndependent/glslang.y" +#line 372 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 5215 "MachineIndependent/glslang_tab.cpp" +#line 5245 "MachineIndependent/glslang_tab.cpp" break; case 7: /* primary_expression: UINTCONSTANT */ -#line 412 "MachineIndependent/glslang.y" +#line 375 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 5224 "MachineIndependent/glslang_tab.cpp" +#line 5254 "MachineIndependent/glslang_tab.cpp" break; case 8: /* primary_expression: BOOLCONSTANT */ -#line 416 "MachineIndependent/glslang.y" +#line 379 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); } -#line 5232 "MachineIndependent/glslang_tab.cpp" +#line 5262 "MachineIndependent/glslang_tab.cpp" break; case 9: /* primary_expression: STRING_LITERAL */ -#line 420 "MachineIndependent/glslang.y" +#line 382 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true); } -#line 5240 "MachineIndependent/glslang_tab.cpp" +#line 5270 "MachineIndependent/glslang_tab.cpp" break; case 10: /* primary_expression: INT32CONSTANT */ -#line 423 "MachineIndependent/glslang.y" +#line 385 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 5249 "MachineIndependent/glslang_tab.cpp" +#line 5279 "MachineIndependent/glslang_tab.cpp" break; case 11: /* primary_expression: UINT32CONSTANT */ -#line 427 "MachineIndependent/glslang.y" +#line 389 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 5258 "MachineIndependent/glslang_tab.cpp" +#line 5288 "MachineIndependent/glslang_tab.cpp" break; case 12: /* primary_expression: INT64CONSTANT */ -#line 431 "MachineIndependent/glslang.y" +#line 393 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i64, (yyvsp[0].lex).loc, true); } -#line 5267 "MachineIndependent/glslang_tab.cpp" +#line 5297 "MachineIndependent/glslang_tab.cpp" break; case 13: /* primary_expression: UINT64CONSTANT */ -#line 435 "MachineIndependent/glslang.y" +#line 397 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u64, (yyvsp[0].lex).loc, true); } -#line 5276 "MachineIndependent/glslang_tab.cpp" +#line 5306 "MachineIndependent/glslang_tab.cpp" break; case 14: /* primary_expression: INT16CONSTANT */ -#line 439 "MachineIndependent/glslang.y" +#line 401 "MachineIndependent/glslang.y" { parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((short)(yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 5285 "MachineIndependent/glslang_tab.cpp" +#line 5315 "MachineIndependent/glslang_tab.cpp" break; case 15: /* primary_expression: UINT16CONSTANT */ -#line 443 "MachineIndependent/glslang.y" +#line 405 "MachineIndependent/glslang.y" { parseContext.explicitInt16Check((yyvsp[0].lex).loc, "16-bit unsigned integer literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((unsigned short)(yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 5294 "MachineIndependent/glslang_tab.cpp" +#line 5324 "MachineIndependent/glslang_tab.cpp" break; case 16: /* primary_expression: DOUBLECONSTANT */ -#line 447 "MachineIndependent/glslang.y" +#line 409 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double literal"); if (! parseContext.symbolTable.atBuiltInLevel()) parseContext.doubleCheck((yyvsp[0].lex).loc, "double literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtDouble, (yyvsp[0].lex).loc, true); } -#line 5305 "MachineIndependent/glslang_tab.cpp" +#line 5335 "MachineIndependent/glslang_tab.cpp" break; case 17: /* primary_expression: FLOAT16CONSTANT */ -#line 453 "MachineIndependent/glslang.y" +#line 415 "MachineIndependent/glslang.y" { parseContext.float16Check((yyvsp[0].lex).loc, "half float literal"); (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat16, (yyvsp[0].lex).loc, true); } -#line 5314 "MachineIndependent/glslang_tab.cpp" +#line 5344 "MachineIndependent/glslang_tab.cpp" break; case 18: /* postfix_expression: primary_expression */ -#line 461 "MachineIndependent/glslang.y" +#line 422 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5322 "MachineIndependent/glslang_tab.cpp" +#line 5352 "MachineIndependent/glslang_tab.cpp" break; case 19: /* postfix_expression: postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET */ -#line 464 "MachineIndependent/glslang.y" +#line 425 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBracketDereference((yyvsp[-2].lex).loc, (yyvsp[-3].interm.intermTypedNode), (yyvsp[-1].interm.intermTypedNode)); } -#line 5330 "MachineIndependent/glslang_tab.cpp" +#line 5360 "MachineIndependent/glslang_tab.cpp" break; case 20: /* postfix_expression: function_call */ -#line 467 "MachineIndependent/glslang.y" +#line 428 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5338 "MachineIndependent/glslang_tab.cpp" +#line 5368 "MachineIndependent/glslang_tab.cpp" break; case 21: /* postfix_expression: postfix_expression DOT IDENTIFIER */ -#line 470 "MachineIndependent/glslang.y" +#line 431 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleDotDereference((yyvsp[0].lex).loc, (yyvsp[-2].interm.intermTypedNode), *(yyvsp[0].lex).string); } -#line 5346 "MachineIndependent/glslang_tab.cpp" +#line 5376 "MachineIndependent/glslang_tab.cpp" break; case 22: /* postfix_expression: postfix_expression INC_OP */ -#line 473 "MachineIndependent/glslang.y" +#line 434 "MachineIndependent/glslang.y" { parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "++", (yyvsp[-1].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "++", EOpPostIncrement, (yyvsp[-1].interm.intermTypedNode)); } -#line 5356 "MachineIndependent/glslang_tab.cpp" +#line 5386 "MachineIndependent/glslang_tab.cpp" break; case 23: /* postfix_expression: postfix_expression DEC_OP */ -#line 478 "MachineIndependent/glslang.y" +#line 439 "MachineIndependent/glslang.y" { parseContext.variableCheck((yyvsp[-1].interm.intermTypedNode)); parseContext.lValueErrorCheck((yyvsp[0].lex).loc, "--", (yyvsp[-1].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[0].lex).loc, "--", EOpPostDecrement, (yyvsp[-1].interm.intermTypedNode)); } -#line 5366 "MachineIndependent/glslang_tab.cpp" +#line 5396 "MachineIndependent/glslang_tab.cpp" break; case 24: /* integer_expression: expression */ -#line 486 "MachineIndependent/glslang.y" +#line 447 "MachineIndependent/glslang.y" { parseContext.integerCheck((yyvsp[0].interm.intermTypedNode), "[]"); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5375 "MachineIndependent/glslang_tab.cpp" +#line 5405 "MachineIndependent/glslang_tab.cpp" break; case 25: /* function_call: function_call_or_method */ -#line 493 "MachineIndependent/glslang.y" +#line 454 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleFunctionCall((yyvsp[0].interm).loc, (yyvsp[0].interm).function, (yyvsp[0].interm).intermNode); delete (yyvsp[0].interm).function; } -#line 5384 "MachineIndependent/glslang_tab.cpp" +#line 5414 "MachineIndependent/glslang_tab.cpp" break; case 26: /* function_call_or_method: function_call_generic */ -#line 500 "MachineIndependent/glslang.y" +#line 461 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); } -#line 5392 "MachineIndependent/glslang_tab.cpp" +#line 5422 "MachineIndependent/glslang_tab.cpp" break; case 27: /* function_call_generic: function_call_header_with_parameters RIGHT_PAREN */ -#line 506 "MachineIndependent/glslang.y" +#line 467 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-1].interm); (yyval.interm).loc = (yyvsp[0].lex).loc; } -#line 5401 "MachineIndependent/glslang_tab.cpp" +#line 5431 "MachineIndependent/glslang_tab.cpp" break; case 28: /* function_call_generic: function_call_header_no_parameters RIGHT_PAREN */ -#line 510 "MachineIndependent/glslang.y" +#line 471 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-1].interm); (yyval.interm).loc = (yyvsp[0].lex).loc; } -#line 5410 "MachineIndependent/glslang_tab.cpp" +#line 5440 "MachineIndependent/glslang_tab.cpp" break; case 29: /* function_call_header_no_parameters: function_call_header VOID */ -#line 517 "MachineIndependent/glslang.y" +#line 478 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-1].interm); } -#line 5418 "MachineIndependent/glslang_tab.cpp" +#line 5448 "MachineIndependent/glslang_tab.cpp" break; case 30: /* function_call_header_no_parameters: function_call_header */ -#line 520 "MachineIndependent/glslang.y" +#line 481 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); } -#line 5426 "MachineIndependent/glslang_tab.cpp" +#line 5456 "MachineIndependent/glslang_tab.cpp" break; case 31: /* function_call_header_with_parameters: function_call_header assignment_expression */ -#line 526 "MachineIndependent/glslang.y" +#line 487 "MachineIndependent/glslang.y" { - TParameter param = { 0, new TType }; - param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); - (yyvsp[-1].interm).function->addParameter(param); - (yyval.interm).function = (yyvsp[-1].interm).function; - (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); + if (parseContext.spvVersion.vulkan > 0 + && parseContext.spvVersion.vulkanRelaxed + && (yyvsp[0].interm.intermTypedNode)->getType().containsOpaque()) + { + (yyval.interm).intermNode = parseContext.vkRelaxedRemapFunctionArgument((yyval.interm).loc, (yyvsp[-1].interm).function, (yyvsp[0].interm.intermTypedNode)); + (yyval.interm).function = (yyvsp[-1].interm).function; + } + else + { + TParameter param = { 0, new TType, {} }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + + (yyvsp[-1].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-1].interm).function; + (yyval.interm).intermNode = (yyvsp[0].interm.intermTypedNode); + } } -#line 5438 "MachineIndependent/glslang_tab.cpp" +#line 5479 "MachineIndependent/glslang_tab.cpp" break; case 32: /* function_call_header_with_parameters: function_call_header_with_parameters COMMA assignment_expression */ -#line 533 "MachineIndependent/glslang.y" +#line 505 "MachineIndependent/glslang.y" { - TParameter param = { 0, new TType }; - param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); - (yyvsp[-2].interm).function->addParameter(param); - (yyval.interm).function = (yyvsp[-2].interm).function; - (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + if (parseContext.spvVersion.vulkan > 0 + && parseContext.spvVersion.vulkanRelaxed + && (yyvsp[0].interm.intermTypedNode)->getType().containsOpaque()) + { + TIntermNode* remappedNode = parseContext.vkRelaxedRemapFunctionArgument((yyvsp[-1].lex).loc, (yyvsp[-2].interm).function, (yyvsp[0].interm.intermTypedNode)); + if (remappedNode == (yyvsp[0].interm.intermTypedNode)) + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + else + (yyval.interm).intermNode = parseContext.intermediate.mergeAggregate((yyvsp[-2].interm).intermNode, remappedNode, (yyvsp[-1].lex).loc); + (yyval.interm).function = (yyvsp[-2].interm).function; + } + else + { + TParameter param = { 0, new TType, {} }; + param.type->shallowCopy((yyvsp[0].interm.intermTypedNode)->getType()); + + (yyvsp[-2].interm).function->addParameter(param); + (yyval.interm).function = (yyvsp[-2].interm).function; + (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); + } } -#line 5450 "MachineIndependent/glslang_tab.cpp" +#line 5506 "MachineIndependent/glslang_tab.cpp" break; case 33: /* function_call_header: function_identifier LEFT_PAREN */ -#line 543 "MachineIndependent/glslang.y" +#line 530 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-1].interm); } -#line 5458 "MachineIndependent/glslang_tab.cpp" +#line 5514 "MachineIndependent/glslang_tab.cpp" break; case 34: /* function_identifier: type_specifier */ -#line 551 "MachineIndependent/glslang.y" +#line 538 "MachineIndependent/glslang.y" { // Constructor (yyval.interm).intermNode = 0; (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); } -#line 5468 "MachineIndependent/glslang_tab.cpp" +#line 5524 "MachineIndependent/glslang_tab.cpp" break; case 35: /* function_identifier: postfix_expression */ -#line 556 "MachineIndependent/glslang.y" +#line 543 "MachineIndependent/glslang.y" { // // Should be a method or subroutine call, but we haven't recognized the arguments yet. @@ -5496,50 +5552,50 @@ yyreduce: (yyval.interm).function = new TFunction(empty, TType(EbtVoid), EOpNull); } } -#line 5500 "MachineIndependent/glslang_tab.cpp" +#line 5556 "MachineIndependent/glslang_tab.cpp" break; case 36: /* function_identifier: non_uniform_qualifier */ -#line 584 "MachineIndependent/glslang.y" +#line 570 "MachineIndependent/glslang.y" { // Constructor (yyval.interm).intermNode = 0; (yyval.interm).function = parseContext.handleConstructorCall((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); } -#line 5510 "MachineIndependent/glslang_tab.cpp" +#line 5566 "MachineIndependent/glslang_tab.cpp" break; case 37: /* unary_expression: postfix_expression */ -#line 593 "MachineIndependent/glslang.y" +#line 578 "MachineIndependent/glslang.y" { parseContext.variableCheck((yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); if (TIntermMethod* method = (yyvsp[0].interm.intermTypedNode)->getAsMethodNode()) parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "incomplete method syntax", method->getMethodName().c_str(), ""); } -#line 5521 "MachineIndependent/glslang_tab.cpp" +#line 5577 "MachineIndependent/glslang_tab.cpp" break; case 38: /* unary_expression: INC_OP unary_expression */ -#line 599 "MachineIndependent/glslang.y" +#line 584 "MachineIndependent/glslang.y" { parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "++", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "++", EOpPreIncrement, (yyvsp[0].interm.intermTypedNode)); } -#line 5530 "MachineIndependent/glslang_tab.cpp" +#line 5586 "MachineIndependent/glslang_tab.cpp" break; case 39: /* unary_expression: DEC_OP unary_expression */ -#line 603 "MachineIndependent/glslang.y" +#line 588 "MachineIndependent/glslang.y" { parseContext.lValueErrorCheck((yyvsp[-1].lex).loc, "--", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.handleUnaryMath((yyvsp[-1].lex).loc, "--", EOpPreDecrement, (yyvsp[0].interm.intermTypedNode)); } -#line 5539 "MachineIndependent/glslang_tab.cpp" +#line 5595 "MachineIndependent/glslang_tab.cpp" break; case 40: /* unary_expression: unary_operator unary_expression */ -#line 607 "MachineIndependent/glslang.y" +#line 592 "MachineIndependent/glslang.y" { if ((yyvsp[-1].interm).op != EOpNull) { char errorOp[2] = {0, 0}; @@ -5556,179 +5612,179 @@ yyreduce: (yyval.interm.intermTypedNode)->getAsConstantUnion()->setExpression(); } } -#line 5560 "MachineIndependent/glslang_tab.cpp" +#line 5616 "MachineIndependent/glslang_tab.cpp" break; case 41: /* unary_operator: PLUS */ -#line 627 "MachineIndependent/glslang.y" +#line 612 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNull; } -#line 5566 "MachineIndependent/glslang_tab.cpp" +#line 5622 "MachineIndependent/glslang_tab.cpp" break; case 42: /* unary_operator: DASH */ -#line 628 "MachineIndependent/glslang.y" +#line 613 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpNegative; } -#line 5572 "MachineIndependent/glslang_tab.cpp" +#line 5628 "MachineIndependent/glslang_tab.cpp" break; case 43: /* unary_operator: BANG */ -#line 629 "MachineIndependent/glslang.y" +#line 614 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLogicalNot; } -#line 5578 "MachineIndependent/glslang_tab.cpp" +#line 5634 "MachineIndependent/glslang_tab.cpp" break; case 44: /* unary_operator: TILDE */ -#line 630 "MachineIndependent/glslang.y" +#line 615 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpBitwiseNot; parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise not"); } -#line 5585 "MachineIndependent/glslang_tab.cpp" +#line 5641 "MachineIndependent/glslang_tab.cpp" break; case 45: /* multiplicative_expression: unary_expression */ -#line 636 "MachineIndependent/glslang.y" +#line 621 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5591 "MachineIndependent/glslang_tab.cpp" +#line 5647 "MachineIndependent/glslang_tab.cpp" break; case 46: /* multiplicative_expression: multiplicative_expression STAR unary_expression */ -#line 637 "MachineIndependent/glslang.y" +#line 622 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "*", EOpMul, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5601 "MachineIndependent/glslang_tab.cpp" +#line 5657 "MachineIndependent/glslang_tab.cpp" break; case 47: /* multiplicative_expression: multiplicative_expression SLASH unary_expression */ -#line 642 "MachineIndependent/glslang.y" +#line 627 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "/", EOpDiv, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5611 "MachineIndependent/glslang_tab.cpp" +#line 5667 "MachineIndependent/glslang_tab.cpp" break; case 48: /* multiplicative_expression: multiplicative_expression PERCENT unary_expression */ -#line 647 "MachineIndependent/glslang.y" +#line 632 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "%"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "%", EOpMod, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5622 "MachineIndependent/glslang_tab.cpp" +#line 5678 "MachineIndependent/glslang_tab.cpp" break; case 49: /* additive_expression: multiplicative_expression */ -#line 656 "MachineIndependent/glslang.y" +#line 641 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5628 "MachineIndependent/glslang_tab.cpp" +#line 5684 "MachineIndependent/glslang_tab.cpp" break; case 50: /* additive_expression: additive_expression PLUS multiplicative_expression */ -#line 657 "MachineIndependent/glslang.y" +#line 642 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "+", EOpAdd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5638 "MachineIndependent/glslang_tab.cpp" +#line 5694 "MachineIndependent/glslang_tab.cpp" break; case 51: /* additive_expression: additive_expression DASH multiplicative_expression */ -#line 662 "MachineIndependent/glslang.y" +#line 647 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "-", EOpSub, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5648 "MachineIndependent/glslang_tab.cpp" +#line 5704 "MachineIndependent/glslang_tab.cpp" break; case 52: /* shift_expression: additive_expression */ -#line 670 "MachineIndependent/glslang.y" +#line 655 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5654 "MachineIndependent/glslang_tab.cpp" +#line 5710 "MachineIndependent/glslang_tab.cpp" break; case 53: /* shift_expression: shift_expression LEFT_OP additive_expression */ -#line 671 "MachineIndependent/glslang.y" +#line 656 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift left"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<<", EOpLeftShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5665 "MachineIndependent/glslang_tab.cpp" +#line 5721 "MachineIndependent/glslang_tab.cpp" break; case 54: /* shift_expression: shift_expression RIGHT_OP additive_expression */ -#line 677 "MachineIndependent/glslang.y" +#line 662 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bit shift right"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">>", EOpRightShift, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5676 "MachineIndependent/glslang_tab.cpp" +#line 5732 "MachineIndependent/glslang_tab.cpp" break; case 55: /* relational_expression: shift_expression */ -#line 686 "MachineIndependent/glslang.y" +#line 671 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5682 "MachineIndependent/glslang_tab.cpp" +#line 5738 "MachineIndependent/glslang_tab.cpp" break; case 56: /* relational_expression: relational_expression LEFT_ANGLE shift_expression */ -#line 687 "MachineIndependent/glslang.y" +#line 672 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<", EOpLessThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5692 "MachineIndependent/glslang_tab.cpp" +#line 5748 "MachineIndependent/glslang_tab.cpp" break; case 57: /* relational_expression: relational_expression RIGHT_ANGLE shift_expression */ -#line 692 "MachineIndependent/glslang.y" +#line 677 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">", EOpGreaterThan, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5702 "MachineIndependent/glslang_tab.cpp" +#line 5758 "MachineIndependent/glslang_tab.cpp" break; case 58: /* relational_expression: relational_expression LE_OP shift_expression */ -#line 697 "MachineIndependent/glslang.y" +#line 682 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "<=", EOpLessThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5712 "MachineIndependent/glslang_tab.cpp" +#line 5768 "MachineIndependent/glslang_tab.cpp" break; case 59: /* relational_expression: relational_expression GE_OP shift_expression */ -#line 702 "MachineIndependent/glslang.y" +#line 687 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, ">=", EOpGreaterThanEqual, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5722 "MachineIndependent/glslang_tab.cpp" +#line 5778 "MachineIndependent/glslang_tab.cpp" break; case 60: /* equality_expression: relational_expression */ -#line 710 "MachineIndependent/glslang.y" +#line 695 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5728 "MachineIndependent/glslang_tab.cpp" +#line 5784 "MachineIndependent/glslang_tab.cpp" break; case 61: /* equality_expression: equality_expression EQ_OP relational_expression */ -#line 711 "MachineIndependent/glslang.y" +#line 696 "MachineIndependent/glslang.y" { parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "=="); @@ -5738,11 +5794,11 @@ yyreduce: if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5742 "MachineIndependent/glslang_tab.cpp" +#line 5798 "MachineIndependent/glslang_tab.cpp" break; case 62: /* equality_expression: equality_expression NE_OP relational_expression */ -#line 720 "MachineIndependent/glslang.y" +#line 705 "MachineIndependent/glslang.y" { parseContext.arrayObjectCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array comparison"); parseContext.opaqueCheck((yyvsp[-1].lex).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "!="); @@ -5752,124 +5808,124 @@ yyreduce: if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5756 "MachineIndependent/glslang_tab.cpp" +#line 5812 "MachineIndependent/glslang_tab.cpp" break; case 63: /* and_expression: equality_expression */ -#line 732 "MachineIndependent/glslang.y" +#line 717 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5762 "MachineIndependent/glslang_tab.cpp" +#line 5818 "MachineIndependent/glslang_tab.cpp" break; case 64: /* and_expression: and_expression AMPERSAND equality_expression */ -#line 733 "MachineIndependent/glslang.y" +#line 718 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise and"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&", EOpAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5773 "MachineIndependent/glslang_tab.cpp" +#line 5829 "MachineIndependent/glslang_tab.cpp" break; case 65: /* exclusive_or_expression: and_expression */ -#line 742 "MachineIndependent/glslang.y" +#line 727 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5779 "MachineIndependent/glslang_tab.cpp" +#line 5835 "MachineIndependent/glslang_tab.cpp" break; case 66: /* exclusive_or_expression: exclusive_or_expression CARET and_expression */ -#line 743 "MachineIndependent/glslang.y" +#line 728 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise exclusive or"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^", EOpExclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5790 "MachineIndependent/glslang_tab.cpp" +#line 5846 "MachineIndependent/glslang_tab.cpp" break; case 67: /* inclusive_or_expression: exclusive_or_expression */ -#line 752 "MachineIndependent/glslang.y" +#line 737 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5796 "MachineIndependent/glslang_tab.cpp" +#line 5852 "MachineIndependent/glslang_tab.cpp" break; case 68: /* inclusive_or_expression: inclusive_or_expression VERTICAL_BAR exclusive_or_expression */ -#line 753 "MachineIndependent/glslang.y" +#line 738 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[-1].lex).loc, "bitwise inclusive or"); (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "|", EOpInclusiveOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 5807 "MachineIndependent/glslang_tab.cpp" +#line 5863 "MachineIndependent/glslang_tab.cpp" break; case 69: /* logical_and_expression: inclusive_or_expression */ -#line 762 "MachineIndependent/glslang.y" +#line 747 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5813 "MachineIndependent/glslang_tab.cpp" +#line 5869 "MachineIndependent/glslang_tab.cpp" break; case 70: /* logical_and_expression: logical_and_expression AND_OP inclusive_or_expression */ -#line 763 "MachineIndependent/glslang.y" +#line 748 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "&&", EOpLogicalAnd, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5823 "MachineIndependent/glslang_tab.cpp" +#line 5879 "MachineIndependent/glslang_tab.cpp" break; case 71: /* logical_xor_expression: logical_and_expression */ -#line 771 "MachineIndependent/glslang.y" +#line 756 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5829 "MachineIndependent/glslang_tab.cpp" +#line 5885 "MachineIndependent/glslang_tab.cpp" break; case 72: /* logical_xor_expression: logical_xor_expression XOR_OP logical_and_expression */ -#line 772 "MachineIndependent/glslang.y" +#line 757 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "^^", EOpLogicalXor, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5839 "MachineIndependent/glslang_tab.cpp" +#line 5895 "MachineIndependent/glslang_tab.cpp" break; case 73: /* logical_or_expression: logical_xor_expression */ -#line 780 "MachineIndependent/glslang.y" +#line 765 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5845 "MachineIndependent/glslang_tab.cpp" +#line 5901 "MachineIndependent/glslang_tab.cpp" break; case 74: /* logical_or_expression: logical_or_expression OR_OP logical_xor_expression */ -#line 781 "MachineIndependent/glslang.y" +#line 766 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.handleBinaryMath((yyvsp[-1].lex).loc, "||", EOpLogicalOr, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) (yyval.interm.intermTypedNode) = parseContext.intermediate.addConstantUnion(false, (yyvsp[-1].lex).loc); } -#line 5855 "MachineIndependent/glslang_tab.cpp" +#line 5911 "MachineIndependent/glslang_tab.cpp" break; case 75: /* conditional_expression: logical_or_expression */ -#line 789 "MachineIndependent/glslang.y" +#line 774 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5861 "MachineIndependent/glslang_tab.cpp" +#line 5917 "MachineIndependent/glslang_tab.cpp" break; case 76: /* $@1: %empty */ -#line 790 "MachineIndependent/glslang.y" +#line 775 "MachineIndependent/glslang.y" { ++parseContext.controlFlowNestingLevel; } -#line 5869 "MachineIndependent/glslang_tab.cpp" +#line 5925 "MachineIndependent/glslang_tab.cpp" break; case 77: /* conditional_expression: logical_or_expression QUESTION $@1 expression COLON assignment_expression */ -#line 793 "MachineIndependent/glslang.y" +#line 778 "MachineIndependent/glslang.y" { --parseContext.controlFlowNestingLevel; parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-5].interm.intermTypedNode)); @@ -5878,21 +5934,21 @@ yyreduce: parseContext.rValueErrorCheck((yyvsp[-1].lex).loc, ":", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.intermediate.addSelection((yyvsp[-5].interm.intermTypedNode), (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-4].lex).loc); if ((yyval.interm.intermTypedNode) == 0) { - parseContext.binaryOpError((yyvsp[-4].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + parseContext.binaryOpError((yyvsp[-4].lex).loc, ":", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs()), (yyvsp[0].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs())); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } } -#line 5886 "MachineIndependent/glslang_tab.cpp" +#line 5942 "MachineIndependent/glslang_tab.cpp" break; case 78: /* assignment_expression: conditional_expression */ -#line 808 "MachineIndependent/glslang.y" +#line 793 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 5892 "MachineIndependent/glslang_tab.cpp" +#line 5948 "MachineIndependent/glslang_tab.cpp" break; case 79: /* assignment_expression: unary_expression assignment_operator assignment_expression */ -#line 809 "MachineIndependent/glslang.y" +#line 794 "MachineIndependent/glslang.y" { parseContext.arrayObjectCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "array assignment"); parseContext.opaqueCheck((yyvsp[-1].interm).loc, (yyvsp[-2].interm.intermTypedNode)->getType(), "="); @@ -5902,155 +5958,155 @@ yyreduce: parseContext.rValueErrorCheck((yyvsp[-1].interm).loc, "assign", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.addAssign((yyvsp[-1].interm).loc, (yyvsp[-1].interm).op, (yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); if ((yyval.interm.intermTypedNode) == 0) { - parseContext.assignError((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + parseContext.assignError((yyvsp[-1].interm).loc, "assign", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs()), (yyvsp[0].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs())); (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } } -#line 5910 "MachineIndependent/glslang_tab.cpp" +#line 5966 "MachineIndependent/glslang_tab.cpp" break; case 80: /* assignment_operator: EQUAL */ -#line 825 "MachineIndependent/glslang.y" +#line 810 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAssign; } -#line 5919 "MachineIndependent/glslang_tab.cpp" +#line 5975 "MachineIndependent/glslang_tab.cpp" break; case 81: /* assignment_operator: MUL_ASSIGN */ -#line 829 "MachineIndependent/glslang.y" +#line 814 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpMulAssign; } -#line 5928 "MachineIndependent/glslang_tab.cpp" +#line 5984 "MachineIndependent/glslang_tab.cpp" break; case 82: /* assignment_operator: DIV_ASSIGN */ -#line 833 "MachineIndependent/glslang.y" +#line 818 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpDivAssign; } -#line 5937 "MachineIndependent/glslang_tab.cpp" +#line 5993 "MachineIndependent/glslang_tab.cpp" break; case 83: /* assignment_operator: MOD_ASSIGN */ -#line 837 "MachineIndependent/glslang.y" +#line 822 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "%="); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpModAssign; } -#line 5947 "MachineIndependent/glslang_tab.cpp" +#line 6003 "MachineIndependent/glslang_tab.cpp" break; case 84: /* assignment_operator: ADD_ASSIGN */ -#line 842 "MachineIndependent/glslang.y" +#line 827 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAddAssign; } -#line 5956 "MachineIndependent/glslang_tab.cpp" +#line 6012 "MachineIndependent/glslang_tab.cpp" break; case 85: /* assignment_operator: SUB_ASSIGN */ -#line 846 "MachineIndependent/glslang.y" +#line 831 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpSubAssign; } -#line 5965 "MachineIndependent/glslang_tab.cpp" +#line 6021 "MachineIndependent/glslang_tab.cpp" break; case 86: /* assignment_operator: LEFT_ASSIGN */ -#line 850 "MachineIndependent/glslang.y" +#line 835 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift left assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpLeftShiftAssign; } -#line 5974 "MachineIndependent/glslang_tab.cpp" +#line 6030 "MachineIndependent/glslang_tab.cpp" break; case 87: /* assignment_operator: RIGHT_ASSIGN */ -#line 854 "MachineIndependent/glslang.y" +#line 839 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bit-shift right assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpRightShiftAssign; } -#line 5983 "MachineIndependent/glslang_tab.cpp" +#line 6039 "MachineIndependent/glslang_tab.cpp" break; case 88: /* assignment_operator: AND_ASSIGN */ -#line 858 "MachineIndependent/glslang.y" +#line 843 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-and assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpAndAssign; } -#line 5992 "MachineIndependent/glslang_tab.cpp" +#line 6048 "MachineIndependent/glslang_tab.cpp" break; case 89: /* assignment_operator: XOR_ASSIGN */ -#line 862 "MachineIndependent/glslang.y" +#line 847 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-xor assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpExclusiveOrAssign; } -#line 6001 "MachineIndependent/glslang_tab.cpp" +#line 6057 "MachineIndependent/glslang_tab.cpp" break; case 90: /* assignment_operator: OR_ASSIGN */ -#line 866 "MachineIndependent/glslang.y" +#line 851 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "bitwise-or assign"); (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).op = EOpInclusiveOrAssign; } -#line 6010 "MachineIndependent/glslang_tab.cpp" +#line 6066 "MachineIndependent/glslang_tab.cpp" break; case 91: /* expression: assignment_expression */ -#line 873 "MachineIndependent/glslang.y" +#line 858 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 6018 "MachineIndependent/glslang_tab.cpp" +#line 6074 "MachineIndependent/glslang_tab.cpp" break; case 92: /* expression: expression COMMA assignment_expression */ -#line 876 "MachineIndependent/glslang.y" +#line 861 "MachineIndependent/glslang.y" { parseContext.samplerConstructorLocationCheck((yyvsp[-1].lex).loc, ",", (yyvsp[0].interm.intermTypedNode)); (yyval.interm.intermTypedNode) = parseContext.intermediate.addComma((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode), (yyvsp[-1].lex).loc); if ((yyval.interm.intermTypedNode) == 0) { - parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(), (yyvsp[0].interm.intermTypedNode)->getCompleteString()); + parseContext.binaryOpError((yyvsp[-1].lex).loc, ",", (yyvsp[-2].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs()), (yyvsp[0].interm.intermTypedNode)->getCompleteString(parseContext.intermediate.getEnhancedMsgs())); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } } -#line 6031 "MachineIndependent/glslang_tab.cpp" +#line 6087 "MachineIndependent/glslang_tab.cpp" break; case 93: /* constant_expression: conditional_expression */ -#line 887 "MachineIndependent/glslang.y" +#line 872 "MachineIndependent/glslang.y" { parseContext.constantValueCheck((yyvsp[0].interm.intermTypedNode), ""); (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 6040 "MachineIndependent/glslang_tab.cpp" +#line 6096 "MachineIndependent/glslang_tab.cpp" break; case 94: /* declaration: function_prototype SEMICOLON */ -#line 894 "MachineIndependent/glslang.y" +#line 879 "MachineIndependent/glslang.y" { parseContext.handleFunctionDeclarator((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).function, true /* prototype */); (yyval.interm.intermNode) = 0; // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature } -#line 6050 "MachineIndependent/glslang_tab.cpp" +#line 6106 "MachineIndependent/glslang_tab.cpp" break; case 95: /* declaration: spirv_instruction_qualifier function_prototype SEMICOLON */ -#line 900 "MachineIndependent/glslang.y" +#line 884 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[-1].interm).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V instruction qualifier"); (yyvsp[-1].interm).function->setSpirvInstruction(*(yyvsp[-2].interm.spirvInst)); // Attach SPIR-V intruction qualifier @@ -6058,31 +6114,31 @@ yyreduce: (yyval.interm.intermNode) = 0; // TODO: 4.0 functionality: subroutines: make the identifier a user type for this signature } -#line 6062 "MachineIndependent/glslang_tab.cpp" +#line 6118 "MachineIndependent/glslang_tab.cpp" break; case 96: /* declaration: spirv_execution_mode_qualifier SEMICOLON */ -#line 907 "MachineIndependent/glslang.y" +#line 891 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "SPIR-V execution mode qualifier"); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V execution mode qualifier"); (yyval.interm.intermNode) = 0; } -#line 6072 "MachineIndependent/glslang_tab.cpp" +#line 6128 "MachineIndependent/glslang_tab.cpp" break; case 97: /* declaration: init_declarator_list SEMICOLON */ -#line 913 "MachineIndependent/glslang.y" +#line 896 "MachineIndependent/glslang.y" { if ((yyvsp[-1].interm).intermNode && (yyvsp[-1].interm).intermNode->getAsAggregate()) (yyvsp[-1].interm).intermNode->getAsAggregate()->setOperator(EOpSequence); (yyval.interm.intermNode) = (yyvsp[-1].interm).intermNode; } -#line 6082 "MachineIndependent/glslang_tab.cpp" +#line 6138 "MachineIndependent/glslang_tab.cpp" break; case 98: /* declaration: PRECISION precision_qualifier type_specifier SEMICOLON */ -#line 918 "MachineIndependent/glslang.y" +#line 901 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyvsp[-3].lex).loc, ENoProfile, 130, 0, "precision statement"); // lazy setting of the previous scope's defaults, has effect only the first time it is called in a particular scope @@ -6090,75 +6146,75 @@ yyreduce: parseContext.setDefaultPrecision((yyvsp[-3].lex).loc, (yyvsp[-1].interm.type), (yyvsp[-2].interm.type).qualifier.precision); (yyval.interm.intermNode) = 0; } -#line 6094 "MachineIndependent/glslang_tab.cpp" +#line 6150 "MachineIndependent/glslang_tab.cpp" break; case 99: /* declaration: block_structure SEMICOLON */ -#line 925 "MachineIndependent/glslang.y" +#line 908 "MachineIndependent/glslang.y" { parseContext.declareBlock((yyvsp[-1].interm).loc, *(yyvsp[-1].interm).typeList); (yyval.interm.intermNode) = 0; } -#line 6103 "MachineIndependent/glslang_tab.cpp" +#line 6159 "MachineIndependent/glslang_tab.cpp" break; case 100: /* declaration: block_structure IDENTIFIER SEMICOLON */ -#line 929 "MachineIndependent/glslang.y" +#line 912 "MachineIndependent/glslang.y" { parseContext.declareBlock((yyvsp[-2].interm).loc, *(yyvsp[-2].interm).typeList, (yyvsp[-1].lex).string); (yyval.interm.intermNode) = 0; } -#line 6112 "MachineIndependent/glslang_tab.cpp" +#line 6168 "MachineIndependent/glslang_tab.cpp" break; case 101: /* declaration: block_structure IDENTIFIER array_specifier SEMICOLON */ -#line 933 "MachineIndependent/glslang.y" +#line 916 "MachineIndependent/glslang.y" { parseContext.declareBlock((yyvsp[-3].interm).loc, *(yyvsp[-3].interm).typeList, (yyvsp[-2].lex).string, (yyvsp[-1].interm).arraySizes); (yyval.interm.intermNode) = 0; } -#line 6121 "MachineIndependent/glslang_tab.cpp" +#line 6177 "MachineIndependent/glslang_tab.cpp" break; case 102: /* declaration: type_qualifier SEMICOLON */ -#line 937 "MachineIndependent/glslang.y" +#line 920 "MachineIndependent/glslang.y" { parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); parseContext.updateStandaloneQualifierDefaults((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type)); (yyval.interm.intermNode) = 0; } -#line 6131 "MachineIndependent/glslang_tab.cpp" +#line 6187 "MachineIndependent/glslang_tab.cpp" break; case 103: /* declaration: type_qualifier IDENTIFIER SEMICOLON */ -#line 942 "MachineIndependent/glslang.y" +#line 925 "MachineIndependent/glslang.y" { parseContext.checkNoShaderLayouts((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).shaderQualifiers); parseContext.addQualifierToExisting((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, *(yyvsp[-1].lex).string); (yyval.interm.intermNode) = 0; } -#line 6141 "MachineIndependent/glslang_tab.cpp" +#line 6197 "MachineIndependent/glslang_tab.cpp" break; case 104: /* declaration: type_qualifier IDENTIFIER identifier_list SEMICOLON */ -#line 947 "MachineIndependent/glslang.y" +#line 930 "MachineIndependent/glslang.y" { parseContext.checkNoShaderLayouts((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).shaderQualifiers); (yyvsp[-1].interm.identifierList)->push_back((yyvsp[-2].lex).string); parseContext.addQualifierToExisting((yyvsp[-3].interm.type).loc, (yyvsp[-3].interm.type).qualifier, *(yyvsp[-1].interm.identifierList)); (yyval.interm.intermNode) = 0; } -#line 6152 "MachineIndependent/glslang_tab.cpp" +#line 6208 "MachineIndependent/glslang_tab.cpp" break; case 105: /* $@2: %empty */ -#line 956 "MachineIndependent/glslang.y" +#line 939 "MachineIndependent/glslang.y" { parseContext.nestedBlockCheck((yyvsp[-2].interm.type).loc); } -#line 6158 "MachineIndependent/glslang_tab.cpp" +#line 6214 "MachineIndependent/glslang_tab.cpp" break; case 106: /* block_structure: type_qualifier IDENTIFIER LEFT_BRACE $@2 struct_declaration_list RIGHT_BRACE */ -#line 956 "MachineIndependent/glslang.y" +#line 939 "MachineIndependent/glslang.y" { --parseContext.blockNestingLevel; parseContext.blockName = (yyvsp[-4].lex).string; @@ -6168,101 +6224,113 @@ yyreduce: (yyval.interm).loc = (yyvsp[-5].interm.type).loc; (yyval.interm).typeList = (yyvsp[-1].interm.typeList); } -#line 6172 "MachineIndependent/glslang_tab.cpp" +#line 6228 "MachineIndependent/glslang_tab.cpp" break; case 107: /* identifier_list: COMMA IDENTIFIER */ -#line 967 "MachineIndependent/glslang.y" +#line 950 "MachineIndependent/glslang.y" { (yyval.interm.identifierList) = new TIdentifierList; (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); } -#line 6181 "MachineIndependent/glslang_tab.cpp" +#line 6237 "MachineIndependent/glslang_tab.cpp" break; case 108: /* identifier_list: identifier_list COMMA IDENTIFIER */ -#line 971 "MachineIndependent/glslang.y" +#line 954 "MachineIndependent/glslang.y" { (yyval.interm.identifierList) = (yyvsp[-2].interm.identifierList); (yyval.interm.identifierList)->push_back((yyvsp[0].lex).string); } -#line 6190 "MachineIndependent/glslang_tab.cpp" +#line 6246 "MachineIndependent/glslang_tab.cpp" break; case 109: /* function_prototype: function_declarator RIGHT_PAREN */ -#line 978 "MachineIndependent/glslang.y" +#line 961 "MachineIndependent/glslang.y" { (yyval.interm).function = (yyvsp[-1].interm.function); + if (parseContext.compileOnly) (yyval.interm).function->setExport(); (yyval.interm).loc = (yyvsp[0].lex).loc; } -#line 6199 "MachineIndependent/glslang_tab.cpp" +#line 6256 "MachineIndependent/glslang_tab.cpp" break; case 110: /* function_prototype: function_declarator RIGHT_PAREN attribute */ -#line 982 "MachineIndependent/glslang.y" +#line 966 "MachineIndependent/glslang.y" { (yyval.interm).function = (yyvsp[-2].interm.function); + if (parseContext.compileOnly) (yyval.interm).function->setExport(); (yyval.interm).loc = (yyvsp[-1].lex).loc; - parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + const char * extensions[2] = { E_GL_EXT_subgroup_uniform_control_flow, E_GL_EXT_maximal_reconvergence }; + parseContext.requireExtensions((yyvsp[-1].lex).loc, 2, extensions, "attribute"); parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[0].interm.attributes)); } -#line 6210 "MachineIndependent/glslang_tab.cpp" +#line 6269 "MachineIndependent/glslang_tab.cpp" break; case 111: /* function_prototype: attribute function_declarator RIGHT_PAREN */ -#line 988 "MachineIndependent/glslang.y" +#line 974 "MachineIndependent/glslang.y" { (yyval.interm).function = (yyvsp[-1].interm.function); + if (parseContext.compileOnly) (yyval.interm).function->setExport(); (yyval.interm).loc = (yyvsp[0].lex).loc; - parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + const char * extensions[2] = { E_GL_EXT_subgroup_uniform_control_flow, E_GL_EXT_maximal_reconvergence }; + parseContext.requireExtensions((yyvsp[0].lex).loc, 2, extensions, "attribute"); parseContext.handleFunctionAttributes((yyvsp[0].lex).loc, *(yyvsp[-2].interm.attributes)); } -#line 6221 "MachineIndependent/glslang_tab.cpp" +#line 6282 "MachineIndependent/glslang_tab.cpp" break; case 112: /* function_prototype: attribute function_declarator RIGHT_PAREN attribute */ -#line 994 "MachineIndependent/glslang.y" +#line 982 "MachineIndependent/glslang.y" { (yyval.interm).function = (yyvsp[-2].interm.function); + if (parseContext.compileOnly) (yyval.interm).function->setExport(); (yyval.interm).loc = (yyvsp[-1].lex).loc; - parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_subgroup_uniform_control_flow, "attribute"); + const char * extensions[2] = { E_GL_EXT_subgroup_uniform_control_flow, E_GL_EXT_maximal_reconvergence }; + parseContext.requireExtensions((yyvsp[-1].lex).loc, 2, extensions, "attribute"); parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[-3].interm.attributes)); parseContext.handleFunctionAttributes((yyvsp[-1].lex).loc, *(yyvsp[0].interm.attributes)); } -#line 6233 "MachineIndependent/glslang_tab.cpp" +#line 6296 "MachineIndependent/glslang_tab.cpp" break; case 113: /* function_declarator: function_header */ -#line 1004 "MachineIndependent/glslang.y" +#line 994 "MachineIndependent/glslang.y" { (yyval.interm.function) = (yyvsp[0].interm.function); } -#line 6241 "MachineIndependent/glslang_tab.cpp" +#line 6304 "MachineIndependent/glslang_tab.cpp" break; case 114: /* function_declarator: function_header_with_parameters */ -#line 1007 "MachineIndependent/glslang.y" +#line 997 "MachineIndependent/glslang.y" { (yyval.interm.function) = (yyvsp[0].interm.function); } -#line 6249 "MachineIndependent/glslang_tab.cpp" +#line 6312 "MachineIndependent/glslang_tab.cpp" break; case 115: /* function_header_with_parameters: function_header parameter_declaration */ -#line 1014 "MachineIndependent/glslang.y" +#line 1004 "MachineIndependent/glslang.y" { // Add the parameter (yyval.interm.function) = (yyvsp[-1].interm.function); if ((yyvsp[0].interm).param.type->getBasicType() != EbtVoid) - (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm).param); + { + if (!(parseContext.spvVersion.vulkan > 0 && parseContext.spvVersion.vulkanRelaxed)) + (yyvsp[-1].interm.function)->addParameter((yyvsp[0].interm).param); + else + parseContext.vkRelaxedRemapFunctionParameter((yyvsp[-1].interm.function), (yyvsp[0].interm).param); + } else delete (yyvsp[0].interm).param.type; } -#line 6262 "MachineIndependent/glslang_tab.cpp" +#line 6330 "MachineIndependent/glslang_tab.cpp" break; case 116: /* function_header_with_parameters: function_header_with_parameters COMMA parameter_declaration */ -#line 1022 "MachineIndependent/glslang.y" +#line 1017 "MachineIndependent/glslang.y" { // // Only first parameter of one-parameter functions can be void @@ -6277,14 +6345,17 @@ yyreduce: } else { // Add the parameter (yyval.interm.function) = (yyvsp[-2].interm.function); - (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); + if (!(parseContext.spvVersion.vulkan > 0 && parseContext.spvVersion.vulkanRelaxed)) + (yyvsp[-2].interm.function)->addParameter((yyvsp[0].interm).param); + else + parseContext.vkRelaxedRemapFunctionParameter((yyvsp[-2].interm.function), (yyvsp[0].interm).param); } } -#line 6284 "MachineIndependent/glslang_tab.cpp" +#line 6355 "MachineIndependent/glslang_tab.cpp" break; case 117: /* function_header: fully_specified_type IDENTIFIER LEFT_PAREN */ -#line 1042 "MachineIndependent/glslang.y" +#line 1040 "MachineIndependent/glslang.y" { if ((yyvsp[-2].interm.type).qualifier.storage != EvqGlobal && (yyvsp[-2].interm.type).qualifier.storage != EvqTemporary) { parseContext.error((yyvsp[-1].lex).loc, "no qualifiers allowed for function return", @@ -6304,11 +6375,11 @@ yyreduce: function = new TFunction((yyvsp[-1].lex).string, type); (yyval.interm.function) = function; } -#line 6308 "MachineIndependent/glslang_tab.cpp" +#line 6379 "MachineIndependent/glslang_tab.cpp" break; case 118: /* parameter_declarator: type_specifier IDENTIFIER */ -#line 1065 "MachineIndependent/glslang.y" +#line 1063 "MachineIndependent/glslang.y" { if ((yyvsp[-1].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-1].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -6320,15 +6391,15 @@ yyreduce: } parseContext.reservedErrorCheck((yyvsp[0].lex).loc, *(yyvsp[0].lex).string); - TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type))}; + TParameter param = {(yyvsp[0].lex).string, new TType((yyvsp[-1].interm.type)), {}}; (yyval.interm).loc = (yyvsp[0].lex).loc; (yyval.interm).param = param; } -#line 6328 "MachineIndependent/glslang_tab.cpp" +#line 6399 "MachineIndependent/glslang_tab.cpp" break; case 119: /* parameter_declarator: type_specifier IDENTIFIER array_specifier */ -#line 1080 "MachineIndependent/glslang.y" +#line 1078 "MachineIndependent/glslang.y" { if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -6343,180 +6414,178 @@ yyreduce: parseContext.arraySizeRequiredCheck((yyvsp[0].interm).loc, *(yyvsp[0].interm).arraySizes); parseContext.reservedErrorCheck((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string); - TParameter param = { (yyvsp[-1].lex).string, type }; + TParameter param = { (yyvsp[-1].lex).string, type, {} }; (yyval.interm).loc = (yyvsp[-1].lex).loc; (yyval.interm).param = param; } -#line 6352 "MachineIndependent/glslang_tab.cpp" +#line 6423 "MachineIndependent/glslang_tab.cpp" break; case 120: /* parameter_declaration: type_qualifier parameter_declarator */ -#line 1105 "MachineIndependent/glslang.y" +#line 1103 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier(), (yyval.interm).param.type->isCoopMat()); parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); } -#line 6368 "MachineIndependent/glslang_tab.cpp" +#line 6439 "MachineIndependent/glslang_tab.cpp" break; case 121: /* parameter_declaration: parameter_declarator */ -#line 1116 "MachineIndependent/glslang.y" +#line 1114 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier(), (yyval.interm).param.type->isCoopMat()); } -#line 6380 "MachineIndependent/glslang_tab.cpp" +#line 6451 "MachineIndependent/glslang_tab.cpp" break; case 122: /* parameter_declaration: type_qualifier parameter_type_specifier */ -#line 1126 "MachineIndependent/glslang.y" +#line 1124 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); if ((yyvsp[-1].interm.type).qualifier.precision != EpqNone) (yyval.interm).param.type->getQualifier().precision = (yyvsp[-1].interm.type).qualifier.precision; - parseContext.precisionQualifierCheck((yyvsp[-1].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + parseContext.precisionQualifierCheck((yyvsp[-1].interm.type).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier(), (yyval.interm).param.type->isCoopMat()); parseContext.checkNoShaderLayouts((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, (yyvsp[-1].interm.type).qualifier.storage, *(yyval.interm).param.type); parseContext.paramCheckFix((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, *(yyval.interm).param.type); } -#line 6395 "MachineIndependent/glslang_tab.cpp" +#line 6466 "MachineIndependent/glslang_tab.cpp" break; case 123: /* parameter_declaration: parameter_type_specifier */ -#line 1136 "MachineIndependent/glslang.y" +#line 1134 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); parseContext.parameterTypeCheck((yyvsp[0].interm).loc, EvqIn, *(yyvsp[0].interm).param.type); parseContext.paramCheckFixStorage((yyvsp[0].interm).loc, EvqTemporary, *(yyval.interm).param.type); - parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier()); + parseContext.precisionQualifierCheck((yyval.interm).loc, (yyval.interm).param.type->getBasicType(), (yyval.interm).param.type->getQualifier(), (yyval.interm).param.type->isCoopMat()); } -#line 6407 "MachineIndependent/glslang_tab.cpp" +#line 6478 "MachineIndependent/glslang_tab.cpp" break; case 124: /* parameter_type_specifier: type_specifier */ -#line 1146 "MachineIndependent/glslang.y" +#line 1144 "MachineIndependent/glslang.y" { - TParameter param = { 0, new TType((yyvsp[0].interm.type)) }; + TParameter param = { 0, new TType((yyvsp[0].interm.type)), {} }; (yyval.interm).param = param; if ((yyvsp[0].interm.type).arraySizes) parseContext.arraySizeRequiredCheck((yyvsp[0].interm.type).loc, *(yyvsp[0].interm.type).arraySizes); } -#line 6418 "MachineIndependent/glslang_tab.cpp" +#line 6489 "MachineIndependent/glslang_tab.cpp" break; case 125: /* init_declarator_list: single_declaration */ -#line 1155 "MachineIndependent/glslang.y" +#line 1153 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[0].interm); } -#line 6426 "MachineIndependent/glslang_tab.cpp" +#line 6497 "MachineIndependent/glslang_tab.cpp" break; case 126: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER */ -#line 1158 "MachineIndependent/glslang.y" +#line 1156 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-2].interm); parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-2].interm).type); } -#line 6435 "MachineIndependent/glslang_tab.cpp" +#line 6506 "MachineIndependent/glslang_tab.cpp" break; case 127: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER array_specifier */ -#line 1162 "MachineIndependent/glslang.y" +#line 1160 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-3].interm); parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-3].interm).type, (yyvsp[0].interm).arraySizes); } -#line 6444 "MachineIndependent/glslang_tab.cpp" +#line 6515 "MachineIndependent/glslang_tab.cpp" break; case 128: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER array_specifier EQUAL initializer */ -#line 1166 "MachineIndependent/glslang.y" +#line 1164 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-5].interm).type; TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-5].interm).type, (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-5].interm).intermNode, initNode, (yyvsp[-1].lex).loc); } -#line 6454 "MachineIndependent/glslang_tab.cpp" +#line 6525 "MachineIndependent/glslang_tab.cpp" break; case 129: /* init_declarator_list: init_declarator_list COMMA IDENTIFIER EQUAL initializer */ -#line 1171 "MachineIndependent/glslang.y" +#line 1169 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-4].interm).type; TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-4].interm).type, 0, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate((yyvsp[-4].interm).intermNode, initNode, (yyvsp[-1].lex).loc); } -#line 6464 "MachineIndependent/glslang_tab.cpp" +#line 6535 "MachineIndependent/glslang_tab.cpp" break; case 130: /* single_declaration: fully_specified_type */ -#line 1179 "MachineIndependent/glslang.y" +#line 1177 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[0].interm.type); (yyval.interm).intermNode = 0; - parseContext.declareTypeDefaults((yyval.interm).loc, (yyval.interm).type); - } -#line 6476 "MachineIndependent/glslang_tab.cpp" +#line 6545 "MachineIndependent/glslang_tab.cpp" break; case 131: /* single_declaration: fully_specified_type IDENTIFIER */ -#line 1186 "MachineIndependent/glslang.y" +#line 1182 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-1].interm.type); (yyval.interm).intermNode = 0; parseContext.declareVariable((yyvsp[0].lex).loc, *(yyvsp[0].lex).string, (yyvsp[-1].interm.type)); } -#line 6486 "MachineIndependent/glslang_tab.cpp" +#line 6555 "MachineIndependent/glslang_tab.cpp" break; case 132: /* single_declaration: fully_specified_type IDENTIFIER array_specifier */ -#line 1191 "MachineIndependent/glslang.y" +#line 1187 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-2].interm.type); (yyval.interm).intermNode = 0; parseContext.declareVariable((yyvsp[-1].lex).loc, *(yyvsp[-1].lex).string, (yyvsp[-2].interm.type), (yyvsp[0].interm).arraySizes); } -#line 6496 "MachineIndependent/glslang_tab.cpp" +#line 6565 "MachineIndependent/glslang_tab.cpp" break; case 133: /* single_declaration: fully_specified_type IDENTIFIER array_specifier EQUAL initializer */ -#line 1196 "MachineIndependent/glslang.y" +#line 1192 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-4].interm.type); TIntermNode* initNode = parseContext.declareVariable((yyvsp[-3].lex).loc, *(yyvsp[-3].lex).string, (yyvsp[-4].interm.type), (yyvsp[-2].interm).arraySizes, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); } -#line 6506 "MachineIndependent/glslang_tab.cpp" +#line 6575 "MachineIndependent/glslang_tab.cpp" break; case 134: /* single_declaration: fully_specified_type IDENTIFIER EQUAL initializer */ -#line 1201 "MachineIndependent/glslang.y" +#line 1197 "MachineIndependent/glslang.y" { (yyval.interm).type = (yyvsp[-3].interm.type); TIntermNode* initNode = parseContext.declareVariable((yyvsp[-2].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[-3].interm.type), 0, (yyvsp[0].interm.intermTypedNode)); (yyval.interm).intermNode = parseContext.intermediate.growAggregate(0, initNode, (yyvsp[-1].lex).loc); } -#line 6516 "MachineIndependent/glslang_tab.cpp" +#line 6585 "MachineIndependent/glslang_tab.cpp" break; case 135: /* fully_specified_type: type_specifier */ -#line 1210 "MachineIndependent/glslang.y" +#line 1206 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); @@ -6525,15 +6594,15 @@ yyreduce: parseContext.profileRequires((yyvsp[0].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); parseContext.profileRequires((yyvsp[0].interm.type).loc, EEsProfile, 300, 0, "arrayed type"); } - parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier); + parseContext.precisionQualifierCheck((yyval.interm.type).loc, (yyval.interm.type).basicType, (yyval.interm.type).qualifier, (yyval.interm.type).isCoopmat()); } -#line 6531 "MachineIndependent/glslang_tab.cpp" +#line 6600 "MachineIndependent/glslang_tab.cpp" break; case 136: /* fully_specified_type: type_qualifier type_specifier */ -#line 1220 "MachineIndependent/glslang.y" +#line 1216 "MachineIndependent/glslang.y" { - parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier); + parseContext.globalQualifierFixCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, false, &(yyvsp[0].interm.type)); parseContext.globalQualifierTypeCheck((yyvsp[-1].interm.type).loc, (yyvsp[-1].interm.type).qualifier, (yyvsp[0].interm.type)); if ((yyvsp[0].interm.type).arraySizes) { @@ -6547,7 +6616,7 @@ yyreduce: parseContext.checkNoShaderLayouts((yyvsp[0].interm.type).loc, (yyvsp[-1].interm.type).shaderQualifiers); (yyvsp[0].interm.type).shaderQualifiers.merge((yyvsp[-1].interm.type).shaderQualifiers); parseContext.mergeQualifiers((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier, (yyvsp[-1].interm.type).qualifier, true); - parseContext.precisionQualifierCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).basicType, (yyvsp[0].interm.type).qualifier); + parseContext.precisionQualifierCheck((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).basicType, (yyvsp[0].interm.type).qualifier, (yyvsp[0].interm.type).isCoopmat()); (yyval.interm.type) = (yyvsp[0].interm.type); @@ -6556,22 +6625,22 @@ yyreduce: (parseContext.language == EShLangFragment && (yyval.interm.type).qualifier.storage == EvqVaryingIn))) (yyval.interm.type).qualifier.smooth = true; } -#line 6560 "MachineIndependent/glslang_tab.cpp" +#line 6629 "MachineIndependent/glslang_tab.cpp" break; case 137: /* invariant_qualifier: INVARIANT */ -#line 1247 "MachineIndependent/glslang.y" +#line 1243 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "invariant"); parseContext.profileRequires((yyval.interm.type).loc, ENoProfile, 120, 0, "invariant"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.invariant = true; } -#line 6571 "MachineIndependent/glslang_tab.cpp" +#line 6640 "MachineIndependent/glslang_tab.cpp" break; case 138: /* interpolation_qualifier: SMOOTH */ -#line 1256 "MachineIndependent/glslang.y" +#line 1252 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "smooth"); parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "smooth"); @@ -6579,11 +6648,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.smooth = true; } -#line 6583 "MachineIndependent/glslang_tab.cpp" +#line 6652 "MachineIndependent/glslang_tab.cpp" break; case 139: /* interpolation_qualifier: FLAT */ -#line 1263 "MachineIndependent/glslang.y" +#line 1259 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "flat"); parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "flat"); @@ -6591,11 +6660,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.flat = true; } -#line 6595 "MachineIndependent/glslang_tab.cpp" +#line 6664 "MachineIndependent/glslang_tab.cpp" break; case 140: /* interpolation_qualifier: NOPERSPECTIVE */ -#line 1271 "MachineIndependent/glslang.y" +#line 1266 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "noperspective"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_NV_shader_noperspective_interpolation, "noperspective"); @@ -6603,11 +6672,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.nopersp = true; } -#line 6607 "MachineIndependent/glslang_tab.cpp" +#line 6676 "MachineIndependent/glslang_tab.cpp" break; case 141: /* interpolation_qualifier: EXPLICITINTERPAMD */ -#line 1278 "MachineIndependent/glslang.y" +#line 1273 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "__explicitInterpAMD"); parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 450, E_GL_AMD_shader_explicit_vertex_parameter, "explicit interpolation"); @@ -6615,11 +6684,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.explicitInterp = true; } -#line 6619 "MachineIndependent/glslang_tab.cpp" +#line 6688 "MachineIndependent/glslang_tab.cpp" break; case 142: /* interpolation_qualifier: PERVERTEXNV */ -#line 1285 "MachineIndependent/glslang.y" +#line 1280 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "pervertexNV"); parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 0, E_GL_NV_fragment_shader_barycentric, "fragment shader barycentric"); @@ -6628,123 +6697,151 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.pervertexNV = true; } -#line 6632 "MachineIndependent/glslang_tab.cpp" +#line 6701 "MachineIndependent/glslang_tab.cpp" break; - case 143: /* interpolation_qualifier: PERPRIMITIVENV */ -#line 1293 "MachineIndependent/glslang.y" + case 143: /* interpolation_qualifier: PERVERTEXEXT */ +#line 1288 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "pervertexEXT"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 0, E_GL_EXT_fragment_shader_barycentric, "fragment shader barycentric"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECompatibilityProfile, 0, E_GL_EXT_fragment_shader_barycentric, "fragment shader barycentric"); + parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 0, E_GL_EXT_fragment_shader_barycentric, "fragment shader barycentric"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.pervertexEXT = true; + } +#line 6714 "MachineIndependent/glslang_tab.cpp" + break; + + case 144: /* interpolation_qualifier: PERPRIMITIVENV */ +#line 1296 "MachineIndependent/glslang.y" { // No need for profile version or extension check. Shader stage already checks both. parseContext.globalCheck((yyvsp[0].lex).loc, "perprimitiveNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangFragmentMask | EShLangMeshNVMask), "perprimitiveNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangFragmentMask | EShLangMeshMask), "perprimitiveNV"); // Fragment shader stage doesn't check for extension. So we explicitly add below extension check. if (parseContext.language == EShLangFragment) parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_NV_mesh_shader, "perprimitiveNV"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.perPrimitiveNV = true; } -#line 6647 "MachineIndependent/glslang_tab.cpp" +#line 6729 "MachineIndependent/glslang_tab.cpp" break; - case 144: /* interpolation_qualifier: PERVIEWNV */ -#line 1303 "MachineIndependent/glslang.y" + case 145: /* interpolation_qualifier: PERPRIMITIVEEXT */ +#line 1306 "MachineIndependent/glslang.y" + { + // No need for profile version or extension check. Shader stage already checks both. + parseContext.globalCheck((yyvsp[0].lex).loc, "perprimitiveEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangFragmentMask | EShLangMeshMask), "perprimitiveEXT"); + // Fragment shader stage doesn't check for extension. So we explicitly add below extension check. + if (parseContext.language == EShLangFragment) + parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_mesh_shader, "perprimitiveEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.perPrimitiveNV = true; + } +#line 6744 "MachineIndependent/glslang_tab.cpp" + break; + + case 146: /* interpolation_qualifier: PERVIEWNV */ +#line 1316 "MachineIndependent/glslang.y" { // No need for profile version or extension check. Shader stage already checks both. parseContext.globalCheck((yyvsp[0].lex).loc, "perviewNV"); - parseContext.requireStage((yyvsp[0].lex).loc, EShLangMeshNV, "perviewNV"); + parseContext.requireStage((yyvsp[0].lex).loc, EShLangMesh, "perviewNV"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.perViewNV = true; } -#line 6659 "MachineIndependent/glslang_tab.cpp" +#line 6756 "MachineIndependent/glslang_tab.cpp" break; - case 145: /* interpolation_qualifier: PERTASKNV */ -#line 1310 "MachineIndependent/glslang.y" + case 147: /* interpolation_qualifier: PERTASKNV */ +#line 1323 "MachineIndependent/glslang.y" { // No need for profile version or extension check. Shader stage already checks both. parseContext.globalCheck((yyvsp[0].lex).loc, "taskNV"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTaskNVMask | EShLangMeshNVMask), "taskNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTaskMask | EShLangMeshMask), "taskNV"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.perTaskNV = true; } -#line 6671 "MachineIndependent/glslang_tab.cpp" +#line 6768 "MachineIndependent/glslang_tab.cpp" break; - case 146: /* layout_qualifier: LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN */ -#line 1321 "MachineIndependent/glslang.y" + case 148: /* layout_qualifier: LAYOUT LEFT_PAREN layout_qualifier_id_list RIGHT_PAREN */ +#line 1333 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[-1].interm.type); } -#line 6679 "MachineIndependent/glslang_tab.cpp" +#line 6776 "MachineIndependent/glslang_tab.cpp" break; - case 147: /* layout_qualifier_id_list: layout_qualifier_id */ -#line 1327 "MachineIndependent/glslang.y" + case 149: /* layout_qualifier_id_list: layout_qualifier_id */ +#line 1339 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6687 "MachineIndependent/glslang_tab.cpp" +#line 6784 "MachineIndependent/glslang_tab.cpp" break; - case 148: /* layout_qualifier_id_list: layout_qualifier_id_list COMMA layout_qualifier_id */ -#line 1330 "MachineIndependent/glslang.y" + case 150: /* layout_qualifier_id_list: layout_qualifier_id_list COMMA layout_qualifier_id */ +#line 1342 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[-2].interm.type); (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); parseContext.mergeObjectLayoutQualifiers((yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); } -#line 6697 "MachineIndependent/glslang_tab.cpp" +#line 6794 "MachineIndependent/glslang_tab.cpp" break; - case 149: /* layout_qualifier_id: IDENTIFIER */ -#line 1337 "MachineIndependent/glslang.y" + case 151: /* layout_qualifier_id: IDENTIFIER */ +#line 1349 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), *(yyvsp[0].lex).string); } -#line 6706 "MachineIndependent/glslang_tab.cpp" +#line 6803 "MachineIndependent/glslang_tab.cpp" break; - case 150: /* layout_qualifier_id: IDENTIFIER EQUAL constant_expression */ -#line 1341 "MachineIndependent/glslang.y" + case 152: /* layout_qualifier_id: IDENTIFIER EQUAL constant_expression */ +#line 1353 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-2].lex).loc); parseContext.setLayoutQualifier((yyvsp[-2].lex).loc, (yyval.interm.type), *(yyvsp[-2].lex).string, (yyvsp[0].interm.intermTypedNode)); } -#line 6715 "MachineIndependent/glslang_tab.cpp" +#line 6812 "MachineIndependent/glslang_tab.cpp" break; - case 151: /* layout_qualifier_id: SHARED */ -#line 1345 "MachineIndependent/glslang.y" + case 153: /* layout_qualifier_id: SHARED */ +#line 1357 "MachineIndependent/glslang.y" { // because "shared" is both an identifier and a keyword (yyval.interm.type).init((yyvsp[0].lex).loc); TString strShared("shared"); parseContext.setLayoutQualifier((yyvsp[0].lex).loc, (yyval.interm.type), strShared); } -#line 6725 "MachineIndependent/glslang_tab.cpp" +#line 6822 "MachineIndependent/glslang_tab.cpp" break; - case 152: /* precise_qualifier: PRECISE */ -#line 1354 "MachineIndependent/glslang.y" + case 154: /* precise_qualifier: PRECISE */ +#line 1365 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyval.interm.type).loc, ECoreProfile | ECompatibilityProfile, 400, E_GL_ARB_gpu_shader5, "precise"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 320, Num_AEP_gpu_shader5, AEP_gpu_shader5, "precise"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.noContraction = true; } -#line 6736 "MachineIndependent/glslang_tab.cpp" +#line 6833 "MachineIndependent/glslang_tab.cpp" break; - case 153: /* type_qualifier: single_type_qualifier */ -#line 1364 "MachineIndependent/glslang.y" + case 155: /* type_qualifier: single_type_qualifier */ +#line 1374 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6744 "MachineIndependent/glslang_tab.cpp" +#line 6841 "MachineIndependent/glslang_tab.cpp" break; - case 154: /* type_qualifier: type_qualifier single_type_qualifier */ -#line 1367 "MachineIndependent/glslang.y" + case 156: /* type_qualifier: type_qualifier single_type_qualifier */ +#line 1377 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[-1].interm.type); if ((yyval.interm.type).basicType == EbtVoid) @@ -6753,151 +6850,151 @@ yyreduce: (yyval.interm.type).shaderQualifiers.merge((yyvsp[0].interm.type).shaderQualifiers); parseContext.mergeQualifiers((yyval.interm.type).loc, (yyval.interm.type).qualifier, (yyvsp[0].interm.type).qualifier, false); } -#line 6757 "MachineIndependent/glslang_tab.cpp" +#line 6854 "MachineIndependent/glslang_tab.cpp" break; - case 155: /* single_type_qualifier: storage_qualifier */ -#line 1378 "MachineIndependent/glslang.y" + case 157: /* single_type_qualifier: storage_qualifier */ +#line 1388 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6765 "MachineIndependent/glslang_tab.cpp" +#line 6862 "MachineIndependent/glslang_tab.cpp" break; - case 156: /* single_type_qualifier: layout_qualifier */ -#line 1381 "MachineIndependent/glslang.y" + case 158: /* single_type_qualifier: layout_qualifier */ +#line 1391 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6773 "MachineIndependent/glslang_tab.cpp" +#line 6870 "MachineIndependent/glslang_tab.cpp" break; - case 157: /* single_type_qualifier: precision_qualifier */ -#line 1384 "MachineIndependent/glslang.y" + case 159: /* single_type_qualifier: precision_qualifier */ +#line 1394 "MachineIndependent/glslang.y" { parseContext.checkPrecisionQualifier((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type).qualifier.precision); (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6782 "MachineIndependent/glslang_tab.cpp" +#line 6879 "MachineIndependent/glslang_tab.cpp" break; - case 158: /* single_type_qualifier: interpolation_qualifier */ -#line 1388 "MachineIndependent/glslang.y" + case 160: /* single_type_qualifier: interpolation_qualifier */ +#line 1398 "MachineIndependent/glslang.y" { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6791 "MachineIndependent/glslang_tab.cpp" +#line 6888 "MachineIndependent/glslang_tab.cpp" break; - case 159: /* single_type_qualifier: invariant_qualifier */ -#line 1392 "MachineIndependent/glslang.y" + case 161: /* single_type_qualifier: invariant_qualifier */ +#line 1402 "MachineIndependent/glslang.y" { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6800 "MachineIndependent/glslang_tab.cpp" +#line 6897 "MachineIndependent/glslang_tab.cpp" break; - case 160: /* single_type_qualifier: precise_qualifier */ -#line 1397 "MachineIndependent/glslang.y" + case 162: /* single_type_qualifier: precise_qualifier */ +#line 1406 "MachineIndependent/glslang.y" { // allow inheritance of storage qualifier from block declaration (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6809 "MachineIndependent/glslang_tab.cpp" +#line 6906 "MachineIndependent/glslang_tab.cpp" break; - case 161: /* single_type_qualifier: non_uniform_qualifier */ -#line 1401 "MachineIndependent/glslang.y" + case 163: /* single_type_qualifier: non_uniform_qualifier */ +#line 1410 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6817 "MachineIndependent/glslang_tab.cpp" +#line 6914 "MachineIndependent/glslang_tab.cpp" break; - case 162: /* single_type_qualifier: spirv_storage_class_qualifier */ -#line 1404 "MachineIndependent/glslang.y" + case 164: /* single_type_qualifier: spirv_storage_class_qualifier */ +#line 1413 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].interm.type).loc, "spirv_storage_class"); parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V storage class qualifier"); (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6827 "MachineIndependent/glslang_tab.cpp" +#line 6924 "MachineIndependent/glslang_tab.cpp" break; - case 163: /* single_type_qualifier: spirv_decorate_qualifier */ -#line 1409 "MachineIndependent/glslang.y" + case 165: /* single_type_qualifier: spirv_decorate_qualifier */ +#line 1418 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V decorate qualifier"); (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 6836 "MachineIndependent/glslang_tab.cpp" +#line 6933 "MachineIndependent/glslang_tab.cpp" break; - case 164: /* single_type_qualifier: SPIRV_BY_REFERENCE */ -#line 1413 "MachineIndependent/glslang.y" + case 166: /* single_type_qualifier: SPIRV_BY_REFERENCE */ +#line 1422 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_reference"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.setSpirvByReference(); } -#line 6846 "MachineIndependent/glslang_tab.cpp" +#line 6943 "MachineIndependent/glslang_tab.cpp" break; - case 165: /* single_type_qualifier: SPIRV_LITERAL */ -#line 1418 "MachineIndependent/glslang.y" + case 167: /* single_type_qualifier: SPIRV_LITERAL */ +#line 1427 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_spirv_intrinsics, "spirv_by_literal"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.setSpirvLiteral(); } -#line 6856 "MachineIndependent/glslang_tab.cpp" +#line 6953 "MachineIndependent/glslang_tab.cpp" break; - case 166: /* storage_qualifier: CONST */ -#line 1427 "MachineIndependent/glslang.y" + case 168: /* storage_qualifier: CONST */ +#line 1435 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqConst; // will later turn into EvqConstReadOnly, if the initializer is not constant } -#line 6865 "MachineIndependent/glslang_tab.cpp" +#line 6962 "MachineIndependent/glslang_tab.cpp" break; - case 167: /* storage_qualifier: INOUT */ -#line 1431 "MachineIndependent/glslang.y" + case 169: /* storage_qualifier: INOUT */ +#line 1439 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "inout"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqInOut; } -#line 6875 "MachineIndependent/glslang_tab.cpp" +#line 6972 "MachineIndependent/glslang_tab.cpp" break; - case 168: /* storage_qualifier: IN */ -#line 1436 "MachineIndependent/glslang.y" + case 170: /* storage_qualifier: IN */ +#line 1444 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "in"); (yyval.interm.type).init((yyvsp[0].lex).loc); // whether this is a parameter "in" or a pipeline "in" will get sorted out a bit later (yyval.interm.type).qualifier.storage = EvqIn; } -#line 6886 "MachineIndependent/glslang_tab.cpp" +#line 6983 "MachineIndependent/glslang_tab.cpp" break; - case 169: /* storage_qualifier: OUT */ -#line 1442 "MachineIndependent/glslang.y" + case 171: /* storage_qualifier: OUT */ +#line 1450 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "out"); (yyval.interm.type).init((yyvsp[0].lex).loc); // whether this is a parameter "out" or a pipeline "out" will get sorted out a bit later (yyval.interm.type).qualifier.storage = EvqOut; } -#line 6897 "MachineIndependent/glslang_tab.cpp" +#line 6994 "MachineIndependent/glslang_tab.cpp" break; - case 170: /* storage_qualifier: CENTROID */ -#line 1448 "MachineIndependent/glslang.y" + case 172: /* storage_qualifier: CENTROID */ +#line 1456 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 120, 0, "centroid"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 300, 0, "centroid"); @@ -6905,44 +7002,54 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.centroid = true; } -#line 6909 "MachineIndependent/glslang_tab.cpp" +#line 7006 "MachineIndependent/glslang_tab.cpp" break; - case 171: /* storage_qualifier: UNIFORM */ -#line 1455 "MachineIndependent/glslang.y" + case 173: /* storage_qualifier: UNIFORM */ +#line 1463 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "uniform"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqUniform; } -#line 6919 "MachineIndependent/glslang_tab.cpp" +#line 7016 "MachineIndependent/glslang_tab.cpp" break; - case 172: /* storage_qualifier: SHARED */ -#line 1460 "MachineIndependent/glslang.y" + case 174: /* storage_qualifier: TILEIMAGEEXT */ +#line 1468 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "tileImageEXT"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqTileImageEXT; + } +#line 7026 "MachineIndependent/glslang_tab.cpp" + break; + + case 175: /* storage_qualifier: SHARED */ +#line 1473 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "shared"); parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, 430, E_GL_ARB_compute_shader, "shared"); parseContext.profileRequires((yyvsp[0].lex).loc, EEsProfile, 310, 0, "shared"); - parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangComputeMask | EShLangMeshNVMask | EShLangTaskNVMask), "shared"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangComputeMask | EShLangMeshMask | EShLangTaskMask), "shared"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqShared; } -#line 6932 "MachineIndependent/glslang_tab.cpp" +#line 7039 "MachineIndependent/glslang_tab.cpp" break; - case 173: /* storage_qualifier: BUFFER */ -#line 1468 "MachineIndependent/glslang.y" + case 176: /* storage_qualifier: BUFFER */ +#line 1481 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "buffer"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqBuffer; } -#line 6942 "MachineIndependent/glslang_tab.cpp" +#line 7049 "MachineIndependent/glslang_tab.cpp" break; - case 174: /* storage_qualifier: ATTRIBUTE */ -#line 1474 "MachineIndependent/glslang.y" + case 177: /* storage_qualifier: ATTRIBUTE */ +#line 1486 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangVertex, "attribute"); parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "attribute"); @@ -6955,11 +7062,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqVaryingIn; } -#line 6959 "MachineIndependent/glslang_tab.cpp" +#line 7066 "MachineIndependent/glslang_tab.cpp" break; - case 175: /* storage_qualifier: VARYING */ -#line 1486 "MachineIndependent/glslang.y" + case 178: /* storage_qualifier: VARYING */ +#line 1498 "MachineIndependent/glslang.y" { parseContext.checkDeprecated((yyvsp[0].lex).loc, ENoProfile, 130, "varying"); parseContext.checkDeprecated((yyvsp[0].lex).loc, ECoreProfile, 130, "varying"); @@ -6974,32 +7081,32 @@ yyreduce: else (yyval.interm.type).qualifier.storage = EvqVaryingIn; } -#line 6978 "MachineIndependent/glslang_tab.cpp" +#line 7085 "MachineIndependent/glslang_tab.cpp" break; - case 176: /* storage_qualifier: PATCH */ -#line 1500 "MachineIndependent/glslang.y" + case 179: /* storage_qualifier: PATCH */ +#line 1512 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "patch"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTessControlMask | EShLangTessEvaluationMask), "patch"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.patch = true; } -#line 6989 "MachineIndependent/glslang_tab.cpp" +#line 7096 "MachineIndependent/glslang_tab.cpp" break; - case 177: /* storage_qualifier: SAMPLE */ -#line 1506 "MachineIndependent/glslang.y" + case 180: /* storage_qualifier: SAMPLE */ +#line 1518 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "sample"); (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.sample = true; } -#line 6999 "MachineIndependent/glslang_tab.cpp" +#line 7106 "MachineIndependent/glslang_tab.cpp" break; - case 178: /* storage_qualifier: HITATTRNV */ -#line 1511 "MachineIndependent/glslang.y" + case 181: /* storage_qualifier: HITATTRNV */ +#line 1523 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeNV"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask @@ -7008,11 +7115,24 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqHitAttr; } -#line 7012 "MachineIndependent/glslang_tab.cpp" +#line 7119 "MachineIndependent/glslang_tab.cpp" break; - case 179: /* storage_qualifier: HITATTREXT */ -#line 1519 "MachineIndependent/glslang.y" + case 182: /* storage_qualifier: HITOBJECTATTRNV */ +#line 1531 "MachineIndependent/glslang.y" + { + parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeNV"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask + | EShLangMissMask), "hitObjectAttributeNV"); + parseContext.profileRequires((yyvsp[0].lex).loc, ECoreProfile, 460, E_GL_NV_shader_invocation_reorder, "hitObjectAttributeNV"); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqHitObjectAttrNV; + } +#line 7132 "MachineIndependent/glslang_tab.cpp" + break; + + case 183: /* storage_qualifier: HITATTREXT */ +#line 1539 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "hitAttributeEXT"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangIntersectMask | EShLangClosestHitMask @@ -7021,11 +7141,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqHitAttr; } -#line 7025 "MachineIndependent/glslang_tab.cpp" +#line 7145 "MachineIndependent/glslang_tab.cpp" break; - case 180: /* storage_qualifier: PAYLOADNV */ -#line 1527 "MachineIndependent/glslang.y" + case 184: /* storage_qualifier: PAYLOADNV */ +#line 1547 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadNV"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | @@ -7034,11 +7154,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqPayload; } -#line 7038 "MachineIndependent/glslang_tab.cpp" +#line 7158 "MachineIndependent/glslang_tab.cpp" break; - case 181: /* storage_qualifier: PAYLOADEXT */ -#line 1535 "MachineIndependent/glslang.y" + case 185: /* storage_qualifier: PAYLOADEXT */ +#line 1555 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadEXT"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | EShLangClosestHitMask | @@ -7047,11 +7167,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqPayload; } -#line 7051 "MachineIndependent/glslang_tab.cpp" +#line 7171 "MachineIndependent/glslang_tab.cpp" break; - case 182: /* storage_qualifier: PAYLOADINNV */ -#line 1543 "MachineIndependent/glslang.y" + case 186: /* storage_qualifier: PAYLOADINNV */ +#line 1563 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadInNV"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangClosestHitMask | @@ -7060,11 +7180,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqPayloadIn; } -#line 7064 "MachineIndependent/glslang_tab.cpp" +#line 7184 "MachineIndependent/glslang_tab.cpp" break; - case 183: /* storage_qualifier: PAYLOADINEXT */ -#line 1551 "MachineIndependent/glslang.y" + case 187: /* storage_qualifier: PAYLOADINEXT */ +#line 1571 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "rayPayloadInEXT"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangClosestHitMask | @@ -7073,11 +7193,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqPayloadIn; } -#line 7077 "MachineIndependent/glslang_tab.cpp" +#line 7197 "MachineIndependent/glslang_tab.cpp" break; - case 184: /* storage_qualifier: CALLDATANV */ -#line 1559 "MachineIndependent/glslang.y" + case 188: /* storage_qualifier: CALLDATANV */ +#line 1579 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataNV"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | @@ -7086,11 +7206,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqCallableData; } -#line 7090 "MachineIndependent/glslang_tab.cpp" +#line 7210 "MachineIndependent/glslang_tab.cpp" break; - case 185: /* storage_qualifier: CALLDATAEXT */ -#line 1567 "MachineIndependent/glslang.y" + case 189: /* storage_qualifier: CALLDATAEXT */ +#line 1587 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataEXT"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangRayGenMask | @@ -7099,11 +7219,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqCallableData; } -#line 7103 "MachineIndependent/glslang_tab.cpp" +#line 7223 "MachineIndependent/glslang_tab.cpp" break; - case 186: /* storage_qualifier: CALLDATAINNV */ -#line 1575 "MachineIndependent/glslang.y" + case 190: /* storage_qualifier: CALLDATAINNV */ +#line 1595 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataInNV"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInNV"); @@ -7111,11 +7231,11 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqCallableDataIn; } -#line 7115 "MachineIndependent/glslang_tab.cpp" +#line 7235 "MachineIndependent/glslang_tab.cpp" break; - case 187: /* storage_qualifier: CALLDATAINEXT */ -#line 1582 "MachineIndependent/glslang.y" + case 191: /* storage_qualifier: CALLDATAINEXT */ +#line 1602 "MachineIndependent/glslang.y" { parseContext.globalCheck((yyvsp[0].lex).loc, "callableDataInEXT"); parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangCallableMask), "callableDataInEXT"); @@ -7123,197 +7243,212 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.storage = EvqCallableDataIn; } -#line 7127 "MachineIndependent/glslang_tab.cpp" +#line 7247 "MachineIndependent/glslang_tab.cpp" break; - case 188: /* storage_qualifier: COHERENT */ -#line 1589 "MachineIndependent/glslang.y" + case 192: /* storage_qualifier: COHERENT */ +#line 1609 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.coherent = true; } -#line 7136 "MachineIndependent/glslang_tab.cpp" +#line 7256 "MachineIndependent/glslang_tab.cpp" break; - case 189: /* storage_qualifier: DEVICECOHERENT */ -#line 1593 "MachineIndependent/glslang.y" + case 193: /* storage_qualifier: DEVICECOHERENT */ +#line 1613 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "devicecoherent"); (yyval.interm.type).qualifier.devicecoherent = true; } -#line 7146 "MachineIndependent/glslang_tab.cpp" +#line 7266 "MachineIndependent/glslang_tab.cpp" break; - case 190: /* storage_qualifier: QUEUEFAMILYCOHERENT */ -#line 1598 "MachineIndependent/glslang.y" + case 194: /* storage_qualifier: QUEUEFAMILYCOHERENT */ +#line 1618 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "queuefamilycoherent"); (yyval.interm.type).qualifier.queuefamilycoherent = true; } -#line 7156 "MachineIndependent/glslang_tab.cpp" +#line 7276 "MachineIndependent/glslang_tab.cpp" break; - case 191: /* storage_qualifier: WORKGROUPCOHERENT */ -#line 1603 "MachineIndependent/glslang.y" + case 195: /* storage_qualifier: WORKGROUPCOHERENT */ +#line 1623 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "workgroupcoherent"); (yyval.interm.type).qualifier.workgroupcoherent = true; } -#line 7166 "MachineIndependent/glslang_tab.cpp" +#line 7286 "MachineIndependent/glslang_tab.cpp" break; - case 192: /* storage_qualifier: SUBGROUPCOHERENT */ -#line 1608 "MachineIndependent/glslang.y" + case 196: /* storage_qualifier: SUBGROUPCOHERENT */ +#line 1628 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "subgroupcoherent"); (yyval.interm.type).qualifier.subgroupcoherent = true; } -#line 7176 "MachineIndependent/glslang_tab.cpp" +#line 7296 "MachineIndependent/glslang_tab.cpp" break; - case 193: /* storage_qualifier: NONPRIVATE */ -#line 1613 "MachineIndependent/glslang.y" + case 197: /* storage_qualifier: NONPRIVATE */ +#line 1633 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_KHR_memory_scope_semantics, "nonprivate"); (yyval.interm.type).qualifier.nonprivate = true; } -#line 7186 "MachineIndependent/glslang_tab.cpp" +#line 7306 "MachineIndependent/glslang_tab.cpp" break; - case 194: /* storage_qualifier: SHADERCALLCOHERENT */ -#line 1618 "MachineIndependent/glslang.y" + case 198: /* storage_qualifier: SHADERCALLCOHERENT */ +#line 1638 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); parseContext.requireExtensions((yyvsp[0].lex).loc, 1, &E_GL_EXT_ray_tracing, "shadercallcoherent"); (yyval.interm.type).qualifier.shadercallcoherent = true; } -#line 7196 "MachineIndependent/glslang_tab.cpp" +#line 7316 "MachineIndependent/glslang_tab.cpp" break; - case 195: /* storage_qualifier: VOLATILE */ -#line 1623 "MachineIndependent/glslang.y" + case 199: /* storage_qualifier: VOLATILE */ +#line 1643 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.volatil = true; } -#line 7205 "MachineIndependent/glslang_tab.cpp" +#line 7325 "MachineIndependent/glslang_tab.cpp" break; - case 196: /* storage_qualifier: RESTRICT */ -#line 1627 "MachineIndependent/glslang.y" + case 200: /* storage_qualifier: RESTRICT */ +#line 1647 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.restrict = true; } -#line 7214 "MachineIndependent/glslang_tab.cpp" +#line 7334 "MachineIndependent/glslang_tab.cpp" break; - case 197: /* storage_qualifier: READONLY */ -#line 1631 "MachineIndependent/glslang.y" + case 201: /* storage_qualifier: READONLY */ +#line 1651 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.readonly = true; } -#line 7223 "MachineIndependent/glslang_tab.cpp" +#line 7343 "MachineIndependent/glslang_tab.cpp" break; - case 198: /* storage_qualifier: WRITEONLY */ -#line 1635 "MachineIndependent/glslang.y" + case 202: /* storage_qualifier: WRITEONLY */ +#line 1655 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.writeonly = true; } -#line 7232 "MachineIndependent/glslang_tab.cpp" +#line 7352 "MachineIndependent/glslang_tab.cpp" break; - case 199: /* storage_qualifier: SUBROUTINE */ -#line 1639 "MachineIndependent/glslang.y" + case 203: /* storage_qualifier: SUBROUTINE */ +#line 1659 "MachineIndependent/glslang.y" { parseContext.spvRemoved((yyvsp[0].lex).loc, "subroutine"); parseContext.globalCheck((yyvsp[0].lex).loc, "subroutine"); parseContext.unimplemented((yyvsp[0].lex).loc, "subroutine"); (yyval.interm.type).init((yyvsp[0].lex).loc); } -#line 7243 "MachineIndependent/glslang_tab.cpp" +#line 7363 "MachineIndependent/glslang_tab.cpp" break; - case 200: /* storage_qualifier: SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN */ -#line 1645 "MachineIndependent/glslang.y" + case 204: /* storage_qualifier: SUBROUTINE LEFT_PAREN type_name_list RIGHT_PAREN */ +#line 1665 "MachineIndependent/glslang.y" { parseContext.spvRemoved((yyvsp[-3].lex).loc, "subroutine"); parseContext.globalCheck((yyvsp[-3].lex).loc, "subroutine"); parseContext.unimplemented((yyvsp[-3].lex).loc, "subroutine"); (yyval.interm.type).init((yyvsp[-3].lex).loc); } -#line 7254 "MachineIndependent/glslang_tab.cpp" +#line 7374 "MachineIndependent/glslang_tab.cpp" break; - case 201: /* non_uniform_qualifier: NONUNIFORM */ -#line 1656 "MachineIndependent/glslang.y" + case 205: /* storage_qualifier: TASKPAYLOADWORKGROUPEXT */ +#line 1671 "MachineIndependent/glslang.y" + { + // No need for profile version or extension check. Shader stage already checks both. + parseContext.globalCheck((yyvsp[0].lex).loc, "taskPayloadSharedEXT"); + parseContext.requireStage((yyvsp[0].lex).loc, (EShLanguageMask)(EShLangTaskMask | EShLangMeshMask), "taskPayloadSharedEXT "); + (yyval.interm.type).init((yyvsp[0].lex).loc); + (yyval.interm.type).qualifier.storage = EvqtaskPayloadSharedEXT; + } +#line 7386 "MachineIndependent/glslang_tab.cpp" + break; + + case 206: /* non_uniform_qualifier: NONUNIFORM */ +#line 1681 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc); (yyval.interm.type).qualifier.nonUniform = true; } -#line 7263 "MachineIndependent/glslang_tab.cpp" +#line 7395 "MachineIndependent/glslang_tab.cpp" break; - case 202: /* type_name_list: IDENTIFIER */ -#line 1663 "MachineIndependent/glslang.y" + case 207: /* type_name_list: IDENTIFIER */ +#line 1688 "MachineIndependent/glslang.y" { // TODO } -#line 7271 "MachineIndependent/glslang_tab.cpp" +#line 7403 "MachineIndependent/glslang_tab.cpp" break; - case 203: /* type_name_list: type_name_list COMMA IDENTIFIER */ -#line 1666 "MachineIndependent/glslang.y" + case 208: /* type_name_list: type_name_list COMMA IDENTIFIER */ +#line 1691 "MachineIndependent/glslang.y" { // TODO: 4.0 semantics: subroutines // 1) make sure each identifier is a type declared earlier with SUBROUTINE // 2) save all of the identifiers for future comparison with the declared function } -#line 7281 "MachineIndependent/glslang_tab.cpp" +#line 7413 "MachineIndependent/glslang_tab.cpp" break; - case 204: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt */ -#line 1675 "MachineIndependent/glslang.y" + case 209: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt */ +#line 1699 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[-1].interm.type); (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); (yyval.interm.type).typeParameters = (yyvsp[0].interm.typeParameters); + parseContext.coopMatTypeParametersCheck((yyvsp[-1].interm.type).loc, (yyval.interm.type)); + } -#line 7291 "MachineIndependent/glslang_tab.cpp" +#line 7425 "MachineIndependent/glslang_tab.cpp" break; - case 205: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt array_specifier */ -#line 1680 "MachineIndependent/glslang.y" + case 210: /* type_specifier: type_specifier_nonarray type_parameter_specifier_opt array_specifier */ +#line 1706 "MachineIndependent/glslang.y" { parseContext.arrayOfArrayVersionCheck((yyvsp[0].interm).loc, (yyvsp[0].interm).arraySizes); (yyval.interm.type) = (yyvsp[-2].interm.type); (yyval.interm.type).qualifier.precision = parseContext.getDefaultPrecision((yyval.interm.type)); (yyval.interm.type).typeParameters = (yyvsp[-1].interm.typeParameters); (yyval.interm.type).arraySizes = (yyvsp[0].interm).arraySizes; + parseContext.coopMatTypeParametersCheck((yyvsp[-2].interm.type).loc, (yyval.interm.type)); } -#line 7303 "MachineIndependent/glslang_tab.cpp" +#line 7438 "MachineIndependent/glslang_tab.cpp" break; - case 206: /* array_specifier: LEFT_BRACKET RIGHT_BRACKET */ -#line 1690 "MachineIndependent/glslang.y" + case 211: /* array_specifier: LEFT_BRACKET RIGHT_BRACKET */ +#line 1717 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[-1].lex).loc; (yyval.interm).arraySizes = new TArraySizes; (yyval.interm).arraySizes->addInnerSize(); } -#line 7313 "MachineIndependent/glslang_tab.cpp" +#line 7448 "MachineIndependent/glslang_tab.cpp" break; - case 207: /* array_specifier: LEFT_BRACKET conditional_expression RIGHT_BRACKET */ -#line 1695 "MachineIndependent/glslang.y" + case 212: /* array_specifier: LEFT_BRACKET conditional_expression RIGHT_BRACKET */ +#line 1722 "MachineIndependent/glslang.y" { (yyval.interm).loc = (yyvsp[-2].lex).loc; (yyval.interm).arraySizes = new TArraySizes; @@ -7322,20 +7457,20 @@ yyreduce: parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); (yyval.interm).arraySizes->addInnerSize(size); } -#line 7326 "MachineIndependent/glslang_tab.cpp" +#line 7461 "MachineIndependent/glslang_tab.cpp" break; - case 208: /* array_specifier: array_specifier LEFT_BRACKET RIGHT_BRACKET */ -#line 1703 "MachineIndependent/glslang.y" + case 213: /* array_specifier: array_specifier LEFT_BRACKET RIGHT_BRACKET */ +#line 1730 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-2].interm); (yyval.interm).arraySizes->addInnerSize(); } -#line 7335 "MachineIndependent/glslang_tab.cpp" +#line 7470 "MachineIndependent/glslang_tab.cpp" break; - case 209: /* array_specifier: array_specifier LEFT_BRACKET conditional_expression RIGHT_BRACKET */ -#line 1707 "MachineIndependent/glslang.y" + case 214: /* array_specifier: array_specifier LEFT_BRACKET conditional_expression RIGHT_BRACKET */ +#line 1734 "MachineIndependent/glslang.y" { (yyval.interm) = (yyvsp[-3].interm); @@ -7343,348 +7478,360 @@ yyreduce: parseContext.arraySizeCheck((yyvsp[-1].interm.intermTypedNode)->getLoc(), (yyvsp[-1].interm.intermTypedNode), size, "array size"); (yyval.interm).arraySizes->addInnerSize(size); } -#line 7347 "MachineIndependent/glslang_tab.cpp" +#line 7482 "MachineIndependent/glslang_tab.cpp" break; - case 210: /* type_parameter_specifier_opt: type_parameter_specifier */ -#line 1717 "MachineIndependent/glslang.y" + case 215: /* type_parameter_specifier_opt: type_parameter_specifier */ +#line 1744 "MachineIndependent/glslang.y" { (yyval.interm.typeParameters) = (yyvsp[0].interm.typeParameters); } -#line 7355 "MachineIndependent/glslang_tab.cpp" +#line 7490 "MachineIndependent/glslang_tab.cpp" break; - case 211: /* type_parameter_specifier_opt: %empty */ -#line 1720 "MachineIndependent/glslang.y" + case 216: /* type_parameter_specifier_opt: %empty */ +#line 1747 "MachineIndependent/glslang.y" { (yyval.interm.typeParameters) = 0; } -#line 7363 "MachineIndependent/glslang_tab.cpp" +#line 7498 "MachineIndependent/glslang_tab.cpp" break; - case 212: /* type_parameter_specifier: LEFT_ANGLE type_parameter_specifier_list RIGHT_ANGLE */ -#line 1726 "MachineIndependent/glslang.y" + case 217: /* type_parameter_specifier: LEFT_ANGLE type_parameter_specifier_list RIGHT_ANGLE */ +#line 1753 "MachineIndependent/glslang.y" { (yyval.interm.typeParameters) = (yyvsp[-1].interm.typeParameters); } -#line 7371 "MachineIndependent/glslang_tab.cpp" +#line 7506 "MachineIndependent/glslang_tab.cpp" break; - case 213: /* type_parameter_specifier_list: unary_expression */ -#line 1732 "MachineIndependent/glslang.y" + case 218: /* type_parameter_specifier_list: type_specifier */ +#line 1759 "MachineIndependent/glslang.y" + { + (yyval.interm.typeParameters) = new TTypeParameters; + (yyval.interm.typeParameters)->arraySizes = new TArraySizes; + (yyval.interm.typeParameters)->spirvType = (yyvsp[0].interm.type).spirvType; + (yyval.interm.typeParameters)->basicType = (yyvsp[0].interm.type).basicType; + } +#line 7517 "MachineIndependent/glslang_tab.cpp" + break; + + case 219: /* type_parameter_specifier_list: unary_expression */ +#line 1765 "MachineIndependent/glslang.y" { - (yyval.interm.typeParameters) = new TArraySizes; + (yyval.interm.typeParameters) = new TTypeParameters; + (yyval.interm.typeParameters)->arraySizes = new TArraySizes; TArraySize size; - parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); - (yyval.interm.typeParameters)->addInnerSize(size); + parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter", true); + (yyval.interm.typeParameters)->arraySizes->addInnerSize(size); } -#line 7383 "MachineIndependent/glslang_tab.cpp" +#line 7530 "MachineIndependent/glslang_tab.cpp" break; - case 214: /* type_parameter_specifier_list: type_parameter_specifier_list COMMA unary_expression */ -#line 1739 "MachineIndependent/glslang.y" + case 220: /* type_parameter_specifier_list: type_parameter_specifier_list COMMA unary_expression */ +#line 1773 "MachineIndependent/glslang.y" { (yyval.interm.typeParameters) = (yyvsp[-2].interm.typeParameters); TArraySize size; - parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter"); - (yyval.interm.typeParameters)->addInnerSize(size); + parseContext.arraySizeCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode), size, "type parameter", true); + (yyval.interm.typeParameters)->arraySizes->addInnerSize(size); } -#line 7395 "MachineIndependent/glslang_tab.cpp" +#line 7542 "MachineIndependent/glslang_tab.cpp" break; - case 215: /* type_specifier_nonarray: VOID */ -#line 1749 "MachineIndependent/glslang.y" + case 221: /* type_specifier_nonarray: VOID */ +#line 1783 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtVoid; } -#line 7404 "MachineIndependent/glslang_tab.cpp" +#line 7551 "MachineIndependent/glslang_tab.cpp" break; - case 216: /* type_specifier_nonarray: FLOAT */ -#line 1753 "MachineIndependent/glslang.y" + case 222: /* type_specifier_nonarray: FLOAT */ +#line 1787 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; } -#line 7413 "MachineIndependent/glslang_tab.cpp" +#line 7560 "MachineIndependent/glslang_tab.cpp" break; - case 217: /* type_specifier_nonarray: INT */ -#line 1757 "MachineIndependent/glslang.y" + case 223: /* type_specifier_nonarray: INT */ +#line 1791 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; } -#line 7422 "MachineIndependent/glslang_tab.cpp" +#line 7569 "MachineIndependent/glslang_tab.cpp" break; - case 218: /* type_specifier_nonarray: UINT */ -#line 1761 "MachineIndependent/glslang.y" + case 224: /* type_specifier_nonarray: UINT */ +#line 1795 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; } -#line 7432 "MachineIndependent/glslang_tab.cpp" +#line 7579 "MachineIndependent/glslang_tab.cpp" break; - case 219: /* type_specifier_nonarray: BOOL */ -#line 1766 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - } -#line 7441 "MachineIndependent/glslang_tab.cpp" - break; - - case 220: /* type_specifier_nonarray: VEC2 */ -#line 1770 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(2); - } -#line 7451 "MachineIndependent/glslang_tab.cpp" - break; - - case 221: /* type_specifier_nonarray: VEC3 */ -#line 1775 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(3); - } -#line 7461 "MachineIndependent/glslang_tab.cpp" - break; - - case 222: /* type_specifier_nonarray: VEC4 */ -#line 1780 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(4); - } -#line 7471 "MachineIndependent/glslang_tab.cpp" - break; - - case 223: /* type_specifier_nonarray: BVEC2 */ -#line 1785 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(2); - } -#line 7481 "MachineIndependent/glslang_tab.cpp" - break; - - case 224: /* type_specifier_nonarray: BVEC3 */ -#line 1790 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(3); - } -#line 7491 "MachineIndependent/glslang_tab.cpp" - break; - - case 225: /* type_specifier_nonarray: BVEC4 */ -#line 1795 "MachineIndependent/glslang.y" - { - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtBool; - (yyval.interm.type).setVector(4); - } -#line 7501 "MachineIndependent/glslang_tab.cpp" - break; - - case 226: /* type_specifier_nonarray: IVEC2 */ + case 225: /* type_specifier_nonarray: BOOL */ #line 1800 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + } +#line 7588 "MachineIndependent/glslang_tab.cpp" + break; + + case 226: /* type_specifier_nonarray: VEC2 */ +#line 1804 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 7598 "MachineIndependent/glslang_tab.cpp" + break; + + case 227: /* type_specifier_nonarray: VEC3 */ +#line 1809 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 7608 "MachineIndependent/glslang_tab.cpp" + break; + + case 228: /* type_specifier_nonarray: VEC4 */ +#line 1814 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 7618 "MachineIndependent/glslang_tab.cpp" + break; + + case 229: /* type_specifier_nonarray: BVEC2 */ +#line 1819 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(2); + } +#line 7628 "MachineIndependent/glslang_tab.cpp" + break; + + case 230: /* type_specifier_nonarray: BVEC3 */ +#line 1824 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(3); + } +#line 7638 "MachineIndependent/glslang_tab.cpp" + break; + + case 231: /* type_specifier_nonarray: BVEC4 */ +#line 1829 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtBool; + (yyval.interm.type).setVector(4); + } +#line 7648 "MachineIndependent/glslang_tab.cpp" + break; + + case 232: /* type_specifier_nonarray: IVEC2 */ +#line 1834 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(2); } -#line 7511 "MachineIndependent/glslang_tab.cpp" +#line 7658 "MachineIndependent/glslang_tab.cpp" break; - case 227: /* type_specifier_nonarray: IVEC3 */ -#line 1805 "MachineIndependent/glslang.y" + case 233: /* type_specifier_nonarray: IVEC3 */ +#line 1839 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(3); } -#line 7521 "MachineIndependent/glslang_tab.cpp" +#line 7668 "MachineIndependent/glslang_tab.cpp" break; - case 228: /* type_specifier_nonarray: IVEC4 */ -#line 1810 "MachineIndependent/glslang.y" + case 234: /* type_specifier_nonarray: IVEC4 */ +#line 1844 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(4); } -#line 7531 "MachineIndependent/glslang_tab.cpp" +#line 7678 "MachineIndependent/glslang_tab.cpp" break; - case 229: /* type_specifier_nonarray: UVEC2 */ -#line 1815 "MachineIndependent/glslang.y" + case 235: /* type_specifier_nonarray: UVEC2 */ +#line 1849 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; (yyval.interm.type).setVector(2); } -#line 7542 "MachineIndependent/glslang_tab.cpp" +#line 7689 "MachineIndependent/glslang_tab.cpp" break; - case 230: /* type_specifier_nonarray: UVEC3 */ -#line 1821 "MachineIndependent/glslang.y" + case 236: /* type_specifier_nonarray: UVEC3 */ +#line 1855 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; (yyval.interm.type).setVector(3); } -#line 7553 "MachineIndependent/glslang_tab.cpp" +#line 7700 "MachineIndependent/glslang_tab.cpp" break; - case 231: /* type_specifier_nonarray: UVEC4 */ -#line 1827 "MachineIndependent/glslang.y" + case 237: /* type_specifier_nonarray: UVEC4 */ +#line 1861 "MachineIndependent/glslang.y" { parseContext.fullIntegerCheck((yyvsp[0].lex).loc, "unsigned integer vector"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; (yyval.interm.type).setVector(4); } -#line 7564 "MachineIndependent/glslang_tab.cpp" +#line 7711 "MachineIndependent/glslang_tab.cpp" break; - case 232: /* type_specifier_nonarray: MAT2 */ -#line 1833 "MachineIndependent/glslang.y" + case 238: /* type_specifier_nonarray: MAT2 */ +#line 1867 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 7574 "MachineIndependent/glslang_tab.cpp" +#line 7721 "MachineIndependent/glslang_tab.cpp" break; - case 233: /* type_specifier_nonarray: MAT3 */ -#line 1838 "MachineIndependent/glslang.y" + case 239: /* type_specifier_nonarray: MAT3 */ +#line 1872 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 7584 "MachineIndependent/glslang_tab.cpp" +#line 7731 "MachineIndependent/glslang_tab.cpp" break; - case 234: /* type_specifier_nonarray: MAT4 */ -#line 1843 "MachineIndependent/glslang.y" + case 240: /* type_specifier_nonarray: MAT4 */ +#line 1877 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 7594 "MachineIndependent/glslang_tab.cpp" +#line 7741 "MachineIndependent/glslang_tab.cpp" break; - case 235: /* type_specifier_nonarray: MAT2X2 */ -#line 1848 "MachineIndependent/glslang.y" + case 241: /* type_specifier_nonarray: MAT2X2 */ +#line 1882 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 7604 "MachineIndependent/glslang_tab.cpp" +#line 7751 "MachineIndependent/glslang_tab.cpp" break; - case 236: /* type_specifier_nonarray: MAT2X3 */ -#line 1853 "MachineIndependent/glslang.y" + case 242: /* type_specifier_nonarray: MAT2X3 */ +#line 1887 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 3); } -#line 7614 "MachineIndependent/glslang_tab.cpp" +#line 7761 "MachineIndependent/glslang_tab.cpp" break; - case 237: /* type_specifier_nonarray: MAT2X4 */ -#line 1858 "MachineIndependent/glslang.y" + case 243: /* type_specifier_nonarray: MAT2X4 */ +#line 1892 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 4); } -#line 7624 "MachineIndependent/glslang_tab.cpp" +#line 7771 "MachineIndependent/glslang_tab.cpp" break; - case 238: /* type_specifier_nonarray: MAT3X2 */ -#line 1863 "MachineIndependent/glslang.y" + case 244: /* type_specifier_nonarray: MAT3X2 */ +#line 1897 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 2); } -#line 7634 "MachineIndependent/glslang_tab.cpp" +#line 7781 "MachineIndependent/glslang_tab.cpp" break; - case 239: /* type_specifier_nonarray: MAT3X3 */ -#line 1868 "MachineIndependent/glslang.y" + case 245: /* type_specifier_nonarray: MAT3X3 */ +#line 1902 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 7644 "MachineIndependent/glslang_tab.cpp" +#line 7791 "MachineIndependent/glslang_tab.cpp" break; - case 240: /* type_specifier_nonarray: MAT3X4 */ -#line 1873 "MachineIndependent/glslang.y" + case 246: /* type_specifier_nonarray: MAT3X4 */ +#line 1907 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 4); } -#line 7654 "MachineIndependent/glslang_tab.cpp" +#line 7801 "MachineIndependent/glslang_tab.cpp" break; - case 241: /* type_specifier_nonarray: MAT4X2 */ -#line 1878 "MachineIndependent/glslang.y" + case 247: /* type_specifier_nonarray: MAT4X2 */ +#line 1912 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 2); } -#line 7664 "MachineIndependent/glslang_tab.cpp" +#line 7811 "MachineIndependent/glslang_tab.cpp" break; - case 242: /* type_specifier_nonarray: MAT4X3 */ -#line 1883 "MachineIndependent/glslang.y" + case 248: /* type_specifier_nonarray: MAT4X3 */ +#line 1917 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 3); } -#line 7674 "MachineIndependent/glslang_tab.cpp" +#line 7821 "MachineIndependent/glslang_tab.cpp" break; - case 243: /* type_specifier_nonarray: MAT4X4 */ -#line 1888 "MachineIndependent/glslang.y" + case 249: /* type_specifier_nonarray: MAT4X4 */ +#line 1922 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 7684 "MachineIndependent/glslang_tab.cpp" +#line 7831 "MachineIndependent/glslang_tab.cpp" break; - case 244: /* type_specifier_nonarray: DOUBLE */ -#line 1894 "MachineIndependent/glslang.y" + case 250: /* type_specifier_nonarray: DOUBLE */ +#line 1927 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -7692,121 +7839,121 @@ yyreduce: (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; } -#line 7696 "MachineIndependent/glslang_tab.cpp" +#line 7843 "MachineIndependent/glslang_tab.cpp" break; - case 245: /* type_specifier_nonarray: FLOAT16_T */ -#line 1901 "MachineIndependent/glslang.y" + case 251: /* type_specifier_nonarray: FLOAT16_T */ +#line 1934 "MachineIndependent/glslang.y" { parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "float16_t", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat16; } -#line 7706 "MachineIndependent/glslang_tab.cpp" +#line 7853 "MachineIndependent/glslang_tab.cpp" break; - case 246: /* type_specifier_nonarray: FLOAT32_T */ -#line 1906 "MachineIndependent/glslang.y" + case 252: /* type_specifier_nonarray: FLOAT32_T */ +#line 1939 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; } -#line 7716 "MachineIndependent/glslang_tab.cpp" +#line 7863 "MachineIndependent/glslang_tab.cpp" break; - case 247: /* type_specifier_nonarray: FLOAT64_T */ -#line 1911 "MachineIndependent/glslang.y" + case 253: /* type_specifier_nonarray: FLOAT64_T */ +#line 1944 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; } -#line 7726 "MachineIndependent/glslang_tab.cpp" +#line 7873 "MachineIndependent/glslang_tab.cpp" break; - case 248: /* type_specifier_nonarray: INT8_T */ -#line 1916 "MachineIndependent/glslang.y" + case 254: /* type_specifier_nonarray: INT8_T */ +#line 1949 "MachineIndependent/glslang.y" { parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt8; } -#line 7736 "MachineIndependent/glslang_tab.cpp" +#line 7883 "MachineIndependent/glslang_tab.cpp" break; - case 249: /* type_specifier_nonarray: UINT8_T */ -#line 1921 "MachineIndependent/glslang.y" + case 255: /* type_specifier_nonarray: UINT8_T */ +#line 1954 "MachineIndependent/glslang.y" { parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint8; } -#line 7746 "MachineIndependent/glslang_tab.cpp" +#line 7893 "MachineIndependent/glslang_tab.cpp" break; - case 250: /* type_specifier_nonarray: INT16_T */ -#line 1926 "MachineIndependent/glslang.y" + case 256: /* type_specifier_nonarray: INT16_T */ +#line 1959 "MachineIndependent/glslang.y" { parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt16; } -#line 7756 "MachineIndependent/glslang_tab.cpp" +#line 7903 "MachineIndependent/glslang_tab.cpp" break; - case 251: /* type_specifier_nonarray: UINT16_T */ -#line 1931 "MachineIndependent/glslang.y" + case 257: /* type_specifier_nonarray: UINT16_T */ +#line 1964 "MachineIndependent/glslang.y" { parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint16; } -#line 7766 "MachineIndependent/glslang_tab.cpp" +#line 7913 "MachineIndependent/glslang_tab.cpp" break; - case 252: /* type_specifier_nonarray: INT32_T */ -#line 1936 "MachineIndependent/glslang.y" + case 258: /* type_specifier_nonarray: INT32_T */ +#line 1969 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; } -#line 7776 "MachineIndependent/glslang_tab.cpp" +#line 7923 "MachineIndependent/glslang_tab.cpp" break; - case 253: /* type_specifier_nonarray: UINT32_T */ -#line 1941 "MachineIndependent/glslang.y" + case 259: /* type_specifier_nonarray: UINT32_T */ +#line 1974 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; } -#line 7786 "MachineIndependent/glslang_tab.cpp" +#line 7933 "MachineIndependent/glslang_tab.cpp" break; - case 254: /* type_specifier_nonarray: INT64_T */ -#line 1946 "MachineIndependent/glslang.y" + case 260: /* type_specifier_nonarray: INT64_T */ +#line 1979 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt64; } -#line 7796 "MachineIndependent/glslang_tab.cpp" +#line 7943 "MachineIndependent/glslang_tab.cpp" break; - case 255: /* type_specifier_nonarray: UINT64_T */ -#line 1951 "MachineIndependent/glslang.y" + case 261: /* type_specifier_nonarray: UINT64_T */ +#line 1984 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint64; } -#line 7806 "MachineIndependent/glslang_tab.cpp" +#line 7953 "MachineIndependent/glslang_tab.cpp" break; - case 256: /* type_specifier_nonarray: DVEC2 */ -#line 1956 "MachineIndependent/glslang.y" + case 262: /* type_specifier_nonarray: DVEC2 */ +#line 1989 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -7815,426 +7962,426 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setVector(2); } -#line 7819 "MachineIndependent/glslang_tab.cpp" - break; - - case 257: /* type_specifier_nonarray: DVEC3 */ -#line 1964 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(3); - } -#line 7832 "MachineIndependent/glslang_tab.cpp" - break; - - case 258: /* type_specifier_nonarray: DVEC4 */ -#line 1972 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(4); - } -#line 7845 "MachineIndependent/glslang_tab.cpp" - break; - - case 259: /* type_specifier_nonarray: F16VEC2 */ -#line 1980 "MachineIndependent/glslang.y" - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(2); - } -#line 7856 "MachineIndependent/glslang_tab.cpp" - break; - - case 260: /* type_specifier_nonarray: F16VEC3 */ -#line 1986 "MachineIndependent/glslang.y" - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(3); - } -#line 7867 "MachineIndependent/glslang_tab.cpp" - break; - - case 261: /* type_specifier_nonarray: F16VEC4 */ -#line 1992 "MachineIndependent/glslang.y" - { - parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setVector(4); - } -#line 7878 "MachineIndependent/glslang_tab.cpp" - break; - - case 262: /* type_specifier_nonarray: F32VEC2 */ -#line 1998 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(2); - } -#line 7889 "MachineIndependent/glslang_tab.cpp" - break; - - case 263: /* type_specifier_nonarray: F32VEC3 */ -#line 2004 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(3); - } -#line 7900 "MachineIndependent/glslang_tab.cpp" - break; - - case 264: /* type_specifier_nonarray: F32VEC4 */ -#line 2010 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).setVector(4); - } -#line 7911 "MachineIndependent/glslang_tab.cpp" - break; - - case 265: /* type_specifier_nonarray: F64VEC2 */ -#line 2016 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(2); - } -#line 7922 "MachineIndependent/glslang_tab.cpp" - break; - - case 266: /* type_specifier_nonarray: F64VEC3 */ -#line 2022 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(3); - } -#line 7933 "MachineIndependent/glslang_tab.cpp" - break; - - case 267: /* type_specifier_nonarray: F64VEC4 */ -#line 2028 "MachineIndependent/glslang.y" - { - parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setVector(4); - } -#line 7944 "MachineIndependent/glslang_tab.cpp" - break; - - case 268: /* type_specifier_nonarray: I8VEC2 */ -#line 2034 "MachineIndependent/glslang.y" - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - (yyval.interm.type).setVector(2); - } -#line 7955 "MachineIndependent/glslang_tab.cpp" - break; - - case 269: /* type_specifier_nonarray: I8VEC3 */ -#line 2040 "MachineIndependent/glslang.y" - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtInt8; - (yyval.interm.type).setVector(3); - } #line 7966 "MachineIndependent/glslang_tab.cpp" break; - case 270: /* type_specifier_nonarray: I8VEC4 */ -#line 2046 "MachineIndependent/glslang.y" + case 263: /* type_specifier_nonarray: DVEC3 */ +#line 1997 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 7979 "MachineIndependent/glslang_tab.cpp" + break; + + case 264: /* type_specifier_nonarray: DVEC4 */ +#line 2005 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double vector"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double vector"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 7992 "MachineIndependent/glslang_tab.cpp" + break; + + case 265: /* type_specifier_nonarray: F16VEC2 */ +#line 2013 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(2); + } +#line 8003 "MachineIndependent/glslang_tab.cpp" + break; + + case 266: /* type_specifier_nonarray: F16VEC3 */ +#line 2019 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(3); + } +#line 8014 "MachineIndependent/glslang_tab.cpp" + break; + + case 267: /* type_specifier_nonarray: F16VEC4 */ +#line 2025 "MachineIndependent/glslang.y" + { + parseContext.float16ScalarVectorCheck((yyvsp[0].lex).loc, "half float vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setVector(4); + } +#line 8025 "MachineIndependent/glslang_tab.cpp" + break; + + case 268: /* type_specifier_nonarray: F32VEC2 */ +#line 2031 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(2); + } +#line 8036 "MachineIndependent/glslang_tab.cpp" + break; + + case 269: /* type_specifier_nonarray: F32VEC3 */ +#line 2037 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(3); + } +#line 8047 "MachineIndependent/glslang_tab.cpp" + break; + + case 270: /* type_specifier_nonarray: F32VEC4 */ +#line 2043 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat; + (yyval.interm.type).setVector(4); + } +#line 8058 "MachineIndependent/glslang_tab.cpp" + break; + + case 271: /* type_specifier_nonarray: F64VEC2 */ +#line 2049 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(2); + } +#line 8069 "MachineIndependent/glslang_tab.cpp" + break; + + case 272: /* type_specifier_nonarray: F64VEC3 */ +#line 2055 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(3); + } +#line 8080 "MachineIndependent/glslang_tab.cpp" + break; + + case 273: /* type_specifier_nonarray: F64VEC4 */ +#line 2061 "MachineIndependent/glslang.y" + { + parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setVector(4); + } +#line 8091 "MachineIndependent/glslang_tab.cpp" + break; + + case 274: /* type_specifier_nonarray: I8VEC2 */ +#line 2067 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(2); + } +#line 8102 "MachineIndependent/glslang_tab.cpp" + break; + + case 275: /* type_specifier_nonarray: I8VEC3 */ +#line 2073 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtInt8; + (yyval.interm.type).setVector(3); + } +#line 8113 "MachineIndependent/glslang_tab.cpp" + break; + + case 276: /* type_specifier_nonarray: I8VEC4 */ +#line 2079 "MachineIndependent/glslang.y" { parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt8; (yyval.interm.type).setVector(4); } -#line 7977 "MachineIndependent/glslang_tab.cpp" +#line 8124 "MachineIndependent/glslang_tab.cpp" break; - case 271: /* type_specifier_nonarray: I16VEC2 */ -#line 2052 "MachineIndependent/glslang.y" + case 277: /* type_specifier_nonarray: I16VEC2 */ +#line 2085 "MachineIndependent/glslang.y" { parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt16; (yyval.interm.type).setVector(2); } -#line 7988 "MachineIndependent/glslang_tab.cpp" +#line 8135 "MachineIndependent/glslang_tab.cpp" break; - case 272: /* type_specifier_nonarray: I16VEC3 */ -#line 2058 "MachineIndependent/glslang.y" + case 278: /* type_specifier_nonarray: I16VEC3 */ +#line 2091 "MachineIndependent/glslang.y" { parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt16; (yyval.interm.type).setVector(3); } -#line 7999 "MachineIndependent/glslang_tab.cpp" +#line 8146 "MachineIndependent/glslang_tab.cpp" break; - case 273: /* type_specifier_nonarray: I16VEC4 */ -#line 2064 "MachineIndependent/glslang.y" + case 279: /* type_specifier_nonarray: I16VEC4 */ +#line 2097 "MachineIndependent/glslang.y" { parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt16; (yyval.interm.type).setVector(4); } -#line 8010 "MachineIndependent/glslang_tab.cpp" +#line 8157 "MachineIndependent/glslang_tab.cpp" break; - case 274: /* type_specifier_nonarray: I32VEC2 */ -#line 2070 "MachineIndependent/glslang.y" + case 280: /* type_specifier_nonarray: I32VEC2 */ +#line 2103 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(2); } -#line 8021 "MachineIndependent/glslang_tab.cpp" +#line 8168 "MachineIndependent/glslang_tab.cpp" break; - case 275: /* type_specifier_nonarray: I32VEC3 */ -#line 2076 "MachineIndependent/glslang.y" + case 281: /* type_specifier_nonarray: I32VEC3 */ +#line 2109 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(3); } -#line 8032 "MachineIndependent/glslang_tab.cpp" +#line 8179 "MachineIndependent/glslang_tab.cpp" break; - case 276: /* type_specifier_nonarray: I32VEC4 */ -#line 2082 "MachineIndependent/glslang.y" + case 282: /* type_specifier_nonarray: I32VEC4 */ +#line 2115 "MachineIndependent/glslang.y" { parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit signed integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; (yyval.interm.type).setVector(4); } -#line 8043 "MachineIndependent/glslang_tab.cpp" +#line 8190 "MachineIndependent/glslang_tab.cpp" break; - case 277: /* type_specifier_nonarray: I64VEC2 */ -#line 2088 "MachineIndependent/glslang.y" + case 283: /* type_specifier_nonarray: I64VEC2 */ +#line 2121 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt64; (yyval.interm.type).setVector(2); } -#line 8054 "MachineIndependent/glslang_tab.cpp" +#line 8201 "MachineIndependent/glslang_tab.cpp" break; - case 278: /* type_specifier_nonarray: I64VEC3 */ -#line 2094 "MachineIndependent/glslang.y" + case 284: /* type_specifier_nonarray: I64VEC3 */ +#line 2127 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt64; (yyval.interm.type).setVector(3); } -#line 8065 "MachineIndependent/glslang_tab.cpp" +#line 8212 "MachineIndependent/glslang_tab.cpp" break; - case 279: /* type_specifier_nonarray: I64VEC4 */ -#line 2100 "MachineIndependent/glslang.y" + case 285: /* type_specifier_nonarray: I64VEC4 */ +#line 2133 "MachineIndependent/glslang.y" { parseContext.int64Check((yyvsp[0].lex).loc, "64-bit integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt64; (yyval.interm.type).setVector(4); } -#line 8076 "MachineIndependent/glslang_tab.cpp" +#line 8223 "MachineIndependent/glslang_tab.cpp" break; - case 280: /* type_specifier_nonarray: U8VEC2 */ -#line 2106 "MachineIndependent/glslang.y" + case 286: /* type_specifier_nonarray: U8VEC2 */ +#line 2139 "MachineIndependent/glslang.y" { parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint8; (yyval.interm.type).setVector(2); } -#line 8087 "MachineIndependent/glslang_tab.cpp" - break; - - case 281: /* type_specifier_nonarray: U8VEC3 */ -#line 2112 "MachineIndependent/glslang.y" - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - (yyval.interm.type).setVector(3); - } -#line 8098 "MachineIndependent/glslang_tab.cpp" - break; - - case 282: /* type_specifier_nonarray: U8VEC4 */ -#line 2118 "MachineIndependent/glslang.y" - { - parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint8; - (yyval.interm.type).setVector(4); - } -#line 8109 "MachineIndependent/glslang_tab.cpp" - break; - - case 283: /* type_specifier_nonarray: U16VEC2 */ -#line 2124 "MachineIndependent/glslang.y" - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(2); - } -#line 8120 "MachineIndependent/glslang_tab.cpp" - break; - - case 284: /* type_specifier_nonarray: U16VEC3 */ -#line 2130 "MachineIndependent/glslang.y" - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(3); - } -#line 8131 "MachineIndependent/glslang_tab.cpp" - break; - - case 285: /* type_specifier_nonarray: U16VEC4 */ -#line 2136 "MachineIndependent/glslang.y" - { - parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint16; - (yyval.interm.type).setVector(4); - } -#line 8142 "MachineIndependent/glslang_tab.cpp" - break; - - case 286: /* type_specifier_nonarray: U32VEC2 */ -#line 2142 "MachineIndependent/glslang.y" - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(2); - } -#line 8153 "MachineIndependent/glslang_tab.cpp" - break; - - case 287: /* type_specifier_nonarray: U32VEC3 */ -#line 2148 "MachineIndependent/glslang.y" - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(3); - } -#line 8164 "MachineIndependent/glslang_tab.cpp" - break; - - case 288: /* type_specifier_nonarray: U32VEC4 */ -#line 2154 "MachineIndependent/glslang.y" - { - parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).setVector(4); - } -#line 8175 "MachineIndependent/glslang_tab.cpp" - break; - - case 289: /* type_specifier_nonarray: U64VEC2 */ -#line 2160 "MachineIndependent/glslang.y" - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(2); - } -#line 8186 "MachineIndependent/glslang_tab.cpp" - break; - - case 290: /* type_specifier_nonarray: U64VEC3 */ -#line 2166 "MachineIndependent/glslang.y" - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(3); - } -#line 8197 "MachineIndependent/glslang_tab.cpp" - break; - - case 291: /* type_specifier_nonarray: U64VEC4 */ -#line 2172 "MachineIndependent/glslang.y" - { - parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtUint64; - (yyval.interm.type).setVector(4); - } -#line 8208 "MachineIndependent/glslang_tab.cpp" - break; - - case 292: /* type_specifier_nonarray: DMAT2 */ -#line 2178 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(2, 2); - } -#line 8221 "MachineIndependent/glslang_tab.cpp" - break; - - case 293: /* type_specifier_nonarray: DMAT3 */ -#line 2186 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(3, 3); - } #line 8234 "MachineIndependent/glslang_tab.cpp" break; - case 294: /* type_specifier_nonarray: DMAT4 */ -#line 2194 "MachineIndependent/glslang.y" + case 287: /* type_specifier_nonarray: U8VEC3 */ +#line 2145 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(3); + } +#line 8245 "MachineIndependent/glslang_tab.cpp" + break; + + case 288: /* type_specifier_nonarray: U8VEC4 */ +#line 2151 "MachineIndependent/glslang.y" + { + parseContext.int8ScalarVectorCheck((yyvsp[0].lex).loc, "8-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint8; + (yyval.interm.type).setVector(4); + } +#line 8256 "MachineIndependent/glslang_tab.cpp" + break; + + case 289: /* type_specifier_nonarray: U16VEC2 */ +#line 2157 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(2); + } +#line 8267 "MachineIndependent/glslang_tab.cpp" + break; + + case 290: /* type_specifier_nonarray: U16VEC3 */ +#line 2163 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(3); + } +#line 8278 "MachineIndependent/glslang_tab.cpp" + break; + + case 291: /* type_specifier_nonarray: U16VEC4 */ +#line 2169 "MachineIndependent/glslang.y" + { + parseContext.int16ScalarVectorCheck((yyvsp[0].lex).loc, "16-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint16; + (yyval.interm.type).setVector(4); + } +#line 8289 "MachineIndependent/glslang_tab.cpp" + break; + + case 292: /* type_specifier_nonarray: U32VEC2 */ +#line 2175 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(2); + } +#line 8300 "MachineIndependent/glslang_tab.cpp" + break; + + case 293: /* type_specifier_nonarray: U32VEC3 */ +#line 2181 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(3); + } +#line 8311 "MachineIndependent/glslang_tab.cpp" + break; + + case 294: /* type_specifier_nonarray: U32VEC4 */ +#line 2187 "MachineIndependent/glslang.y" + { + parseContext.explicitInt32Check((yyvsp[0].lex).loc, "32-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint; + (yyval.interm.type).setVector(4); + } +#line 8322 "MachineIndependent/glslang_tab.cpp" + break; + + case 295: /* type_specifier_nonarray: U64VEC2 */ +#line 2193 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(2); + } +#line 8333 "MachineIndependent/glslang_tab.cpp" + break; + + case 296: /* type_specifier_nonarray: U64VEC3 */ +#line 2199 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(3); + } +#line 8344 "MachineIndependent/glslang_tab.cpp" + break; + + case 297: /* type_specifier_nonarray: U64VEC4 */ +#line 2205 "MachineIndependent/glslang.y" + { + parseContext.int64Check((yyvsp[0].lex).loc, "64-bit unsigned integer vector", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtUint64; + (yyval.interm.type).setVector(4); + } +#line 8355 "MachineIndependent/glslang_tab.cpp" + break; + + case 298: /* type_specifier_nonarray: DMAT2 */ +#line 2211 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8368 "MachineIndependent/glslang_tab.cpp" + break; + + case 299: /* type_specifier_nonarray: DMAT3 */ +#line 2219 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8381 "MachineIndependent/glslang_tab.cpp" + break; + + case 300: /* type_specifier_nonarray: DMAT4 */ +#line 2227 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8243,11 +8390,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 4); } -#line 8247 "MachineIndependent/glslang_tab.cpp" +#line 8394 "MachineIndependent/glslang_tab.cpp" break; - case 295: /* type_specifier_nonarray: DMAT2X2 */ -#line 2202 "MachineIndependent/glslang.y" + case 301: /* type_specifier_nonarray: DMAT2X2 */ +#line 2235 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8256,11 +8403,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 2); } -#line 8260 "MachineIndependent/glslang_tab.cpp" +#line 8407 "MachineIndependent/glslang_tab.cpp" break; - case 296: /* type_specifier_nonarray: DMAT2X3 */ -#line 2210 "MachineIndependent/glslang.y" + case 302: /* type_specifier_nonarray: DMAT2X3 */ +#line 2243 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8269,11 +8416,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 3); } -#line 8273 "MachineIndependent/glslang_tab.cpp" +#line 8420 "MachineIndependent/glslang_tab.cpp" break; - case 297: /* type_specifier_nonarray: DMAT2X4 */ -#line 2218 "MachineIndependent/glslang.y" + case 303: /* type_specifier_nonarray: DMAT2X4 */ +#line 2251 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8282,11 +8429,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 4); } -#line 8286 "MachineIndependent/glslang_tab.cpp" +#line 8433 "MachineIndependent/glslang_tab.cpp" break; - case 298: /* type_specifier_nonarray: DMAT3X2 */ -#line 2226 "MachineIndependent/glslang.y" + case 304: /* type_specifier_nonarray: DMAT3X2 */ +#line 2259 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8295,11 +8442,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 2); } -#line 8299 "MachineIndependent/glslang_tab.cpp" +#line 8446 "MachineIndependent/glslang_tab.cpp" break; - case 299: /* type_specifier_nonarray: DMAT3X3 */ -#line 2234 "MachineIndependent/glslang.y" + case 305: /* type_specifier_nonarray: DMAT3X3 */ +#line 2267 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8308,11 +8455,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 3); } -#line 8312 "MachineIndependent/glslang_tab.cpp" +#line 8459 "MachineIndependent/glslang_tab.cpp" break; - case 300: /* type_specifier_nonarray: DMAT3X4 */ -#line 2242 "MachineIndependent/glslang.y" + case 306: /* type_specifier_nonarray: DMAT3X4 */ +#line 2275 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8321,11 +8468,11 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 4); } -#line 8325 "MachineIndependent/glslang_tab.cpp" +#line 8472 "MachineIndependent/glslang_tab.cpp" break; - case 301: /* type_specifier_nonarray: DMAT4X2 */ -#line 2250 "MachineIndependent/glslang.y" + case 307: /* type_specifier_nonarray: DMAT4X2 */ +#line 2283 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); if (! parseContext.symbolTable.atBuiltInLevel()) @@ -8334,2254 +8481,2287 @@ yyreduce: (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 2); } -#line 8338 "MachineIndependent/glslang_tab.cpp" - break; - - case 302: /* type_specifier_nonarray: DMAT4X3 */ -#line 2258 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 3); - } -#line 8351 "MachineIndependent/glslang_tab.cpp" - break; - - case 303: /* type_specifier_nonarray: DMAT4X4 */ -#line 2266 "MachineIndependent/glslang.y" - { - parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); - if (! parseContext.symbolTable.atBuiltInLevel()) - parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtDouble; - (yyval.interm.type).setMatrix(4, 4); - } -#line 8364 "MachineIndependent/glslang_tab.cpp" - break; - - case 304: /* type_specifier_nonarray: F16MAT2 */ -#line 2274 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 2); - } -#line 8375 "MachineIndependent/glslang_tab.cpp" - break; - - case 305: /* type_specifier_nonarray: F16MAT3 */ -#line 2280 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 3); - } -#line 8386 "MachineIndependent/glslang_tab.cpp" - break; - - case 306: /* type_specifier_nonarray: F16MAT4 */ -#line 2286 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 4); - } -#line 8397 "MachineIndependent/glslang_tab.cpp" - break; - - case 307: /* type_specifier_nonarray: F16MAT2X2 */ -#line 2292 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 2); - } -#line 8408 "MachineIndependent/glslang_tab.cpp" - break; - - case 308: /* type_specifier_nonarray: F16MAT2X3 */ -#line 2298 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 3); - } -#line 8419 "MachineIndependent/glslang_tab.cpp" - break; - - case 309: /* type_specifier_nonarray: F16MAT2X4 */ -#line 2304 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(2, 4); - } -#line 8430 "MachineIndependent/glslang_tab.cpp" - break; - - case 310: /* type_specifier_nonarray: F16MAT3X2 */ -#line 2310 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 2); - } -#line 8441 "MachineIndependent/glslang_tab.cpp" - break; - - case 311: /* type_specifier_nonarray: F16MAT3X3 */ -#line 2316 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 3); - } -#line 8452 "MachineIndependent/glslang_tab.cpp" - break; - - case 312: /* type_specifier_nonarray: F16MAT3X4 */ -#line 2322 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(3, 4); - } -#line 8463 "MachineIndependent/glslang_tab.cpp" - break; - - case 313: /* type_specifier_nonarray: F16MAT4X2 */ -#line 2328 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 2); - } -#line 8474 "MachineIndependent/glslang_tab.cpp" - break; - - case 314: /* type_specifier_nonarray: F16MAT4X3 */ -#line 2334 "MachineIndependent/glslang.y" - { - parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); - (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); - (yyval.interm.type).basicType = EbtFloat16; - (yyval.interm.type).setMatrix(4, 3); - } #line 8485 "MachineIndependent/glslang_tab.cpp" break; - case 315: /* type_specifier_nonarray: F16MAT4X4 */ -#line 2340 "MachineIndependent/glslang.y" + case 308: /* type_specifier_nonarray: DMAT4X3 */ +#line 2291 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8498 "MachineIndependent/glslang_tab.cpp" + break; + + case 309: /* type_specifier_nonarray: DMAT4X4 */ +#line 2299 "MachineIndependent/glslang.y" + { + parseContext.requireProfile((yyvsp[0].lex).loc, ECoreProfile | ECompatibilityProfile, "double matrix"); + if (! parseContext.symbolTable.atBuiltInLevel()) + parseContext.doubleCheck((yyvsp[0].lex).loc, "double matrix"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtDouble; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8511 "MachineIndependent/glslang_tab.cpp" + break; + + case 310: /* type_specifier_nonarray: F16MAT2 */ +#line 2307 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8522 "MachineIndependent/glslang_tab.cpp" + break; + + case 311: /* type_specifier_nonarray: F16MAT3 */ +#line 2313 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8533 "MachineIndependent/glslang_tab.cpp" + break; + + case 312: /* type_specifier_nonarray: F16MAT4 */ +#line 2319 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 4); + } +#line 8544 "MachineIndependent/glslang_tab.cpp" + break; + + case 313: /* type_specifier_nonarray: F16MAT2X2 */ +#line 2325 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 2); + } +#line 8555 "MachineIndependent/glslang_tab.cpp" + break; + + case 314: /* type_specifier_nonarray: F16MAT2X3 */ +#line 2331 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 3); + } +#line 8566 "MachineIndependent/glslang_tab.cpp" + break; + + case 315: /* type_specifier_nonarray: F16MAT2X4 */ +#line 2337 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(2, 4); + } +#line 8577 "MachineIndependent/glslang_tab.cpp" + break; + + case 316: /* type_specifier_nonarray: F16MAT3X2 */ +#line 2343 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 2); + } +#line 8588 "MachineIndependent/glslang_tab.cpp" + break; + + case 317: /* type_specifier_nonarray: F16MAT3X3 */ +#line 2349 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 3); + } +#line 8599 "MachineIndependent/glslang_tab.cpp" + break; + + case 318: /* type_specifier_nonarray: F16MAT3X4 */ +#line 2355 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(3, 4); + } +#line 8610 "MachineIndependent/glslang_tab.cpp" + break; + + case 319: /* type_specifier_nonarray: F16MAT4X2 */ +#line 2361 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 2); + } +#line 8621 "MachineIndependent/glslang_tab.cpp" + break; + + case 320: /* type_specifier_nonarray: F16MAT4X3 */ +#line 2367 "MachineIndependent/glslang.y" + { + parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtFloat16; + (yyval.interm.type).setMatrix(4, 3); + } +#line 8632 "MachineIndependent/glslang_tab.cpp" + break; + + case 321: /* type_specifier_nonarray: F16MAT4X4 */ +#line 2373 "MachineIndependent/glslang.y" { parseContext.float16Check((yyvsp[0].lex).loc, "half float matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat16; (yyval.interm.type).setMatrix(4, 4); } -#line 8496 "MachineIndependent/glslang_tab.cpp" +#line 8643 "MachineIndependent/glslang_tab.cpp" break; - case 316: /* type_specifier_nonarray: F32MAT2 */ -#line 2346 "MachineIndependent/glslang.y" + case 322: /* type_specifier_nonarray: F32MAT2 */ +#line 2379 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 8507 "MachineIndependent/glslang_tab.cpp" +#line 8654 "MachineIndependent/glslang_tab.cpp" break; - case 317: /* type_specifier_nonarray: F32MAT3 */ -#line 2352 "MachineIndependent/glslang.y" + case 323: /* type_specifier_nonarray: F32MAT3 */ +#line 2385 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 8518 "MachineIndependent/glslang_tab.cpp" +#line 8665 "MachineIndependent/glslang_tab.cpp" break; - case 318: /* type_specifier_nonarray: F32MAT4 */ -#line 2358 "MachineIndependent/glslang.y" + case 324: /* type_specifier_nonarray: F32MAT4 */ +#line 2391 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 8529 "MachineIndependent/glslang_tab.cpp" +#line 8676 "MachineIndependent/glslang_tab.cpp" break; - case 319: /* type_specifier_nonarray: F32MAT2X2 */ -#line 2364 "MachineIndependent/glslang.y" + case 325: /* type_specifier_nonarray: F32MAT2X2 */ +#line 2397 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 2); } -#line 8540 "MachineIndependent/glslang_tab.cpp" +#line 8687 "MachineIndependent/glslang_tab.cpp" break; - case 320: /* type_specifier_nonarray: F32MAT2X3 */ -#line 2370 "MachineIndependent/glslang.y" + case 326: /* type_specifier_nonarray: F32MAT2X3 */ +#line 2403 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 3); } -#line 8551 "MachineIndependent/glslang_tab.cpp" +#line 8698 "MachineIndependent/glslang_tab.cpp" break; - case 321: /* type_specifier_nonarray: F32MAT2X4 */ -#line 2376 "MachineIndependent/glslang.y" + case 327: /* type_specifier_nonarray: F32MAT2X4 */ +#line 2409 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(2, 4); } -#line 8562 "MachineIndependent/glslang_tab.cpp" +#line 8709 "MachineIndependent/glslang_tab.cpp" break; - case 322: /* type_specifier_nonarray: F32MAT3X2 */ -#line 2382 "MachineIndependent/glslang.y" + case 328: /* type_specifier_nonarray: F32MAT3X2 */ +#line 2415 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 2); } -#line 8573 "MachineIndependent/glslang_tab.cpp" +#line 8720 "MachineIndependent/glslang_tab.cpp" break; - case 323: /* type_specifier_nonarray: F32MAT3X3 */ -#line 2388 "MachineIndependent/glslang.y" + case 329: /* type_specifier_nonarray: F32MAT3X3 */ +#line 2421 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 3); } -#line 8584 "MachineIndependent/glslang_tab.cpp" +#line 8731 "MachineIndependent/glslang_tab.cpp" break; - case 324: /* type_specifier_nonarray: F32MAT3X4 */ -#line 2394 "MachineIndependent/glslang.y" + case 330: /* type_specifier_nonarray: F32MAT3X4 */ +#line 2427 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(3, 4); } -#line 8595 "MachineIndependent/glslang_tab.cpp" +#line 8742 "MachineIndependent/glslang_tab.cpp" break; - case 325: /* type_specifier_nonarray: F32MAT4X2 */ -#line 2400 "MachineIndependent/glslang.y" + case 331: /* type_specifier_nonarray: F32MAT4X2 */ +#line 2433 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 2); } -#line 8606 "MachineIndependent/glslang_tab.cpp" +#line 8753 "MachineIndependent/glslang_tab.cpp" break; - case 326: /* type_specifier_nonarray: F32MAT4X3 */ -#line 2406 "MachineIndependent/glslang.y" + case 332: /* type_specifier_nonarray: F32MAT4X3 */ +#line 2439 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 3); } -#line 8617 "MachineIndependent/glslang_tab.cpp" +#line 8764 "MachineIndependent/glslang_tab.cpp" break; - case 327: /* type_specifier_nonarray: F32MAT4X4 */ -#line 2412 "MachineIndependent/glslang.y" + case 333: /* type_specifier_nonarray: F32MAT4X4 */ +#line 2445 "MachineIndependent/glslang.y" { parseContext.explicitFloat32Check((yyvsp[0].lex).loc, "float32_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; (yyval.interm.type).setMatrix(4, 4); } -#line 8628 "MachineIndependent/glslang_tab.cpp" +#line 8775 "MachineIndependent/glslang_tab.cpp" break; - case 328: /* type_specifier_nonarray: F64MAT2 */ -#line 2418 "MachineIndependent/glslang.y" + case 334: /* type_specifier_nonarray: F64MAT2 */ +#line 2451 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 2); } -#line 8639 "MachineIndependent/glslang_tab.cpp" +#line 8786 "MachineIndependent/glslang_tab.cpp" break; - case 329: /* type_specifier_nonarray: F64MAT3 */ -#line 2424 "MachineIndependent/glslang.y" + case 335: /* type_specifier_nonarray: F64MAT3 */ +#line 2457 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 3); } -#line 8650 "MachineIndependent/glslang_tab.cpp" +#line 8797 "MachineIndependent/glslang_tab.cpp" break; - case 330: /* type_specifier_nonarray: F64MAT4 */ -#line 2430 "MachineIndependent/glslang.y" + case 336: /* type_specifier_nonarray: F64MAT4 */ +#line 2463 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 4); } -#line 8661 "MachineIndependent/glslang_tab.cpp" +#line 8808 "MachineIndependent/glslang_tab.cpp" break; - case 331: /* type_specifier_nonarray: F64MAT2X2 */ -#line 2436 "MachineIndependent/glslang.y" + case 337: /* type_specifier_nonarray: F64MAT2X2 */ +#line 2469 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 2); } -#line 8672 "MachineIndependent/glslang_tab.cpp" +#line 8819 "MachineIndependent/glslang_tab.cpp" break; - case 332: /* type_specifier_nonarray: F64MAT2X3 */ -#line 2442 "MachineIndependent/glslang.y" + case 338: /* type_specifier_nonarray: F64MAT2X3 */ +#line 2475 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 3); } -#line 8683 "MachineIndependent/glslang_tab.cpp" +#line 8830 "MachineIndependent/glslang_tab.cpp" break; - case 333: /* type_specifier_nonarray: F64MAT2X4 */ -#line 2448 "MachineIndependent/glslang.y" + case 339: /* type_specifier_nonarray: F64MAT2X4 */ +#line 2481 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(2, 4); } -#line 8694 "MachineIndependent/glslang_tab.cpp" +#line 8841 "MachineIndependent/glslang_tab.cpp" break; - case 334: /* type_specifier_nonarray: F64MAT3X2 */ -#line 2454 "MachineIndependent/glslang.y" + case 340: /* type_specifier_nonarray: F64MAT3X2 */ +#line 2487 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 2); } -#line 8705 "MachineIndependent/glslang_tab.cpp" +#line 8852 "MachineIndependent/glslang_tab.cpp" break; - case 335: /* type_specifier_nonarray: F64MAT3X3 */ -#line 2460 "MachineIndependent/glslang.y" + case 341: /* type_specifier_nonarray: F64MAT3X3 */ +#line 2493 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 3); } -#line 8716 "MachineIndependent/glslang_tab.cpp" +#line 8863 "MachineIndependent/glslang_tab.cpp" break; - case 336: /* type_specifier_nonarray: F64MAT3X4 */ -#line 2466 "MachineIndependent/glslang.y" + case 342: /* type_specifier_nonarray: F64MAT3X4 */ +#line 2499 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(3, 4); } -#line 8727 "MachineIndependent/glslang_tab.cpp" +#line 8874 "MachineIndependent/glslang_tab.cpp" break; - case 337: /* type_specifier_nonarray: F64MAT4X2 */ -#line 2472 "MachineIndependent/glslang.y" + case 343: /* type_specifier_nonarray: F64MAT4X2 */ +#line 2505 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 2); } -#line 8738 "MachineIndependent/glslang_tab.cpp" +#line 8885 "MachineIndependent/glslang_tab.cpp" break; - case 338: /* type_specifier_nonarray: F64MAT4X3 */ -#line 2478 "MachineIndependent/glslang.y" + case 344: /* type_specifier_nonarray: F64MAT4X3 */ +#line 2511 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 3); } -#line 8749 "MachineIndependent/glslang_tab.cpp" +#line 8896 "MachineIndependent/glslang_tab.cpp" break; - case 339: /* type_specifier_nonarray: F64MAT4X4 */ -#line 2484 "MachineIndependent/glslang.y" + case 345: /* type_specifier_nonarray: F64MAT4X4 */ +#line 2517 "MachineIndependent/glslang.y" { parseContext.explicitFloat64Check((yyvsp[0].lex).loc, "float64_t matrix", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtDouble; (yyval.interm.type).setMatrix(4, 4); } -#line 8760 "MachineIndependent/glslang_tab.cpp" +#line 8907 "MachineIndependent/glslang_tab.cpp" break; - case 340: /* type_specifier_nonarray: ACCSTRUCTNV */ -#line 2490 "MachineIndependent/glslang.y" + case 346: /* type_specifier_nonarray: ACCSTRUCTNV */ +#line 2523 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtAccStruct; } -#line 8769 "MachineIndependent/glslang_tab.cpp" +#line 8916 "MachineIndependent/glslang_tab.cpp" break; - case 341: /* type_specifier_nonarray: ACCSTRUCTEXT */ -#line 2494 "MachineIndependent/glslang.y" + case 347: /* type_specifier_nonarray: ACCSTRUCTEXT */ +#line 2527 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtAccStruct; } -#line 8778 "MachineIndependent/glslang_tab.cpp" +#line 8925 "MachineIndependent/glslang_tab.cpp" break; - case 342: /* type_specifier_nonarray: RAYQUERYEXT */ -#line 2498 "MachineIndependent/glslang.y" + case 348: /* type_specifier_nonarray: RAYQUERYEXT */ +#line 2531 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtRayQuery; } -#line 8787 "MachineIndependent/glslang_tab.cpp" +#line 8934 "MachineIndependent/glslang_tab.cpp" break; - case 343: /* type_specifier_nonarray: ATOMIC_UINT */ -#line 2502 "MachineIndependent/glslang.y" + case 349: /* type_specifier_nonarray: ATOMIC_UINT */ +#line 2535 "MachineIndependent/glslang.y" { parseContext.vulkanRemoved((yyvsp[0].lex).loc, "atomic counter types"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtAtomicUint; } -#line 8797 "MachineIndependent/glslang_tab.cpp" +#line 8944 "MachineIndependent/glslang_tab.cpp" break; - case 344: /* type_specifier_nonarray: SAMPLER1D */ -#line 2507 "MachineIndependent/glslang.y" + case 350: /* type_specifier_nonarray: SAMPLER1D */ +#line 2540 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D); } -#line 8807 "MachineIndependent/glslang_tab.cpp" +#line 8954 "MachineIndependent/glslang_tab.cpp" break; - case 345: /* type_specifier_nonarray: SAMPLER2D */ -#line 2513 "MachineIndependent/glslang.y" + case 351: /* type_specifier_nonarray: SAMPLER2D */ +#line 2545 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D); } -#line 8817 "MachineIndependent/glslang_tab.cpp" +#line 8964 "MachineIndependent/glslang_tab.cpp" break; - case 346: /* type_specifier_nonarray: SAMPLER3D */ -#line 2518 "MachineIndependent/glslang.y" + case 352: /* type_specifier_nonarray: SAMPLER3D */ +#line 2550 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd3D); } -#line 8827 "MachineIndependent/glslang_tab.cpp" +#line 8974 "MachineIndependent/glslang_tab.cpp" break; - case 347: /* type_specifier_nonarray: SAMPLERCUBE */ -#line 2523 "MachineIndependent/glslang.y" + case 353: /* type_specifier_nonarray: SAMPLERCUBE */ +#line 2555 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube); } -#line 8837 "MachineIndependent/glslang_tab.cpp" +#line 8984 "MachineIndependent/glslang_tab.cpp" break; - case 348: /* type_specifier_nonarray: SAMPLER2DSHADOW */ -#line 2528 "MachineIndependent/glslang.y" + case 354: /* type_specifier_nonarray: SAMPLER2DSHADOW */ +#line 2560 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, true); } -#line 8847 "MachineIndependent/glslang_tab.cpp" +#line 8994 "MachineIndependent/glslang_tab.cpp" break; - case 349: /* type_specifier_nonarray: SAMPLERCUBESHADOW */ -#line 2533 "MachineIndependent/glslang.y" + case 355: /* type_specifier_nonarray: SAMPLERCUBESHADOW */ +#line 2565 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, false, true); } -#line 8857 "MachineIndependent/glslang_tab.cpp" +#line 9004 "MachineIndependent/glslang_tab.cpp" break; - case 350: /* type_specifier_nonarray: SAMPLER2DARRAY */ -#line 2538 "MachineIndependent/glslang.y" + case 356: /* type_specifier_nonarray: SAMPLER2DARRAY */ +#line 2570 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true); } -#line 8867 "MachineIndependent/glslang_tab.cpp" +#line 9014 "MachineIndependent/glslang_tab.cpp" break; - case 351: /* type_specifier_nonarray: SAMPLER2DARRAYSHADOW */ -#line 2543 "MachineIndependent/glslang.y" + case 357: /* type_specifier_nonarray: SAMPLER2DARRAYSHADOW */ +#line 2575 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, true); } -#line 8877 "MachineIndependent/glslang_tab.cpp" +#line 9024 "MachineIndependent/glslang_tab.cpp" break; - case 352: /* type_specifier_nonarray: SAMPLER1DSHADOW */ -#line 2549 "MachineIndependent/glslang.y" + case 358: /* type_specifier_nonarray: SAMPLER1DSHADOW */ +#line 2580 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, false, true); } -#line 8887 "MachineIndependent/glslang_tab.cpp" +#line 9034 "MachineIndependent/glslang_tab.cpp" break; - case 353: /* type_specifier_nonarray: SAMPLER1DARRAY */ -#line 2554 "MachineIndependent/glslang.y" + case 359: /* type_specifier_nonarray: SAMPLER1DARRAY */ +#line 2585 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true); } -#line 8897 "MachineIndependent/glslang_tab.cpp" +#line 9044 "MachineIndependent/glslang_tab.cpp" break; - case 354: /* type_specifier_nonarray: SAMPLER1DARRAYSHADOW */ -#line 2559 "MachineIndependent/glslang.y" + case 360: /* type_specifier_nonarray: SAMPLER1DARRAYSHADOW */ +#line 2590 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd1D, true, true); } -#line 8907 "MachineIndependent/glslang_tab.cpp" +#line 9054 "MachineIndependent/glslang_tab.cpp" break; - case 355: /* type_specifier_nonarray: SAMPLERCUBEARRAY */ -#line 2564 "MachineIndependent/glslang.y" + case 361: /* type_specifier_nonarray: SAMPLERCUBEARRAY */ +#line 2595 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true); } -#line 8917 "MachineIndependent/glslang_tab.cpp" +#line 9064 "MachineIndependent/glslang_tab.cpp" break; - case 356: /* type_specifier_nonarray: SAMPLERCUBEARRAYSHADOW */ -#line 2569 "MachineIndependent/glslang.y" + case 362: /* type_specifier_nonarray: SAMPLERCUBEARRAYSHADOW */ +#line 2600 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdCube, true, true); } -#line 8927 "MachineIndependent/glslang_tab.cpp" +#line 9074 "MachineIndependent/glslang_tab.cpp" break; - case 357: /* type_specifier_nonarray: F16SAMPLER1D */ -#line 2574 "MachineIndependent/glslang.y" + case 363: /* type_specifier_nonarray: F16SAMPLER1D */ +#line 2605 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd1D); } -#line 8938 "MachineIndependent/glslang_tab.cpp" +#line 9085 "MachineIndependent/glslang_tab.cpp" break; - case 358: /* type_specifier_nonarray: F16SAMPLER2D */ -#line 2580 "MachineIndependent/glslang.y" + case 364: /* type_specifier_nonarray: F16SAMPLER2D */ +#line 2611 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D); } -#line 8949 "MachineIndependent/glslang_tab.cpp" +#line 9096 "MachineIndependent/glslang_tab.cpp" break; - case 359: /* type_specifier_nonarray: F16SAMPLER3D */ -#line 2586 "MachineIndependent/glslang.y" + case 365: /* type_specifier_nonarray: F16SAMPLER3D */ +#line 2617 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd3D); } -#line 8960 "MachineIndependent/glslang_tab.cpp" +#line 9107 "MachineIndependent/glslang_tab.cpp" break; - case 360: /* type_specifier_nonarray: F16SAMPLERCUBE */ -#line 2592 "MachineIndependent/glslang.y" + case 366: /* type_specifier_nonarray: F16SAMPLERCUBE */ +#line 2623 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdCube); } -#line 8971 "MachineIndependent/glslang_tab.cpp" +#line 9118 "MachineIndependent/glslang_tab.cpp" break; - case 361: /* type_specifier_nonarray: F16SAMPLER1DSHADOW */ -#line 2598 "MachineIndependent/glslang.y" + case 367: /* type_specifier_nonarray: F16SAMPLER1DSHADOW */ +#line 2629 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, false, true); } -#line 8982 "MachineIndependent/glslang_tab.cpp" +#line 9129 "MachineIndependent/glslang_tab.cpp" break; - case 362: /* type_specifier_nonarray: F16SAMPLER2DSHADOW */ -#line 2604 "MachineIndependent/glslang.y" + case 368: /* type_specifier_nonarray: F16SAMPLER2DSHADOW */ +#line 2635 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, true); } -#line 8993 "MachineIndependent/glslang_tab.cpp" +#line 9140 "MachineIndependent/glslang_tab.cpp" break; - case 363: /* type_specifier_nonarray: F16SAMPLERCUBESHADOW */ -#line 2610 "MachineIndependent/glslang.y" + case 369: /* type_specifier_nonarray: F16SAMPLERCUBESHADOW */ +#line 2641 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, false, true); } -#line 9004 "MachineIndependent/glslang_tab.cpp" +#line 9151 "MachineIndependent/glslang_tab.cpp" break; - case 364: /* type_specifier_nonarray: F16SAMPLER1DARRAY */ -#line 2616 "MachineIndependent/glslang.y" + case 370: /* type_specifier_nonarray: F16SAMPLER1DARRAY */ +#line 2647 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true); } -#line 9015 "MachineIndependent/glslang_tab.cpp" +#line 9162 "MachineIndependent/glslang_tab.cpp" break; - case 365: /* type_specifier_nonarray: F16SAMPLER2DARRAY */ -#line 2622 "MachineIndependent/glslang.y" + case 371: /* type_specifier_nonarray: F16SAMPLER2DARRAY */ +#line 2653 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true); } -#line 9026 "MachineIndependent/glslang_tab.cpp" +#line 9173 "MachineIndependent/glslang_tab.cpp" break; - case 366: /* type_specifier_nonarray: F16SAMPLER1DARRAYSHADOW */ -#line 2628 "MachineIndependent/glslang.y" + case 372: /* type_specifier_nonarray: F16SAMPLER1DARRAYSHADOW */ +#line 2659 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd1D, true, true); } -#line 9037 "MachineIndependent/glslang_tab.cpp" +#line 9184 "MachineIndependent/glslang_tab.cpp" break; - case 367: /* type_specifier_nonarray: F16SAMPLER2DARRAYSHADOW */ -#line 2634 "MachineIndependent/glslang.y" + case 373: /* type_specifier_nonarray: F16SAMPLER2DARRAYSHADOW */ +#line 2665 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, true); } -#line 9048 "MachineIndependent/glslang_tab.cpp" +#line 9195 "MachineIndependent/glslang_tab.cpp" break; - case 368: /* type_specifier_nonarray: F16SAMPLERCUBEARRAY */ -#line 2640 "MachineIndependent/glslang.y" + case 374: /* type_specifier_nonarray: F16SAMPLERCUBEARRAY */ +#line 2671 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true); } -#line 9059 "MachineIndependent/glslang_tab.cpp" +#line 9206 "MachineIndependent/glslang_tab.cpp" break; - case 369: /* type_specifier_nonarray: F16SAMPLERCUBEARRAYSHADOW */ -#line 2646 "MachineIndependent/glslang.y" + case 375: /* type_specifier_nonarray: F16SAMPLERCUBEARRAYSHADOW */ +#line 2677 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdCube, true, true); } -#line 9070 "MachineIndependent/glslang_tab.cpp" +#line 9217 "MachineIndependent/glslang_tab.cpp" break; - case 370: /* type_specifier_nonarray: ISAMPLER1D */ -#line 2652 "MachineIndependent/glslang.y" + case 376: /* type_specifier_nonarray: ISAMPLER1D */ +#line 2683 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd1D); } -#line 9080 "MachineIndependent/glslang_tab.cpp" +#line 9227 "MachineIndependent/glslang_tab.cpp" break; - case 371: /* type_specifier_nonarray: ISAMPLER2D */ -#line 2658 "MachineIndependent/glslang.y" + case 377: /* type_specifier_nonarray: ISAMPLER2D */ +#line 2688 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D); } -#line 9090 "MachineIndependent/glslang_tab.cpp" +#line 9237 "MachineIndependent/glslang_tab.cpp" break; - case 372: /* type_specifier_nonarray: ISAMPLER3D */ -#line 2663 "MachineIndependent/glslang.y" + case 378: /* type_specifier_nonarray: ISAMPLER3D */ +#line 2693 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd3D); } -#line 9100 "MachineIndependent/glslang_tab.cpp" +#line 9247 "MachineIndependent/glslang_tab.cpp" break; - case 373: /* type_specifier_nonarray: ISAMPLERCUBE */ -#line 2668 "MachineIndependent/glslang.y" + case 379: /* type_specifier_nonarray: ISAMPLERCUBE */ +#line 2698 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdCube); } -#line 9110 "MachineIndependent/glslang_tab.cpp" +#line 9257 "MachineIndependent/glslang_tab.cpp" break; - case 374: /* type_specifier_nonarray: ISAMPLER2DARRAY */ -#line 2673 "MachineIndependent/glslang.y" + case 380: /* type_specifier_nonarray: ISAMPLER2DARRAY */ +#line 2703 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, true); } -#line 9120 "MachineIndependent/glslang_tab.cpp" +#line 9267 "MachineIndependent/glslang_tab.cpp" break; - case 375: /* type_specifier_nonarray: USAMPLER2D */ -#line 2678 "MachineIndependent/glslang.y" + case 381: /* type_specifier_nonarray: USAMPLER2D */ +#line 2708 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D); } -#line 9130 "MachineIndependent/glslang_tab.cpp" +#line 9277 "MachineIndependent/glslang_tab.cpp" break; - case 376: /* type_specifier_nonarray: USAMPLER3D */ -#line 2683 "MachineIndependent/glslang.y" + case 382: /* type_specifier_nonarray: USAMPLER3D */ +#line 2713 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd3D); } -#line 9140 "MachineIndependent/glslang_tab.cpp" +#line 9287 "MachineIndependent/glslang_tab.cpp" break; - case 377: /* type_specifier_nonarray: USAMPLERCUBE */ -#line 2688 "MachineIndependent/glslang.y" + case 383: /* type_specifier_nonarray: USAMPLERCUBE */ +#line 2718 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdCube); } -#line 9150 "MachineIndependent/glslang_tab.cpp" +#line 9297 "MachineIndependent/glslang_tab.cpp" break; - case 378: /* type_specifier_nonarray: ISAMPLER1DARRAY */ -#line 2694 "MachineIndependent/glslang.y" + case 384: /* type_specifier_nonarray: ISAMPLER1DARRAY */ +#line 2723 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd1D, true); } -#line 9160 "MachineIndependent/glslang_tab.cpp" +#line 9307 "MachineIndependent/glslang_tab.cpp" break; - case 379: /* type_specifier_nonarray: ISAMPLERCUBEARRAY */ -#line 2699 "MachineIndependent/glslang.y" + case 385: /* type_specifier_nonarray: ISAMPLERCUBEARRAY */ +#line 2728 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdCube, true); } -#line 9170 "MachineIndependent/glslang_tab.cpp" +#line 9317 "MachineIndependent/glslang_tab.cpp" break; - case 380: /* type_specifier_nonarray: USAMPLER1D */ -#line 2704 "MachineIndependent/glslang.y" + case 386: /* type_specifier_nonarray: USAMPLER1D */ +#line 2733 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd1D); } -#line 9180 "MachineIndependent/glslang_tab.cpp" +#line 9327 "MachineIndependent/glslang_tab.cpp" break; - case 381: /* type_specifier_nonarray: USAMPLER1DARRAY */ -#line 2709 "MachineIndependent/glslang.y" + case 387: /* type_specifier_nonarray: USAMPLER1DARRAY */ +#line 2738 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd1D, true); } -#line 9190 "MachineIndependent/glslang_tab.cpp" +#line 9337 "MachineIndependent/glslang_tab.cpp" break; - case 382: /* type_specifier_nonarray: USAMPLERCUBEARRAY */ -#line 2714 "MachineIndependent/glslang.y" + case 388: /* type_specifier_nonarray: USAMPLERCUBEARRAY */ +#line 2743 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdCube, true); } -#line 9200 "MachineIndependent/glslang_tab.cpp" +#line 9347 "MachineIndependent/glslang_tab.cpp" break; - case 383: /* type_specifier_nonarray: TEXTURECUBEARRAY */ -#line 2719 "MachineIndependent/glslang.y" + case 389: /* type_specifier_nonarray: TEXTURECUBEARRAY */ +#line 2748 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube, true); } -#line 9210 "MachineIndependent/glslang_tab.cpp" +#line 9357 "MachineIndependent/glslang_tab.cpp" break; - case 384: /* type_specifier_nonarray: ITEXTURECUBEARRAY */ -#line 2724 "MachineIndependent/glslang.y" + case 390: /* type_specifier_nonarray: ITEXTURECUBEARRAY */ +#line 2753 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube, true); } -#line 9220 "MachineIndependent/glslang_tab.cpp" +#line 9367 "MachineIndependent/glslang_tab.cpp" break; - case 385: /* type_specifier_nonarray: UTEXTURECUBEARRAY */ -#line 2729 "MachineIndependent/glslang.y" + case 391: /* type_specifier_nonarray: UTEXTURECUBEARRAY */ +#line 2758 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube, true); } -#line 9230 "MachineIndependent/glslang_tab.cpp" +#line 9377 "MachineIndependent/glslang_tab.cpp" break; - case 386: /* type_specifier_nonarray: USAMPLER2DARRAY */ -#line 2735 "MachineIndependent/glslang.y" + case 392: /* type_specifier_nonarray: USAMPLER2DARRAY */ +#line 2763 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, true); } -#line 9240 "MachineIndependent/glslang_tab.cpp" +#line 9387 "MachineIndependent/glslang_tab.cpp" break; - case 387: /* type_specifier_nonarray: TEXTURE2D */ -#line 2740 "MachineIndependent/glslang.y" + case 393: /* type_specifier_nonarray: TEXTURE2D */ +#line 2768 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D); } -#line 9250 "MachineIndependent/glslang_tab.cpp" +#line 9397 "MachineIndependent/glslang_tab.cpp" break; - case 388: /* type_specifier_nonarray: TEXTURE3D */ -#line 2745 "MachineIndependent/glslang.y" + case 394: /* type_specifier_nonarray: TEXTURE3D */ +#line 2773 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd3D); } -#line 9260 "MachineIndependent/glslang_tab.cpp" +#line 9407 "MachineIndependent/glslang_tab.cpp" break; - case 389: /* type_specifier_nonarray: TEXTURE2DARRAY */ -#line 2750 "MachineIndependent/glslang.y" + case 395: /* type_specifier_nonarray: TEXTURE2DARRAY */ +#line 2778 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true); } -#line 9270 "MachineIndependent/glslang_tab.cpp" +#line 9417 "MachineIndependent/glslang_tab.cpp" break; - case 390: /* type_specifier_nonarray: TEXTURECUBE */ -#line 2755 "MachineIndependent/glslang.y" + case 396: /* type_specifier_nonarray: TEXTURECUBE */ +#line 2783 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdCube); } -#line 9280 "MachineIndependent/glslang_tab.cpp" +#line 9427 "MachineIndependent/glslang_tab.cpp" break; - case 391: /* type_specifier_nonarray: ITEXTURE2D */ -#line 2760 "MachineIndependent/glslang.y" + case 397: /* type_specifier_nonarray: ITEXTURE2D */ +#line 2788 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D); } -#line 9290 "MachineIndependent/glslang_tab.cpp" +#line 9437 "MachineIndependent/glslang_tab.cpp" break; - case 392: /* type_specifier_nonarray: ITEXTURE3D */ -#line 2765 "MachineIndependent/glslang.y" + case 398: /* type_specifier_nonarray: ITEXTURE3D */ +#line 2793 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd3D); } -#line 9300 "MachineIndependent/glslang_tab.cpp" +#line 9447 "MachineIndependent/glslang_tab.cpp" break; - case 393: /* type_specifier_nonarray: ITEXTURECUBE */ -#line 2770 "MachineIndependent/glslang.y" + case 399: /* type_specifier_nonarray: ITEXTURECUBE */ +#line 2798 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdCube); } -#line 9310 "MachineIndependent/glslang_tab.cpp" +#line 9457 "MachineIndependent/glslang_tab.cpp" break; - case 394: /* type_specifier_nonarray: ITEXTURE2DARRAY */ -#line 2775 "MachineIndependent/glslang.y" + case 400: /* type_specifier_nonarray: ITEXTURE2DARRAY */ +#line 2803 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true); } -#line 9320 "MachineIndependent/glslang_tab.cpp" +#line 9467 "MachineIndependent/glslang_tab.cpp" break; - case 395: /* type_specifier_nonarray: UTEXTURE2D */ -#line 2780 "MachineIndependent/glslang.y" + case 401: /* type_specifier_nonarray: UTEXTURE2D */ +#line 2808 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D); } -#line 9330 "MachineIndependent/glslang_tab.cpp" +#line 9477 "MachineIndependent/glslang_tab.cpp" break; - case 396: /* type_specifier_nonarray: UTEXTURE3D */ -#line 2785 "MachineIndependent/glslang.y" + case 402: /* type_specifier_nonarray: UTEXTURE3D */ +#line 2813 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd3D); } -#line 9340 "MachineIndependent/glslang_tab.cpp" +#line 9487 "MachineIndependent/glslang_tab.cpp" break; - case 397: /* type_specifier_nonarray: UTEXTURECUBE */ -#line 2790 "MachineIndependent/glslang.y" + case 403: /* type_specifier_nonarray: UTEXTURECUBE */ +#line 2818 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdCube); } -#line 9350 "MachineIndependent/glslang_tab.cpp" +#line 9497 "MachineIndependent/glslang_tab.cpp" break; - case 398: /* type_specifier_nonarray: UTEXTURE2DARRAY */ -#line 2795 "MachineIndependent/glslang.y" + case 404: /* type_specifier_nonarray: UTEXTURE2DARRAY */ +#line 2823 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true); } -#line 9360 "MachineIndependent/glslang_tab.cpp" +#line 9507 "MachineIndependent/glslang_tab.cpp" break; - case 399: /* type_specifier_nonarray: SAMPLER */ -#line 2800 "MachineIndependent/glslang.y" + case 405: /* type_specifier_nonarray: SAMPLER */ +#line 2828 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setPureSampler(false); } -#line 9370 "MachineIndependent/glslang_tab.cpp" +#line 9517 "MachineIndependent/glslang_tab.cpp" break; - case 400: /* type_specifier_nonarray: SAMPLERSHADOW */ -#line 2805 "MachineIndependent/glslang.y" + case 406: /* type_specifier_nonarray: SAMPLERSHADOW */ +#line 2833 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setPureSampler(true); } -#line 9380 "MachineIndependent/glslang_tab.cpp" +#line 9527 "MachineIndependent/glslang_tab.cpp" break; - case 401: /* type_specifier_nonarray: SAMPLER2DRECT */ -#line 2811 "MachineIndependent/glslang.y" + case 407: /* type_specifier_nonarray: SAMPLER2DRECT */ +#line 2838 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdRect); } -#line 9390 "MachineIndependent/glslang_tab.cpp" +#line 9537 "MachineIndependent/glslang_tab.cpp" break; - case 402: /* type_specifier_nonarray: SAMPLER2DRECTSHADOW */ -#line 2816 "MachineIndependent/glslang.y" + case 408: /* type_specifier_nonarray: SAMPLER2DRECTSHADOW */ +#line 2843 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdRect, false, true); } -#line 9400 "MachineIndependent/glslang_tab.cpp" +#line 9547 "MachineIndependent/glslang_tab.cpp" break; - case 403: /* type_specifier_nonarray: F16SAMPLER2DRECT */ -#line 2821 "MachineIndependent/glslang.y" + case 409: /* type_specifier_nonarray: F16SAMPLER2DRECT */ +#line 2848 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdRect); } -#line 9411 "MachineIndependent/glslang_tab.cpp" +#line 9558 "MachineIndependent/glslang_tab.cpp" break; - case 404: /* type_specifier_nonarray: F16SAMPLER2DRECTSHADOW */ -#line 2827 "MachineIndependent/glslang.y" + case 410: /* type_specifier_nonarray: F16SAMPLER2DRECTSHADOW */ +#line 2854 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdRect, false, true); } -#line 9422 "MachineIndependent/glslang_tab.cpp" +#line 9569 "MachineIndependent/glslang_tab.cpp" break; - case 405: /* type_specifier_nonarray: ISAMPLER2DRECT */ -#line 2833 "MachineIndependent/glslang.y" + case 411: /* type_specifier_nonarray: ISAMPLER2DRECT */ +#line 2860 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdRect); } -#line 9432 "MachineIndependent/glslang_tab.cpp" +#line 9579 "MachineIndependent/glslang_tab.cpp" break; - case 406: /* type_specifier_nonarray: USAMPLER2DRECT */ -#line 2838 "MachineIndependent/glslang.y" + case 412: /* type_specifier_nonarray: USAMPLER2DRECT */ +#line 2865 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdRect); } -#line 9442 "MachineIndependent/glslang_tab.cpp" +#line 9589 "MachineIndependent/glslang_tab.cpp" break; - case 407: /* type_specifier_nonarray: SAMPLERBUFFER */ -#line 2843 "MachineIndependent/glslang.y" + case 413: /* type_specifier_nonarray: SAMPLERBUFFER */ +#line 2870 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, EsdBuffer); } -#line 9452 "MachineIndependent/glslang_tab.cpp" +#line 9599 "MachineIndependent/glslang_tab.cpp" break; - case 408: /* type_specifier_nonarray: F16SAMPLERBUFFER */ -#line 2848 "MachineIndependent/glslang.y" + case 414: /* type_specifier_nonarray: F16SAMPLERBUFFER */ +#line 2875 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, EsdBuffer); } -#line 9463 "MachineIndependent/glslang_tab.cpp" +#line 9610 "MachineIndependent/glslang_tab.cpp" break; - case 409: /* type_specifier_nonarray: ISAMPLERBUFFER */ -#line 2854 "MachineIndependent/glslang.y" + case 415: /* type_specifier_nonarray: ISAMPLERBUFFER */ +#line 2881 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, EsdBuffer); } -#line 9473 "MachineIndependent/glslang_tab.cpp" +#line 9620 "MachineIndependent/glslang_tab.cpp" break; - case 410: /* type_specifier_nonarray: USAMPLERBUFFER */ -#line 2859 "MachineIndependent/glslang.y" + case 416: /* type_specifier_nonarray: USAMPLERBUFFER */ +#line 2886 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, EsdBuffer); } -#line 9483 "MachineIndependent/glslang_tab.cpp" +#line 9630 "MachineIndependent/glslang_tab.cpp" break; - case 411: /* type_specifier_nonarray: SAMPLER2DMS */ -#line 2864 "MachineIndependent/glslang.y" + case 417: /* type_specifier_nonarray: SAMPLER2DMS */ +#line 2891 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, false, false, true); } -#line 9493 "MachineIndependent/glslang_tab.cpp" +#line 9640 "MachineIndependent/glslang_tab.cpp" break; - case 412: /* type_specifier_nonarray: F16SAMPLER2DMS */ -#line 2869 "MachineIndependent/glslang.y" + case 418: /* type_specifier_nonarray: F16SAMPLER2DMS */ +#line 2896 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, false, false, true); } -#line 9504 "MachineIndependent/glslang_tab.cpp" +#line 9651 "MachineIndependent/glslang_tab.cpp" break; - case 413: /* type_specifier_nonarray: ISAMPLER2DMS */ -#line 2875 "MachineIndependent/glslang.y" + case 419: /* type_specifier_nonarray: ISAMPLER2DMS */ +#line 2902 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, false, false, true); } -#line 9514 "MachineIndependent/glslang_tab.cpp" +#line 9661 "MachineIndependent/glslang_tab.cpp" break; - case 414: /* type_specifier_nonarray: USAMPLER2DMS */ -#line 2880 "MachineIndependent/glslang.y" + case 420: /* type_specifier_nonarray: USAMPLER2DMS */ +#line 2907 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, false, false, true); } -#line 9524 "MachineIndependent/glslang_tab.cpp" +#line 9671 "MachineIndependent/glslang_tab.cpp" break; - case 415: /* type_specifier_nonarray: SAMPLER2DMSARRAY */ -#line 2885 "MachineIndependent/glslang.y" + case 421: /* type_specifier_nonarray: SAMPLER2DMSARRAY */ +#line 2912 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D, true, false, true); } -#line 9534 "MachineIndependent/glslang_tab.cpp" +#line 9681 "MachineIndependent/glslang_tab.cpp" break; - case 416: /* type_specifier_nonarray: F16SAMPLER2DMSARRAY */ -#line 2890 "MachineIndependent/glslang.y" + case 422: /* type_specifier_nonarray: F16SAMPLER2DMSARRAY */ +#line 2917 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float sampler", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat16, Esd2D, true, false, true); } -#line 9545 "MachineIndependent/glslang_tab.cpp" +#line 9692 "MachineIndependent/glslang_tab.cpp" break; - case 417: /* type_specifier_nonarray: ISAMPLER2DMSARRAY */ -#line 2896 "MachineIndependent/glslang.y" + case 423: /* type_specifier_nonarray: ISAMPLER2DMSARRAY */ +#line 2923 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtInt, Esd2D, true, false, true); } -#line 9555 "MachineIndependent/glslang_tab.cpp" +#line 9702 "MachineIndependent/glslang_tab.cpp" break; - case 418: /* type_specifier_nonarray: USAMPLER2DMSARRAY */ -#line 2901 "MachineIndependent/glslang.y" + case 424: /* type_specifier_nonarray: USAMPLER2DMSARRAY */ +#line 2928 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtUint, Esd2D, true, false, true); } -#line 9565 "MachineIndependent/glslang_tab.cpp" +#line 9712 "MachineIndependent/glslang_tab.cpp" break; - case 419: /* type_specifier_nonarray: TEXTURE1D */ -#line 2906 "MachineIndependent/glslang.y" + case 425: /* type_specifier_nonarray: TEXTURE1D */ +#line 2933 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D); } -#line 9575 "MachineIndependent/glslang_tab.cpp" +#line 9722 "MachineIndependent/glslang_tab.cpp" break; - case 420: /* type_specifier_nonarray: F16TEXTURE1D */ -#line 2911 "MachineIndependent/glslang.y" + case 426: /* type_specifier_nonarray: F16TEXTURE1D */ +#line 2938 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D); } -#line 9586 "MachineIndependent/glslang_tab.cpp" +#line 9733 "MachineIndependent/glslang_tab.cpp" break; - case 421: /* type_specifier_nonarray: F16TEXTURE2D */ -#line 2917 "MachineIndependent/glslang.y" + case 427: /* type_specifier_nonarray: F16TEXTURE2D */ +#line 2944 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D); } -#line 9597 "MachineIndependent/glslang_tab.cpp" +#line 9744 "MachineIndependent/glslang_tab.cpp" break; - case 422: /* type_specifier_nonarray: F16TEXTURE3D */ -#line 2923 "MachineIndependent/glslang.y" + case 428: /* type_specifier_nonarray: F16TEXTURE3D */ +#line 2950 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd3D); } -#line 9608 "MachineIndependent/glslang_tab.cpp" +#line 9755 "MachineIndependent/glslang_tab.cpp" break; - case 423: /* type_specifier_nonarray: F16TEXTURECUBE */ -#line 2929 "MachineIndependent/glslang.y" + case 429: /* type_specifier_nonarray: F16TEXTURECUBE */ +#line 2956 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube); } -#line 9619 "MachineIndependent/glslang_tab.cpp" +#line 9766 "MachineIndependent/glslang_tab.cpp" break; - case 424: /* type_specifier_nonarray: TEXTURE1DARRAY */ -#line 2935 "MachineIndependent/glslang.y" + case 430: /* type_specifier_nonarray: TEXTURE1DARRAY */ +#line 2962 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd1D, true); } -#line 9629 "MachineIndependent/glslang_tab.cpp" +#line 9776 "MachineIndependent/glslang_tab.cpp" break; - case 425: /* type_specifier_nonarray: F16TEXTURE1DARRAY */ -#line 2940 "MachineIndependent/glslang.y" + case 431: /* type_specifier_nonarray: F16TEXTURE1DARRAY */ +#line 2967 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd1D, true); } -#line 9640 "MachineIndependent/glslang_tab.cpp" +#line 9787 "MachineIndependent/glslang_tab.cpp" break; - case 426: /* type_specifier_nonarray: F16TEXTURE2DARRAY */ -#line 2946 "MachineIndependent/glslang.y" + case 432: /* type_specifier_nonarray: F16TEXTURE2DARRAY */ +#line 2973 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true); } -#line 9651 "MachineIndependent/glslang_tab.cpp" +#line 9798 "MachineIndependent/glslang_tab.cpp" break; - case 427: /* type_specifier_nonarray: F16TEXTURECUBEARRAY */ -#line 2952 "MachineIndependent/glslang.y" + case 433: /* type_specifier_nonarray: F16TEXTURECUBEARRAY */ +#line 2979 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdCube, true); } -#line 9662 "MachineIndependent/glslang_tab.cpp" +#line 9809 "MachineIndependent/glslang_tab.cpp" break; - case 428: /* type_specifier_nonarray: ITEXTURE1D */ -#line 2958 "MachineIndependent/glslang.y" + case 434: /* type_specifier_nonarray: ITEXTURE1D */ +#line 2985 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D); } -#line 9672 "MachineIndependent/glslang_tab.cpp" +#line 9819 "MachineIndependent/glslang_tab.cpp" break; - case 429: /* type_specifier_nonarray: ITEXTURE1DARRAY */ -#line 2963 "MachineIndependent/glslang.y" + case 435: /* type_specifier_nonarray: ITEXTURE1DARRAY */ +#line 2990 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd1D, true); } -#line 9682 "MachineIndependent/glslang_tab.cpp" +#line 9829 "MachineIndependent/glslang_tab.cpp" break; - case 430: /* type_specifier_nonarray: UTEXTURE1D */ -#line 2968 "MachineIndependent/glslang.y" + case 436: /* type_specifier_nonarray: UTEXTURE1D */ +#line 2995 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D); } -#line 9692 "MachineIndependent/glslang_tab.cpp" +#line 9839 "MachineIndependent/glslang_tab.cpp" break; - case 431: /* type_specifier_nonarray: UTEXTURE1DARRAY */ -#line 2973 "MachineIndependent/glslang.y" + case 437: /* type_specifier_nonarray: UTEXTURE1DARRAY */ +#line 3000 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd1D, true); } -#line 9702 "MachineIndependent/glslang_tab.cpp" +#line 9849 "MachineIndependent/glslang_tab.cpp" break; - case 432: /* type_specifier_nonarray: TEXTURE2DRECT */ -#line 2978 "MachineIndependent/glslang.y" + case 438: /* type_specifier_nonarray: TEXTURE2DRECT */ +#line 3005 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdRect); } -#line 9712 "MachineIndependent/glslang_tab.cpp" +#line 9859 "MachineIndependent/glslang_tab.cpp" break; - case 433: /* type_specifier_nonarray: F16TEXTURE2DRECT */ -#line 2983 "MachineIndependent/glslang.y" + case 439: /* type_specifier_nonarray: F16TEXTURE2DRECT */ +#line 3010 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdRect); } -#line 9723 "MachineIndependent/glslang_tab.cpp" +#line 9870 "MachineIndependent/glslang_tab.cpp" break; - case 434: /* type_specifier_nonarray: ITEXTURE2DRECT */ -#line 2989 "MachineIndependent/glslang.y" + case 440: /* type_specifier_nonarray: ITEXTURE2DRECT */ +#line 3016 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdRect); } -#line 9733 "MachineIndependent/glslang_tab.cpp" +#line 9880 "MachineIndependent/glslang_tab.cpp" break; - case 435: /* type_specifier_nonarray: UTEXTURE2DRECT */ -#line 2994 "MachineIndependent/glslang.y" + case 441: /* type_specifier_nonarray: UTEXTURE2DRECT */ +#line 3021 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdRect); } -#line 9743 "MachineIndependent/glslang_tab.cpp" +#line 9890 "MachineIndependent/glslang_tab.cpp" break; - case 436: /* type_specifier_nonarray: TEXTUREBUFFER */ -#line 2999 "MachineIndependent/glslang.y" + case 442: /* type_specifier_nonarray: TEXTUREBUFFER */ +#line 3026 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, EsdBuffer); } -#line 9753 "MachineIndependent/glslang_tab.cpp" +#line 9900 "MachineIndependent/glslang_tab.cpp" break; - case 437: /* type_specifier_nonarray: F16TEXTUREBUFFER */ -#line 3004 "MachineIndependent/glslang.y" + case 443: /* type_specifier_nonarray: F16TEXTUREBUFFER */ +#line 3031 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, EsdBuffer); } -#line 9764 "MachineIndependent/glslang_tab.cpp" +#line 9911 "MachineIndependent/glslang_tab.cpp" break; - case 438: /* type_specifier_nonarray: ITEXTUREBUFFER */ -#line 3010 "MachineIndependent/glslang.y" + case 444: /* type_specifier_nonarray: ITEXTUREBUFFER */ +#line 3037 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, EsdBuffer); } -#line 9774 "MachineIndependent/glslang_tab.cpp" +#line 9921 "MachineIndependent/glslang_tab.cpp" break; - case 439: /* type_specifier_nonarray: UTEXTUREBUFFER */ -#line 3015 "MachineIndependent/glslang.y" + case 445: /* type_specifier_nonarray: UTEXTUREBUFFER */ +#line 3042 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, EsdBuffer); } -#line 9784 "MachineIndependent/glslang_tab.cpp" +#line 9931 "MachineIndependent/glslang_tab.cpp" break; - case 440: /* type_specifier_nonarray: TEXTURE2DMS */ -#line 3020 "MachineIndependent/glslang.y" + case 446: /* type_specifier_nonarray: TEXTURE2DMS */ +#line 3047 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, false, false, true); } -#line 9794 "MachineIndependent/glslang_tab.cpp" +#line 9941 "MachineIndependent/glslang_tab.cpp" break; - case 441: /* type_specifier_nonarray: F16TEXTURE2DMS */ -#line 3025 "MachineIndependent/glslang.y" + case 447: /* type_specifier_nonarray: F16TEXTURE2DMS */ +#line 3052 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, false, false, true); } -#line 9805 "MachineIndependent/glslang_tab.cpp" +#line 9952 "MachineIndependent/glslang_tab.cpp" break; - case 442: /* type_specifier_nonarray: ITEXTURE2DMS */ -#line 3031 "MachineIndependent/glslang.y" + case 448: /* type_specifier_nonarray: ITEXTURE2DMS */ +#line 3058 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, false, false, true); } -#line 9815 "MachineIndependent/glslang_tab.cpp" +#line 9962 "MachineIndependent/glslang_tab.cpp" break; - case 443: /* type_specifier_nonarray: UTEXTURE2DMS */ -#line 3036 "MachineIndependent/glslang.y" + case 449: /* type_specifier_nonarray: UTEXTURE2DMS */ +#line 3063 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, false, false, true); } -#line 9825 "MachineIndependent/glslang_tab.cpp" +#line 9972 "MachineIndependent/glslang_tab.cpp" break; - case 444: /* type_specifier_nonarray: TEXTURE2DMSARRAY */ -#line 3041 "MachineIndependent/glslang.y" + case 450: /* type_specifier_nonarray: TEXTURE2DMSARRAY */ +#line 3068 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat, Esd2D, true, false, true); } -#line 9835 "MachineIndependent/glslang_tab.cpp" +#line 9982 "MachineIndependent/glslang_tab.cpp" break; - case 445: /* type_specifier_nonarray: F16TEXTURE2DMSARRAY */ -#line 3046 "MachineIndependent/glslang.y" + case 451: /* type_specifier_nonarray: F16TEXTURE2DMSARRAY */ +#line 3073 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float texture", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtFloat16, Esd2D, true, false, true); } -#line 9846 "MachineIndependent/glslang_tab.cpp" +#line 9993 "MachineIndependent/glslang_tab.cpp" break; - case 446: /* type_specifier_nonarray: ITEXTURE2DMSARRAY */ -#line 3052 "MachineIndependent/glslang.y" + case 452: /* type_specifier_nonarray: ITEXTURE2DMSARRAY */ +#line 3079 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtInt, Esd2D, true, false, true); } -#line 9856 "MachineIndependent/glslang_tab.cpp" +#line 10003 "MachineIndependent/glslang_tab.cpp" break; - case 447: /* type_specifier_nonarray: UTEXTURE2DMSARRAY */ -#line 3057 "MachineIndependent/glslang.y" + case 453: /* type_specifier_nonarray: UTEXTURE2DMSARRAY */ +#line 3084 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setTexture(EbtUint, Esd2D, true, false, true); } -#line 9866 "MachineIndependent/glslang_tab.cpp" +#line 10013 "MachineIndependent/glslang_tab.cpp" break; - case 448: /* type_specifier_nonarray: IMAGE1D */ -#line 3062 "MachineIndependent/glslang.y" + case 454: /* type_specifier_nonarray: IMAGE1D */ +#line 3089 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D); } -#line 9876 "MachineIndependent/glslang_tab.cpp" +#line 10023 "MachineIndependent/glslang_tab.cpp" break; - case 449: /* type_specifier_nonarray: F16IMAGE1D */ -#line 3067 "MachineIndependent/glslang.y" + case 455: /* type_specifier_nonarray: F16IMAGE1D */ +#line 3094 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D); } -#line 9887 "MachineIndependent/glslang_tab.cpp" +#line 10034 "MachineIndependent/glslang_tab.cpp" break; - case 450: /* type_specifier_nonarray: IIMAGE1D */ -#line 3073 "MachineIndependent/glslang.y" + case 456: /* type_specifier_nonarray: IIMAGE1D */ +#line 3100 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd1D); } -#line 9897 "MachineIndependent/glslang_tab.cpp" +#line 10044 "MachineIndependent/glslang_tab.cpp" break; - case 451: /* type_specifier_nonarray: UIMAGE1D */ -#line 3078 "MachineIndependent/glslang.y" + case 457: /* type_specifier_nonarray: UIMAGE1D */ +#line 3105 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd1D); } -#line 9907 "MachineIndependent/glslang_tab.cpp" +#line 10054 "MachineIndependent/glslang_tab.cpp" break; - case 452: /* type_specifier_nonarray: IMAGE2D */ -#line 3083 "MachineIndependent/glslang.y" + case 458: /* type_specifier_nonarray: IMAGE2D */ +#line 3110 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D); } -#line 9917 "MachineIndependent/glslang_tab.cpp" +#line 10064 "MachineIndependent/glslang_tab.cpp" break; - case 453: /* type_specifier_nonarray: F16IMAGE2D */ -#line 3088 "MachineIndependent/glslang.y" + case 459: /* type_specifier_nonarray: F16IMAGE2D */ +#line 3115 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D); } -#line 9928 "MachineIndependent/glslang_tab.cpp" +#line 10075 "MachineIndependent/glslang_tab.cpp" break; - case 454: /* type_specifier_nonarray: IIMAGE2D */ -#line 3094 "MachineIndependent/glslang.y" + case 460: /* type_specifier_nonarray: IIMAGE2D */ +#line 3121 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D); } -#line 9938 "MachineIndependent/glslang_tab.cpp" +#line 10085 "MachineIndependent/glslang_tab.cpp" break; - case 455: /* type_specifier_nonarray: UIMAGE2D */ -#line 3099 "MachineIndependent/glslang.y" + case 461: /* type_specifier_nonarray: UIMAGE2D */ +#line 3126 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D); } -#line 9948 "MachineIndependent/glslang_tab.cpp" +#line 10095 "MachineIndependent/glslang_tab.cpp" break; - case 456: /* type_specifier_nonarray: IMAGE3D */ -#line 3104 "MachineIndependent/glslang.y" + case 462: /* type_specifier_nonarray: IMAGE3D */ +#line 3131 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd3D); } -#line 9958 "MachineIndependent/glslang_tab.cpp" +#line 10105 "MachineIndependent/glslang_tab.cpp" break; - case 457: /* type_specifier_nonarray: F16IMAGE3D */ -#line 3109 "MachineIndependent/glslang.y" + case 463: /* type_specifier_nonarray: F16IMAGE3D */ +#line 3136 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd3D); } -#line 9969 "MachineIndependent/glslang_tab.cpp" +#line 10116 "MachineIndependent/glslang_tab.cpp" break; - case 458: /* type_specifier_nonarray: IIMAGE3D */ -#line 3115 "MachineIndependent/glslang.y" + case 464: /* type_specifier_nonarray: IIMAGE3D */ +#line 3142 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd3D); } -#line 9979 "MachineIndependent/glslang_tab.cpp" +#line 10126 "MachineIndependent/glslang_tab.cpp" break; - case 459: /* type_specifier_nonarray: UIMAGE3D */ -#line 3120 "MachineIndependent/glslang.y" + case 465: /* type_specifier_nonarray: UIMAGE3D */ +#line 3147 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd3D); } -#line 9989 "MachineIndependent/glslang_tab.cpp" +#line 10136 "MachineIndependent/glslang_tab.cpp" break; - case 460: /* type_specifier_nonarray: IMAGE2DRECT */ -#line 3125 "MachineIndependent/glslang.y" + case 466: /* type_specifier_nonarray: IMAGE2DRECT */ +#line 3152 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdRect); } -#line 9999 "MachineIndependent/glslang_tab.cpp" +#line 10146 "MachineIndependent/glslang_tab.cpp" break; - case 461: /* type_specifier_nonarray: F16IMAGE2DRECT */ -#line 3130 "MachineIndependent/glslang.y" + case 467: /* type_specifier_nonarray: F16IMAGE2DRECT */ +#line 3157 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, EsdRect); } -#line 10010 "MachineIndependent/glslang_tab.cpp" +#line 10157 "MachineIndependent/glslang_tab.cpp" break; - case 462: /* type_specifier_nonarray: IIMAGE2DRECT */ -#line 3136 "MachineIndependent/glslang.y" + case 468: /* type_specifier_nonarray: IIMAGE2DRECT */ +#line 3163 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdRect); } -#line 10020 "MachineIndependent/glslang_tab.cpp" +#line 10167 "MachineIndependent/glslang_tab.cpp" break; - case 463: /* type_specifier_nonarray: UIMAGE2DRECT */ -#line 3141 "MachineIndependent/glslang.y" + case 469: /* type_specifier_nonarray: UIMAGE2DRECT */ +#line 3168 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdRect); } -#line 10030 "MachineIndependent/glslang_tab.cpp" +#line 10177 "MachineIndependent/glslang_tab.cpp" break; - case 464: /* type_specifier_nonarray: IMAGECUBE */ -#line 3146 "MachineIndependent/glslang.y" + case 470: /* type_specifier_nonarray: IMAGECUBE */ +#line 3173 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube); } -#line 10040 "MachineIndependent/glslang_tab.cpp" +#line 10187 "MachineIndependent/glslang_tab.cpp" break; - case 465: /* type_specifier_nonarray: F16IMAGECUBE */ -#line 3151 "MachineIndependent/glslang.y" + case 471: /* type_specifier_nonarray: F16IMAGECUBE */ +#line 3178 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube); } -#line 10051 "MachineIndependent/glslang_tab.cpp" +#line 10198 "MachineIndependent/glslang_tab.cpp" break; - case 466: /* type_specifier_nonarray: IIMAGECUBE */ -#line 3157 "MachineIndependent/glslang.y" + case 472: /* type_specifier_nonarray: IIMAGECUBE */ +#line 3184 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdCube); } -#line 10061 "MachineIndependent/glslang_tab.cpp" +#line 10208 "MachineIndependent/glslang_tab.cpp" break; - case 467: /* type_specifier_nonarray: UIMAGECUBE */ -#line 3162 "MachineIndependent/glslang.y" + case 473: /* type_specifier_nonarray: UIMAGECUBE */ +#line 3189 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdCube); } -#line 10071 "MachineIndependent/glslang_tab.cpp" +#line 10218 "MachineIndependent/glslang_tab.cpp" break; - case 468: /* type_specifier_nonarray: IMAGEBUFFER */ -#line 3167 "MachineIndependent/glslang.y" + case 474: /* type_specifier_nonarray: IMAGEBUFFER */ +#line 3194 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdBuffer); } -#line 10081 "MachineIndependent/glslang_tab.cpp" +#line 10228 "MachineIndependent/glslang_tab.cpp" break; - case 469: /* type_specifier_nonarray: F16IMAGEBUFFER */ -#line 3172 "MachineIndependent/glslang.y" + case 475: /* type_specifier_nonarray: F16IMAGEBUFFER */ +#line 3199 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, EsdBuffer); } -#line 10092 "MachineIndependent/glslang_tab.cpp" +#line 10239 "MachineIndependent/glslang_tab.cpp" break; - case 470: /* type_specifier_nonarray: IIMAGEBUFFER */ -#line 3178 "MachineIndependent/glslang.y" + case 476: /* type_specifier_nonarray: IIMAGEBUFFER */ +#line 3205 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdBuffer); } -#line 10102 "MachineIndependent/glslang_tab.cpp" +#line 10249 "MachineIndependent/glslang_tab.cpp" break; - case 471: /* type_specifier_nonarray: UIMAGEBUFFER */ -#line 3183 "MachineIndependent/glslang.y" + case 477: /* type_specifier_nonarray: UIMAGEBUFFER */ +#line 3210 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdBuffer); } -#line 10112 "MachineIndependent/glslang_tab.cpp" +#line 10259 "MachineIndependent/glslang_tab.cpp" break; - case 472: /* type_specifier_nonarray: IMAGE1DARRAY */ -#line 3188 "MachineIndependent/glslang.y" + case 478: /* type_specifier_nonarray: IMAGE1DARRAY */ +#line 3215 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd1D, true); } -#line 10122 "MachineIndependent/glslang_tab.cpp" +#line 10269 "MachineIndependent/glslang_tab.cpp" break; - case 473: /* type_specifier_nonarray: F16IMAGE1DARRAY */ -#line 3193 "MachineIndependent/glslang.y" + case 479: /* type_specifier_nonarray: F16IMAGE1DARRAY */ +#line 3220 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd1D, true); } -#line 10133 "MachineIndependent/glslang_tab.cpp" +#line 10280 "MachineIndependent/glslang_tab.cpp" break; - case 474: /* type_specifier_nonarray: IIMAGE1DARRAY */ -#line 3199 "MachineIndependent/glslang.y" + case 480: /* type_specifier_nonarray: IIMAGE1DARRAY */ +#line 3226 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd1D, true); } -#line 10143 "MachineIndependent/glslang_tab.cpp" +#line 10290 "MachineIndependent/glslang_tab.cpp" break; - case 475: /* type_specifier_nonarray: UIMAGE1DARRAY */ -#line 3204 "MachineIndependent/glslang.y" + case 481: /* type_specifier_nonarray: UIMAGE1DARRAY */ +#line 3231 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd1D, true); } -#line 10153 "MachineIndependent/glslang_tab.cpp" +#line 10300 "MachineIndependent/glslang_tab.cpp" break; - case 476: /* type_specifier_nonarray: IMAGE2DARRAY */ -#line 3209 "MachineIndependent/glslang.y" + case 482: /* type_specifier_nonarray: IMAGE2DARRAY */ +#line 3236 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true); } -#line 10163 "MachineIndependent/glslang_tab.cpp" +#line 10310 "MachineIndependent/glslang_tab.cpp" break; - case 477: /* type_specifier_nonarray: F16IMAGE2DARRAY */ -#line 3214 "MachineIndependent/glslang.y" + case 483: /* type_specifier_nonarray: F16IMAGE2DARRAY */ +#line 3241 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true); } -#line 10174 "MachineIndependent/glslang_tab.cpp" +#line 10321 "MachineIndependent/glslang_tab.cpp" break; - case 478: /* type_specifier_nonarray: IIMAGE2DARRAY */ -#line 3220 "MachineIndependent/glslang.y" + case 484: /* type_specifier_nonarray: IIMAGE2DARRAY */ +#line 3247 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true); } -#line 10184 "MachineIndependent/glslang_tab.cpp" +#line 10331 "MachineIndependent/glslang_tab.cpp" break; - case 479: /* type_specifier_nonarray: UIMAGE2DARRAY */ -#line 3225 "MachineIndependent/glslang.y" + case 485: /* type_specifier_nonarray: UIMAGE2DARRAY */ +#line 3252 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true); } -#line 10194 "MachineIndependent/glslang_tab.cpp" +#line 10341 "MachineIndependent/glslang_tab.cpp" break; - case 480: /* type_specifier_nonarray: IMAGECUBEARRAY */ -#line 3230 "MachineIndependent/glslang.y" + case 486: /* type_specifier_nonarray: IMAGECUBEARRAY */ +#line 3257 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, EsdCube, true); } -#line 10204 "MachineIndependent/glslang_tab.cpp" +#line 10351 "MachineIndependent/glslang_tab.cpp" break; - case 481: /* type_specifier_nonarray: F16IMAGECUBEARRAY */ -#line 3235 "MachineIndependent/glslang.y" + case 487: /* type_specifier_nonarray: F16IMAGECUBEARRAY */ +#line 3262 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, EsdCube, true); } -#line 10215 "MachineIndependent/glslang_tab.cpp" +#line 10362 "MachineIndependent/glslang_tab.cpp" break; - case 482: /* type_specifier_nonarray: IIMAGECUBEARRAY */ -#line 3241 "MachineIndependent/glslang.y" + case 488: /* type_specifier_nonarray: IIMAGECUBEARRAY */ +#line 3268 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, EsdCube, true); } -#line 10225 "MachineIndependent/glslang_tab.cpp" +#line 10372 "MachineIndependent/glslang_tab.cpp" break; - case 483: /* type_specifier_nonarray: UIMAGECUBEARRAY */ -#line 3246 "MachineIndependent/glslang.y" + case 489: /* type_specifier_nonarray: UIMAGECUBEARRAY */ +#line 3273 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, EsdCube, true); } -#line 10235 "MachineIndependent/glslang_tab.cpp" +#line 10382 "MachineIndependent/glslang_tab.cpp" break; - case 484: /* type_specifier_nonarray: IMAGE2DMS */ -#line 3251 "MachineIndependent/glslang.y" + case 490: /* type_specifier_nonarray: IMAGE2DMS */ +#line 3278 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, false, false, true); } -#line 10245 "MachineIndependent/glslang_tab.cpp" +#line 10392 "MachineIndependent/glslang_tab.cpp" break; - case 485: /* type_specifier_nonarray: F16IMAGE2DMS */ -#line 3256 "MachineIndependent/glslang.y" + case 491: /* type_specifier_nonarray: F16IMAGE2DMS */ +#line 3283 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, false, false, true); } -#line 10256 "MachineIndependent/glslang_tab.cpp" +#line 10403 "MachineIndependent/glslang_tab.cpp" break; - case 486: /* type_specifier_nonarray: IIMAGE2DMS */ -#line 3262 "MachineIndependent/glslang.y" + case 492: /* type_specifier_nonarray: IIMAGE2DMS */ +#line 3289 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, false, false, true); } -#line 10266 "MachineIndependent/glslang_tab.cpp" +#line 10413 "MachineIndependent/glslang_tab.cpp" break; - case 487: /* type_specifier_nonarray: UIMAGE2DMS */ -#line 3267 "MachineIndependent/glslang.y" + case 493: /* type_specifier_nonarray: UIMAGE2DMS */ +#line 3294 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, false, false, true); } -#line 10276 "MachineIndependent/glslang_tab.cpp" +#line 10423 "MachineIndependent/glslang_tab.cpp" break; - case 488: /* type_specifier_nonarray: IMAGE2DMSARRAY */ -#line 3272 "MachineIndependent/glslang.y" + case 494: /* type_specifier_nonarray: IMAGE2DMSARRAY */ +#line 3299 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat, Esd2D, true, false, true); } -#line 10286 "MachineIndependent/glslang_tab.cpp" +#line 10433 "MachineIndependent/glslang_tab.cpp" break; - case 489: /* type_specifier_nonarray: F16IMAGE2DMSARRAY */ -#line 3277 "MachineIndependent/glslang.y" + case 495: /* type_specifier_nonarray: F16IMAGE2DMSARRAY */ +#line 3304 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float image", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtFloat16, Esd2D, true, false, true); } -#line 10297 "MachineIndependent/glslang_tab.cpp" +#line 10444 "MachineIndependent/glslang_tab.cpp" break; - case 490: /* type_specifier_nonarray: IIMAGE2DMSARRAY */ -#line 3283 "MachineIndependent/glslang.y" + case 496: /* type_specifier_nonarray: IIMAGE2DMSARRAY */ +#line 3310 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt, Esd2D, true, false, true); } -#line 10307 "MachineIndependent/glslang_tab.cpp" +#line 10454 "MachineIndependent/glslang_tab.cpp" break; - case 491: /* type_specifier_nonarray: UIMAGE2DMSARRAY */ -#line 3288 "MachineIndependent/glslang.y" + case 497: /* type_specifier_nonarray: UIMAGE2DMSARRAY */ +#line 3315 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint, Esd2D, true, false, true); } -#line 10317 "MachineIndependent/glslang_tab.cpp" +#line 10464 "MachineIndependent/glslang_tab.cpp" break; - case 492: /* type_specifier_nonarray: I64IMAGE1D */ -#line 3293 "MachineIndependent/glslang.y" + case 498: /* type_specifier_nonarray: I64IMAGE1D */ +#line 3320 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd1D); } -#line 10327 "MachineIndependent/glslang_tab.cpp" +#line 10474 "MachineIndependent/glslang_tab.cpp" break; - case 493: /* type_specifier_nonarray: U64IMAGE1D */ -#line 3298 "MachineIndependent/glslang.y" + case 499: /* type_specifier_nonarray: U64IMAGE1D */ +#line 3325 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd1D); } -#line 10337 "MachineIndependent/glslang_tab.cpp" +#line 10484 "MachineIndependent/glslang_tab.cpp" break; - case 494: /* type_specifier_nonarray: I64IMAGE2D */ -#line 3303 "MachineIndependent/glslang.y" + case 500: /* type_specifier_nonarray: I64IMAGE2D */ +#line 3330 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D); } -#line 10347 "MachineIndependent/glslang_tab.cpp" +#line 10494 "MachineIndependent/glslang_tab.cpp" break; - case 495: /* type_specifier_nonarray: U64IMAGE2D */ -#line 3308 "MachineIndependent/glslang.y" + case 501: /* type_specifier_nonarray: U64IMAGE2D */ +#line 3335 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D); } -#line 10357 "MachineIndependent/glslang_tab.cpp" +#line 10504 "MachineIndependent/glslang_tab.cpp" break; - case 496: /* type_specifier_nonarray: I64IMAGE3D */ -#line 3313 "MachineIndependent/glslang.y" + case 502: /* type_specifier_nonarray: I64IMAGE3D */ +#line 3340 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd3D); } -#line 10367 "MachineIndependent/glslang_tab.cpp" +#line 10514 "MachineIndependent/glslang_tab.cpp" break; - case 497: /* type_specifier_nonarray: U64IMAGE3D */ -#line 3318 "MachineIndependent/glslang.y" + case 503: /* type_specifier_nonarray: U64IMAGE3D */ +#line 3345 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd3D); } -#line 10377 "MachineIndependent/glslang_tab.cpp" +#line 10524 "MachineIndependent/glslang_tab.cpp" break; - case 498: /* type_specifier_nonarray: I64IMAGE2DRECT */ -#line 3323 "MachineIndependent/glslang.y" + case 504: /* type_specifier_nonarray: I64IMAGE2DRECT */ +#line 3350 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, EsdRect); } -#line 10387 "MachineIndependent/glslang_tab.cpp" +#line 10534 "MachineIndependent/glslang_tab.cpp" break; - case 499: /* type_specifier_nonarray: U64IMAGE2DRECT */ -#line 3328 "MachineIndependent/glslang.y" + case 505: /* type_specifier_nonarray: U64IMAGE2DRECT */ +#line 3355 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, EsdRect); } -#line 10397 "MachineIndependent/glslang_tab.cpp" +#line 10544 "MachineIndependent/glslang_tab.cpp" break; - case 500: /* type_specifier_nonarray: I64IMAGECUBE */ -#line 3333 "MachineIndependent/glslang.y" + case 506: /* type_specifier_nonarray: I64IMAGECUBE */ +#line 3360 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, EsdCube); } -#line 10407 "MachineIndependent/glslang_tab.cpp" +#line 10554 "MachineIndependent/glslang_tab.cpp" break; - case 501: /* type_specifier_nonarray: U64IMAGECUBE */ -#line 3338 "MachineIndependent/glslang.y" + case 507: /* type_specifier_nonarray: U64IMAGECUBE */ +#line 3365 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, EsdCube); } -#line 10417 "MachineIndependent/glslang_tab.cpp" +#line 10564 "MachineIndependent/glslang_tab.cpp" break; - case 502: /* type_specifier_nonarray: I64IMAGEBUFFER */ -#line 3343 "MachineIndependent/glslang.y" + case 508: /* type_specifier_nonarray: I64IMAGEBUFFER */ +#line 3370 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, EsdBuffer); } -#line 10427 "MachineIndependent/glslang_tab.cpp" +#line 10574 "MachineIndependent/glslang_tab.cpp" break; - case 503: /* type_specifier_nonarray: U64IMAGEBUFFER */ -#line 3348 "MachineIndependent/glslang.y" + case 509: /* type_specifier_nonarray: U64IMAGEBUFFER */ +#line 3375 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, EsdBuffer); } -#line 10437 "MachineIndependent/glslang_tab.cpp" +#line 10584 "MachineIndependent/glslang_tab.cpp" break; - case 504: /* type_specifier_nonarray: I64IMAGE1DARRAY */ -#line 3353 "MachineIndependent/glslang.y" + case 510: /* type_specifier_nonarray: I64IMAGE1DARRAY */ +#line 3380 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd1D, true); } -#line 10447 "MachineIndependent/glslang_tab.cpp" +#line 10594 "MachineIndependent/glslang_tab.cpp" break; - case 505: /* type_specifier_nonarray: U64IMAGE1DARRAY */ -#line 3358 "MachineIndependent/glslang.y" + case 511: /* type_specifier_nonarray: U64IMAGE1DARRAY */ +#line 3385 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd1D, true); } -#line 10457 "MachineIndependent/glslang_tab.cpp" +#line 10604 "MachineIndependent/glslang_tab.cpp" break; - case 506: /* type_specifier_nonarray: I64IMAGE2DARRAY */ -#line 3363 "MachineIndependent/glslang.y" + case 512: /* type_specifier_nonarray: I64IMAGE2DARRAY */ +#line 3390 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, true); } -#line 10467 "MachineIndependent/glslang_tab.cpp" +#line 10614 "MachineIndependent/glslang_tab.cpp" break; - case 507: /* type_specifier_nonarray: U64IMAGE2DARRAY */ -#line 3368 "MachineIndependent/glslang.y" + case 513: /* type_specifier_nonarray: U64IMAGE2DARRAY */ +#line 3395 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, true); } -#line 10477 "MachineIndependent/glslang_tab.cpp" +#line 10624 "MachineIndependent/glslang_tab.cpp" break; - case 508: /* type_specifier_nonarray: I64IMAGECUBEARRAY */ -#line 3373 "MachineIndependent/glslang.y" + case 514: /* type_specifier_nonarray: I64IMAGECUBEARRAY */ +#line 3400 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, EsdCube, true); } -#line 10487 "MachineIndependent/glslang_tab.cpp" +#line 10634 "MachineIndependent/glslang_tab.cpp" break; - case 509: /* type_specifier_nonarray: U64IMAGECUBEARRAY */ -#line 3378 "MachineIndependent/glslang.y" + case 515: /* type_specifier_nonarray: U64IMAGECUBEARRAY */ +#line 3405 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, EsdCube, true); } -#line 10497 "MachineIndependent/glslang_tab.cpp" +#line 10644 "MachineIndependent/glslang_tab.cpp" break; - case 510: /* type_specifier_nonarray: I64IMAGE2DMS */ -#line 3383 "MachineIndependent/glslang.y" + case 516: /* type_specifier_nonarray: I64IMAGE2DMS */ +#line 3410 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, false, false, true); } -#line 10507 "MachineIndependent/glslang_tab.cpp" +#line 10654 "MachineIndependent/glslang_tab.cpp" break; - case 511: /* type_specifier_nonarray: U64IMAGE2DMS */ -#line 3388 "MachineIndependent/glslang.y" + case 517: /* type_specifier_nonarray: U64IMAGE2DMS */ +#line 3415 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, false, false, true); } -#line 10517 "MachineIndependent/glslang_tab.cpp" +#line 10664 "MachineIndependent/glslang_tab.cpp" break; - case 512: /* type_specifier_nonarray: I64IMAGE2DMSARRAY */ -#line 3393 "MachineIndependent/glslang.y" + case 518: /* type_specifier_nonarray: I64IMAGE2DMSARRAY */ +#line 3420 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtInt64, Esd2D, true, false, true); } -#line 10527 "MachineIndependent/glslang_tab.cpp" +#line 10674 "MachineIndependent/glslang_tab.cpp" break; - case 513: /* type_specifier_nonarray: U64IMAGE2DMSARRAY */ -#line 3398 "MachineIndependent/glslang.y" + case 519: /* type_specifier_nonarray: U64IMAGE2DMSARRAY */ +#line 3425 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setImage(EbtUint64, Esd2D, true, false, true); } -#line 10537 "MachineIndependent/glslang_tab.cpp" +#line 10684 "MachineIndependent/glslang_tab.cpp" break; - case 514: /* type_specifier_nonarray: SAMPLEREXTERNALOES */ -#line 3403 "MachineIndependent/glslang.y" + case 520: /* type_specifier_nonarray: SAMPLEREXTERNALOES */ +#line 3430 "MachineIndependent/glslang.y" { // GL_OES_EGL_image_external (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D); (yyval.interm.type).sampler.external = true; } -#line 10548 "MachineIndependent/glslang_tab.cpp" +#line 10695 "MachineIndependent/glslang_tab.cpp" break; - case 515: /* type_specifier_nonarray: SAMPLEREXTERNAL2DY2YEXT */ -#line 3409 "MachineIndependent/glslang.y" + case 521: /* type_specifier_nonarray: SAMPLEREXTERNAL2DY2YEXT */ +#line 3436 "MachineIndependent/glslang.y" { // GL_EXT_YUV_target (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.set(EbtFloat, Esd2D); (yyval.interm.type).sampler.yuv = true; } -#line 10559 "MachineIndependent/glslang_tab.cpp" +#line 10706 "MachineIndependent/glslang_tab.cpp" break; - case 516: /* type_specifier_nonarray: SUBPASSINPUT */ -#line 3415 "MachineIndependent/glslang.y" + case 522: /* type_specifier_nonarray: ATTACHMENTEXT */ +#line 3442 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "attachmentEXT input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setAttachmentEXT(EbtFloat); + } +#line 10717 "MachineIndependent/glslang_tab.cpp" + break; + + case 523: /* type_specifier_nonarray: IATTACHMENTEXT */ +#line 3448 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "attachmentEXT input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setAttachmentEXT(EbtInt); + } +#line 10728 "MachineIndependent/glslang_tab.cpp" + break; + + case 524: /* type_specifier_nonarray: UATTACHMENTEXT */ +#line 3454 "MachineIndependent/glslang.y" + { + parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "attachmentEXT input"); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtSampler; + (yyval.interm.type).sampler.setAttachmentEXT(EbtUint); + } +#line 10739 "MachineIndependent/glslang_tab.cpp" + break; + + case 525: /* type_specifier_nonarray: SUBPASSINPUT */ +#line 3460 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat); } -#line 10570 "MachineIndependent/glslang_tab.cpp" +#line 10750 "MachineIndependent/glslang_tab.cpp" break; - case 517: /* type_specifier_nonarray: SUBPASSINPUTMS */ -#line 3421 "MachineIndependent/glslang.y" + case 526: /* type_specifier_nonarray: SUBPASSINPUTMS */ +#line 3466 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat, true); } -#line 10581 "MachineIndependent/glslang_tab.cpp" +#line 10761 "MachineIndependent/glslang_tab.cpp" break; - case 518: /* type_specifier_nonarray: F16SUBPASSINPUT */ -#line 3427 "MachineIndependent/glslang.y" + case 527: /* type_specifier_nonarray: F16SUBPASSINPUT */ +#line 3472 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); @@ -10589,11 +10769,11 @@ yyreduce: (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat16); } -#line 10593 "MachineIndependent/glslang_tab.cpp" +#line 10773 "MachineIndependent/glslang_tab.cpp" break; - case 519: /* type_specifier_nonarray: F16SUBPASSINPUTMS */ -#line 3434 "MachineIndependent/glslang.y" + case 528: /* type_specifier_nonarray: F16SUBPASSINPUTMS */ +#line 3479 "MachineIndependent/glslang.y" { parseContext.float16OpaqueCheck((yyvsp[0].lex).loc, "half float subpass input", parseContext.symbolTable.atBuiltInLevel()); parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); @@ -10601,107 +10781,131 @@ yyreduce: (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtFloat16, true); } -#line 10605 "MachineIndependent/glslang_tab.cpp" +#line 10785 "MachineIndependent/glslang_tab.cpp" break; - case 520: /* type_specifier_nonarray: ISUBPASSINPUT */ -#line 3441 "MachineIndependent/glslang.y" + case 529: /* type_specifier_nonarray: ISUBPASSINPUT */ +#line 3486 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtInt); } -#line 10616 "MachineIndependent/glslang_tab.cpp" +#line 10796 "MachineIndependent/glslang_tab.cpp" break; - case 521: /* type_specifier_nonarray: ISUBPASSINPUTMS */ -#line 3447 "MachineIndependent/glslang.y" + case 530: /* type_specifier_nonarray: ISUBPASSINPUTMS */ +#line 3492 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtInt, true); } -#line 10627 "MachineIndependent/glslang_tab.cpp" +#line 10807 "MachineIndependent/glslang_tab.cpp" break; - case 522: /* type_specifier_nonarray: USUBPASSINPUT */ -#line 3453 "MachineIndependent/glslang.y" + case 531: /* type_specifier_nonarray: USUBPASSINPUT */ +#line 3498 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtUint); } -#line 10638 "MachineIndependent/glslang_tab.cpp" +#line 10818 "MachineIndependent/glslang_tab.cpp" break; - case 523: /* type_specifier_nonarray: USUBPASSINPUTMS */ -#line 3459 "MachineIndependent/glslang.y" + case 532: /* type_specifier_nonarray: USUBPASSINPUTMS */ +#line 3504 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[0].lex).loc, EShLangFragment, "subpass input"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtSampler; (yyval.interm.type).sampler.setSubpass(EbtUint, true); } -#line 10649 "MachineIndependent/glslang_tab.cpp" +#line 10829 "MachineIndependent/glslang_tab.cpp" break; - case 524: /* type_specifier_nonarray: FCOOPMATNV */ -#line 3465 "MachineIndependent/glslang.y" + case 533: /* type_specifier_nonarray: FCOOPMATNV */ +#line 3510 "MachineIndependent/glslang.y" { - parseContext.fcoopmatCheck((yyvsp[0].lex).loc, "fcoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + parseContext.fcoopmatCheckNV((yyvsp[0].lex).loc, "fcoopmatNV", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtFloat; - (yyval.interm.type).coopmat = true; + (yyval.interm.type).coopmatNV = true; + (yyval.interm.type).coopmatKHR = false; } -#line 10660 "MachineIndependent/glslang_tab.cpp" +#line 10841 "MachineIndependent/glslang_tab.cpp" break; - case 525: /* type_specifier_nonarray: ICOOPMATNV */ -#line 3471 "MachineIndependent/glslang.y" + case 534: /* type_specifier_nonarray: ICOOPMATNV */ +#line 3517 "MachineIndependent/glslang.y" { - parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "icoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + parseContext.intcoopmatCheckNV((yyvsp[0].lex).loc, "icoopmatNV", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtInt; - (yyval.interm.type).coopmat = true; + (yyval.interm.type).coopmatNV = true; + (yyval.interm.type).coopmatKHR = false; } -#line 10671 "MachineIndependent/glslang_tab.cpp" +#line 10853 "MachineIndependent/glslang_tab.cpp" break; - case 526: /* type_specifier_nonarray: UCOOPMATNV */ -#line 3477 "MachineIndependent/glslang.y" + case 535: /* type_specifier_nonarray: UCOOPMATNV */ +#line 3524 "MachineIndependent/glslang.y" { - parseContext.intcoopmatCheck((yyvsp[0].lex).loc, "ucoopmatNV", parseContext.symbolTable.atBuiltInLevel()); + parseContext.intcoopmatCheckNV((yyvsp[0].lex).loc, "ucoopmatNV", parseContext.symbolTable.atBuiltInLevel()); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).basicType = EbtUint; - (yyval.interm.type).coopmat = true; + (yyval.interm.type).coopmatNV = true; + (yyval.interm.type).coopmatKHR = false; } -#line 10682 "MachineIndependent/glslang_tab.cpp" +#line 10865 "MachineIndependent/glslang_tab.cpp" break; - case 527: /* type_specifier_nonarray: spirv_type_specifier */ -#line 3483 "MachineIndependent/glslang.y" + case 536: /* type_specifier_nonarray: COOPMAT */ +#line 3531 "MachineIndependent/glslang.y" + { + parseContext.coopmatCheck((yyvsp[0].lex).loc, "coopmat", parseContext.symbolTable.atBuiltInLevel()); + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtCoopmat; + (yyval.interm.type).coopmatNV = false; + (yyval.interm.type).coopmatKHR = true; + } +#line 10877 "MachineIndependent/glslang_tab.cpp" + break; + + case 537: /* type_specifier_nonarray: spirv_type_specifier */ +#line 3538 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].interm.type).loc, 1, &E_GL_EXT_spirv_intrinsics, "SPIR-V type specifier"); (yyval.interm.type) = (yyvsp[0].interm.type); } -#line 10691 "MachineIndependent/glslang_tab.cpp" +#line 10886 "MachineIndependent/glslang_tab.cpp" break; - case 528: /* type_specifier_nonarray: struct_specifier */ -#line 3488 "MachineIndependent/glslang.y" + case 538: /* type_specifier_nonarray: HITOBJECTNV */ +#line 3542 "MachineIndependent/glslang.y" + { + (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); + (yyval.interm.type).basicType = EbtHitObjectNV; + } +#line 10895 "MachineIndependent/glslang_tab.cpp" + break; + + case 539: /* type_specifier_nonarray: struct_specifier */ +#line 3546 "MachineIndependent/glslang.y" { (yyval.interm.type) = (yyvsp[0].interm.type); (yyval.interm.type).qualifier.storage = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; parseContext.structTypeCheck((yyval.interm.type).loc, (yyval.interm.type)); } -#line 10701 "MachineIndependent/glslang_tab.cpp" +#line 10905 "MachineIndependent/glslang_tab.cpp" break; - case 529: /* type_specifier_nonarray: TYPE_NAME */ -#line 3493 "MachineIndependent/glslang.y" + case 540: /* type_specifier_nonarray: TYPE_NAME */ +#line 3551 "MachineIndependent/glslang.y" { // // This is for user defined type names. The lexical phase looked up the @@ -10715,69 +10919,75 @@ yyreduce: } else parseContext.error((yyvsp[0].lex).loc, "expected type name", (yyvsp[0].lex).string->c_str(), ""); } -#line 10719 "MachineIndependent/glslang_tab.cpp" +#line 10923 "MachineIndependent/glslang_tab.cpp" break; - case 530: /* precision_qualifier: HIGH_PRECISION */ -#line 3509 "MachineIndependent/glslang.y" + case 541: /* precision_qualifier: HIGH_PRECISION */ +#line 3567 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "highp precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqHigh); } -#line 10729 "MachineIndependent/glslang_tab.cpp" +#line 10933 "MachineIndependent/glslang_tab.cpp" break; - case 531: /* precision_qualifier: MEDIUM_PRECISION */ -#line 3514 "MachineIndependent/glslang.y" + case 542: /* precision_qualifier: MEDIUM_PRECISION */ +#line 3572 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "mediump precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqMedium); } -#line 10739 "MachineIndependent/glslang_tab.cpp" +#line 10943 "MachineIndependent/glslang_tab.cpp" break; - case 532: /* precision_qualifier: LOW_PRECISION */ -#line 3519 "MachineIndependent/glslang.y" + case 543: /* precision_qualifier: LOW_PRECISION */ +#line 3577 "MachineIndependent/glslang.y" { parseContext.profileRequires((yyvsp[0].lex).loc, ENoProfile, 130, 0, "lowp precision qualifier"); (yyval.interm.type).init((yyvsp[0].lex).loc, parseContext.symbolTable.atGlobalLevel()); parseContext.handlePrecisionQualifier((yyvsp[0].lex).loc, (yyval.interm.type).qualifier, EpqLow); } -#line 10749 "MachineIndependent/glslang_tab.cpp" +#line 10953 "MachineIndependent/glslang_tab.cpp" break; - case 533: /* $@3: %empty */ -#line 3527 "MachineIndependent/glslang.y" + case 544: /* $@3: %empty */ +#line 3585 "MachineIndependent/glslang.y" { parseContext.nestedStructCheck((yyvsp[-2].lex).loc); } -#line 10755 "MachineIndependent/glslang_tab.cpp" +#line 10959 "MachineIndependent/glslang_tab.cpp" break; - case 534: /* struct_specifier: STRUCT IDENTIFIER LEFT_BRACE $@3 struct_declaration_list RIGHT_BRACE */ -#line 3527 "MachineIndependent/glslang.y" + case 545: /* struct_specifier: STRUCT IDENTIFIER LEFT_BRACE $@3 struct_declaration_list RIGHT_BRACE */ +#line 3585 "MachineIndependent/glslang.y" { + TType* structure = new TType((yyvsp[-1].interm.typeList), *(yyvsp[-4].lex).string); parseContext.structArrayCheck((yyvsp[-4].lex).loc, *structure); + TVariable* userTypeDef = new TVariable((yyvsp[-4].lex).string, *structure, true); if (! parseContext.symbolTable.insert(*userTypeDef)) parseContext.error((yyvsp[-4].lex).loc, "redefinition", (yyvsp[-4].lex).string->c_str(), "struct"); + else if (parseContext.spvVersion.vulkanRelaxed + && structure->containsOpaque()) + parseContext.relaxedSymbols.push_back(structure->getTypeName()); + (yyval.interm.type).init((yyvsp[-5].lex).loc); (yyval.interm.type).basicType = EbtStruct; (yyval.interm.type).userDef = structure; --parseContext.structNestingLevel; } -#line 10771 "MachineIndependent/glslang_tab.cpp" +#line 10981 "MachineIndependent/glslang_tab.cpp" break; - case 535: /* $@4: %empty */ -#line 3538 "MachineIndependent/glslang.y" + case 546: /* $@4: %empty */ +#line 3602 "MachineIndependent/glslang.y" { parseContext.nestedStructCheck((yyvsp[-1].lex).loc); } -#line 10777 "MachineIndependent/glslang_tab.cpp" +#line 10987 "MachineIndependent/glslang_tab.cpp" break; - case 536: /* struct_specifier: STRUCT LEFT_BRACE $@4 struct_declaration_list RIGHT_BRACE */ -#line 3538 "MachineIndependent/glslang.y" + case 547: /* struct_specifier: STRUCT LEFT_BRACE $@4 struct_declaration_list RIGHT_BRACE */ +#line 3602 "MachineIndependent/glslang.y" { TType* structure = new TType((yyvsp[-1].interm.typeList), TString("")); (yyval.interm.type).init((yyvsp[-4].lex).loc); @@ -10785,19 +10995,19 @@ yyreduce: (yyval.interm.type).userDef = structure; --parseContext.structNestingLevel; } -#line 10789 "MachineIndependent/glslang_tab.cpp" +#line 10999 "MachineIndependent/glslang_tab.cpp" break; - case 537: /* struct_declaration_list: struct_declaration */ -#line 3548 "MachineIndependent/glslang.y" + case 548: /* struct_declaration_list: struct_declaration */ +#line 3612 "MachineIndependent/glslang.y" { (yyval.interm.typeList) = (yyvsp[0].interm.typeList); } -#line 10797 "MachineIndependent/glslang_tab.cpp" +#line 11007 "MachineIndependent/glslang_tab.cpp" break; - case 538: /* struct_declaration_list: struct_declaration_list struct_declaration */ -#line 3551 "MachineIndependent/glslang.y" + case 549: /* struct_declaration_list: struct_declaration_list struct_declaration */ +#line 3615 "MachineIndependent/glslang.y" { (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); for (unsigned int i = 0; i < (yyvsp[0].interm.typeList)->size(); ++i) { @@ -10808,11 +11018,11 @@ yyreduce: (yyval.interm.typeList)->push_back((*(yyvsp[0].interm.typeList))[i]); } } -#line 10812 "MachineIndependent/glslang_tab.cpp" +#line 11022 "MachineIndependent/glslang_tab.cpp" break; - case 539: /* struct_declaration: type_specifier struct_declarator_list SEMICOLON */ -#line 3564 "MachineIndependent/glslang.y" + case 550: /* struct_declaration: type_specifier struct_declarator_list SEMICOLON */ +#line 3628 "MachineIndependent/glslang.y" { if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -10824,7 +11034,7 @@ yyreduce: (yyval.interm.typeList) = (yyvsp[-1].interm.typeList); parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); - parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier, (yyvsp[-2].interm.type).isCoopmat()); for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { TType type((yyvsp[-2].interm.type)); @@ -10835,11 +11045,11 @@ yyreduce: (*(yyval.interm.typeList))[i].type->shallowCopy(type); } } -#line 10839 "MachineIndependent/glslang_tab.cpp" +#line 11049 "MachineIndependent/glslang_tab.cpp" break; - case 540: /* struct_declaration: type_qualifier type_specifier struct_declarator_list SEMICOLON */ -#line 3586 "MachineIndependent/glslang.y" + case 551: /* struct_declaration: type_qualifier type_specifier struct_declarator_list SEMICOLON */ +#line 3650 "MachineIndependent/glslang.y" { if ((yyvsp[-2].interm.type).arraySizes) { parseContext.profileRequires((yyvsp[-2].interm.type).loc, ENoProfile, 120, E_GL_3DL_array_objects, "arrayed type"); @@ -10853,7 +11063,7 @@ yyreduce: parseContext.memberQualifierCheck((yyvsp[-3].interm.type)); parseContext.voidErrorCheck((yyvsp[-2].interm.type).loc, (*(yyvsp[-1].interm.typeList))[0].type->getFieldName(), (yyvsp[-2].interm.type).basicType); parseContext.mergeQualifiers((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).qualifier, (yyvsp[-3].interm.type).qualifier, true); - parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier); + parseContext.precisionQualifierCheck((yyvsp[-2].interm.type).loc, (yyvsp[-2].interm.type).basicType, (yyvsp[-2].interm.type).qualifier, (yyvsp[-2].interm.type).isCoopmat()); for (unsigned int i = 0; i < (yyval.interm.typeList)->size(); ++i) { TType type((yyvsp[-2].interm.type)); @@ -10864,38 +11074,38 @@ yyreduce: (*(yyval.interm.typeList))[i].type->shallowCopy(type); } } -#line 10868 "MachineIndependent/glslang_tab.cpp" +#line 11078 "MachineIndependent/glslang_tab.cpp" break; - case 541: /* struct_declarator_list: struct_declarator */ -#line 3613 "MachineIndependent/glslang.y" + case 552: /* struct_declarator_list: struct_declarator */ +#line 3677 "MachineIndependent/glslang.y" { (yyval.interm.typeList) = new TTypeList; (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); } -#line 10877 "MachineIndependent/glslang_tab.cpp" +#line 11087 "MachineIndependent/glslang_tab.cpp" break; - case 542: /* struct_declarator_list: struct_declarator_list COMMA struct_declarator */ -#line 3617 "MachineIndependent/glslang.y" + case 553: /* struct_declarator_list: struct_declarator_list COMMA struct_declarator */ +#line 3681 "MachineIndependent/glslang.y" { (yyval.interm.typeList)->push_back((yyvsp[0].interm.typeLine)); } -#line 10885 "MachineIndependent/glslang_tab.cpp" +#line 11095 "MachineIndependent/glslang_tab.cpp" break; - case 543: /* struct_declarator: IDENTIFIER */ -#line 3623 "MachineIndependent/glslang.y" + case 554: /* struct_declarator: IDENTIFIER */ +#line 3687 "MachineIndependent/glslang.y" { (yyval.interm.typeLine).type = new TType(EbtVoid); (yyval.interm.typeLine).loc = (yyvsp[0].lex).loc; (yyval.interm.typeLine).type->setFieldName(*(yyvsp[0].lex).string); } -#line 10895 "MachineIndependent/glslang_tab.cpp" +#line 11105 "MachineIndependent/glslang_tab.cpp" break; - case 544: /* struct_declarator: IDENTIFIER array_specifier */ -#line 3628 "MachineIndependent/glslang.y" + case 555: /* struct_declarator: IDENTIFIER array_specifier */ +#line 3692 "MachineIndependent/glslang.y" { parseContext.arrayOfArrayVersionCheck((yyvsp[-1].lex).loc, (yyvsp[0].interm).arraySizes); @@ -10904,246 +11114,246 @@ yyreduce: (yyval.interm.typeLine).type->setFieldName(*(yyvsp[-1].lex).string); (yyval.interm.typeLine).type->transferArraySizes((yyvsp[0].interm).arraySizes); } -#line 10908 "MachineIndependent/glslang_tab.cpp" +#line 11118 "MachineIndependent/glslang_tab.cpp" break; - case 545: /* initializer: assignment_expression */ -#line 3639 "MachineIndependent/glslang.y" + case 556: /* initializer: assignment_expression */ +#line 3703 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 10916 "MachineIndependent/glslang_tab.cpp" +#line 11126 "MachineIndependent/glslang_tab.cpp" break; - case 546: /* initializer: LEFT_BRACE initializer_list RIGHT_BRACE */ -#line 3643 "MachineIndependent/glslang.y" + case 557: /* initializer: LEFT_BRACE initializer_list RIGHT_BRACE */ +#line 3706 "MachineIndependent/glslang.y" { const char* initFeature = "{ } style initializers"; parseContext.requireProfile((yyvsp[-2].lex).loc, ~EEsProfile, initFeature); parseContext.profileRequires((yyvsp[-2].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); (yyval.interm.intermTypedNode) = (yyvsp[-1].interm.intermTypedNode); } -#line 10927 "MachineIndependent/glslang_tab.cpp" +#line 11137 "MachineIndependent/glslang_tab.cpp" break; - case 547: /* initializer: LEFT_BRACE initializer_list COMMA RIGHT_BRACE */ -#line 3649 "MachineIndependent/glslang.y" + case 558: /* initializer: LEFT_BRACE initializer_list COMMA RIGHT_BRACE */ +#line 3712 "MachineIndependent/glslang.y" { const char* initFeature = "{ } style initializers"; parseContext.requireProfile((yyvsp[-3].lex).loc, ~EEsProfile, initFeature); parseContext.profileRequires((yyvsp[-3].lex).loc, ~EEsProfile, 420, E_GL_ARB_shading_language_420pack, initFeature); (yyval.interm.intermTypedNode) = (yyvsp[-2].interm.intermTypedNode); } -#line 10938 "MachineIndependent/glslang_tab.cpp" +#line 11148 "MachineIndependent/glslang_tab.cpp" break; - case 548: /* initializer: LEFT_BRACE RIGHT_BRACE */ -#line 3655 "MachineIndependent/glslang.y" + case 559: /* initializer: LEFT_BRACE RIGHT_BRACE */ +#line 3718 "MachineIndependent/glslang.y" { const char* initFeature = "empty { } initializer"; parseContext.profileRequires((yyvsp[-1].lex).loc, EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); parseContext.profileRequires((yyvsp[-1].lex).loc, ~EEsProfile, 0, E_GL_EXT_null_initializer, initFeature); (yyval.interm.intermTypedNode) = parseContext.intermediate.makeAggregate((yyvsp[-1].lex).loc); } -#line 10949 "MachineIndependent/glslang_tab.cpp" +#line 11159 "MachineIndependent/glslang_tab.cpp" break; - case 549: /* initializer_list: initializer */ -#line 3666 "MachineIndependent/glslang.y" + case 560: /* initializer_list: initializer */ +#line 3727 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate(0, (yyvsp[0].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)->getLoc()); } -#line 10957 "MachineIndependent/glslang_tab.cpp" +#line 11167 "MachineIndependent/glslang_tab.cpp" break; - case 550: /* initializer_list: initializer_list COMMA initializer */ -#line 3669 "MachineIndependent/glslang.y" + case 561: /* initializer_list: initializer_list COMMA initializer */ +#line 3730 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.intermTypedNode)); } -#line 10965 "MachineIndependent/glslang_tab.cpp" +#line 11175 "MachineIndependent/glslang_tab.cpp" break; - case 551: /* declaration_statement: declaration */ -#line 3676 "MachineIndependent/glslang.y" + case 562: /* declaration_statement: declaration */ +#line 3736 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 10971 "MachineIndependent/glslang_tab.cpp" +#line 11181 "MachineIndependent/glslang_tab.cpp" break; - case 552: /* statement: compound_statement */ -#line 3680 "MachineIndependent/glslang.y" + case 563: /* statement: compound_statement */ +#line 3740 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 10977 "MachineIndependent/glslang_tab.cpp" +#line 11187 "MachineIndependent/glslang_tab.cpp" break; - case 553: /* statement: simple_statement */ -#line 3681 "MachineIndependent/glslang.y" + case 564: /* statement: simple_statement */ +#line 3741 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 10983 "MachineIndependent/glslang_tab.cpp" +#line 11193 "MachineIndependent/glslang_tab.cpp" break; - case 554: /* simple_statement: declaration_statement */ -#line 3687 "MachineIndependent/glslang.y" + case 565: /* simple_statement: declaration_statement */ +#line 3747 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 10989 "MachineIndependent/glslang_tab.cpp" +#line 11199 "MachineIndependent/glslang_tab.cpp" break; - case 555: /* simple_statement: expression_statement */ -#line 3688 "MachineIndependent/glslang.y" + case 566: /* simple_statement: expression_statement */ +#line 3748 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 10995 "MachineIndependent/glslang_tab.cpp" +#line 11205 "MachineIndependent/glslang_tab.cpp" break; - case 556: /* simple_statement: selection_statement */ -#line 3689 "MachineIndependent/glslang.y" + case 567: /* simple_statement: selection_statement */ +#line 3749 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11001 "MachineIndependent/glslang_tab.cpp" +#line 11211 "MachineIndependent/glslang_tab.cpp" break; - case 557: /* simple_statement: switch_statement */ -#line 3690 "MachineIndependent/glslang.y" + case 568: /* simple_statement: switch_statement */ +#line 3750 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11007 "MachineIndependent/glslang_tab.cpp" +#line 11217 "MachineIndependent/glslang_tab.cpp" break; - case 558: /* simple_statement: case_label */ -#line 3691 "MachineIndependent/glslang.y" + case 569: /* simple_statement: case_label */ +#line 3751 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11013 "MachineIndependent/glslang_tab.cpp" +#line 11223 "MachineIndependent/glslang_tab.cpp" break; - case 559: /* simple_statement: iteration_statement */ -#line 3692 "MachineIndependent/glslang.y" + case 570: /* simple_statement: iteration_statement */ +#line 3752 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11019 "MachineIndependent/glslang_tab.cpp" +#line 11229 "MachineIndependent/glslang_tab.cpp" break; - case 560: /* simple_statement: jump_statement */ -#line 3693 "MachineIndependent/glslang.y" + case 571: /* simple_statement: jump_statement */ +#line 3753 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11025 "MachineIndependent/glslang_tab.cpp" +#line 11235 "MachineIndependent/glslang_tab.cpp" break; - case 561: /* simple_statement: demote_statement */ -#line 3695 "MachineIndependent/glslang.y" + case 572: /* simple_statement: demote_statement */ +#line 3754 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11031 "MachineIndependent/glslang_tab.cpp" +#line 11241 "MachineIndependent/glslang_tab.cpp" break; - case 562: /* demote_statement: DEMOTE SEMICOLON */ -#line 3701 "MachineIndependent/glslang.y" + case 573: /* demote_statement: DEMOTE SEMICOLON */ +#line 3758 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "demote"); parseContext.requireExtensions((yyvsp[-1].lex).loc, 1, &E_GL_EXT_demote_to_helper_invocation, "demote"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDemote, (yyvsp[-1].lex).loc); } -#line 11041 "MachineIndependent/glslang_tab.cpp" +#line 11251 "MachineIndependent/glslang_tab.cpp" break; - case 563: /* compound_statement: LEFT_BRACE RIGHT_BRACE */ -#line 3710 "MachineIndependent/glslang.y" + case 574: /* compound_statement: LEFT_BRACE RIGHT_BRACE */ +#line 3766 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; } -#line 11047 "MachineIndependent/glslang_tab.cpp" +#line 11257 "MachineIndependent/glslang_tab.cpp" break; - case 564: /* $@5: %empty */ -#line 3711 "MachineIndependent/glslang.y" + case 575: /* $@5: %empty */ +#line 3767 "MachineIndependent/glslang.y" { parseContext.symbolTable.push(); ++parseContext.statementNestingLevel; } -#line 11056 "MachineIndependent/glslang_tab.cpp" +#line 11266 "MachineIndependent/glslang_tab.cpp" break; - case 565: /* $@6: %empty */ -#line 3715 "MachineIndependent/glslang.y" + case 576: /* $@6: %empty */ +#line 3771 "MachineIndependent/glslang.y" { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); --parseContext.statementNestingLevel; } -#line 11065 "MachineIndependent/glslang_tab.cpp" +#line 11275 "MachineIndependent/glslang_tab.cpp" break; - case 566: /* compound_statement: LEFT_BRACE $@5 statement_list $@6 RIGHT_BRACE */ -#line 3719 "MachineIndependent/glslang.y" + case 577: /* compound_statement: LEFT_BRACE $@5 statement_list $@6 RIGHT_BRACE */ +#line 3775 "MachineIndependent/glslang.y" { if ((yyvsp[-2].interm.intermNode) && (yyvsp[-2].interm.intermNode)->getAsAggregate()) - (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); + (yyvsp[-2].interm.intermNode)->getAsAggregate()->setOperator(parseContext.intermediate.getDebugInfo() ? EOpScope : EOpSequence); (yyval.interm.intermNode) = (yyvsp[-2].interm.intermNode); } -#line 11075 "MachineIndependent/glslang_tab.cpp" +#line 11285 "MachineIndependent/glslang_tab.cpp" break; - case 567: /* statement_no_new_scope: compound_statement_no_new_scope */ -#line 3727 "MachineIndependent/glslang.y" + case 578: /* statement_no_new_scope: compound_statement_no_new_scope */ +#line 3783 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11081 "MachineIndependent/glslang_tab.cpp" +#line 11291 "MachineIndependent/glslang_tab.cpp" break; - case 568: /* statement_no_new_scope: simple_statement */ -#line 3728 "MachineIndependent/glslang.y" + case 579: /* statement_no_new_scope: simple_statement */ +#line 3784 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11087 "MachineIndependent/glslang_tab.cpp" +#line 11297 "MachineIndependent/glslang_tab.cpp" break; - case 569: /* $@7: %empty */ -#line 3732 "MachineIndependent/glslang.y" + case 580: /* $@7: %empty */ +#line 3788 "MachineIndependent/glslang.y" { ++parseContext.controlFlowNestingLevel; } -#line 11095 "MachineIndependent/glslang_tab.cpp" +#line 11305 "MachineIndependent/glslang_tab.cpp" break; - case 570: /* statement_scoped: $@7 compound_statement */ -#line 3735 "MachineIndependent/glslang.y" + case 581: /* statement_scoped: $@7 compound_statement */ +#line 3791 "MachineIndependent/glslang.y" { --parseContext.controlFlowNestingLevel; (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11104 "MachineIndependent/glslang_tab.cpp" +#line 11314 "MachineIndependent/glslang_tab.cpp" break; - case 571: /* $@8: %empty */ -#line 3739 "MachineIndependent/glslang.y" + case 582: /* $@8: %empty */ +#line 3795 "MachineIndependent/glslang.y" { parseContext.symbolTable.push(); ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 11114 "MachineIndependent/glslang_tab.cpp" +#line 11324 "MachineIndependent/glslang_tab.cpp" break; - case 572: /* statement_scoped: $@8 simple_statement */ -#line 3744 "MachineIndependent/glslang.y" + case 583: /* statement_scoped: $@8 simple_statement */ +#line 3800 "MachineIndependent/glslang.y" { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11125 "MachineIndependent/glslang_tab.cpp" +#line 11335 "MachineIndependent/glslang_tab.cpp" break; - case 573: /* compound_statement_no_new_scope: LEFT_BRACE RIGHT_BRACE */ -#line 3753 "MachineIndependent/glslang.y" + case 584: /* compound_statement_no_new_scope: LEFT_BRACE RIGHT_BRACE */ +#line 3809 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; } -#line 11133 "MachineIndependent/glslang_tab.cpp" +#line 11343 "MachineIndependent/glslang_tab.cpp" break; - case 574: /* compound_statement_no_new_scope: LEFT_BRACE statement_list RIGHT_BRACE */ -#line 3756 "MachineIndependent/glslang.y" + case 585: /* compound_statement_no_new_scope: LEFT_BRACE statement_list RIGHT_BRACE */ +#line 3812 "MachineIndependent/glslang.y" { if ((yyvsp[-1].interm.intermNode) && (yyvsp[-1].interm.intermNode)->getAsAggregate()) (yyvsp[-1].interm.intermNode)->getAsAggregate()->setOperator(EOpSequence); (yyval.interm.intermNode) = (yyvsp[-1].interm.intermNode); } -#line 11143 "MachineIndependent/glslang_tab.cpp" +#line 11353 "MachineIndependent/glslang_tab.cpp" break; - case 575: /* statement_list: statement */ -#line 3764 "MachineIndependent/glslang.y" + case 586: /* statement_list: statement */ +#line 3820 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || @@ -11152,11 +11362,11 @@ yyreduce: (yyval.interm.intermNode) = 0; // start a fresh subsequence for what's after this case } } -#line 11156 "MachineIndependent/glslang_tab.cpp" +#line 11366 "MachineIndependent/glslang_tab.cpp" break; - case 576: /* statement_list: statement_list statement */ -#line 3772 "MachineIndependent/glslang.y" + case 587: /* statement_list: statement_list statement */ +#line 3828 "MachineIndependent/glslang.y" { if ((yyvsp[0].interm.intermNode) && (yyvsp[0].interm.intermNode)->getAsBranchNode() && ((yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpCase || (yyvsp[0].interm.intermNode)->getAsBranchNode()->getFlowOp() == EOpDefault)) { @@ -11165,77 +11375,77 @@ yyreduce: } else (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); } -#line 11169 "MachineIndependent/glslang_tab.cpp" +#line 11379 "MachineIndependent/glslang_tab.cpp" break; - case 577: /* expression_statement: SEMICOLON */ -#line 3783 "MachineIndependent/glslang.y" + case 588: /* expression_statement: SEMICOLON */ +#line 3839 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; } -#line 11175 "MachineIndependent/glslang_tab.cpp" +#line 11385 "MachineIndependent/glslang_tab.cpp" break; - case 578: /* expression_statement: expression SEMICOLON */ -#line 3784 "MachineIndependent/glslang.y" + case 589: /* expression_statement: expression SEMICOLON */ +#line 3840 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = static_cast((yyvsp[-1].interm.intermTypedNode)); } -#line 11181 "MachineIndependent/glslang_tab.cpp" +#line 11391 "MachineIndependent/glslang_tab.cpp" break; - case 579: /* selection_statement: selection_statement_nonattributed */ -#line 3788 "MachineIndependent/glslang.y" + case 590: /* selection_statement: selection_statement_nonattributed */ +#line 3844 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11189 "MachineIndependent/glslang_tab.cpp" +#line 11399 "MachineIndependent/glslang_tab.cpp" break; - case 580: /* selection_statement: attribute selection_statement_nonattributed */ -#line 3792 "MachineIndependent/glslang.y" + case 591: /* selection_statement: attribute selection_statement_nonattributed */ +#line 3847 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSelectionAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11199 "MachineIndependent/glslang_tab.cpp" +#line 11409 "MachineIndependent/glslang_tab.cpp" break; - case 581: /* selection_statement_nonattributed: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement */ -#line 3800 "MachineIndependent/glslang.y" + case 592: /* selection_statement_nonattributed: IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement */ +#line 3854 "MachineIndependent/glslang.y" { parseContext.boolCheck((yyvsp[-4].lex).loc, (yyvsp[-2].interm.intermTypedNode)); (yyval.interm.intermNode) = parseContext.intermediate.addSelection((yyvsp[-2].interm.intermTypedNode), (yyvsp[0].interm.nodePair), (yyvsp[-4].lex).loc); } -#line 11208 "MachineIndependent/glslang_tab.cpp" +#line 11418 "MachineIndependent/glslang_tab.cpp" break; - case 582: /* selection_rest_statement: statement_scoped ELSE statement_scoped */ -#line 3807 "MachineIndependent/glslang.y" + case 593: /* selection_rest_statement: statement_scoped ELSE statement_scoped */ +#line 3861 "MachineIndependent/glslang.y" { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermNode); (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermNode); } -#line 11217 "MachineIndependent/glslang_tab.cpp" +#line 11427 "MachineIndependent/glslang_tab.cpp" break; - case 583: /* selection_rest_statement: statement_scoped */ -#line 3811 "MachineIndependent/glslang.y" + case 594: /* selection_rest_statement: statement_scoped */ +#line 3865 "MachineIndependent/glslang.y" { (yyval.interm.nodePair).node1 = (yyvsp[0].interm.intermNode); (yyval.interm.nodePair).node2 = 0; } -#line 11226 "MachineIndependent/glslang_tab.cpp" +#line 11436 "MachineIndependent/glslang_tab.cpp" break; - case 584: /* condition: expression */ -#line 3819 "MachineIndependent/glslang.y" + case 595: /* condition: expression */ +#line 3873 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); parseContext.boolCheck((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)); } -#line 11235 "MachineIndependent/glslang_tab.cpp" +#line 11445 "MachineIndependent/glslang_tab.cpp" break; - case 585: /* condition: fully_specified_type IDENTIFIER EQUAL initializer */ -#line 3823 "MachineIndependent/glslang.y" + case 596: /* condition: fully_specified_type IDENTIFIER EQUAL initializer */ +#line 3877 "MachineIndependent/glslang.y" { parseContext.boolCheck((yyvsp[-2].lex).loc, (yyvsp[-3].interm.type)); @@ -11246,29 +11456,29 @@ yyreduce: else (yyval.interm.intermTypedNode) = 0; } -#line 11250 "MachineIndependent/glslang_tab.cpp" +#line 11460 "MachineIndependent/glslang_tab.cpp" break; - case 586: /* switch_statement: switch_statement_nonattributed */ -#line 3836 "MachineIndependent/glslang.y" + case 597: /* switch_statement: switch_statement_nonattributed */ +#line 3890 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11258 "MachineIndependent/glslang_tab.cpp" +#line 11468 "MachineIndependent/glslang_tab.cpp" break; - case 587: /* switch_statement: attribute switch_statement_nonattributed */ -#line 3840 "MachineIndependent/glslang.y" + case 598: /* switch_statement: attribute switch_statement_nonattributed */ +#line 3893 "MachineIndependent/glslang.y" { parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); parseContext.handleSwitchAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11268 "MachineIndependent/glslang_tab.cpp" +#line 11478 "MachineIndependent/glslang_tab.cpp" break; - case 588: /* $@9: %empty */ -#line 3848 "MachineIndependent/glslang.y" + case 599: /* $@9: %empty */ +#line 3900 "MachineIndependent/glslang.y" { // start new switch sequence on the switch stack ++parseContext.controlFlowNestingLevel; @@ -11277,11 +11487,11 @@ yyreduce: parseContext.switchLevel.push_back(parseContext.statementNestingLevel); parseContext.symbolTable.push(); } -#line 11281 "MachineIndependent/glslang_tab.cpp" +#line 11491 "MachineIndependent/glslang_tab.cpp" break; - case 589: /* switch_statement_nonattributed: SWITCH LEFT_PAREN expression RIGHT_PAREN $@9 LEFT_BRACE switch_statement_list RIGHT_BRACE */ -#line 3856 "MachineIndependent/glslang.y" + case 600: /* switch_statement_nonattributed: SWITCH LEFT_PAREN expression RIGHT_PAREN $@9 LEFT_BRACE switch_statement_list RIGHT_BRACE */ +#line 3908 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.addSwitch((yyvsp[-7].lex).loc, (yyvsp[-5].interm.intermTypedNode), (yyvsp[-1].interm.intermNode) ? (yyvsp[-1].interm.intermNode)->getAsAggregate() : 0); delete parseContext.switchSequenceStack.back(); @@ -11291,27 +11501,27 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 11295 "MachineIndependent/glslang_tab.cpp" +#line 11505 "MachineIndependent/glslang_tab.cpp" break; - case 590: /* switch_statement_list: %empty */ -#line 3868 "MachineIndependent/glslang.y" + case 601: /* switch_statement_list: %empty */ +#line 3920 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; } -#line 11303 "MachineIndependent/glslang_tab.cpp" +#line 11513 "MachineIndependent/glslang_tab.cpp" break; - case 591: /* switch_statement_list: statement_list */ -#line 3871 "MachineIndependent/glslang.y" + case 602: /* switch_statement_list: statement_list */ +#line 3923 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11311 "MachineIndependent/glslang_tab.cpp" +#line 11521 "MachineIndependent/glslang_tab.cpp" break; - case 592: /* case_label: CASE expression COLON */ -#line 3877 "MachineIndependent/glslang.y" + case 603: /* case_label: CASE expression COLON */ +#line 3929 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; if (parseContext.switchLevel.size() == 0) @@ -11324,11 +11534,11 @@ yyreduce: (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpCase, (yyvsp[-1].interm.intermTypedNode), (yyvsp[-2].lex).loc); } } -#line 11328 "MachineIndependent/glslang_tab.cpp" +#line 11538 "MachineIndependent/glslang_tab.cpp" break; - case 593: /* case_label: DEFAULT COLON */ -#line 3889 "MachineIndependent/glslang.y" + case 604: /* case_label: DEFAULT COLON */ +#line 3941 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = 0; if (parseContext.switchLevel.size() == 0) @@ -11338,29 +11548,30 @@ yyreduce: else (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpDefault, (yyvsp[-1].lex).loc); } -#line 11342 "MachineIndependent/glslang_tab.cpp" +#line 11552 "MachineIndependent/glslang_tab.cpp" break; - case 594: /* iteration_statement: iteration_statement_nonattributed */ -#line 3901 "MachineIndependent/glslang.y" + case 605: /* iteration_statement: iteration_statement_nonattributed */ +#line 3953 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11350 "MachineIndependent/glslang_tab.cpp" +#line 11560 "MachineIndependent/glslang_tab.cpp" break; - case 595: /* iteration_statement: attribute iteration_statement_nonattributed */ -#line 3905 "MachineIndependent/glslang.y" + case 606: /* iteration_statement: attribute iteration_statement_nonattributed */ +#line 3956 "MachineIndependent/glslang.y" { - parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 1, &E_GL_EXT_control_flow_attributes, "attribute"); + const char * extensions[2] = { E_GL_EXT_control_flow_attributes, E_GL_EXT_control_flow_attributes2 }; + parseContext.requireExtensions((yyvsp[0].interm.intermNode)->getLoc(), 2, extensions, "attribute"); parseContext.handleLoopAttributes(*(yyvsp[-1].interm.attributes), (yyvsp[0].interm.intermNode)); (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11360 "MachineIndependent/glslang_tab.cpp" +#line 11571 "MachineIndependent/glslang_tab.cpp" break; - case 596: /* $@10: %empty */ -#line 3913 "MachineIndependent/glslang.y" + case 607: /* $@10: %empty */ +#line 3964 "MachineIndependent/glslang.y" { if (! parseContext.limits.whileLoops) parseContext.error((yyvsp[-1].lex).loc, "while loops not available", "limitation", ""); @@ -11369,11 +11580,11 @@ yyreduce: ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 11373 "MachineIndependent/glslang_tab.cpp" +#line 11584 "MachineIndependent/glslang_tab.cpp" break; - case 597: /* iteration_statement_nonattributed: WHILE LEFT_PAREN $@10 condition RIGHT_PAREN statement_no_new_scope */ -#line 3921 "MachineIndependent/glslang.y" + case 608: /* iteration_statement_nonattributed: WHILE LEFT_PAREN $@10 condition RIGHT_PAREN statement_no_new_scope */ +#line 3972 "MachineIndependent/glslang.y" { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); (yyval.interm.intermNode) = parseContext.intermediate.addLoop((yyvsp[0].interm.intermNode), (yyvsp[-2].interm.intermTypedNode), 0, true, (yyvsp[-5].lex).loc); @@ -11381,22 +11592,22 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 11385 "MachineIndependent/glslang_tab.cpp" +#line 11596 "MachineIndependent/glslang_tab.cpp" break; - case 598: /* $@11: %empty */ -#line 3928 "MachineIndependent/glslang.y" + case 609: /* $@11: %empty */ +#line 3979 "MachineIndependent/glslang.y" { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 11396 "MachineIndependent/glslang_tab.cpp" +#line 11607 "MachineIndependent/glslang_tab.cpp" break; - case 599: /* iteration_statement_nonattributed: DO $@11 statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON */ -#line 3934 "MachineIndependent/glslang.y" + case 610: /* iteration_statement_nonattributed: DO $@11 statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON */ +#line 3985 "MachineIndependent/glslang.y" { if (! parseContext.limits.whileLoops) parseContext.error((yyvsp[-7].lex).loc, "do-while loops not available", "limitation", ""); @@ -11409,22 +11620,22 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 11413 "MachineIndependent/glslang_tab.cpp" +#line 11624 "MachineIndependent/glslang_tab.cpp" break; - case 600: /* $@12: %empty */ -#line 3946 "MachineIndependent/glslang.y" + case 611: /* $@12: %empty */ +#line 3997 "MachineIndependent/glslang.y" { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; ++parseContext.statementNestingLevel; ++parseContext.controlFlowNestingLevel; } -#line 11424 "MachineIndependent/glslang_tab.cpp" +#line 11635 "MachineIndependent/glslang_tab.cpp" break; - case 601: /* iteration_statement_nonattributed: FOR LEFT_PAREN $@12 for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope */ -#line 3952 "MachineIndependent/glslang.y" + case 612: /* iteration_statement_nonattributed: FOR LEFT_PAREN $@12 for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope */ +#line 4003 "MachineIndependent/glslang.y" { parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[-3].interm.intermNode), (yyvsp[-5].lex).loc); @@ -11437,81 +11648,81 @@ yyreduce: --parseContext.statementNestingLevel; --parseContext.controlFlowNestingLevel; } -#line 11441 "MachineIndependent/glslang_tab.cpp" +#line 11652 "MachineIndependent/glslang_tab.cpp" break; - case 602: /* for_init_statement: expression_statement */ -#line 3967 "MachineIndependent/glslang.y" + case 613: /* for_init_statement: expression_statement */ +#line 4018 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11449 "MachineIndependent/glslang_tab.cpp" +#line 11660 "MachineIndependent/glslang_tab.cpp" break; - case 603: /* for_init_statement: declaration_statement */ -#line 3970 "MachineIndependent/glslang.y" + case 614: /* for_init_statement: declaration_statement */ +#line 4021 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11457 "MachineIndependent/glslang_tab.cpp" +#line 11668 "MachineIndependent/glslang_tab.cpp" break; - case 604: /* conditionopt: condition */ -#line 3976 "MachineIndependent/glslang.y" + case 615: /* conditionopt: condition */ +#line 4027 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = (yyvsp[0].interm.intermTypedNode); } -#line 11465 "MachineIndependent/glslang_tab.cpp" +#line 11676 "MachineIndependent/glslang_tab.cpp" break; - case 605: /* conditionopt: %empty */ -#line 3979 "MachineIndependent/glslang.y" + case 616: /* conditionopt: %empty */ +#line 4030 "MachineIndependent/glslang.y" { (yyval.interm.intermTypedNode) = 0; } -#line 11473 "MachineIndependent/glslang_tab.cpp" +#line 11684 "MachineIndependent/glslang_tab.cpp" break; - case 606: /* for_rest_statement: conditionopt SEMICOLON */ -#line 3985 "MachineIndependent/glslang.y" + case 617: /* for_rest_statement: conditionopt SEMICOLON */ +#line 4036 "MachineIndependent/glslang.y" { (yyval.interm.nodePair).node1 = (yyvsp[-1].interm.intermTypedNode); (yyval.interm.nodePair).node2 = 0; } -#line 11482 "MachineIndependent/glslang_tab.cpp" +#line 11693 "MachineIndependent/glslang_tab.cpp" break; - case 607: /* for_rest_statement: conditionopt SEMICOLON expression */ -#line 3989 "MachineIndependent/glslang.y" + case 618: /* for_rest_statement: conditionopt SEMICOLON expression */ +#line 4040 "MachineIndependent/glslang.y" { (yyval.interm.nodePair).node1 = (yyvsp[-2].interm.intermTypedNode); (yyval.interm.nodePair).node2 = (yyvsp[0].interm.intermTypedNode); } -#line 11491 "MachineIndependent/glslang_tab.cpp" +#line 11702 "MachineIndependent/glslang_tab.cpp" break; - case 608: /* jump_statement: CONTINUE SEMICOLON */ -#line 3996 "MachineIndependent/glslang.y" + case 619: /* jump_statement: CONTINUE SEMICOLON */ +#line 4047 "MachineIndependent/glslang.y" { if (parseContext.loopNestingLevel <= 0) parseContext.error((yyvsp[-1].lex).loc, "continue statement only allowed in loops", "", ""); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpContinue, (yyvsp[-1].lex).loc); } -#line 11501 "MachineIndependent/glslang_tab.cpp" +#line 11712 "MachineIndependent/glslang_tab.cpp" break; - case 609: /* jump_statement: BREAK SEMICOLON */ -#line 4001 "MachineIndependent/glslang.y" + case 620: /* jump_statement: BREAK SEMICOLON */ +#line 4052 "MachineIndependent/glslang.y" { if (parseContext.loopNestingLevel + parseContext.switchSequenceStack.size() <= 0) parseContext.error((yyvsp[-1].lex).loc, "break statement only allowed in switch and loops", "", ""); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpBreak, (yyvsp[-1].lex).loc); } -#line 11511 "MachineIndependent/glslang_tab.cpp" +#line 11722 "MachineIndependent/glslang_tab.cpp" break; - case 610: /* jump_statement: RETURN SEMICOLON */ -#line 4006 "MachineIndependent/glslang.y" + case 621: /* jump_statement: RETURN SEMICOLON */ +#line 4057 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpReturn, (yyvsp[-1].lex).loc); if (parseContext.currentFunctionType->getBasicType() != EbtVoid) @@ -11519,101 +11730,101 @@ yyreduce: if (parseContext.inMain) parseContext.postEntryPointReturn = true; } -#line 11523 "MachineIndependent/glslang_tab.cpp" +#line 11734 "MachineIndependent/glslang_tab.cpp" break; - case 611: /* jump_statement: RETURN expression SEMICOLON */ -#line 4013 "MachineIndependent/glslang.y" + case 622: /* jump_statement: RETURN expression SEMICOLON */ +#line 4064 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.handleReturnValue((yyvsp[-2].lex).loc, (yyvsp[-1].interm.intermTypedNode)); } -#line 11531 "MachineIndependent/glslang_tab.cpp" +#line 11742 "MachineIndependent/glslang_tab.cpp" break; - case 612: /* jump_statement: DISCARD SEMICOLON */ -#line 4016 "MachineIndependent/glslang.y" + case 623: /* jump_statement: DISCARD SEMICOLON */ +#line 4067 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "discard"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpKill, (yyvsp[-1].lex).loc); } -#line 11540 "MachineIndependent/glslang_tab.cpp" +#line 11751 "MachineIndependent/glslang_tab.cpp" break; - case 613: /* jump_statement: TERMINATE_INVOCATION SEMICOLON */ -#line 4020 "MachineIndependent/glslang.y" + case 624: /* jump_statement: TERMINATE_INVOCATION SEMICOLON */ +#line 4071 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangFragment, "terminateInvocation"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpTerminateInvocation, (yyvsp[-1].lex).loc); } -#line 11549 "MachineIndependent/glslang_tab.cpp" +#line 11760 "MachineIndependent/glslang_tab.cpp" break; - case 614: /* jump_statement: TERMINATE_RAY SEMICOLON */ -#line 4025 "MachineIndependent/glslang.y" + case 625: /* jump_statement: TERMINATE_RAY SEMICOLON */ +#line 4075 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangAnyHit, "terminateRayEXT"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpTerminateRayKHR, (yyvsp[-1].lex).loc); } -#line 11558 "MachineIndependent/glslang_tab.cpp" +#line 11769 "MachineIndependent/glslang_tab.cpp" break; - case 615: /* jump_statement: IGNORE_INTERSECTION SEMICOLON */ -#line 4029 "MachineIndependent/glslang.y" + case 626: /* jump_statement: IGNORE_INTERSECTION SEMICOLON */ +#line 4079 "MachineIndependent/glslang.y" { parseContext.requireStage((yyvsp[-1].lex).loc, EShLangAnyHit, "ignoreIntersectionEXT"); (yyval.interm.intermNode) = parseContext.intermediate.addBranch(EOpIgnoreIntersectionKHR, (yyvsp[-1].lex).loc); } -#line 11567 "MachineIndependent/glslang_tab.cpp" +#line 11778 "MachineIndependent/glslang_tab.cpp" break; - case 616: /* translation_unit: external_declaration */ -#line 4039 "MachineIndependent/glslang.y" + case 627: /* translation_unit: external_declaration */ +#line 4088 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); } -#line 11576 "MachineIndependent/glslang_tab.cpp" +#line 11787 "MachineIndependent/glslang_tab.cpp" break; - case 617: /* translation_unit: translation_unit external_declaration */ -#line 4043 "MachineIndependent/glslang.y" + case 628: /* translation_unit: translation_unit external_declaration */ +#line 4092 "MachineIndependent/glslang.y" { if ((yyvsp[0].interm.intermNode) != nullptr) { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-1].interm.intermNode), (yyvsp[0].interm.intermNode)); parseContext.intermediate.setTreeRoot((yyval.interm.intermNode)); } } -#line 11587 "MachineIndependent/glslang_tab.cpp" +#line 11798 "MachineIndependent/glslang_tab.cpp" break; - case 618: /* external_declaration: function_definition */ -#line 4052 "MachineIndependent/glslang.y" + case 629: /* external_declaration: function_definition */ +#line 4101 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11595 "MachineIndependent/glslang_tab.cpp" +#line 11806 "MachineIndependent/glslang_tab.cpp" break; - case 619: /* external_declaration: declaration */ -#line 4055 "MachineIndependent/glslang.y" + case 630: /* external_declaration: declaration */ +#line 4104 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = (yyvsp[0].interm.intermNode); } -#line 11603 "MachineIndependent/glslang_tab.cpp" +#line 11814 "MachineIndependent/glslang_tab.cpp" break; - case 620: /* external_declaration: SEMICOLON */ -#line 4059 "MachineIndependent/glslang.y" + case 631: /* external_declaration: SEMICOLON */ +#line 4107 "MachineIndependent/glslang.y" { parseContext.requireProfile((yyvsp[0].lex).loc, ~EEsProfile, "extraneous semicolon"); parseContext.profileRequires((yyvsp[0].lex).loc, ~EEsProfile, 460, nullptr, "extraneous semicolon"); (yyval.interm.intermNode) = nullptr; } -#line 11613 "MachineIndependent/glslang_tab.cpp" +#line 11824 "MachineIndependent/glslang_tab.cpp" break; - case 621: /* $@13: %empty */ -#line 4068 "MachineIndependent/glslang.y" + case 632: /* $@13: %empty */ +#line 4115 "MachineIndependent/glslang.y" { (yyvsp[0].interm).function = parseContext.handleFunctionDeclarator((yyvsp[0].interm).loc, *(yyvsp[0].interm).function, false /* not prototype */); (yyvsp[0].interm).intermNode = parseContext.handleFunctionDefinition((yyvsp[0].interm).loc, *(yyvsp[0].interm).function); @@ -11626,17 +11837,18 @@ yyreduce: ++parseContext.statementNestingLevel; } } -#line 11630 "MachineIndependent/glslang_tab.cpp" +#line 11841 "MachineIndependent/glslang_tab.cpp" break; - case 622: /* function_definition: function_prototype $@13 compound_statement_no_new_scope */ -#line 4080 "MachineIndependent/glslang.y" + case 633: /* function_definition: function_prototype $@13 compound_statement_no_new_scope */ +#line 4127 "MachineIndependent/glslang.y" { // May be best done as post process phase on intermediate code if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) parseContext.error((yyvsp[-2].interm).loc, "function does not return a value:", "", (yyvsp[-2].interm).function->getName().c_str()); parseContext.symbolTable.pop(&parseContext.defaultPrecision[0]); (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm).intermNode, (yyvsp[0].interm.intermNode)); + (yyval.interm.intermNode)->getAsAggregate()->setLinkType((yyvsp[-2].interm).function->getLinkType()); parseContext.intermediate.setAggregateOperator((yyval.interm.intermNode), EOpFunction, (yyvsp[-2].interm).function->getType(), (yyvsp[-2].interm).loc); (yyval.interm.intermNode)->getAsAggregate()->setName((yyvsp[-2].interm).function->getMangledName().c_str()); @@ -11657,228 +11869,228 @@ yyreduce: --parseContext.statementNestingLevel; } } -#line 11661 "MachineIndependent/glslang_tab.cpp" +#line 11873 "MachineIndependent/glslang_tab.cpp" break; - case 623: /* attribute: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET */ -#line 4110 "MachineIndependent/glslang.y" + case 634: /* attribute: LEFT_BRACKET LEFT_BRACKET attribute_list RIGHT_BRACKET RIGHT_BRACKET */ +#line 4157 "MachineIndependent/glslang.y" { (yyval.interm.attributes) = (yyvsp[-2].interm.attributes); } -#line 11669 "MachineIndependent/glslang_tab.cpp" +#line 11881 "MachineIndependent/glslang_tab.cpp" break; - case 624: /* attribute_list: single_attribute */ -#line 4115 "MachineIndependent/glslang.y" + case 635: /* attribute_list: single_attribute */ +#line 4162 "MachineIndependent/glslang.y" { (yyval.interm.attributes) = (yyvsp[0].interm.attributes); } -#line 11677 "MachineIndependent/glslang_tab.cpp" +#line 11889 "MachineIndependent/glslang_tab.cpp" break; - case 625: /* attribute_list: attribute_list COMMA single_attribute */ -#line 4118 "MachineIndependent/glslang.y" + case 636: /* attribute_list: attribute_list COMMA single_attribute */ +#line 4165 "MachineIndependent/glslang.y" { (yyval.interm.attributes) = parseContext.mergeAttributes((yyvsp[-2].interm.attributes), (yyvsp[0].interm.attributes)); } -#line 11685 "MachineIndependent/glslang_tab.cpp" +#line 11897 "MachineIndependent/glslang_tab.cpp" break; - case 626: /* single_attribute: IDENTIFIER */ -#line 4123 "MachineIndependent/glslang.y" + case 637: /* single_attribute: IDENTIFIER */ +#line 4170 "MachineIndependent/glslang.y" { (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[0].lex).string); } -#line 11693 "MachineIndependent/glslang_tab.cpp" +#line 11905 "MachineIndependent/glslang_tab.cpp" break; - case 627: /* single_attribute: IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN */ -#line 4126 "MachineIndependent/glslang.y" + case 638: /* single_attribute: IDENTIFIER LEFT_PAREN constant_expression RIGHT_PAREN */ +#line 4173 "MachineIndependent/glslang.y" { (yyval.interm.attributes) = parseContext.makeAttributes(*(yyvsp[-3].lex).string, (yyvsp[-1].interm.intermTypedNode)); } -#line 11701 "MachineIndependent/glslang_tab.cpp" +#line 11913 "MachineIndependent/glslang_tab.cpp" break; - case 628: /* spirv_requirements_list: spirv_requirements_parameter */ -#line 4133 "MachineIndependent/glslang.y" + case 639: /* spirv_requirements_list: spirv_requirements_parameter */ +#line 4178 "MachineIndependent/glslang.y" { (yyval.interm.spirvReq) = (yyvsp[0].interm.spirvReq); } -#line 11709 "MachineIndependent/glslang_tab.cpp" +#line 11921 "MachineIndependent/glslang_tab.cpp" break; - case 629: /* spirv_requirements_list: spirv_requirements_list COMMA spirv_requirements_parameter */ -#line 4136 "MachineIndependent/glslang.y" + case 640: /* spirv_requirements_list: spirv_requirements_list COMMA spirv_requirements_parameter */ +#line 4181 "MachineIndependent/glslang.y" { (yyval.interm.spirvReq) = parseContext.mergeSpirvRequirements((yyvsp[-1].lex).loc, (yyvsp[-2].interm.spirvReq), (yyvsp[0].interm.spirvReq)); } -#line 11717 "MachineIndependent/glslang_tab.cpp" +#line 11929 "MachineIndependent/glslang_tab.cpp" break; - case 630: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_extension_list RIGHT_BRACKET */ -#line 4141 "MachineIndependent/glslang.y" + case 641: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_extension_list RIGHT_BRACKET */ +#line 4186 "MachineIndependent/glslang.y" { (yyval.interm.spirvReq) = parseContext.makeSpirvRequirement((yyvsp[-3].lex).loc, *(yyvsp[-4].lex).string, (yyvsp[-1].interm.intermNode)->getAsAggregate(), nullptr); } -#line 11725 "MachineIndependent/glslang_tab.cpp" +#line 11937 "MachineIndependent/glslang_tab.cpp" break; - case 631: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_capability_list RIGHT_BRACKET */ -#line 4144 "MachineIndependent/glslang.y" + case 642: /* spirv_requirements_parameter: IDENTIFIER EQUAL LEFT_BRACKET spirv_capability_list RIGHT_BRACKET */ +#line 4189 "MachineIndependent/glslang.y" { (yyval.interm.spirvReq) = parseContext.makeSpirvRequirement((yyvsp[-3].lex).loc, *(yyvsp[-4].lex).string, nullptr, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11733 "MachineIndependent/glslang_tab.cpp" +#line 11945 "MachineIndependent/glslang_tab.cpp" break; - case 632: /* spirv_extension_list: STRING_LITERAL */ -#line 4149 "MachineIndependent/glslang.y" + case 643: /* spirv_extension_list: STRING_LITERAL */ +#line 4194 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); } -#line 11741 "MachineIndependent/glslang_tab.cpp" +#line 11953 "MachineIndependent/glslang_tab.cpp" break; - case 633: /* spirv_extension_list: spirv_extension_list COMMA STRING_LITERAL */ -#line 4152 "MachineIndependent/glslang.y" + case 644: /* spirv_extension_list: spirv_extension_list COMMA STRING_LITERAL */ +#line 4197 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); } -#line 11749 "MachineIndependent/glslang_tab.cpp" +#line 11961 "MachineIndependent/glslang_tab.cpp" break; - case 634: /* spirv_capability_list: INTCONSTANT */ -#line 4157 "MachineIndependent/glslang.y" + case 645: /* spirv_capability_list: INTCONSTANT */ +#line 4202 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate(parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true)); } -#line 11757 "MachineIndependent/glslang_tab.cpp" +#line 11969 "MachineIndependent/glslang_tab.cpp" break; - case 635: /* spirv_capability_list: spirv_capability_list COMMA INTCONSTANT */ -#line 4160 "MachineIndependent/glslang.y" + case 646: /* spirv_capability_list: spirv_capability_list COMMA INTCONSTANT */ +#line 4205 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true)); } -#line 11765 "MachineIndependent/glslang_tab.cpp" +#line 11977 "MachineIndependent/glslang_tab.cpp" break; - case 636: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ -#line 4165 "MachineIndependent/glslang.y" + case 647: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4210 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-1].lex).i); (yyval.interm.intermNode) = 0; } -#line 11774 "MachineIndependent/glslang_tab.cpp" +#line 11986 "MachineIndependent/glslang_tab.cpp" break; - case 637: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ -#line 4169 "MachineIndependent/glslang.y" + case 648: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4214 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-1].lex).i); (yyval.interm.intermNode) = 0; } -#line 11784 "MachineIndependent/glslang_tab.cpp" +#line 11996 "MachineIndependent/glslang_tab.cpp" break; - case 638: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ -#line 4174 "MachineIndependent/glslang.y" + case 649: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ +#line 4219 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); (yyval.interm.intermNode) = 0; } -#line 11793 "MachineIndependent/glslang_tab.cpp" +#line 12005 "MachineIndependent/glslang_tab.cpp" break; - case 639: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ -#line 4178 "MachineIndependent/glslang.y" + case 650: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_parameter_list RIGHT_PAREN */ +#line 4223 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); parseContext.intermediate.insertSpirvExecutionMode((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); (yyval.interm.intermNode) = 0; } -#line 11803 "MachineIndependent/glslang_tab.cpp" +#line 12015 "MachineIndependent/glslang_tab.cpp" break; - case 640: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ -#line 4183 "MachineIndependent/glslang.y" + case 651: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ +#line 4228 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvExecutionModeId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); (yyval.interm.intermNode) = 0; } -#line 11812 "MachineIndependent/glslang_tab.cpp" +#line 12024 "MachineIndependent/glslang_tab.cpp" break; - case 641: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ -#line 4187 "MachineIndependent/glslang.y" + case 652: /* spirv_execution_mode_qualifier: SPIRV_EXECUTION_MODE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_execution_mode_id_parameter_list RIGHT_PAREN */ +#line 4232 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); parseContext.intermediate.insertSpirvExecutionModeId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); (yyval.interm.intermNode) = 0; } -#line 11822 "MachineIndependent/glslang_tab.cpp" +#line 12034 "MachineIndependent/glslang_tab.cpp" break; - case 642: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter */ -#line 4194 "MachineIndependent/glslang.y" + case 653: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter */ +#line 4239 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); } -#line 11830 "MachineIndependent/glslang_tab.cpp" +#line 12042 "MachineIndependent/glslang_tab.cpp" break; - case 643: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter_list COMMA spirv_execution_mode_parameter */ -#line 4197 "MachineIndependent/glslang.y" + case 654: /* spirv_execution_mode_parameter_list: spirv_execution_mode_parameter_list COMMA spirv_execution_mode_parameter */ +#line 4242 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermNode)); } -#line 11838 "MachineIndependent/glslang_tab.cpp" +#line 12050 "MachineIndependent/glslang_tab.cpp" break; - case 644: /* spirv_execution_mode_parameter: FLOATCONSTANT */ -#line 4202 "MachineIndependent/glslang.y" + case 655: /* spirv_execution_mode_parameter: FLOATCONSTANT */ +#line 4247 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); } -#line 11846 "MachineIndependent/glslang_tab.cpp" +#line 12058 "MachineIndependent/glslang_tab.cpp" break; - case 645: /* spirv_execution_mode_parameter: INTCONSTANT */ -#line 4205 "MachineIndependent/glslang.y" + case 656: /* spirv_execution_mode_parameter: INTCONSTANT */ +#line 4250 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 11854 "MachineIndependent/glslang_tab.cpp" +#line 12066 "MachineIndependent/glslang_tab.cpp" break; - case 646: /* spirv_execution_mode_parameter: UINTCONSTANT */ -#line 4208 "MachineIndependent/glslang.y" + case 657: /* spirv_execution_mode_parameter: UINTCONSTANT */ +#line 4253 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 11862 "MachineIndependent/glslang_tab.cpp" +#line 12074 "MachineIndependent/glslang_tab.cpp" break; - case 647: /* spirv_execution_mode_parameter: BOOLCONSTANT */ -#line 4211 "MachineIndependent/glslang.y" + case 658: /* spirv_execution_mode_parameter: BOOLCONSTANT */ +#line 4256 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); } -#line 11870 "MachineIndependent/glslang_tab.cpp" +#line 12082 "MachineIndependent/glslang_tab.cpp" break; - case 648: /* spirv_execution_mode_parameter: STRING_LITERAL */ -#line 4214 "MachineIndependent/glslang.y" + case 659: /* spirv_execution_mode_parameter: STRING_LITERAL */ +#line 4259 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true); } -#line 11878 "MachineIndependent/glslang_tab.cpp" +#line 12090 "MachineIndependent/glslang_tab.cpp" break; - case 649: /* spirv_execution_mode_id_parameter_list: constant_expression */ -#line 4219 "MachineIndependent/glslang.y" + case 660: /* spirv_execution_mode_id_parameter_list: constant_expression */ +#line 4264 "MachineIndependent/glslang.y" { if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && @@ -11888,11 +12100,11 @@ yyreduce: parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode)); } -#line 11892 "MachineIndependent/glslang_tab.cpp" +#line 12104 "MachineIndependent/glslang_tab.cpp" break; - case 650: /* spirv_execution_mode_id_parameter_list: spirv_execution_mode_id_parameter_list COMMA constant_expression */ -#line 4228 "MachineIndependent/glslang.y" + case 661: /* spirv_execution_mode_id_parameter_list: spirv_execution_mode_id_parameter_list COMMA constant_expression */ +#line 4273 "MachineIndependent/glslang.y" { if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && @@ -11902,310 +12114,351 @@ yyreduce: parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermTypedNode)); } -#line 11906 "MachineIndependent/glslang_tab.cpp" +#line 12118 "MachineIndependent/glslang_tab.cpp" break; - case 651: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN INTCONSTANT RIGHT_PAREN */ -#line 4239 "MachineIndependent/glslang.y" + case 662: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4284 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-3].lex).loc); (yyval.interm.type).qualifier.storage = EvqSpirvStorageClass; (yyval.interm.type).qualifier.spirvStorageClass = (yyvsp[-1].lex).i; } -#line 11916 "MachineIndependent/glslang_tab.cpp" +#line 12128 "MachineIndependent/glslang_tab.cpp" break; - case 652: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ -#line 4244 "MachineIndependent/glslang.y" + case 663: /* spirv_storage_class_qualifier: SPIRV_STORAGE_CLASS LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4289 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc); parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); (yyval.interm.type).qualifier.storage = EvqSpirvStorageClass; (yyval.interm.type).qualifier.spirvStorageClass = (yyvsp[-1].lex).i; } -#line 11927 "MachineIndependent/glslang_tab.cpp" +#line 12139 "MachineIndependent/glslang_tab.cpp" break; - case 653: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ -#line 4252 "MachineIndependent/glslang.y" + case 664: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT RIGHT_PAREN */ +#line 4297 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-3].lex).loc); (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-1].lex).i); } -#line 11936 "MachineIndependent/glslang_tab.cpp" +#line 12148 "MachineIndependent/glslang_tab.cpp" break; - case 654: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ -#line 4256 "MachineIndependent/glslang.y" + case 665: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT RIGHT_PAREN */ +#line 4301 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc); parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-1].lex).i); } -#line 11946 "MachineIndependent/glslang_tab.cpp" +#line 12158 "MachineIndependent/glslang_tab.cpp" break; - case 655: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ -#line 4261 "MachineIndependent/glslang.y" + case 666: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ +#line 4306 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc); (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11955 "MachineIndependent/glslang_tab.cpp" +#line 12167 "MachineIndependent/glslang_tab.cpp" break; - case 656: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ -#line 4265 "MachineIndependent/glslang.y" + case 667: /* spirv_decorate_qualifier: SPIRV_DECORATE LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_parameter_list RIGHT_PAREN */ +#line 4310 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-7].lex).loc); parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); (yyval.interm.type).qualifier.setSpirvDecorate((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11965 "MachineIndependent/glslang_tab.cpp" +#line 12177 "MachineIndependent/glslang_tab.cpp" break; - case 657: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ -#line 4270 "MachineIndependent/glslang.y" + case 668: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ +#line 4315 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc); (yyval.interm.type).qualifier.setSpirvDecorateId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11974 "MachineIndependent/glslang_tab.cpp" +#line 12186 "MachineIndependent/glslang_tab.cpp" break; - case 658: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ -#line 4274 "MachineIndependent/glslang.y" + case 669: /* spirv_decorate_qualifier: SPIRV_DECORATE_ID LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_id_parameter_list RIGHT_PAREN */ +#line 4319 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-7].lex).loc); parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); (yyval.interm.type).qualifier.setSpirvDecorateId((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11984 "MachineIndependent/glslang_tab.cpp" +#line 12196 "MachineIndependent/glslang_tab.cpp" break; - case 659: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ -#line 4279 "MachineIndependent/glslang.y" + case 670: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ +#line 4324 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc); (yyval.interm.type).qualifier.setSpirvDecorateString((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 11993 "MachineIndependent/glslang_tab.cpp" +#line 12205 "MachineIndependent/glslang_tab.cpp" break; - case 660: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ -#line 4283 "MachineIndependent/glslang.y" + case 671: /* spirv_decorate_qualifier: SPIRV_DECORATE_STRING LEFT_PAREN spirv_requirements_list COMMA INTCONSTANT COMMA spirv_decorate_string_parameter_list RIGHT_PAREN */ +#line 4328 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-7].lex).loc); parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); (yyval.interm.type).qualifier.setSpirvDecorateString((yyvsp[-3].lex).i, (yyvsp[-1].interm.intermNode)->getAsAggregate()); } -#line 12003 "MachineIndependent/glslang_tab.cpp" +#line 12215 "MachineIndependent/glslang_tab.cpp" break; - case 661: /* spirv_decorate_parameter_list: spirv_decorate_parameter */ -#line 4290 "MachineIndependent/glslang.y" + case 672: /* spirv_decorate_parameter_list: spirv_decorate_parameter */ +#line 4335 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); } -#line 12011 "MachineIndependent/glslang_tab.cpp" +#line 12223 "MachineIndependent/glslang_tab.cpp" break; - case 662: /* spirv_decorate_parameter_list: spirv_decorate_parameter_list COMMA spirv_decorate_parameter */ -#line 4293 "MachineIndependent/glslang.y" + case 673: /* spirv_decorate_parameter_list: spirv_decorate_parameter_list COMMA spirv_decorate_parameter */ +#line 4338 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermNode)); } -#line 12019 "MachineIndependent/glslang_tab.cpp" +#line 12231 "MachineIndependent/glslang_tab.cpp" break; - case 663: /* spirv_decorate_parameter: FLOATCONSTANT */ -#line 4298 "MachineIndependent/glslang.y" + case 674: /* spirv_decorate_parameter: FLOATCONSTANT */ +#line 4343 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); } -#line 12027 "MachineIndependent/glslang_tab.cpp" +#line 12239 "MachineIndependent/glslang_tab.cpp" break; - case 664: /* spirv_decorate_parameter: INTCONSTANT */ -#line 4301 "MachineIndependent/glslang.y" + case 675: /* spirv_decorate_parameter: INTCONSTANT */ +#line 4346 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); } -#line 12035 "MachineIndependent/glslang_tab.cpp" +#line 12247 "MachineIndependent/glslang_tab.cpp" break; - case 665: /* spirv_decorate_parameter: UINTCONSTANT */ -#line 4304 "MachineIndependent/glslang.y" + case 676: /* spirv_decorate_parameter: UINTCONSTANT */ +#line 4349 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); } -#line 12043 "MachineIndependent/glslang_tab.cpp" +#line 12255 "MachineIndependent/glslang_tab.cpp" break; - case 666: /* spirv_decorate_parameter: BOOLCONSTANT */ -#line 4307 "MachineIndependent/glslang.y" + case 677: /* spirv_decorate_parameter: BOOLCONSTANT */ +#line 4352 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); } -#line 12051 "MachineIndependent/glslang_tab.cpp" +#line 12263 "MachineIndependent/glslang_tab.cpp" break; - case 667: /* spirv_decorate_id_parameter_list: constant_expression */ -#line 4312 "MachineIndependent/glslang.y" + case 678: /* spirv_decorate_id_parameter_list: spirv_decorate_id_parameter */ +#line 4357 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermNode)); + } +#line 12271 "MachineIndependent/glslang_tab.cpp" + break; + + case 679: /* spirv_decorate_id_parameter_list: spirv_decorate_id_parameter_list COMMA spirv_decorate_id_parameter */ +#line 4360 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermNode)); + } +#line 12279 "MachineIndependent/glslang_tab.cpp" + break; + + case 680: /* spirv_decorate_id_parameter: variable_identifier */ +#line 4365 "MachineIndependent/glslang.y" { - if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool) - parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); - (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate((yyvsp[0].interm.intermTypedNode)); + if ((yyvsp[0].interm.intermTypedNode)->getAsConstantUnion() || (yyvsp[0].interm.intermTypedNode)->getAsSymbolNode()) + (yyval.interm.intermNode) = (yyvsp[0].interm.intermTypedNode); + else + parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "only allow constants or variables which are not elements of a composite", "", ""); } -#line 12064 "MachineIndependent/glslang_tab.cpp" +#line 12290 "MachineIndependent/glslang_tab.cpp" break; - case 668: /* spirv_decorate_id_parameter_list: spirv_decorate_id_parameter_list COMMA constant_expression */ -#line 4320 "MachineIndependent/glslang.y" - { - if ((yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtFloat && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtInt && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtUint && - (yyvsp[0].interm.intermTypedNode)->getBasicType() != EbtBool) - parseContext.error((yyvsp[0].interm.intermTypedNode)->getLoc(), "this type not allowed", (yyvsp[0].interm.intermTypedNode)->getType().getBasicString(), ""); - (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), (yyvsp[0].interm.intermTypedNode)); + case 681: /* spirv_decorate_id_parameter: FLOATCONSTANT */ +#line 4371 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).d, EbtFloat, (yyvsp[0].lex).loc, true); } -#line 12077 "MachineIndependent/glslang_tab.cpp" +#line 12298 "MachineIndependent/glslang_tab.cpp" break; - case 669: /* spirv_decorate_string_parameter_list: STRING_LITERAL */ -#line 4330 "MachineIndependent/glslang.y" + case 682: /* spirv_decorate_id_parameter: INTCONSTANT */ +#line 4374 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).i, (yyvsp[0].lex).loc, true); + } +#line 12306 "MachineIndependent/glslang_tab.cpp" + break; + + case 683: /* spirv_decorate_id_parameter: UINTCONSTANT */ +#line 4377 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).u, (yyvsp[0].lex).loc, true); + } +#line 12314 "MachineIndependent/glslang_tab.cpp" + break; + + case 684: /* spirv_decorate_id_parameter: BOOLCONSTANT */ +#line 4380 "MachineIndependent/glslang.y" + { + (yyval.interm.intermNode) = parseContext.intermediate.addConstantUnion((yyvsp[0].lex).b, (yyvsp[0].lex).loc, true); + } +#line 12322 "MachineIndependent/glslang_tab.cpp" + break; + + case 685: /* spirv_decorate_string_parameter_list: STRING_LITERAL */ +#line 4385 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.makeAggregate( parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); } -#line 12086 "MachineIndependent/glslang_tab.cpp" +#line 12331 "MachineIndependent/glslang_tab.cpp" break; - case 670: /* spirv_decorate_string_parameter_list: spirv_decorate_string_parameter_list COMMA STRING_LITERAL */ -#line 4334 "MachineIndependent/glslang.y" + case 686: /* spirv_decorate_string_parameter_list: spirv_decorate_string_parameter_list COMMA STRING_LITERAL */ +#line 4389 "MachineIndependent/glslang.y" { (yyval.interm.intermNode) = parseContext.intermediate.growAggregate((yyvsp[-2].interm.intermNode), parseContext.intermediate.addConstantUnion((yyvsp[0].lex).string, (yyvsp[0].lex).loc, true)); } -#line 12094 "MachineIndependent/glslang_tab.cpp" +#line 12339 "MachineIndependent/glslang_tab.cpp" break; - case 671: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ -#line 4339 "MachineIndependent/glslang.y" + case 687: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ +#line 4394 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).setSpirvType(*(yyvsp[-3].interm.spirvInst), (yyvsp[-1].interm.spirvTypeParams)); } -#line 12103 "MachineIndependent/glslang_tab.cpp" +#line 12348 "MachineIndependent/glslang_tab.cpp" break; - case 672: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ -#line 4343 "MachineIndependent/glslang.y" + case 688: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list COMMA spirv_type_parameter_list RIGHT_PAREN */ +#line 4398 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-7].lex).loc, parseContext.symbolTable.atGlobalLevel()); parseContext.intermediate.insertSpirvRequirement((yyvsp[-5].interm.spirvReq)); (yyval.interm.type).setSpirvType(*(yyvsp[-3].interm.spirvInst), (yyvsp[-1].interm.spirvTypeParams)); } -#line 12113 "MachineIndependent/glslang_tab.cpp" +#line 12358 "MachineIndependent/glslang_tab.cpp" break; - case 673: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ -#line 4348 "MachineIndependent/glslang.y" + case 689: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4403 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-3].lex).loc, parseContext.symbolTable.atGlobalLevel()); (yyval.interm.type).setSpirvType(*(yyvsp[-1].interm.spirvInst)); } -#line 12122 "MachineIndependent/glslang_tab.cpp" +#line 12367 "MachineIndependent/glslang_tab.cpp" break; - case 674: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ -#line 4352 "MachineIndependent/glslang.y" + case 690: /* spirv_type_specifier: SPIRV_TYPE LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4407 "MachineIndependent/glslang.y" { (yyval.interm.type).init((yyvsp[-5].lex).loc, parseContext.symbolTable.atGlobalLevel()); parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); (yyval.interm.type).setSpirvType(*(yyvsp[-1].interm.spirvInst)); } -#line 12132 "MachineIndependent/glslang_tab.cpp" +#line 12377 "MachineIndependent/glslang_tab.cpp" break; - case 675: /* spirv_type_parameter_list: spirv_type_parameter */ -#line 4359 "MachineIndependent/glslang.y" + case 691: /* spirv_type_parameter_list: spirv_type_parameter */ +#line 4414 "MachineIndependent/glslang.y" { (yyval.interm.spirvTypeParams) = (yyvsp[0].interm.spirvTypeParams); } -#line 12140 "MachineIndependent/glslang_tab.cpp" +#line 12385 "MachineIndependent/glslang_tab.cpp" break; - case 676: /* spirv_type_parameter_list: spirv_type_parameter_list COMMA spirv_type_parameter */ -#line 4362 "MachineIndependent/glslang.y" + case 692: /* spirv_type_parameter_list: spirv_type_parameter_list COMMA spirv_type_parameter */ +#line 4417 "MachineIndependent/glslang.y" { (yyval.interm.spirvTypeParams) = parseContext.mergeSpirvTypeParameters((yyvsp[-2].interm.spirvTypeParams), (yyvsp[0].interm.spirvTypeParams)); } -#line 12148 "MachineIndependent/glslang_tab.cpp" +#line 12393 "MachineIndependent/glslang_tab.cpp" break; - case 677: /* spirv_type_parameter: constant_expression */ -#line 4367 "MachineIndependent/glslang.y" + case 693: /* spirv_type_parameter: constant_expression */ +#line 4422 "MachineIndependent/glslang.y" { (yyval.interm.spirvTypeParams) = parseContext.makeSpirvTypeParameters((yyvsp[0].interm.intermTypedNode)->getLoc(), (yyvsp[0].interm.intermTypedNode)->getAsConstantUnion()); } -#line 12156 "MachineIndependent/glslang_tab.cpp" +#line 12401 "MachineIndependent/glslang_tab.cpp" break; - case 678: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ -#line 4372 "MachineIndependent/glslang.y" + case 694: /* spirv_type_parameter: type_specifier_nonarray */ +#line 4425 "MachineIndependent/glslang.y" + { + (yyval.interm.spirvTypeParams) = parseContext.makeSpirvTypeParameters((yyvsp[0].interm.type).loc, (yyvsp[0].interm.type)); + } +#line 12409 "MachineIndependent/glslang_tab.cpp" + break; + + case 695: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4430 "MachineIndependent/glslang.y" { (yyval.interm.spirvInst) = (yyvsp[-1].interm.spirvInst); } -#line 12164 "MachineIndependent/glslang_tab.cpp" +#line 12417 "MachineIndependent/glslang_tab.cpp" break; - case 679: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ -#line 4375 "MachineIndependent/glslang.y" + case 696: /* spirv_instruction_qualifier: SPIRV_INSTRUCTION LEFT_PAREN spirv_requirements_list COMMA spirv_instruction_qualifier_list RIGHT_PAREN */ +#line 4433 "MachineIndependent/glslang.y" { parseContext.intermediate.insertSpirvRequirement((yyvsp[-3].interm.spirvReq)); (yyval.interm.spirvInst) = (yyvsp[-1].interm.spirvInst); } -#line 12173 "MachineIndependent/glslang_tab.cpp" +#line 12426 "MachineIndependent/glslang_tab.cpp" break; - case 680: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_id */ -#line 4381 "MachineIndependent/glslang.y" + case 697: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_id */ +#line 4439 "MachineIndependent/glslang.y" { (yyval.interm.spirvInst) = (yyvsp[0].interm.spirvInst); } -#line 12181 "MachineIndependent/glslang_tab.cpp" +#line 12434 "MachineIndependent/glslang_tab.cpp" break; - case 681: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_list COMMA spirv_instruction_qualifier_id */ -#line 4384 "MachineIndependent/glslang.y" + case 698: /* spirv_instruction_qualifier_list: spirv_instruction_qualifier_list COMMA spirv_instruction_qualifier_id */ +#line 4442 "MachineIndependent/glslang.y" { (yyval.interm.spirvInst) = parseContext.mergeSpirvInstruction((yyvsp[-1].lex).loc, (yyvsp[-2].interm.spirvInst), (yyvsp[0].interm.spirvInst)); } -#line 12189 "MachineIndependent/glslang_tab.cpp" +#line 12442 "MachineIndependent/glslang_tab.cpp" break; - case 682: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL STRING_LITERAL */ -#line 4389 "MachineIndependent/glslang.y" + case 699: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL STRING_LITERAL */ +#line 4447 "MachineIndependent/glslang.y" { (yyval.interm.spirvInst) = parseContext.makeSpirvInstruction((yyvsp[-1].lex).loc, *(yyvsp[-2].lex).string, *(yyvsp[0].lex).string); } -#line 12197 "MachineIndependent/glslang_tab.cpp" +#line 12450 "MachineIndependent/glslang_tab.cpp" break; - case 683: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL INTCONSTANT */ -#line 4392 "MachineIndependent/glslang.y" + case 700: /* spirv_instruction_qualifier_id: IDENTIFIER EQUAL INTCONSTANT */ +#line 4450 "MachineIndependent/glslang.y" { (yyval.interm.spirvInst) = parseContext.makeSpirvInstruction((yyvsp[-1].lex).loc, *(yyvsp[-2].lex).string, (yyvsp[0].lex).i); } -#line 12205 "MachineIndependent/glslang_tab.cpp" +#line 12458 "MachineIndependent/glslang_tab.cpp" break; -#line 12209 "MachineIndependent/glslang_tab.cpp" +#line 12462 "MachineIndependent/glslang_tab.cpp" default: break; } @@ -12281,7 +12534,7 @@ yyerrlab: } yyerror (pParseContext, yymsgp); if (yysyntax_error_status == YYENOMEM) - goto yyexhaustedlab; + YYNOMEM; } } @@ -12317,6 +12570,7 @@ yyerrorlab: label yyerrorlab therefore never appears in user code. */ if (0) YYERROR; + ++yynerrs; /* Do not reclaim the symbols of the rule whose action triggered this YYERROR. */ @@ -12377,7 +12631,7 @@ yyerrlab1: `-------------------------------------*/ yyacceptlab: yyresult = 0; - goto yyreturn; + goto yyreturnlab; /*-----------------------------------. @@ -12385,24 +12639,22 @@ yyacceptlab: `-----------------------------------*/ yyabortlab: yyresult = 1; - goto yyreturn; + goto yyreturnlab; -#if 1 -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ +/*-----------------------------------------------------------. +| yyexhaustedlab -- YYNOMEM (memory exhaustion) comes here. | +`-----------------------------------------------------------*/ yyexhaustedlab: yyerror (pParseContext, YY_("memory exhausted")); yyresult = 2; - goto yyreturn; -#endif + goto yyreturnlab; -/*-------------------------------------------------------. -| yyreturn -- parsing is finished, clean up and return. | -`-------------------------------------------------------*/ -yyreturn: +/*----------------------------------------------------------. +| yyreturnlab -- parsing is finished, clean up and return. | +`----------------------------------------------------------*/ +yyreturnlab: if (yychar != YYEMPTY) { /* Make sure we have latest lookahead translation. See comments at @@ -12430,5 +12682,5 @@ yyreturn: return yyresult; } -#line 4397 "MachineIndependent/glslang.y" +#line 4454 "MachineIndependent/glslang.y" diff --git a/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h b/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h index 596a10e6d..d6484924d 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h +++ b/src/libraries/glslang/glslang/MachineIndependent/glslang_tab.cpp.h @@ -1,8 +1,8 @@ -/* A Bison parser, made by GNU Bison 3.7.4. */ +/* A Bison parser, made by GNU Bison 3.8.2. */ /* Bison interface for Yacc-like parsers in C - Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2020 Free Software Foundation, + Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify @@ -16,7 +16,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . */ + along with this program. If not, see . */ /* As a special exception, you may create a larger work that contains part or all of the Bison parser skeleton and distribute that work @@ -217,295 +217,305 @@ extern int yydebug; FCOOPMATNV = 418, /* FCOOPMATNV */ ICOOPMATNV = 419, /* ICOOPMATNV */ UCOOPMATNV = 420, /* UCOOPMATNV */ - SAMPLERCUBEARRAY = 421, /* SAMPLERCUBEARRAY */ - SAMPLERCUBEARRAYSHADOW = 422, /* SAMPLERCUBEARRAYSHADOW */ - ISAMPLERCUBEARRAY = 423, /* ISAMPLERCUBEARRAY */ - USAMPLERCUBEARRAY = 424, /* USAMPLERCUBEARRAY */ - SAMPLER1D = 425, /* SAMPLER1D */ - SAMPLER1DARRAY = 426, /* SAMPLER1DARRAY */ - SAMPLER1DARRAYSHADOW = 427, /* SAMPLER1DARRAYSHADOW */ - ISAMPLER1D = 428, /* ISAMPLER1D */ - SAMPLER1DSHADOW = 429, /* SAMPLER1DSHADOW */ - SAMPLER2DRECT = 430, /* SAMPLER2DRECT */ - SAMPLER2DRECTSHADOW = 431, /* SAMPLER2DRECTSHADOW */ - ISAMPLER2DRECT = 432, /* ISAMPLER2DRECT */ - USAMPLER2DRECT = 433, /* USAMPLER2DRECT */ - SAMPLERBUFFER = 434, /* SAMPLERBUFFER */ - ISAMPLERBUFFER = 435, /* ISAMPLERBUFFER */ - USAMPLERBUFFER = 436, /* USAMPLERBUFFER */ - SAMPLER2DMS = 437, /* SAMPLER2DMS */ - ISAMPLER2DMS = 438, /* ISAMPLER2DMS */ - USAMPLER2DMS = 439, /* USAMPLER2DMS */ - SAMPLER2DMSARRAY = 440, /* SAMPLER2DMSARRAY */ - ISAMPLER2DMSARRAY = 441, /* ISAMPLER2DMSARRAY */ - USAMPLER2DMSARRAY = 442, /* USAMPLER2DMSARRAY */ - SAMPLEREXTERNALOES = 443, /* SAMPLEREXTERNALOES */ - SAMPLEREXTERNAL2DY2YEXT = 444, /* SAMPLEREXTERNAL2DY2YEXT */ - ISAMPLER1DARRAY = 445, /* ISAMPLER1DARRAY */ - USAMPLER1D = 446, /* USAMPLER1D */ - USAMPLER1DARRAY = 447, /* USAMPLER1DARRAY */ - F16SAMPLER1D = 448, /* F16SAMPLER1D */ - F16SAMPLER2D = 449, /* F16SAMPLER2D */ - F16SAMPLER3D = 450, /* F16SAMPLER3D */ - F16SAMPLER2DRECT = 451, /* F16SAMPLER2DRECT */ - F16SAMPLERCUBE = 452, /* F16SAMPLERCUBE */ - F16SAMPLER1DARRAY = 453, /* F16SAMPLER1DARRAY */ - F16SAMPLER2DARRAY = 454, /* F16SAMPLER2DARRAY */ - F16SAMPLERCUBEARRAY = 455, /* F16SAMPLERCUBEARRAY */ - F16SAMPLERBUFFER = 456, /* F16SAMPLERBUFFER */ - F16SAMPLER2DMS = 457, /* F16SAMPLER2DMS */ - F16SAMPLER2DMSARRAY = 458, /* F16SAMPLER2DMSARRAY */ - F16SAMPLER1DSHADOW = 459, /* F16SAMPLER1DSHADOW */ - F16SAMPLER2DSHADOW = 460, /* F16SAMPLER2DSHADOW */ - F16SAMPLER1DARRAYSHADOW = 461, /* F16SAMPLER1DARRAYSHADOW */ - F16SAMPLER2DARRAYSHADOW = 462, /* F16SAMPLER2DARRAYSHADOW */ - F16SAMPLER2DRECTSHADOW = 463, /* F16SAMPLER2DRECTSHADOW */ - F16SAMPLERCUBESHADOW = 464, /* F16SAMPLERCUBESHADOW */ - F16SAMPLERCUBEARRAYSHADOW = 465, /* F16SAMPLERCUBEARRAYSHADOW */ - IMAGE1D = 466, /* IMAGE1D */ - IIMAGE1D = 467, /* IIMAGE1D */ - UIMAGE1D = 468, /* UIMAGE1D */ - IMAGE2D = 469, /* IMAGE2D */ - IIMAGE2D = 470, /* IIMAGE2D */ - UIMAGE2D = 471, /* UIMAGE2D */ - IMAGE3D = 472, /* IMAGE3D */ - IIMAGE3D = 473, /* IIMAGE3D */ - UIMAGE3D = 474, /* UIMAGE3D */ - IMAGE2DRECT = 475, /* IMAGE2DRECT */ - IIMAGE2DRECT = 476, /* IIMAGE2DRECT */ - UIMAGE2DRECT = 477, /* UIMAGE2DRECT */ - IMAGECUBE = 478, /* IMAGECUBE */ - IIMAGECUBE = 479, /* IIMAGECUBE */ - UIMAGECUBE = 480, /* UIMAGECUBE */ - IMAGEBUFFER = 481, /* IMAGEBUFFER */ - IIMAGEBUFFER = 482, /* IIMAGEBUFFER */ - UIMAGEBUFFER = 483, /* UIMAGEBUFFER */ - IMAGE1DARRAY = 484, /* IMAGE1DARRAY */ - IIMAGE1DARRAY = 485, /* IIMAGE1DARRAY */ - UIMAGE1DARRAY = 486, /* UIMAGE1DARRAY */ - IMAGE2DARRAY = 487, /* IMAGE2DARRAY */ - IIMAGE2DARRAY = 488, /* IIMAGE2DARRAY */ - UIMAGE2DARRAY = 489, /* UIMAGE2DARRAY */ - IMAGECUBEARRAY = 490, /* IMAGECUBEARRAY */ - IIMAGECUBEARRAY = 491, /* IIMAGECUBEARRAY */ - UIMAGECUBEARRAY = 492, /* UIMAGECUBEARRAY */ - IMAGE2DMS = 493, /* IMAGE2DMS */ - IIMAGE2DMS = 494, /* IIMAGE2DMS */ - UIMAGE2DMS = 495, /* UIMAGE2DMS */ - IMAGE2DMSARRAY = 496, /* IMAGE2DMSARRAY */ - IIMAGE2DMSARRAY = 497, /* IIMAGE2DMSARRAY */ - UIMAGE2DMSARRAY = 498, /* UIMAGE2DMSARRAY */ - F16IMAGE1D = 499, /* F16IMAGE1D */ - F16IMAGE2D = 500, /* F16IMAGE2D */ - F16IMAGE3D = 501, /* F16IMAGE3D */ - F16IMAGE2DRECT = 502, /* F16IMAGE2DRECT */ - F16IMAGECUBE = 503, /* F16IMAGECUBE */ - F16IMAGE1DARRAY = 504, /* F16IMAGE1DARRAY */ - F16IMAGE2DARRAY = 505, /* F16IMAGE2DARRAY */ - F16IMAGECUBEARRAY = 506, /* F16IMAGECUBEARRAY */ - F16IMAGEBUFFER = 507, /* F16IMAGEBUFFER */ - F16IMAGE2DMS = 508, /* F16IMAGE2DMS */ - F16IMAGE2DMSARRAY = 509, /* F16IMAGE2DMSARRAY */ - I64IMAGE1D = 510, /* I64IMAGE1D */ - U64IMAGE1D = 511, /* U64IMAGE1D */ - I64IMAGE2D = 512, /* I64IMAGE2D */ - U64IMAGE2D = 513, /* U64IMAGE2D */ - I64IMAGE3D = 514, /* I64IMAGE3D */ - U64IMAGE3D = 515, /* U64IMAGE3D */ - I64IMAGE2DRECT = 516, /* I64IMAGE2DRECT */ - U64IMAGE2DRECT = 517, /* U64IMAGE2DRECT */ - I64IMAGECUBE = 518, /* I64IMAGECUBE */ - U64IMAGECUBE = 519, /* U64IMAGECUBE */ - I64IMAGEBUFFER = 520, /* I64IMAGEBUFFER */ - U64IMAGEBUFFER = 521, /* U64IMAGEBUFFER */ - I64IMAGE1DARRAY = 522, /* I64IMAGE1DARRAY */ - U64IMAGE1DARRAY = 523, /* U64IMAGE1DARRAY */ - I64IMAGE2DARRAY = 524, /* I64IMAGE2DARRAY */ - U64IMAGE2DARRAY = 525, /* U64IMAGE2DARRAY */ - I64IMAGECUBEARRAY = 526, /* I64IMAGECUBEARRAY */ - U64IMAGECUBEARRAY = 527, /* U64IMAGECUBEARRAY */ - I64IMAGE2DMS = 528, /* I64IMAGE2DMS */ - U64IMAGE2DMS = 529, /* U64IMAGE2DMS */ - I64IMAGE2DMSARRAY = 530, /* I64IMAGE2DMSARRAY */ - U64IMAGE2DMSARRAY = 531, /* U64IMAGE2DMSARRAY */ - TEXTURECUBEARRAY = 532, /* TEXTURECUBEARRAY */ - ITEXTURECUBEARRAY = 533, /* ITEXTURECUBEARRAY */ - UTEXTURECUBEARRAY = 534, /* UTEXTURECUBEARRAY */ - TEXTURE1D = 535, /* TEXTURE1D */ - ITEXTURE1D = 536, /* ITEXTURE1D */ - UTEXTURE1D = 537, /* UTEXTURE1D */ - TEXTURE1DARRAY = 538, /* TEXTURE1DARRAY */ - ITEXTURE1DARRAY = 539, /* ITEXTURE1DARRAY */ - UTEXTURE1DARRAY = 540, /* UTEXTURE1DARRAY */ - TEXTURE2DRECT = 541, /* TEXTURE2DRECT */ - ITEXTURE2DRECT = 542, /* ITEXTURE2DRECT */ - UTEXTURE2DRECT = 543, /* UTEXTURE2DRECT */ - TEXTUREBUFFER = 544, /* TEXTUREBUFFER */ - ITEXTUREBUFFER = 545, /* ITEXTUREBUFFER */ - UTEXTUREBUFFER = 546, /* UTEXTUREBUFFER */ - TEXTURE2DMS = 547, /* TEXTURE2DMS */ - ITEXTURE2DMS = 548, /* ITEXTURE2DMS */ - UTEXTURE2DMS = 549, /* UTEXTURE2DMS */ - TEXTURE2DMSARRAY = 550, /* TEXTURE2DMSARRAY */ - ITEXTURE2DMSARRAY = 551, /* ITEXTURE2DMSARRAY */ - UTEXTURE2DMSARRAY = 552, /* UTEXTURE2DMSARRAY */ - F16TEXTURE1D = 553, /* F16TEXTURE1D */ - F16TEXTURE2D = 554, /* F16TEXTURE2D */ - F16TEXTURE3D = 555, /* F16TEXTURE3D */ - F16TEXTURE2DRECT = 556, /* F16TEXTURE2DRECT */ - F16TEXTURECUBE = 557, /* F16TEXTURECUBE */ - F16TEXTURE1DARRAY = 558, /* F16TEXTURE1DARRAY */ - F16TEXTURE2DARRAY = 559, /* F16TEXTURE2DARRAY */ - F16TEXTURECUBEARRAY = 560, /* F16TEXTURECUBEARRAY */ - F16TEXTUREBUFFER = 561, /* F16TEXTUREBUFFER */ - F16TEXTURE2DMS = 562, /* F16TEXTURE2DMS */ - F16TEXTURE2DMSARRAY = 563, /* F16TEXTURE2DMSARRAY */ - SUBPASSINPUT = 564, /* SUBPASSINPUT */ - SUBPASSINPUTMS = 565, /* SUBPASSINPUTMS */ - ISUBPASSINPUT = 566, /* ISUBPASSINPUT */ - ISUBPASSINPUTMS = 567, /* ISUBPASSINPUTMS */ - USUBPASSINPUT = 568, /* USUBPASSINPUT */ - USUBPASSINPUTMS = 569, /* USUBPASSINPUTMS */ - F16SUBPASSINPUT = 570, /* F16SUBPASSINPUT */ - F16SUBPASSINPUTMS = 571, /* F16SUBPASSINPUTMS */ - SPIRV_INSTRUCTION = 572, /* SPIRV_INSTRUCTION */ - SPIRV_EXECUTION_MODE = 573, /* SPIRV_EXECUTION_MODE */ - SPIRV_EXECUTION_MODE_ID = 574, /* SPIRV_EXECUTION_MODE_ID */ - SPIRV_DECORATE = 575, /* SPIRV_DECORATE */ - SPIRV_DECORATE_ID = 576, /* SPIRV_DECORATE_ID */ - SPIRV_DECORATE_STRING = 577, /* SPIRV_DECORATE_STRING */ - SPIRV_TYPE = 578, /* SPIRV_TYPE */ - SPIRV_STORAGE_CLASS = 579, /* SPIRV_STORAGE_CLASS */ - SPIRV_BY_REFERENCE = 580, /* SPIRV_BY_REFERENCE */ - SPIRV_LITERAL = 581, /* SPIRV_LITERAL */ - LEFT_OP = 582, /* LEFT_OP */ - RIGHT_OP = 583, /* RIGHT_OP */ - INC_OP = 584, /* INC_OP */ - DEC_OP = 585, /* DEC_OP */ - LE_OP = 586, /* LE_OP */ - GE_OP = 587, /* GE_OP */ - EQ_OP = 588, /* EQ_OP */ - NE_OP = 589, /* NE_OP */ - AND_OP = 590, /* AND_OP */ - OR_OP = 591, /* OR_OP */ - XOR_OP = 592, /* XOR_OP */ - MUL_ASSIGN = 593, /* MUL_ASSIGN */ - DIV_ASSIGN = 594, /* DIV_ASSIGN */ - ADD_ASSIGN = 595, /* ADD_ASSIGN */ - MOD_ASSIGN = 596, /* MOD_ASSIGN */ - LEFT_ASSIGN = 597, /* LEFT_ASSIGN */ - RIGHT_ASSIGN = 598, /* RIGHT_ASSIGN */ - AND_ASSIGN = 599, /* AND_ASSIGN */ - XOR_ASSIGN = 600, /* XOR_ASSIGN */ - OR_ASSIGN = 601, /* OR_ASSIGN */ - SUB_ASSIGN = 602, /* SUB_ASSIGN */ - STRING_LITERAL = 603, /* STRING_LITERAL */ - LEFT_PAREN = 604, /* LEFT_PAREN */ - RIGHT_PAREN = 605, /* RIGHT_PAREN */ - LEFT_BRACKET = 606, /* LEFT_BRACKET */ - RIGHT_BRACKET = 607, /* RIGHT_BRACKET */ - LEFT_BRACE = 608, /* LEFT_BRACE */ - RIGHT_BRACE = 609, /* RIGHT_BRACE */ - DOT = 610, /* DOT */ - COMMA = 611, /* COMMA */ - COLON = 612, /* COLON */ - EQUAL = 613, /* EQUAL */ - SEMICOLON = 614, /* SEMICOLON */ - BANG = 615, /* BANG */ - DASH = 616, /* DASH */ - TILDE = 617, /* TILDE */ - PLUS = 618, /* PLUS */ - STAR = 619, /* STAR */ - SLASH = 620, /* SLASH */ - PERCENT = 621, /* PERCENT */ - LEFT_ANGLE = 622, /* LEFT_ANGLE */ - RIGHT_ANGLE = 623, /* RIGHT_ANGLE */ - VERTICAL_BAR = 624, /* VERTICAL_BAR */ - CARET = 625, /* CARET */ - AMPERSAND = 626, /* AMPERSAND */ - QUESTION = 627, /* QUESTION */ - INVARIANT = 628, /* INVARIANT */ - HIGH_PRECISION = 629, /* HIGH_PRECISION */ - MEDIUM_PRECISION = 630, /* MEDIUM_PRECISION */ - LOW_PRECISION = 631, /* LOW_PRECISION */ - PRECISION = 632, /* PRECISION */ - PACKED = 633, /* PACKED */ - RESOURCE = 634, /* RESOURCE */ - SUPERP = 635, /* SUPERP */ - FLOATCONSTANT = 636, /* FLOATCONSTANT */ - INTCONSTANT = 637, /* INTCONSTANT */ - UINTCONSTANT = 638, /* UINTCONSTANT */ - BOOLCONSTANT = 639, /* BOOLCONSTANT */ - IDENTIFIER = 640, /* IDENTIFIER */ - TYPE_NAME = 641, /* TYPE_NAME */ - CENTROID = 642, /* CENTROID */ - IN = 643, /* IN */ - OUT = 644, /* OUT */ - INOUT = 645, /* INOUT */ - STRUCT = 646, /* STRUCT */ - VOID = 647, /* VOID */ - WHILE = 648, /* WHILE */ - BREAK = 649, /* BREAK */ - CONTINUE = 650, /* CONTINUE */ - DO = 651, /* DO */ - ELSE = 652, /* ELSE */ - FOR = 653, /* FOR */ - IF = 654, /* IF */ - DISCARD = 655, /* DISCARD */ - RETURN = 656, /* RETURN */ - SWITCH = 657, /* SWITCH */ - CASE = 658, /* CASE */ - DEFAULT = 659, /* DEFAULT */ - TERMINATE_INVOCATION = 660, /* TERMINATE_INVOCATION */ - TERMINATE_RAY = 661, /* TERMINATE_RAY */ - IGNORE_INTERSECTION = 662, /* IGNORE_INTERSECTION */ - UNIFORM = 663, /* UNIFORM */ - SHARED = 664, /* SHARED */ - BUFFER = 665, /* BUFFER */ - FLAT = 666, /* FLAT */ - SMOOTH = 667, /* SMOOTH */ - LAYOUT = 668, /* LAYOUT */ - DOUBLECONSTANT = 669, /* DOUBLECONSTANT */ - INT16CONSTANT = 670, /* INT16CONSTANT */ - UINT16CONSTANT = 671, /* UINT16CONSTANT */ - FLOAT16CONSTANT = 672, /* FLOAT16CONSTANT */ - INT32CONSTANT = 673, /* INT32CONSTANT */ - UINT32CONSTANT = 674, /* UINT32CONSTANT */ - INT64CONSTANT = 675, /* INT64CONSTANT */ - UINT64CONSTANT = 676, /* UINT64CONSTANT */ - SUBROUTINE = 677, /* SUBROUTINE */ - DEMOTE = 678, /* DEMOTE */ - PAYLOADNV = 679, /* PAYLOADNV */ - PAYLOADINNV = 680, /* PAYLOADINNV */ - HITATTRNV = 681, /* HITATTRNV */ - CALLDATANV = 682, /* CALLDATANV */ - CALLDATAINNV = 683, /* CALLDATAINNV */ - PAYLOADEXT = 684, /* PAYLOADEXT */ - PAYLOADINEXT = 685, /* PAYLOADINEXT */ - HITATTREXT = 686, /* HITATTREXT */ - CALLDATAEXT = 687, /* CALLDATAEXT */ - CALLDATAINEXT = 688, /* CALLDATAINEXT */ - PATCH = 689, /* PATCH */ - SAMPLE = 690, /* SAMPLE */ - NONUNIFORM = 691, /* NONUNIFORM */ - COHERENT = 692, /* COHERENT */ - VOLATILE = 693, /* VOLATILE */ - RESTRICT = 694, /* RESTRICT */ - READONLY = 695, /* READONLY */ - WRITEONLY = 696, /* WRITEONLY */ - DEVICECOHERENT = 697, /* DEVICECOHERENT */ - QUEUEFAMILYCOHERENT = 698, /* QUEUEFAMILYCOHERENT */ - WORKGROUPCOHERENT = 699, /* WORKGROUPCOHERENT */ - SUBGROUPCOHERENT = 700, /* SUBGROUPCOHERENT */ - NONPRIVATE = 701, /* NONPRIVATE */ - SHADERCALLCOHERENT = 702, /* SHADERCALLCOHERENT */ - NOPERSPECTIVE = 703, /* NOPERSPECTIVE */ - EXPLICITINTERPAMD = 704, /* EXPLICITINTERPAMD */ - PERVERTEXNV = 705, /* PERVERTEXNV */ - PERPRIMITIVENV = 706, /* PERPRIMITIVENV */ - PERVIEWNV = 707, /* PERVIEWNV */ - PERTASKNV = 708, /* PERTASKNV */ - PRECISE = 709 /* PRECISE */ + COOPMAT = 421, /* COOPMAT */ + HITOBJECTNV = 422, /* HITOBJECTNV */ + HITOBJECTATTRNV = 423, /* HITOBJECTATTRNV */ + SAMPLERCUBEARRAY = 424, /* SAMPLERCUBEARRAY */ + SAMPLERCUBEARRAYSHADOW = 425, /* SAMPLERCUBEARRAYSHADOW */ + ISAMPLERCUBEARRAY = 426, /* ISAMPLERCUBEARRAY */ + USAMPLERCUBEARRAY = 427, /* USAMPLERCUBEARRAY */ + SAMPLER1D = 428, /* SAMPLER1D */ + SAMPLER1DARRAY = 429, /* SAMPLER1DARRAY */ + SAMPLER1DARRAYSHADOW = 430, /* SAMPLER1DARRAYSHADOW */ + ISAMPLER1D = 431, /* ISAMPLER1D */ + SAMPLER1DSHADOW = 432, /* SAMPLER1DSHADOW */ + SAMPLER2DRECT = 433, /* SAMPLER2DRECT */ + SAMPLER2DRECTSHADOW = 434, /* SAMPLER2DRECTSHADOW */ + ISAMPLER2DRECT = 435, /* ISAMPLER2DRECT */ + USAMPLER2DRECT = 436, /* USAMPLER2DRECT */ + SAMPLERBUFFER = 437, /* SAMPLERBUFFER */ + ISAMPLERBUFFER = 438, /* ISAMPLERBUFFER */ + USAMPLERBUFFER = 439, /* USAMPLERBUFFER */ + SAMPLER2DMS = 440, /* SAMPLER2DMS */ + ISAMPLER2DMS = 441, /* ISAMPLER2DMS */ + USAMPLER2DMS = 442, /* USAMPLER2DMS */ + SAMPLER2DMSARRAY = 443, /* SAMPLER2DMSARRAY */ + ISAMPLER2DMSARRAY = 444, /* ISAMPLER2DMSARRAY */ + USAMPLER2DMSARRAY = 445, /* USAMPLER2DMSARRAY */ + SAMPLEREXTERNALOES = 446, /* SAMPLEREXTERNALOES */ + SAMPLEREXTERNAL2DY2YEXT = 447, /* SAMPLEREXTERNAL2DY2YEXT */ + ISAMPLER1DARRAY = 448, /* ISAMPLER1DARRAY */ + USAMPLER1D = 449, /* USAMPLER1D */ + USAMPLER1DARRAY = 450, /* USAMPLER1DARRAY */ + F16SAMPLER1D = 451, /* F16SAMPLER1D */ + F16SAMPLER2D = 452, /* F16SAMPLER2D */ + F16SAMPLER3D = 453, /* F16SAMPLER3D */ + F16SAMPLER2DRECT = 454, /* F16SAMPLER2DRECT */ + F16SAMPLERCUBE = 455, /* F16SAMPLERCUBE */ + F16SAMPLER1DARRAY = 456, /* F16SAMPLER1DARRAY */ + F16SAMPLER2DARRAY = 457, /* F16SAMPLER2DARRAY */ + F16SAMPLERCUBEARRAY = 458, /* F16SAMPLERCUBEARRAY */ + F16SAMPLERBUFFER = 459, /* F16SAMPLERBUFFER */ + F16SAMPLER2DMS = 460, /* F16SAMPLER2DMS */ + F16SAMPLER2DMSARRAY = 461, /* F16SAMPLER2DMSARRAY */ + F16SAMPLER1DSHADOW = 462, /* F16SAMPLER1DSHADOW */ + F16SAMPLER2DSHADOW = 463, /* F16SAMPLER2DSHADOW */ + F16SAMPLER1DARRAYSHADOW = 464, /* F16SAMPLER1DARRAYSHADOW */ + F16SAMPLER2DARRAYSHADOW = 465, /* F16SAMPLER2DARRAYSHADOW */ + F16SAMPLER2DRECTSHADOW = 466, /* F16SAMPLER2DRECTSHADOW */ + F16SAMPLERCUBESHADOW = 467, /* F16SAMPLERCUBESHADOW */ + F16SAMPLERCUBEARRAYSHADOW = 468, /* F16SAMPLERCUBEARRAYSHADOW */ + IMAGE1D = 469, /* IMAGE1D */ + IIMAGE1D = 470, /* IIMAGE1D */ + UIMAGE1D = 471, /* UIMAGE1D */ + IMAGE2D = 472, /* IMAGE2D */ + IIMAGE2D = 473, /* IIMAGE2D */ + UIMAGE2D = 474, /* UIMAGE2D */ + IMAGE3D = 475, /* IMAGE3D */ + IIMAGE3D = 476, /* IIMAGE3D */ + UIMAGE3D = 477, /* UIMAGE3D */ + IMAGE2DRECT = 478, /* IMAGE2DRECT */ + IIMAGE2DRECT = 479, /* IIMAGE2DRECT */ + UIMAGE2DRECT = 480, /* UIMAGE2DRECT */ + IMAGECUBE = 481, /* IMAGECUBE */ + IIMAGECUBE = 482, /* IIMAGECUBE */ + UIMAGECUBE = 483, /* UIMAGECUBE */ + IMAGEBUFFER = 484, /* IMAGEBUFFER */ + IIMAGEBUFFER = 485, /* IIMAGEBUFFER */ + UIMAGEBUFFER = 486, /* UIMAGEBUFFER */ + IMAGE1DARRAY = 487, /* IMAGE1DARRAY */ + IIMAGE1DARRAY = 488, /* IIMAGE1DARRAY */ + UIMAGE1DARRAY = 489, /* UIMAGE1DARRAY */ + IMAGE2DARRAY = 490, /* IMAGE2DARRAY */ + IIMAGE2DARRAY = 491, /* IIMAGE2DARRAY */ + UIMAGE2DARRAY = 492, /* UIMAGE2DARRAY */ + IMAGECUBEARRAY = 493, /* IMAGECUBEARRAY */ + IIMAGECUBEARRAY = 494, /* IIMAGECUBEARRAY */ + UIMAGECUBEARRAY = 495, /* UIMAGECUBEARRAY */ + IMAGE2DMS = 496, /* IMAGE2DMS */ + IIMAGE2DMS = 497, /* IIMAGE2DMS */ + UIMAGE2DMS = 498, /* UIMAGE2DMS */ + IMAGE2DMSARRAY = 499, /* IMAGE2DMSARRAY */ + IIMAGE2DMSARRAY = 500, /* IIMAGE2DMSARRAY */ + UIMAGE2DMSARRAY = 501, /* UIMAGE2DMSARRAY */ + F16IMAGE1D = 502, /* F16IMAGE1D */ + F16IMAGE2D = 503, /* F16IMAGE2D */ + F16IMAGE3D = 504, /* F16IMAGE3D */ + F16IMAGE2DRECT = 505, /* F16IMAGE2DRECT */ + F16IMAGECUBE = 506, /* F16IMAGECUBE */ + F16IMAGE1DARRAY = 507, /* F16IMAGE1DARRAY */ + F16IMAGE2DARRAY = 508, /* F16IMAGE2DARRAY */ + F16IMAGECUBEARRAY = 509, /* F16IMAGECUBEARRAY */ + F16IMAGEBUFFER = 510, /* F16IMAGEBUFFER */ + F16IMAGE2DMS = 511, /* F16IMAGE2DMS */ + F16IMAGE2DMSARRAY = 512, /* F16IMAGE2DMSARRAY */ + I64IMAGE1D = 513, /* I64IMAGE1D */ + U64IMAGE1D = 514, /* U64IMAGE1D */ + I64IMAGE2D = 515, /* I64IMAGE2D */ + U64IMAGE2D = 516, /* U64IMAGE2D */ + I64IMAGE3D = 517, /* I64IMAGE3D */ + U64IMAGE3D = 518, /* U64IMAGE3D */ + I64IMAGE2DRECT = 519, /* I64IMAGE2DRECT */ + U64IMAGE2DRECT = 520, /* U64IMAGE2DRECT */ + I64IMAGECUBE = 521, /* I64IMAGECUBE */ + U64IMAGECUBE = 522, /* U64IMAGECUBE */ + I64IMAGEBUFFER = 523, /* I64IMAGEBUFFER */ + U64IMAGEBUFFER = 524, /* U64IMAGEBUFFER */ + I64IMAGE1DARRAY = 525, /* I64IMAGE1DARRAY */ + U64IMAGE1DARRAY = 526, /* U64IMAGE1DARRAY */ + I64IMAGE2DARRAY = 527, /* I64IMAGE2DARRAY */ + U64IMAGE2DARRAY = 528, /* U64IMAGE2DARRAY */ + I64IMAGECUBEARRAY = 529, /* I64IMAGECUBEARRAY */ + U64IMAGECUBEARRAY = 530, /* U64IMAGECUBEARRAY */ + I64IMAGE2DMS = 531, /* I64IMAGE2DMS */ + U64IMAGE2DMS = 532, /* U64IMAGE2DMS */ + I64IMAGE2DMSARRAY = 533, /* I64IMAGE2DMSARRAY */ + U64IMAGE2DMSARRAY = 534, /* U64IMAGE2DMSARRAY */ + TEXTURECUBEARRAY = 535, /* TEXTURECUBEARRAY */ + ITEXTURECUBEARRAY = 536, /* ITEXTURECUBEARRAY */ + UTEXTURECUBEARRAY = 537, /* UTEXTURECUBEARRAY */ + TEXTURE1D = 538, /* TEXTURE1D */ + ITEXTURE1D = 539, /* ITEXTURE1D */ + UTEXTURE1D = 540, /* UTEXTURE1D */ + TEXTURE1DARRAY = 541, /* TEXTURE1DARRAY */ + ITEXTURE1DARRAY = 542, /* ITEXTURE1DARRAY */ + UTEXTURE1DARRAY = 543, /* UTEXTURE1DARRAY */ + TEXTURE2DRECT = 544, /* TEXTURE2DRECT */ + ITEXTURE2DRECT = 545, /* ITEXTURE2DRECT */ + UTEXTURE2DRECT = 546, /* UTEXTURE2DRECT */ + TEXTUREBUFFER = 547, /* TEXTUREBUFFER */ + ITEXTUREBUFFER = 548, /* ITEXTUREBUFFER */ + UTEXTUREBUFFER = 549, /* UTEXTUREBUFFER */ + TEXTURE2DMS = 550, /* TEXTURE2DMS */ + ITEXTURE2DMS = 551, /* ITEXTURE2DMS */ + UTEXTURE2DMS = 552, /* UTEXTURE2DMS */ + TEXTURE2DMSARRAY = 553, /* TEXTURE2DMSARRAY */ + ITEXTURE2DMSARRAY = 554, /* ITEXTURE2DMSARRAY */ + UTEXTURE2DMSARRAY = 555, /* UTEXTURE2DMSARRAY */ + F16TEXTURE1D = 556, /* F16TEXTURE1D */ + F16TEXTURE2D = 557, /* F16TEXTURE2D */ + F16TEXTURE3D = 558, /* F16TEXTURE3D */ + F16TEXTURE2DRECT = 559, /* F16TEXTURE2DRECT */ + F16TEXTURECUBE = 560, /* F16TEXTURECUBE */ + F16TEXTURE1DARRAY = 561, /* F16TEXTURE1DARRAY */ + F16TEXTURE2DARRAY = 562, /* F16TEXTURE2DARRAY */ + F16TEXTURECUBEARRAY = 563, /* F16TEXTURECUBEARRAY */ + F16TEXTUREBUFFER = 564, /* F16TEXTUREBUFFER */ + F16TEXTURE2DMS = 565, /* F16TEXTURE2DMS */ + F16TEXTURE2DMSARRAY = 566, /* F16TEXTURE2DMSARRAY */ + SUBPASSINPUT = 567, /* SUBPASSINPUT */ + SUBPASSINPUTMS = 568, /* SUBPASSINPUTMS */ + ISUBPASSINPUT = 569, /* ISUBPASSINPUT */ + ISUBPASSINPUTMS = 570, /* ISUBPASSINPUTMS */ + USUBPASSINPUT = 571, /* USUBPASSINPUT */ + USUBPASSINPUTMS = 572, /* USUBPASSINPUTMS */ + F16SUBPASSINPUT = 573, /* F16SUBPASSINPUT */ + F16SUBPASSINPUTMS = 574, /* F16SUBPASSINPUTMS */ + SPIRV_INSTRUCTION = 575, /* SPIRV_INSTRUCTION */ + SPIRV_EXECUTION_MODE = 576, /* SPIRV_EXECUTION_MODE */ + SPIRV_EXECUTION_MODE_ID = 577, /* SPIRV_EXECUTION_MODE_ID */ + SPIRV_DECORATE = 578, /* SPIRV_DECORATE */ + SPIRV_DECORATE_ID = 579, /* SPIRV_DECORATE_ID */ + SPIRV_DECORATE_STRING = 580, /* SPIRV_DECORATE_STRING */ + SPIRV_TYPE = 581, /* SPIRV_TYPE */ + SPIRV_STORAGE_CLASS = 582, /* SPIRV_STORAGE_CLASS */ + SPIRV_BY_REFERENCE = 583, /* SPIRV_BY_REFERENCE */ + SPIRV_LITERAL = 584, /* SPIRV_LITERAL */ + ATTACHMENTEXT = 585, /* ATTACHMENTEXT */ + IATTACHMENTEXT = 586, /* IATTACHMENTEXT */ + UATTACHMENTEXT = 587, /* UATTACHMENTEXT */ + LEFT_OP = 588, /* LEFT_OP */ + RIGHT_OP = 589, /* RIGHT_OP */ + INC_OP = 590, /* INC_OP */ + DEC_OP = 591, /* DEC_OP */ + LE_OP = 592, /* LE_OP */ + GE_OP = 593, /* GE_OP */ + EQ_OP = 594, /* EQ_OP */ + NE_OP = 595, /* NE_OP */ + AND_OP = 596, /* AND_OP */ + OR_OP = 597, /* OR_OP */ + XOR_OP = 598, /* XOR_OP */ + MUL_ASSIGN = 599, /* MUL_ASSIGN */ + DIV_ASSIGN = 600, /* DIV_ASSIGN */ + ADD_ASSIGN = 601, /* ADD_ASSIGN */ + MOD_ASSIGN = 602, /* MOD_ASSIGN */ + LEFT_ASSIGN = 603, /* LEFT_ASSIGN */ + RIGHT_ASSIGN = 604, /* RIGHT_ASSIGN */ + AND_ASSIGN = 605, /* AND_ASSIGN */ + XOR_ASSIGN = 606, /* XOR_ASSIGN */ + OR_ASSIGN = 607, /* OR_ASSIGN */ + SUB_ASSIGN = 608, /* SUB_ASSIGN */ + STRING_LITERAL = 609, /* STRING_LITERAL */ + LEFT_PAREN = 610, /* LEFT_PAREN */ + RIGHT_PAREN = 611, /* RIGHT_PAREN */ + LEFT_BRACKET = 612, /* LEFT_BRACKET */ + RIGHT_BRACKET = 613, /* RIGHT_BRACKET */ + LEFT_BRACE = 614, /* LEFT_BRACE */ + RIGHT_BRACE = 615, /* RIGHT_BRACE */ + DOT = 616, /* DOT */ + COMMA = 617, /* COMMA */ + COLON = 618, /* COLON */ + EQUAL = 619, /* EQUAL */ + SEMICOLON = 620, /* SEMICOLON */ + BANG = 621, /* BANG */ + DASH = 622, /* DASH */ + TILDE = 623, /* TILDE */ + PLUS = 624, /* PLUS */ + STAR = 625, /* STAR */ + SLASH = 626, /* SLASH */ + PERCENT = 627, /* PERCENT */ + LEFT_ANGLE = 628, /* LEFT_ANGLE */ + RIGHT_ANGLE = 629, /* RIGHT_ANGLE */ + VERTICAL_BAR = 630, /* VERTICAL_BAR */ + CARET = 631, /* CARET */ + AMPERSAND = 632, /* AMPERSAND */ + QUESTION = 633, /* QUESTION */ + INVARIANT = 634, /* INVARIANT */ + HIGH_PRECISION = 635, /* HIGH_PRECISION */ + MEDIUM_PRECISION = 636, /* MEDIUM_PRECISION */ + LOW_PRECISION = 637, /* LOW_PRECISION */ + PRECISION = 638, /* PRECISION */ + PACKED = 639, /* PACKED */ + RESOURCE = 640, /* RESOURCE */ + SUPERP = 641, /* SUPERP */ + FLOATCONSTANT = 642, /* FLOATCONSTANT */ + INTCONSTANT = 643, /* INTCONSTANT */ + UINTCONSTANT = 644, /* UINTCONSTANT */ + BOOLCONSTANT = 645, /* BOOLCONSTANT */ + IDENTIFIER = 646, /* IDENTIFIER */ + TYPE_NAME = 647, /* TYPE_NAME */ + CENTROID = 648, /* CENTROID */ + IN = 649, /* IN */ + OUT = 650, /* OUT */ + INOUT = 651, /* INOUT */ + STRUCT = 652, /* STRUCT */ + VOID = 653, /* VOID */ + WHILE = 654, /* WHILE */ + BREAK = 655, /* BREAK */ + CONTINUE = 656, /* CONTINUE */ + DO = 657, /* DO */ + ELSE = 658, /* ELSE */ + FOR = 659, /* FOR */ + IF = 660, /* IF */ + DISCARD = 661, /* DISCARD */ + RETURN = 662, /* RETURN */ + SWITCH = 663, /* SWITCH */ + CASE = 664, /* CASE */ + DEFAULT = 665, /* DEFAULT */ + TERMINATE_INVOCATION = 666, /* TERMINATE_INVOCATION */ + TERMINATE_RAY = 667, /* TERMINATE_RAY */ + IGNORE_INTERSECTION = 668, /* IGNORE_INTERSECTION */ + UNIFORM = 669, /* UNIFORM */ + SHARED = 670, /* SHARED */ + BUFFER = 671, /* BUFFER */ + TILEIMAGEEXT = 672, /* TILEIMAGEEXT */ + FLAT = 673, /* FLAT */ + SMOOTH = 674, /* SMOOTH */ + LAYOUT = 675, /* LAYOUT */ + DOUBLECONSTANT = 676, /* DOUBLECONSTANT */ + INT16CONSTANT = 677, /* INT16CONSTANT */ + UINT16CONSTANT = 678, /* UINT16CONSTANT */ + FLOAT16CONSTANT = 679, /* FLOAT16CONSTANT */ + INT32CONSTANT = 680, /* INT32CONSTANT */ + UINT32CONSTANT = 681, /* UINT32CONSTANT */ + INT64CONSTANT = 682, /* INT64CONSTANT */ + UINT64CONSTANT = 683, /* UINT64CONSTANT */ + SUBROUTINE = 684, /* SUBROUTINE */ + DEMOTE = 685, /* DEMOTE */ + PAYLOADNV = 686, /* PAYLOADNV */ + PAYLOADINNV = 687, /* PAYLOADINNV */ + HITATTRNV = 688, /* HITATTRNV */ + CALLDATANV = 689, /* CALLDATANV */ + CALLDATAINNV = 690, /* CALLDATAINNV */ + PAYLOADEXT = 691, /* PAYLOADEXT */ + PAYLOADINEXT = 692, /* PAYLOADINEXT */ + HITATTREXT = 693, /* HITATTREXT */ + CALLDATAEXT = 694, /* CALLDATAEXT */ + CALLDATAINEXT = 695, /* CALLDATAINEXT */ + PATCH = 696, /* PATCH */ + SAMPLE = 697, /* SAMPLE */ + NONUNIFORM = 698, /* NONUNIFORM */ + COHERENT = 699, /* COHERENT */ + VOLATILE = 700, /* VOLATILE */ + RESTRICT = 701, /* RESTRICT */ + READONLY = 702, /* READONLY */ + WRITEONLY = 703, /* WRITEONLY */ + DEVICECOHERENT = 704, /* DEVICECOHERENT */ + QUEUEFAMILYCOHERENT = 705, /* QUEUEFAMILYCOHERENT */ + WORKGROUPCOHERENT = 706, /* WORKGROUPCOHERENT */ + SUBGROUPCOHERENT = 707, /* SUBGROUPCOHERENT */ + NONPRIVATE = 708, /* NONPRIVATE */ + SHADERCALLCOHERENT = 709, /* SHADERCALLCOHERENT */ + NOPERSPECTIVE = 710, /* NOPERSPECTIVE */ + EXPLICITINTERPAMD = 711, /* EXPLICITINTERPAMD */ + PERVERTEXEXT = 712, /* PERVERTEXEXT */ + PERVERTEXNV = 713, /* PERVERTEXNV */ + PERPRIMITIVENV = 714, /* PERPRIMITIVENV */ + PERVIEWNV = 715, /* PERVIEWNV */ + PERTASKNV = 716, /* PERTASKNV */ + PERPRIMITIVEEXT = 717, /* PERPRIMITIVEEXT */ + TASKPAYLOADWORKGROUPEXT = 718, /* TASKPAYLOADWORKGROUPEXT */ + PRECISE = 719 /* PRECISE */ }; typedef enum yytokentype yytoken_kind_t; #endif @@ -514,7 +524,7 @@ extern int yydebug; #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED union YYSTYPE { -#line 97 "MachineIndependent/glslang.y" +#line 72 "MachineIndependent/glslang.y" struct { glslang::TSourceLoc loc; @@ -550,10 +560,10 @@ union YYSTYPE glslang::TArraySizes* arraySizes; glslang::TIdentifierList* identifierList; }; - glslang::TArraySizes* typeParameters; + glslang::TTypeParameters* typeParameters; } interm; -#line 557 "MachineIndependent/glslang_tab.cpp.h" +#line 567 "MachineIndependent/glslang_tab.cpp.h" }; typedef union YYSTYPE YYSTYPE; @@ -563,6 +573,8 @@ typedef union YYSTYPE YYSTYPE; + int yyparse (glslang::TParseContext* pParseContext); + #endif /* !YY_YY_MACHINEINDEPENDENT_GLSLANG_TAB_CPP_H_INCLUDED */ diff --git a/src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp b/src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp index d8a3aab5d..f0621bd9e 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/intermOut.cpp @@ -1,7 +1,7 @@ // // Copyright (C) 2002-2005 3Dlabs Inc. Ltd. // Copyright (C) 2012-2016 LunarG, Inc. -// Copyright (C) 2017 ARM Limited. +// Copyright (C) 2017, 2022-2024 Arm Limited. // Modifications Copyright (C) 2020 Advanced Micro Devices, Inc. All rights reserved. // // All rights reserved. @@ -36,8 +36,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #include "localintermediate.h" #include "../Include/InfoSink.h" @@ -567,6 +565,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpSubgroupShuffleXor: out.debug << "subgroupShuffleXor"; break; case EOpSubgroupShuffleUp: out.debug << "subgroupShuffleUp"; break; case EOpSubgroupShuffleDown: out.debug << "subgroupShuffleDown"; break; + case EOpSubgroupRotate: out.debug << "subgroupRotate"; break; + case EOpSubgroupClusteredRotate: out.debug << "subgroupClusteredRotate"; break; case EOpSubgroupAdd: out.debug << "subgroupAdd"; break; case EOpSubgroupMul: out.debug << "subgroupMul"; break; case EOpSubgroupMin: out.debug << "subgroupMin"; break; @@ -599,6 +599,8 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpSubgroupQuadSwapHorizontal: out.debug << "subgroupQuadSwapHorizontal"; break; case EOpSubgroupQuadSwapVertical: out.debug << "subgroupQuadSwapVertical"; break; case EOpSubgroupQuadSwapDiagonal: out.debug << "subgroupQuadSwapDiagonal"; break; + case EOpSubgroupQuadAll: out.debug << "subgroupQuadAll"; break; + case EOpSubgroupQuadAny: out.debug << "subgroupQuadAny"; break; case EOpSubgroupPartition: out.debug << "subgroupPartitionNV"; break; case EOpSubgroupPartitionedAdd: out.debug << "subgroupPartitionedAddNV"; break; @@ -663,11 +665,13 @@ bool TOutputTraverser::visitUnary(TVisit /* visit */, TIntermUnary* node) case EOpSubpassLoad: out.debug << "subpassLoad"; break; case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break; + case EOpColorAttachmentReadEXT: out.debug << "colorAttachmentReadEXT"; break; + case EOpConstructReference: out.debug << "Construct reference type"; break; -#ifndef GLSLANG_WEB + case EOpDeclare: out.debug << "Declare"; break; + case EOpSpirvInst: out.debug << "spirv_instruction"; break; -#endif default: out.debug.message(EPrefixError, "Bad unary op"); } @@ -692,6 +696,7 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node switch (node->getOp()) { case EOpSequence: out.debug << "Sequence\n"; return true; + case EOpScope: out.debug << "Scope\n"; return true; case EOpLinkerObjects: out.debug << "Linker Objects\n"; return true; case EOpComma: out.debug << "Comma"; break; case EOpFunction: out.debug << "Function Definition: " << node->getName(); break; @@ -804,7 +809,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpConstructStruct: out.debug << "Construct structure"; break; case EOpConstructTextureSampler: out.debug << "Construct combined texture-sampler"; break; case EOpConstructReference: out.debug << "Construct reference"; break; - case EOpConstructCooperativeMatrix: out.debug << "Construct cooperative matrix"; break; + case EOpConstructCooperativeMatrixNV: out.debug << "Construct cooperative matrix NV"; break; + case EOpConstructCooperativeMatrixKHR: out.debug << "Construct cooperative matrix KHR"; break; case EOpConstructAccStruct: out.debug << "Construct acceleration structure"; break; case EOpLessThan: out.debug << "Compare Less Than"; break; @@ -998,6 +1004,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpSubgroupShuffleXor: out.debug << "subgroupShuffleXor"; break; case EOpSubgroupShuffleUp: out.debug << "subgroupShuffleUp"; break; case EOpSubgroupShuffleDown: out.debug << "subgroupShuffleDown"; break; + case EOpSubgroupRotate: out.debug << "subgroupRotate"; break; + case EOpSubgroupClusteredRotate: out.debug << "subgroupClusteredRotate"; break; case EOpSubgroupAdd: out.debug << "subgroupAdd"; break; case EOpSubgroupMul: out.debug << "subgroupMul"; break; case EOpSubgroupMin: out.debug << "subgroupMin"; break; @@ -1030,6 +1038,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpSubgroupQuadSwapHorizontal: out.debug << "subgroupQuadSwapHorizontal"; break; case EOpSubgroupQuadSwapVertical: out.debug << "subgroupQuadSwapVertical"; break; case EOpSubgroupQuadSwapDiagonal: out.debug << "subgroupQuadSwapDiagonal"; break; + case EOpSubgroupQuadAll: out.debug << "subgroupQuadAll"; break; + case EOpSubgroupQuadAny: out.debug << "subgroupQuadAny"; break; case EOpSubgroupPartition: out.debug << "subgroupPartitionNV"; break; case EOpSubgroupPartitionedAdd: out.debug << "subgroupPartitionedAddNV"; break; @@ -1057,6 +1067,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpSubpassLoad: out.debug << "subpassLoad"; break; case EOpSubpassLoadMS: out.debug << "subpassLoadMS"; break; + case EOpColorAttachmentReadEXT: out.debug << "colorAttachmentReadEXT"; break; + case EOpTraceNV: out.debug << "traceNV"; break; case EOpTraceRayMotionNV: out.debug << "traceRayMotionNV"; break; case EOpTraceKHR: out.debug << "traceRayKHR"; break; @@ -1068,6 +1080,8 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpExecuteCallableNV: out.debug << "executeCallableNV"; break; case EOpExecuteCallableKHR: out.debug << "executeCallableKHR"; break; case EOpWritePackedPrimitiveIndices4x8NV: out.debug << "writePackedPrimitiveIndices4x8NV"; break; + case EOpEmitMeshTasksEXT: out.debug << "EmitMeshTasksEXT"; break; + case EOpSetMeshOutputsEXT: out.debug << "SetMeshOutputsEXT"; break; case EOpRayQueryInitialize: out.debug << "rayQueryInitializeEXT"; break; case EOpRayQueryTerminate: out.debug << "rayQueryTerminateEXT"; break; @@ -1092,22 +1106,60 @@ bool TOutputTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node case EOpRayQueryGetWorldRayOrigin: out.debug << "rayQueryGetWorldRayOriginEXT"; break; case EOpRayQueryGetIntersectionObjectToWorld: out.debug << "rayQueryGetIntersectionObjectToWorldEXT"; break; case EOpRayQueryGetIntersectionWorldToObject: out.debug << "rayQueryGetIntersectionWorldToObjectEXT"; break; + case EOpRayQueryGetIntersectionTriangleVertexPositionsEXT: out.debug << "rayQueryGetIntersectionTriangleVertexPositionsEXT"; break; - case EOpCooperativeMatrixLoad: out.debug << "Load cooperative matrix"; break; - case EOpCooperativeMatrixStore: out.debug << "Store cooperative matrix"; break; - case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices"; break; + case EOpCooperativeMatrixLoad: out.debug << "Load cooperative matrix KHR"; break; + case EOpCooperativeMatrixStore: out.debug << "Store cooperative matrix KHR"; break; + case EOpCooperativeMatrixMulAdd: out.debug << "MulAdd cooperative matrices KHR"; break; + case EOpCooperativeMatrixLoadNV: out.debug << "Load cooperative matrix NV"; break; + case EOpCooperativeMatrixStoreNV: out.debug << "Store cooperative matrix NV"; break; + case EOpCooperativeMatrixMulAddNV: out.debug << "MulAdd cooperative matrices NV"; break; case EOpIsHelperInvocation: out.debug << "IsHelperInvocation"; break; case EOpDebugPrintf: out.debug << "Debug printf"; break; -#ifndef GLSLANG_WEB + case EOpHitObjectTraceRayNV: out.debug << "HitObjectTraceRayNV"; break; + case EOpHitObjectTraceRayMotionNV: out.debug << "HitObjectTraceRayMotionNV"; break; + case EOpHitObjectRecordHitNV: out.debug << "HitObjectRecordHitNV"; break; + case EOpHitObjectRecordHitMotionNV: out.debug << "HitObjectRecordHitMotionNV"; break; + case EOpHitObjectRecordHitWithIndexNV: out.debug << "HitObjectRecordHitWithIndexNV"; break; + case EOpHitObjectRecordHitWithIndexMotionNV: out.debug << "HitObjectRecordHitWithIndexMotionNV"; break; + case EOpHitObjectRecordMissNV: out.debug << "HitObjectRecordMissNV"; break; + case EOpHitObjectRecordMissMotionNV: out.debug << "HitObjectRecordMissMotionNV"; break; + case EOpHitObjectRecordEmptyNV: out.debug << "HitObjectRecordEmptyNV"; break; + case EOpHitObjectExecuteShaderNV: out.debug << "HitObjectExecuteShaderNV"; break; + case EOpHitObjectIsEmptyNV: out.debug << "HitObjectIsEmptyNV"; break; + case EOpHitObjectIsMissNV: out.debug << "HitObjectIsMissNV"; break; + case EOpHitObjectIsHitNV: out.debug << "HitObjectIsHitNV"; break; + case EOpHitObjectGetRayTMinNV: out.debug << "HitObjectGetRayTMinNV"; break; + case EOpHitObjectGetRayTMaxNV: out.debug << "HitObjectGetRayTMaxNV"; break; + case EOpHitObjectGetObjectRayOriginNV: out.debug << "HitObjectGetObjectRayOriginNV"; break; + case EOpHitObjectGetObjectRayDirectionNV: out.debug << "HitObjectGetObjectRayDirectionNV"; break; + case EOpHitObjectGetWorldRayOriginNV: out.debug << "HitObjectGetWorldRayOriginNV"; break; + case EOpHitObjectGetWorldRayDirectionNV: out.debug << "HitObjectGetWorldRayDirectionNV"; break; + case EOpHitObjectGetObjectToWorldNV: out.debug << "HitObjectGetObjectToWorldNV"; break; + case EOpHitObjectGetWorldToObjectNV: out.debug << "HitObjectGetWorldToObjectNV"; break; + case EOpHitObjectGetInstanceCustomIndexNV: out.debug<< "HitObjectGetInstanceCustomIndexNV"; break; + case EOpHitObjectGetInstanceIdNV: out.debug << "HitObjectGetInstaneIdNV"; break; + case EOpHitObjectGetGeometryIndexNV: out.debug << "HitObjectGetGeometryIndexNV"; break; + case EOpHitObjectGetPrimitiveIndexNV: out.debug << "HitObjectGetPrimitiveIndexNV"; break; + case EOpHitObjectGetHitKindNV: out.debug << "HitObjectGetHitKindNV"; break; + case EOpHitObjectGetAttributesNV: out.debug << "HitObjectGetAttributesNV"; break; + case EOpHitObjectGetCurrentTimeNV: out.debug << "HitObjectGetCurrentTimeNV"; break; + case EOpHitObjectGetShaderBindingTableRecordIndexNV: out.debug << "HitObjectGetShaderBindingTableRecordIndexNV"; break; + case EOpHitObjectGetShaderRecordBufferHandleNV: out.debug << "HitObjectReadShaderRecordBufferHandleNV"; break; + case EOpReorderThreadNV: out.debug << "ReorderThreadNV"; break; + case EOpFetchMicroTriangleVertexPositionNV: out.debug << "MicroTriangleVertexPositionNV"; break; + case EOpFetchMicroTriangleVertexBarycentricNV: out.debug << "MicroTriangleVertexBarycentricNV"; break; + case EOpSpirvInst: out.debug << "spirv_instruction"; break; -#endif + case EOpStencilAttachmentReadEXT: out.debug << "stencilAttachmentReadEXT"; break; + case EOpDepthAttachmentReadEXT: out.debug << "depthAttachmentReadEXT"; break; default: out.debug.message(EPrefixError, "Bad aggregation op"); } - if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + if (node->getOp() != EOpSequence && node->getOp() != EOpScope && node->getOp() != EOpParameters) out.debug << " (" << node->getCompleteString() << ")"; out.debug << "\n"; @@ -1164,12 +1216,12 @@ bool TOutputTraverser::visitSelection(TVisit /* visit */, TIntermSelection* node // - shows all digits, no premature rounding static void OutputDouble(TInfoSink& out, double value, TOutputTraverser::EExtraOutput extra) { - if (IsInfinity(value)) { + if (std::isinf(value)) { if (value < 0) out.debug << "-1.#INF"; else out.debug << "+1.#INF"; - } else if (IsNan(value)) + } else if (std::isnan(value)) out.debug << "1.#IND"; else { const int maxSize = 340; @@ -1468,6 +1520,9 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) if (getSubgroupUniformControlFlow()) infoSink.debug << "subgroup_uniform_control_flow\n"; + if (getMaximallyReconverges()) + infoSink.debug << "maximally_reconverges\n"; + switch (language) { case EShLangVertex: break; @@ -1507,6 +1562,12 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) infoSink.debug << "using early_fragment_tests\n"; if (postDepthCoverage) infoSink.debug << "using post_depth_coverage\n"; + if (nonCoherentColorAttachmentReadEXT) + infoSink.debug << "using non_coherent_color_attachment_readEXT\n"; + if (nonCoherentDepthAttachmentReadEXT) + infoSink.debug << "using non_coherent_depth_attachment_readEXT\n"; + if (nonCoherentStencilAttachmentReadEXT) + infoSink.debug << "using non_coherent_stencil_attachment_readEXT\n"; if (depthLayout != EldNone) infoSink.debug << "using " << TQualifier::getLayoutDepthString(depthLayout) << "\n"; if (blendEquations != 0) { @@ -1522,12 +1583,12 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) infoSink.debug << "interlock ordering = " << TQualifier::getInterlockOrderingString(interlockOrdering) << "\n"; break; - case EShLangMeshNV: + case EShLangMesh: infoSink.debug << "max_vertices = " << vertices << "\n"; infoSink.debug << "max_primitives = " << primitives << "\n"; infoSink.debug << "output primitive = " << TQualifier::getGeometryString(outputPrimitive) << "\n"; - // Fall through - case EShLangTaskNV: + [[fallthrough]]; + case EShLangTask: // Fall through case EShLangCompute: infoSink.debug << "local_size = (" << localSize[0] << ", " << localSize[1] << ", " << localSize[2] << ")\n"; @@ -1547,7 +1608,7 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) break; } - if (treeRoot == 0 || ! tree) + if (treeRoot == nullptr || ! tree) return; TOutputTraverser it(infoSink); @@ -1557,5 +1618,3 @@ void TIntermediate::output(TInfoSink& infoSink, bool tree) } } // end namespace glslang - -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp b/src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp index a3c53f505..5e94a9e8d 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/iomapper.cpp @@ -33,8 +33,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #include "../Include/Common.h" #include "../Include/InfoSink.h" #include "../Include/Types.h" @@ -87,7 +85,7 @@ public: addGlobalReference(base->getAccessName()); if (target) { - TVarEntryInfo ent = {base->getId(), base, ! traverseAll}; + TVarEntryInfo ent = {base->getId(), base, ! traverseAll, {}, {}, {}, {}, {}, {}, {}}; ent.stage = intermediate.getStage(); TVarLiveMap::iterator at = target->find( ent.symbol->getAccessName()); // std::lower_bound(target->begin(), target->end(), ent, TVarEntryInfo::TOrderById()); @@ -126,7 +124,7 @@ public: else return; - TVarEntryInfo ent = { base->getId() }; + TVarEntryInfo ent = { base->getId(), {}, {}, {}, {}, {}, {}, {}, {}, {} }; // Fix a defect, when block has no instance name, we need to find its block name TVarLiveMap::const_iterator at = source->find(base->getAccessName()); if (at == source->end()) @@ -145,6 +143,8 @@ public: base->getWritableType().getQualifier().layoutComponent = at->second.newComponent; if (at->second.newIndex != -1) base->getWritableType().getQualifier().layoutIndex = at->second.newIndex; + if (at->second.upgradedToPushConstant) + base->getWritableType().getQualifier().layoutPushConstant = true; } private: @@ -203,11 +203,7 @@ struct TResolverUniformAdaptor { inline void operator()(std::pair& entKey) { TVarEntryInfo& ent = entKey.second; - ent.newLocation = -1; - ent.newComponent = -1; - ent.newBinding = -1; - ent.newSet = -1; - ent.newIndex = -1; + ent.clearNewAssignments(); const bool isValid = resolver.validateBinding(stage, ent); if (isValid) { resolver.resolveSet(ent.stage, ent); @@ -281,11 +277,7 @@ struct TResolverInOutAdaptor { inline void operator()(std::pair& entKey) { TVarEntryInfo& ent = entKey.second; - ent.newLocation = -1; - ent.newComponent = -1; - ent.newBinding = -1; - ent.newSet = -1; - ent.newIndex = -1; + ent.clearNewAssignments(); const bool isValid = resolver.validateInOut(ent.stage, ent); if (isValid) { resolver.resolveInOutLocation(stage, ent); @@ -874,7 +866,7 @@ int TDefaultIoResolverBase::resolveInOutLocation(EShLanguage stage, TVarEntryInf } // no locations added if already present, a built-in variable, or a variable with SPIR-V decorate - if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getQualifier().hasSprivDecorate()) { + if (type.getQualifier().hasLocation() || type.isBuiltIn() || type.getQualifier().hasSpirvDecorate()) { return ent.newLocation = -1; } @@ -961,7 +953,7 @@ int TDefaultGlslIoResolver::resolveInOutLocation(EShLanguage stage, TVarEntryInf return ent.newLocation = type.getQualifier().layoutLocation; } // no locations added if already present, a built-in variable, or a variable with SPIR-V decorate - if (type.isBuiltIn() || type.getQualifier().hasSprivDecorate()) { + if (type.isBuiltIn() || type.getQualifier().hasSpirvDecorate()) { return ent.newLocation = -1; } // no locations on blocks of built-in variables @@ -1670,31 +1662,42 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) { if (size <= int(autoPushConstantMaxSize)) { qualifier.setBlockStorage(EbsPushConstant); qualifier.layoutPacking = autoPushConstantBlockPacking; + // Push constants don't have set/binding etc. decorations, remove those. + qualifier.layoutSet = TQualifier::layoutSetEnd; + at->second.clearNewAssignments(); + upgraded = true; } } } - // If it's been upgraded to push_constant, then remove it from the uniformVector + // If it's been upgraded to push_constant, then set the flag so when its traversed + // in the next for loop, all references to this symbol will get their flag changed. // so it doesn't get a set/binding assigned to it. if (upgraded) { - auto at = std::find_if(uniformVector.begin(), uniformVector.end(), - [this](const TVarLivePair& p) { return p.first == autoPushConstantBlockName; }); - if (at != uniformVector.end()) - uniformVector.erase(at); + std::for_each(uniformVector.begin(), uniformVector.end(), + [this](TVarLivePair& p) { + if (p.first == autoPushConstantBlockName) { + p.second.upgradedToPushConstant = true; + } + }); } } for (size_t stage = 0; stage < EShLangCount; stage++) { if (intermediates[stage] != nullptr) { // traverse each stage, set new location to each input/output and unifom symbol, set new binding to - // ubo, ssbo and opaque symbols + // ubo, ssbo and opaque symbols. Assign push_constant upgrades as well. TVarLiveMap** pUniformVarMap = uniformResolve.uniformVarMap; std::for_each(uniformVector.begin(), uniformVector.end(), [pUniformVarMap, stage](TVarLivePair p) { auto at = pUniformVarMap[stage]->find(p.second.symbol->getAccessName()); if (at != pUniformVarMap[stage]->end() && at->second.id == p.second.id){ - int resolvedBinding = at->second.newBinding; - at->second = p.second; - if (resolvedBinding > 0) - at->second.newBinding = resolvedBinding; + if (p.second.upgradedToPushConstant) { + at->second.upgradedToPushConstant = true; + } else { + int resolvedBinding = at->second.newBinding; + at->second = p.second; + if (resolvedBinding > 0) + at->second.newBinding = resolvedBinding; + } } }); TVarSetTraverser iter_iomap(*intermediates[stage], *inVarMaps[stage], *outVarMaps[stage], @@ -1709,5 +1712,3 @@ bool TGlslIoMapper::doMap(TIoMapResolver* resolver, TInfoSink& infoSink) { } } // end namespace glslang - -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/src/libraries/glslang/glslang/MachineIndependent/iomapper.h b/src/libraries/glslang/glslang/MachineIndependent/iomapper.h index c43864e3a..35babbce1 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/iomapper.h +++ b/src/libraries/glslang/glslang/MachineIndependent/iomapper.h @@ -33,8 +33,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #ifndef _IOMAPPER_INCLUDED #define _IOMAPPER_INCLUDED @@ -55,12 +53,23 @@ struct TVarEntryInfo { long long id; TIntermSymbol* symbol; bool live; + bool upgradedToPushConstant; int newBinding; int newSet; int newLocation; int newComponent; int newIndex; EShLanguage stage; + + void clearNewAssignments() { + upgradedToPushConstant = false; + newBinding = -1; + newSet = -1; + newLocation = -1; + newComponent = -1; + newIndex = -1; + } + struct TOrderById { inline bool operator()(const TVarEntryInfo& l, const TVarEntryInfo& r) { return l.id < r.id; } }; @@ -348,5 +357,3 @@ private: } // end namespace glslang #endif // _IOMAPPER_INCLUDED - -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/src/libraries/glslang/glslang/MachineIndependent/limits.cpp b/src/libraries/glslang/glslang/MachineIndependent/limits.cpp index 391570579..4404beca4 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/limits.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/limits.cpp @@ -187,14 +187,12 @@ bool TIndexTraverser::visitAggregate(TVisit /* visit */, TIntermAggregate* node) // void TParseContext::constantIndexExpressionCheck(TIntermNode* index) { -#ifndef GLSLANG_WEB TIndexTraverser it(inductiveLoopIds); index->traverse(&it); if (it.bad) error(it.badLoc, "Non-constant-index-expression", "limitations", ""); -#endif } } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp b/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp index 1fc7d1f14..1bd6678b1 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/linkValidate.cpp @@ -55,23 +55,25 @@ namespace glslang { // // Link-time error emitter. // -void TIntermediate::error(TInfoSink& infoSink, const char* message) +void TIntermediate::error(TInfoSink& infoSink, const char* message, EShLanguage unitStage) { -#ifndef GLSLANG_WEB infoSink.info.prefix(EPrefixError); - infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; -#endif + if (unitStage < EShLangCount) + infoSink.info << "Linking " << StageName(getStage()) << " and " << StageName(unitStage) << " stages: " << message << "\n"; + else + infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; ++numErrors; } // Link-time warning. -void TIntermediate::warn(TInfoSink& infoSink, const char* message) +void TIntermediate::warn(TInfoSink& infoSink, const char* message, EShLanguage unitStage) { -#ifndef GLSLANG_WEB infoSink.info.prefix(EPrefixWarning); - infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; -#endif + if (unitStage < EShLangCount) + infoSink.info << "Linking " << StageName(language) << " and " << StageName(unitStage) << " stages: " << message << "\n"; + else + infoSink.info << "Linking " << StageName(language) << " stage: " << message << "\n"; } // TODO: 4.4 offset/align: "Two blocks linked together in the same program with the same block @@ -83,11 +85,9 @@ void TIntermediate::warn(TInfoSink& infoSink, const char* message) // void TIntermediate::merge(TInfoSink& infoSink, TIntermediate& unit) { -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) mergeCallGraphs(infoSink, unit); mergeModes(infoSink, unit); mergeTrees(infoSink, unit); -#endif } // @@ -114,7 +114,7 @@ void TIntermediate::mergeUniformObjects(TInfoSink& infoSink, TIntermediate& unit } // -// do error checking on the shader boundary in / out vars +// do error checking on the shader boundary in / out vars // void TIntermediate::checkStageIO(TInfoSink& infoSink, TIntermediate& unit) { if (unit.treeRoot == nullptr || treeRoot == nullptr) @@ -155,8 +155,6 @@ void TIntermediate::mergeCallGraphs(TInfoSink& infoSink, TIntermediate& unit) callGraph.insert(callGraph.end(), unit.callGraph.begin(), unit.callGraph.end()); } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #define MERGE_MAX(member) member = std::max(member, unit.member) #define MERGE_TRUE(member) if (unit.member) member = unit.member; @@ -206,7 +204,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) if (vertices == TQualifier::layoutNotSet) vertices = unit.vertices; else if (unit.vertices != TQualifier::layoutNotSet && vertices != unit.vertices) { - if (language == EShLangGeometry || language == EShLangMeshNV) + if (language == EShLangGeometry || language == EShLangMesh) error(infoSink, "Contradictory layout max_vertices values"); else if (language == EShLangTessControl) error(infoSink, "Contradictory layout vertices values"); @@ -216,7 +214,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) if (primitives == TQualifier::layoutNotSet) primitives = unit.primitives; else if (primitives != unit.primitives) { - if (language == EShLangMeshNV) + if (language == EShLangMesh) error(infoSink, "Contradictory layout max_primitives values"); else assert(0); @@ -265,6 +263,9 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) MERGE_TRUE(earlyFragmentTests); MERGE_TRUE(postDepthCoverage); + MERGE_TRUE(nonCoherentColorAttachmentReadEXT); + MERGE_TRUE(nonCoherentDepthAttachmentReadEXT); + MERGE_TRUE(nonCoherentStencilAttachmentReadEXT); if (depthLayout == EldNone) depthLayout = unit.depthLayout; @@ -313,6 +314,7 @@ void TIntermediate::mergeModes(TInfoSink& infoSink, TIntermediate& unit) MERGE_TRUE(autoMapLocations); MERGE_TRUE(invertY); MERGE_TRUE(dxPositionW); + MERGE_TRUE(debugInfo); MERGE_TRUE(flattenUniformArrays); MERGE_TRUE(useUnknownFormat); MERGE_TRUE(hlslOffsets); @@ -371,8 +373,6 @@ void TIntermediate::mergeTrees(TInfoSink& infoSink, TIntermediate& unit) ioAccessed.insert(unit.ioAccessed.begin(), unit.ioAccessed.end()); } -#endif - static const TString& getNameForIdMap(TIntermSymbol* symbol) { TShaderInterface si = symbol->getType().getShaderInterface(); @@ -580,9 +580,6 @@ void TIntermediate::mergeGlobalUniformBlocks(TInfoSink& infoSink, TIntermediate& } void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* block, TIntermSymbol* unitBlock, TIntermediate* unit) { - if (block->getType() == unitBlock->getType()) { - return; - } if (block->getType().getTypeName() != unitBlock->getType().getTypeName() || block->getType().getBasicType() != unitBlock->getType().getBasicType() || @@ -629,44 +626,42 @@ void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* bl } } - TType unitType; - unitType.shallowCopy(unitBlock->getType()); - // update symbol node in unit tree, // and other nodes that may reference it class TMergeBlockTraverser : public TIntermTraverser { public: - TMergeBlockTraverser(const glslang::TType &type, const glslang::TType& unitType, - glslang::TIntermediate& unit, - const std::map& memberIdxUpdates) : - newType(type), unitType(unitType), unit(unit), memberIndexUpdates(memberIdxUpdates) - { } - virtual ~TMergeBlockTraverser() { } + TMergeBlockTraverser(const TIntermSymbol* newSym) + : newSymbol(newSym), newType(nullptr), unit(nullptr), memberIndexUpdates(nullptr) + { + } + TMergeBlockTraverser(const TIntermSymbol* newSym, const glslang::TType* unitType, glslang::TIntermediate* unit, + const std::map* memberIdxUpdates) + : TIntermTraverser(false, true), newSymbol(newSym), newType(unitType), unit(unit), memberIndexUpdates(memberIdxUpdates) + { + } + virtual ~TMergeBlockTraverser() {} - const glslang::TType& newType; // type with modifications - const glslang::TType& unitType; // copy of original type - glslang::TIntermediate& unit; // intermediate that is being updated - const std::map& memberIndexUpdates; + const TIntermSymbol* newSymbol; + const glslang::TType* newType; // shallow copy of the new type + glslang::TIntermediate* unit; // intermediate that is being updated + const std::map* memberIndexUpdates; virtual void visitSymbol(TIntermSymbol* symbol) { - glslang::TType& symType = symbol->getWritableType(); - - if (symType == unitType) { - // each symbol node has a local copy of the unitType - // if merging involves changing properties that aren't shared objects - // they should be updated in all instances - - // e.g. the struct list is a ptr to an object, so it can be updated - // once, outside the traverser - //*symType.getWritableStruct() = *newType.getStruct(); + if (newSymbol->getAccessName() == symbol->getAccessName() && + newSymbol->getQualifier().getBlockStorage() == symbol->getQualifier().getBlockStorage()) { + // Each symbol node may have a local copy of the block structure. + // Update those structures to match the new one post-merge + *(symbol->getWritableType().getWritableStruct()) = *(newSymbol->getType().getStruct()); } - } virtual bool visitBinary(TVisit, glslang::TIntermBinary* node) { - if (node->getOp() == EOpIndexDirectStruct && node->getLeft()->getType() == unitType) { + if (!unit || !newType || !memberIndexUpdates || memberIndexUpdates->empty()) + return true; + + if (node->getOp() == EOpIndexDirectStruct && node->getLeft()->getType() == *newType) { // this is a dereference to a member of the block since the // member list changed, need to update this to point to the // right index @@ -674,8 +669,8 @@ void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* bl glslang::TIntermConstantUnion* constNode = node->getRight()->getAsConstantUnion(); unsigned int memberIdx = constNode->getConstArray()[0].getUConst(); - unsigned int newIdx = memberIndexUpdates.at(memberIdx); - TIntermTyped* newConstNode = unit.addConstantUnion(newIdx, node->getRight()->getLoc()); + unsigned int newIdx = memberIndexUpdates->at(memberIdx); + TIntermTyped* newConstNode = unit->addConstantUnion(newIdx, node->getRight()->getLoc()); node->setRight(newConstNode); delete constNode; @@ -684,10 +679,20 @@ void TIntermediate::mergeBlockDefinitions(TInfoSink& infoSink, TIntermSymbol* bl } return true; } - } finalLinkTraverser(block->getType(), unitType, *unit, memberIndexUpdates); + }; - // update the tree to use the new type - unit->getTreeRoot()->traverse(&finalLinkTraverser); + // 'this' may have symbols that are using the old block structure, so traverse the tree to update those + // in 'visitSymbol' + TMergeBlockTraverser finalLinkTraverser(block); + getTreeRoot()->traverse(&finalLinkTraverser); + + // The 'unit' intermediate needs the block structures update, but also structure entry indices + // may have changed from the old block to the new one that it was merged into, so update those + // in 'visitBinary' + TType newType; + newType.shallowCopy(block->getType()); + TMergeBlockTraverser unitFinalLinkTraverser(block, &newType, unit, &memberIndexUpdates); + unit->getTreeRoot()->traverse(&unitFinalLinkTraverser); // update the member list (*unitMemberList) = (*memberList); @@ -737,6 +742,21 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin symbol->getQualifier().layoutLocation = unitSymbol->getQualifier().layoutLocation; } + // Update implicit array sizes + if (symbol->getWritableType().isImplicitlySizedArray() && unitSymbol->getType().isImplicitlySizedArray()) { + if (unitSymbol->getType().getImplicitArraySize() > symbol->getType().getImplicitArraySize()){ + symbol->getWritableType().updateImplicitArraySize(unitSymbol->getType().getImplicitArraySize()); + } + } + else if (symbol->getWritableType().isImplicitlySizedArray() && unitSymbol->getType().isSizedArray()) { + if (symbol->getWritableType().getImplicitArraySize() > unitSymbol->getType().getOuterArraySize()) + error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders."); + } + else if (unitSymbol->getType().isImplicitlySizedArray() && symbol->getWritableType().isSizedArray()) { + if (unitSymbol->getType().getImplicitArraySize() > symbol->getWritableType().getOuterArraySize()) + error(infoSink, "Implicit size of unsized array doesn't match same symbol among multiple shaders."); + } + // Update implicit array sizes mergeImplicitArraySizes(symbol->getWritableType(), unitSymbol->getType()); @@ -747,6 +767,19 @@ void TIntermediate::mergeLinkerObjects(TInfoSink& infoSink, TIntermSequence& lin else if (symbol->getQualifier().isPushConstant() && unitSymbol->getQualifier().isPushConstant() && getStage() == unitStage) error(infoSink, "Only one push_constant block is allowed per stage"); } + + // Check conflicts between preset primitives and sizes of I/O variables among multiple geometry shaders + if (language == EShLangGeometry && unitStage == EShLangGeometry) + { + TIntermSymbol* unitSymbol = unitLinkerObjects[unitLinkObj]->getAsSymbolNode(); + if (unitSymbol->isArray() && unitSymbol->getQualifier().storage == EvqVaryingIn && unitSymbol->getQualifier().builtIn == EbvNone) + if ((unitSymbol->getArraySizes()->isImplicitlySized() && + unitSymbol->getArraySizes()->getImplicitSize() != TQualifier::mapGeometryToSize(getInputPrimitive())) || + (! unitSymbol->getArraySizes()->isImplicitlySized() && + unitSymbol->getArraySizes()->getDimSize(0) != TQualifier::mapGeometryToSize(getInputPrimitive()))) + error(infoSink, "Not all array sizes match across all geometry shaders in the program"); + } + if (merge) { linkerObjects.push_back(unitLinkerObjects[unitLinkObj]); @@ -816,9 +849,12 @@ void TIntermediate::mergeImplicitArraySizes(TType& type, const TType& unitType) // void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& symbol, const TIntermSymbol& unitSymbol, EShLanguage unitStage) { -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) bool crossStage = getStage() != unitStage; bool writeTypeComparison = false; + bool errorReported = false; + bool printQualifiers = false; + bool printPrecision = false; + bool printType = false; // Types have to match { @@ -847,14 +883,52 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy else { arraysMatch = symbol.getType().sameArrayness(unitSymbol.getType()) || (symbol.getType().isArray() && unitSymbol.getType().isArray() && - (symbol.getType().isUnsizedArray() || unitSymbol.getType().isUnsizedArray())); + (symbol.getType().isImplicitlySizedArray() || unitSymbol.getType().isImplicitlySizedArray() || + symbol.getType().isUnsizedArray() || unitSymbol.getType().isUnsizedArray())); } - if (!symbol.getType().sameElementType(unitSymbol.getType()) || - !symbol.getType().sameTypeParameters(unitSymbol.getType()) || - !arraysMatch ) { + int lpidx = -1; + int rpidx = -1; + if (!symbol.getType().sameElementType(unitSymbol.getType(), &lpidx, &rpidx)) { + if (lpidx >= 0 && rpidx >= 0) { + error(infoSink, "Member names and types must match:", unitStage); + infoSink.info << " Block: " << symbol.getType().getTypeName() << "\n"; + infoSink.info << " " << StageName(getStage()) << " stage: \"" + << (*symbol.getType().getStruct())[lpidx].type->getCompleteString(true, false, false, true, + (*symbol.getType().getStruct())[lpidx].type->getFieldName()) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: \"" + << (*unitSymbol.getType().getStruct())[rpidx].type->getCompleteString(true, false, false, true, + (*unitSymbol.getType().getStruct())[rpidx].type->getFieldName()) << "\"\n"; + errorReported = true; + } else if (lpidx >= 0 && rpidx == -1) { + TString errmsg = StageName(getStage()); + errmsg.append(" block member has no corresponding member in ").append(StageName(unitStage)).append(" block:"); + error(infoSink, errmsg.c_str(), unitStage); + infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: " + << (*symbol.getType().getStruct())[lpidx].type->getFieldName() << "\n"; + infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: n/a \n"; + errorReported = true; + } else if (lpidx == -1 && rpidx >= 0) { + TString errmsg = StageName(unitStage); + errmsg.append(" block member has no corresponding member in ").append(StageName(getStage())).append(" block:"); + error(infoSink, errmsg.c_str(), unitStage); + infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: " + << (*unitSymbol.getType().getStruct())[rpidx].type->getFieldName() << "\n"; + infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: n/a \n"; + errorReported = true; + } else { + error(infoSink, "Types must match:", unitStage); + writeTypeComparison = true; + printType = true; + } + } else if (!arraysMatch) { + error(infoSink, "Array sizes must be compatible:", unitStage); writeTypeComparison = true; - error(infoSink, "Types must match:"); + printType = true; + } else if (!symbol.getType().sameTypeParameters(unitSymbol.getType())) { + error(infoSink, "Type parameters must match:", unitStage); + writeTypeComparison = true; + printType = true; } } @@ -875,13 +949,35 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy } const TQualifier& qualifier = (*symbol.getType().getStruct())[li].type->getQualifier(); const TQualifier & unitQualifier = (*unitSymbol.getType().getStruct())[ri].type->getQualifier(); - if (qualifier.layoutMatrix != unitQualifier.layoutMatrix || - qualifier.layoutOffset != unitQualifier.layoutOffset || - qualifier.layoutAlign != unitQualifier.layoutAlign || - qualifier.layoutLocation != unitQualifier.layoutLocation || - qualifier.layoutComponent != unitQualifier.layoutComponent) { - error(infoSink, "Interface block member layout qualifiers must match:"); - writeTypeComparison = true; + bool layoutQualifierError = false; + if (qualifier.layoutMatrix != unitQualifier.layoutMatrix) { + error(infoSink, "Interface block member layout matrix qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (qualifier.layoutOffset != unitQualifier.layoutOffset) { + error(infoSink, "Interface block member layout offset qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (qualifier.layoutAlign != unitQualifier.layoutAlign) { + error(infoSink, "Interface block member layout align qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (qualifier.layoutLocation != unitQualifier.layoutLocation) { + error(infoSink, "Interface block member layout location qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (qualifier.layoutComponent != unitQualifier.layoutComponent) { + error(infoSink, "Interface block member layout component qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (layoutQualifierError) { + infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << ", Member: " + << (*symbol.getType().getStruct())[li].type->getFieldName() << " \"" + << (*symbol.getType().getStruct())[li].type->getCompleteString(true, true, false, false) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << ", Member: " + << (*unitSymbol.getType().getStruct())[ri].type->getFieldName() << " \"" + << (*unitSymbol.getType().getStruct())[ri].type->getCompleteString(true, true, false, false) << "\"\n"; + errorReported = true; } ++li; ++ri; @@ -895,8 +991,9 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy // Qualifiers have to (almost) match // Storage... if (!isInOut && symbol.getQualifier().storage != unitSymbol.getQualifier().storage) { - error(infoSink, "Storage qualifiers must match:"); + error(infoSink, "Storage qualifiers must match:", unitStage); writeTypeComparison = true; + printQualifiers = true; } // Uniform and buffer blocks must either both have an instance name, or @@ -904,37 +1001,40 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy if (symbol.getQualifier().isUniformOrBuffer() && (IsAnonymous(symbol.getName()) != IsAnonymous(unitSymbol.getName()))) { error(infoSink, "Matched Uniform or Storage blocks must all be anonymous," - " or all be named:"); + " or all be named:", unitStage); writeTypeComparison = true; } if (symbol.getQualifier().storage == unitSymbol.getQualifier().storage && (IsAnonymous(symbol.getName()) != IsAnonymous(unitSymbol.getName()) || (!IsAnonymous(symbol.getName()) && symbol.getName() != unitSymbol.getName()))) { - warn(infoSink, "Matched shader interfaces are using different instance names."); + warn(infoSink, "Matched shader interfaces are using different instance names.", unitStage); writeTypeComparison = true; } // Precision... if (!isInOut && symbol.getQualifier().precision != unitSymbol.getQualifier().precision) { - error(infoSink, "Precision qualifiers must match:"); + error(infoSink, "Precision qualifiers must match:", unitStage); writeTypeComparison = true; + printPrecision = true; } // Invariance... if (! crossStage && symbol.getQualifier().invariant != unitSymbol.getQualifier().invariant) { - error(infoSink, "Presence of invariant qualifier must match:"); + error(infoSink, "Presence of invariant qualifier must match:", unitStage); writeTypeComparison = true; + printQualifiers = true; } // Precise... if (! crossStage && symbol.getQualifier().isNoContraction() != unitSymbol.getQualifier().isNoContraction()) { - error(infoSink, "Presence of precise qualifier must match:"); + error(infoSink, "Presence of precise qualifier must match:", unitStage); writeTypeComparison = true; + printPrecision = true; } // Auxiliary and interpolation... - // "interpolation qualification (e.g., flat) and auxiliary qualification (e.g. centroid) may differ. + // "interpolation qualification (e.g., flat) and auxiliary qualification (e.g. centroid) may differ. // These mismatches are allowed between any pair of stages ... // those provided in the fragment shader supersede those provided in previous stages." if (!crossStage && @@ -944,59 +1044,138 @@ void TIntermediate::mergeErrorCheck(TInfoSink& infoSink, const TIntermSymbol& sy symbol.getQualifier().isSample()!= unitSymbol.getQualifier().isSample() || symbol.getQualifier().isPatch() != unitSymbol.getQualifier().isPatch() || symbol.getQualifier().isNonPerspective() != unitSymbol.getQualifier().isNonPerspective())) { - error(infoSink, "Interpolation and auxiliary storage qualifiers must match:"); + error(infoSink, "Interpolation and auxiliary storage qualifiers must match:", unitStage); writeTypeComparison = true; + printQualifiers = true; } // Memory... - if (symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent || - symbol.getQualifier().devicecoherent != unitSymbol.getQualifier().devicecoherent || - symbol.getQualifier().queuefamilycoherent != unitSymbol.getQualifier().queuefamilycoherent || - symbol.getQualifier().workgroupcoherent != unitSymbol.getQualifier().workgroupcoherent || - symbol.getQualifier().subgroupcoherent != unitSymbol.getQualifier().subgroupcoherent || - symbol.getQualifier().shadercallcoherent!= unitSymbol.getQualifier().shadercallcoherent || - symbol.getQualifier().nonprivate != unitSymbol.getQualifier().nonprivate || - symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil || - symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict || - symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly || - symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) { - error(infoSink, "Memory qualifiers must match:"); - writeTypeComparison = true; + bool memoryQualifierError = false; + if (symbol.getQualifier().coherent != unitSymbol.getQualifier().coherent) { + error(infoSink, "Memory coherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().devicecoherent != unitSymbol.getQualifier().devicecoherent) { + error(infoSink, "Memory devicecoherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().queuefamilycoherent != unitSymbol.getQualifier().queuefamilycoherent) { + error(infoSink, "Memory queuefamilycoherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().workgroupcoherent != unitSymbol.getQualifier().workgroupcoherent) { + error(infoSink, "Memory workgroupcoherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().subgroupcoherent != unitSymbol.getQualifier().subgroupcoherent) { + error(infoSink, "Memory subgroupcoherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().shadercallcoherent != unitSymbol.getQualifier().shadercallcoherent) { + error(infoSink, "Memory shadercallcoherent qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().nonprivate != unitSymbol.getQualifier().nonprivate) { + error(infoSink, "Memory nonprivate qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().volatil != unitSymbol.getQualifier().volatil) { + error(infoSink, "Memory volatil qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().restrict != unitSymbol.getQualifier().restrict) { + error(infoSink, "Memory restrict qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().readonly != unitSymbol.getQualifier().readonly) { + error(infoSink, "Memory readonly qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (symbol.getQualifier().writeonly != unitSymbol.getQualifier().writeonly) { + error(infoSink, "Memory writeonly qualifier must match:", unitStage); + memoryQualifierError = true; + } + if (memoryQualifierError) { + writeTypeComparison = true; + printQualifiers = true; } // Layouts... // TODO: 4.4 enhanced layouts: Generalize to include offset/align: current spec // requires separate user-supplied offset from actual computed offset, but // current implementation only has one offset. - if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix || - symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking || - (symbol.getQualifier().hasLocation() && unitSymbol.getQualifier().hasLocation() && symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation) || - symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent || - symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex || - (symbol.getQualifier().hasBinding() && unitSymbol.getQualifier().hasBinding() && symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding) || - (symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset))) { - error(infoSink, "Layout qualification must match:"); + bool layoutQualifierError = false; + if (symbol.getQualifier().layoutMatrix != unitSymbol.getQualifier().layoutMatrix) { + error(infoSink, "Layout matrix qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().layoutPacking != unitSymbol.getQualifier().layoutPacking) { + error(infoSink, "Layout packing qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().hasLocation() && unitSymbol.getQualifier().hasLocation() && symbol.getQualifier().layoutLocation != unitSymbol.getQualifier().layoutLocation) { + error(infoSink, "Layout location qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().layoutComponent != unitSymbol.getQualifier().layoutComponent) { + error(infoSink, "Layout component qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().layoutIndex != unitSymbol.getQualifier().layoutIndex) { + error(infoSink, "Layout index qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().hasBinding() && unitSymbol.getQualifier().hasBinding() && symbol.getQualifier().layoutBinding != unitSymbol.getQualifier().layoutBinding) { + error(infoSink, "Layout binding qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (symbol.getQualifier().hasBinding() && (symbol.getQualifier().layoutOffset != unitSymbol.getQualifier().layoutOffset)) { + error(infoSink, "Layout offset qualifier must match:", unitStage); + layoutQualifierError = true; + } + if (layoutQualifierError) { writeTypeComparison = true; + printQualifiers = true; } // Initializers have to match, if both are present, and if we don't already know the types don't match - if (! writeTypeComparison) { + if (! writeTypeComparison && ! errorReported) { if (! symbol.getConstArray().empty() && ! unitSymbol.getConstArray().empty()) { if (symbol.getConstArray() != unitSymbol.getConstArray()) { - error(infoSink, "Initializers must match:"); + error(infoSink, "Initializers must match:", unitStage); infoSink.info << " " << symbol.getName() << "\n"; } } } if (writeTypeComparison) { - infoSink.info << " " << symbol.getName() << ": \"" << symbol.getType().getCompleteString() << "\" versus "; - if (symbol.getName() != unitSymbol.getName()) - infoSink.info << unitSymbol.getName() << ": "; - - infoSink.info << "\"" << unitSymbol.getType().getCompleteString() << "\"\n"; + if (symbol.getType().getBasicType() == EbtBlock && unitSymbol.getType().getBasicType() == EbtBlock && + symbol.getType().getStruct() && unitSymbol.getType().getStruct()) { + if (printType) { + infoSink.info << " " << StageName(getStage()) << " stage: \"" << symbol.getType().getCompleteString(true, printQualifiers, printPrecision, + printType, symbol.getName(), symbol.getType().getTypeName()) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: \"" << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, + printType, unitSymbol.getName(), unitSymbol.getType().getTypeName()) << "\"\n"; + } else { + infoSink.info << " " << StageName(getStage()) << " stage: Block: " << symbol.getType().getTypeName() << " Instance: " << symbol.getName() + << ": \"" << symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: Block: " << unitSymbol.getType().getTypeName() << " Instance: " << unitSymbol.getName() + << ": \"" << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n"; + } + } else { + if (printType) { + infoSink.info << " " << StageName(getStage()) << " stage: \"" + << symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType, symbol.getName()) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: \"" + << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType, unitSymbol.getName()) << "\"\n"; + } else { + infoSink.info << " " << StageName(getStage()) << " stage: " << symbol.getName() << " \"" + << symbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n"; + infoSink.info << " " << StageName(unitStage) << " stage: " << unitSymbol.getName() << " \"" + << unitSymbol.getType().getCompleteString(true, printQualifiers, printPrecision, printType) << "\"\n"; + } + } } -#endif } void TIntermediate::sharedBlockCheck(TInfoSink& infoSink) @@ -1043,7 +1222,6 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) // overlap/alias/missing I/O, etc. inOutLocationCheck(infoSink); -#ifndef GLSLANG_WEB if (getNumPushConstants() > 1) error(infoSink, "Only one push_constant block is allowed per stage"); @@ -1136,8 +1314,8 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); break; case EShLangFragment: - // for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in - // ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage + // for GL_ARB_post_depth_coverage, EarlyFragmentTest is set automatically in + // ParseHelper.cpp. So if we reach here, this must be GL_EXT_post_depth_coverage // requiring explicit early_fragment_tests if (getPostDepthCoverage() && !getEarlyFragmentTests()) error(infoSink, "post_depth_coverage requires early_fragment_tests"); @@ -1154,7 +1332,7 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) if (numShaderRecordBlocks > 1) error(infoSink, "Only one shaderRecordNV buffer block is allowed per stage"); break; - case EShLangMeshNV: + case EShLangMesh: // NV_mesh_shader doesn't allow use of both single-view and per-view builtins. if (inIoAccessed("gl_Position") && inIoAccessed("gl_PositionPerViewNV")) error(infoSink, "Can only use one of gl_Position or gl_PositionPerViewNV"); @@ -1172,10 +1350,12 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) error(infoSink, "At least one shader must specify a layout(max_vertices = value)"); if (primitives == TQualifier::layoutNotSet) error(infoSink, "At least one shader must specify a layout(max_primitives = value)"); - // fall through - case EShLangTaskNV: + [[fallthrough]]; + case EShLangTask: if (numTaskNVBlocks > 1) error(infoSink, "Only one taskNV interface block is allowed per shader"); + if (numTaskEXTPayloads > 1) + error(infoSink, "Only single variable of type taskPayloadSharedEXT is allowed per shader"); sharedBlockCheck(infoSink); break; default: @@ -1199,7 +1379,6 @@ void TIntermediate::finalCheck(TInfoSink& infoSink, bool keepUncalled) } finalLinkTraverser; treeRoot->traverse(&finalLinkTraverser); -#endif } // @@ -1222,7 +1401,7 @@ void TIntermediate::checkCallGraphCycles(TInfoSink& infoSink) TCall* newRoot; do { // See if we have unvisited parts of the graph. - newRoot = 0; + newRoot = nullptr; for (TGraph::iterator call = callGraph.begin(); call != callGraph.end(); ++call) { if (! call->visited) { newRoot = &(*call); @@ -1356,7 +1535,10 @@ void TIntermediate::checkCallGraphBodies(TInfoSink& infoSink, bool keepUncalled) if (! keepUncalled) { for (int f = 0; f < (int)functionSequence.size(); ++f) { if (! reachable[f]) + { + resetTopLevelUncalledStatus(functionSequence[f]->getAsAggregate()->getName()); functionSequence[f] = nullptr; + } } functionSequence.erase(std::remove(functionSequence.begin(), functionSequence.end(), nullptr), functionSequence.end()); } @@ -1424,7 +1606,7 @@ bool TIntermediate::userOutputUsed() const return found; } -// Accumulate locations used for inputs, outputs, and uniforms, payload and callable data +// Accumulate locations used for inputs, outputs, and uniforms, payload, callable data, and tileImageEXT // and check for collisions as the accumulation is done. // // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. @@ -1437,7 +1619,6 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ typeCollision = false; int set; - int setRT; if (qualifier.isPipeInput()) set = 0; else if (qualifier.isPipeOutput()) @@ -1446,10 +1627,14 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ set = 2; else if (qualifier.storage == EvqBuffer) set = 3; + else if (qualifier.storage == EvqTileImageEXT) + set = 4; else if (qualifier.isAnyPayload()) - setRT = 0; + set = 0; else if (qualifier.isAnyCallable()) - setRT = 1; + set = 1; + else if (qualifier.isHitObjectAttrNV()) + set = 2; else return -1; @@ -1488,13 +1673,14 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ // For raytracing IO (payloads and callabledata) each declaration occupies a single // slot irrespective of type. int collision = -1; // no collision -#ifndef GLSLANG_WEB - if (qualifier.isAnyPayload() || qualifier.isAnyCallable()) { + if (qualifier.isAnyPayload() || qualifier.isAnyCallable() || qualifier.isHitObjectAttrNV()) { TRange range(qualifier.layoutLocation, qualifier.layoutLocation); - collision = checkLocationRT(setRT, qualifier.layoutLocation); + collision = checkLocationRT(set, qualifier.layoutLocation); if (collision < 0) - usedIoRT[setRT].push_back(range); - } else if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && + usedIoRT[set].push_back(range); + return collision; + } + if (size == 2 && type.getBasicType() == EbtDouble && type.getVectorSize() == 3 && (qualifier.isPipeInput() || qualifier.isPipeOutput())) { // Dealing with dvec3 in/out split across two locations. // Need two io-ranges. @@ -1520,32 +1706,34 @@ int TIntermediate::addUsedLocation(const TQualifier& qualifier, const TType& typ if (collision < 0) usedIo[set].push_back(range2); } - } else -#endif - { - // Not a dvec3 in/out split across two locations, generic path. - // Need a single IO-range block. - - TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); - TRange componentRange(0, 3); - if (qualifier.hasComponent() || type.getVectorSize() > 0) { - int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); - if (qualifier.hasComponent()) - componentRange.start = qualifier.layoutComponent; - componentRange.last = componentRange.start + consumedComponents - 1; - } - - // combine location and component ranges - TIoRange range(locationRange, componentRange, type.getBasicType(), qualifier.hasIndex() ? qualifier.getIndex() : 0); - - // check for collisions, except for vertex inputs on desktop targeting OpenGL - if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) - collision = checkLocationRange(set, range, type, typeCollision); - - if (collision < 0) - usedIo[set].push_back(range); + return collision; } + // Not a dvec3 in/out split across two locations, generic path. + // Need a single IO-range block. + + TRange locationRange(qualifier.layoutLocation, qualifier.layoutLocation + size - 1); + TRange componentRange(0, 3); + if (qualifier.hasComponent() || type.getVectorSize() > 0) { + int consumedComponents = type.getVectorSize() * (type.getBasicType() == EbtDouble ? 2 : 1); + if (qualifier.hasComponent()) + componentRange.start = qualifier.layoutComponent; + componentRange.last = componentRange.start + consumedComponents - 1; + } + + // combine location and component ranges + TBasicType basicTy = type.getBasicType(); + if (basicTy == EbtSampler && type.getSampler().isAttachmentEXT()) + basicTy = type.getSampler().type; + TIoRange range(locationRange, componentRange, basicTy, qualifier.hasIndex() ? qualifier.getIndex() : 0); + + // check for collisions, except for vertex inputs on desktop targeting OpenGL + if (! (!isEsProfile() && language == EShLangVertex && qualifier.isPipeInput()) || spvVersion.vulkan > 0) + collision = checkLocationRange(set, range, type, typeCollision); + + if (collision < 0) + usedIo[set].push_back(range); + return collision; } @@ -1567,6 +1755,19 @@ int TIntermediate::checkLocationRange(int set, const TIoRange& range, const TTyp } } + // check typeCollision between tileImageEXT and out + if (set == 4 || set == 1) { + // if the set is "tileImageEXT", check against "out" and vice versa + int againstSet = (set == 4) ? 1 : 4; + for (size_t r = 0; r < usedIo[againstSet].size(); ++r) { + if (range.location.overlap(usedIo[againstSet][r].location) && type.getBasicType() != usedIo[againstSet][r].basicType) { + // aliased-type mismatch + typeCollision = true; + return std::max(range.location.start, usedIo[againstSet][r].location.start); + } + } + } + return -1; // no collision } @@ -1630,10 +1831,8 @@ int TIntermediate::computeTypeLocationSize(const TType& type, EShLanguage stage) if (type.isSizedArray() && !type.getQualifier().isPerView()) return type.getOuterArraySize() * computeTypeLocationSize(elementType, stage); else { -#ifndef GLSLANG_WEB // unset perViewNV attributes for arrayed per-view outputs: "perviewNV vec4 v[MAX_VIEWS][3];" elementType.getQualifier().perViewNV = false; -#endif return computeTypeLocationSize(elementType, stage); } } @@ -1709,8 +1908,6 @@ int TIntermediate::computeTypeUniformLocationSize(const TType& type) return 1; } -#ifndef GLSLANG_WEB - // Accumulate xfb buffer ranges and check for collisions as the accumulation is done. // // Returns < 0 if no collision, >= 0 if collision and the value returned is a colliding value. @@ -1802,7 +1999,7 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains return size; } - int numComponents; + int numComponents {0}; if (type.isScalar()) numComponents = 1; else if (type.isVector()) @@ -1828,8 +2025,6 @@ unsigned int TIntermediate::computeTypeXfbSize(const TType& type, bool& contains } } -#endif - const int baseAlignmentVec4Std140 = 16; // Return the size and alignment of a component of the given type. @@ -1837,10 +2032,6 @@ const int baseAlignmentVec4Std140 = 16; // Return value is the alignment.. int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) { -#ifdef GLSLANG_WEB - size = 4; return 4; -#endif - switch (type.getBasicType()) { case EbtInt64: case EbtUint64: @@ -1851,6 +2042,15 @@ int TIntermediate::getBaseAlignmentScalar(const TType& type, int& size) case EbtInt16: case EbtUint16: size = 2; return 2; case EbtReference: size = 8; return 8; + case EbtSampler: + { + if (type.isBindlessImage() || type.isBindlessTexture()) { + size = 8; return 8; + } + else { + size = 4; return 4; + } + } default: size = 4; return 4; } } @@ -2068,7 +2268,7 @@ int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, if (type.isVector()) { int scalarAlign = getBaseAlignmentScalar(type, size); - + size *= type.getVectorSize(); return scalarAlign; } @@ -2089,7 +2289,7 @@ int TIntermediate::getScalarAlignment(const TType& type, int& size, int& stride, assert(0); // all cases should be covered above size = 1; - return 1; + return 1; } int TIntermediate::getMemberAlignment(const TType& type, int& size, int& stride, TLayoutPacking layoutPacking, bool rowMajor) @@ -2171,7 +2371,6 @@ int TIntermediate::computeBufferReferenceTypeSize(const TType& type) return size; } -#ifndef GLSLANG_WEB bool TIntermediate::isIoResizeArray(const TType& type, EShLanguage language) { return type.isArray() && ((language == EShLangGeometry && type.getQualifier().storage == EvqVaryingIn) || @@ -2179,10 +2378,9 @@ bool TIntermediate::isIoResizeArray(const TType& type, EShLanguage language) { ! type.getQualifier().patch) || (language == EShLangTessEvaluation && type.getQualifier().storage == EvqVaryingIn) || (language == EShLangFragment && type.getQualifier().storage == EvqVaryingIn && - type.getQualifier().pervertexNV) || - (language == EShLangMeshNV && type.getQualifier().storage == EvqVaryingOut && + (type.getQualifier().pervertexNV || type.getQualifier().pervertexEXT)) || + (language == EShLangMesh && type.getQualifier().storage == EvqVaryingOut && !type.getQualifier().perTaskNV)); } -#endif // not GLSLANG_WEB } // end namespace glslang diff --git a/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h b/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h index 1386cb3a8..db0367f5a 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h +++ b/src/libraries/glslang/glslang/MachineIndependent/localintermediate.h @@ -43,11 +43,12 @@ #include "../Public/ShaderLang.h" #include "Versions.h" +#include +#include +#include +#include #include #include -#include -#include -#include class TInfoSink; @@ -147,7 +148,6 @@ struct TOffsetRange { TRange offset; }; -#ifndef GLSLANG_WEB // Things that need to be tracked per xfb buffer. struct TXfbBuffer { TXfbBuffer() : stride(TQualifier::layoutXfbStrideEnd), implicitStride(0), contains64BitType(false), @@ -159,7 +159,6 @@ struct TXfbBuffer { bool contains32BitType; bool contains16BitType; }; -#endif // Track a set of strings describing how the module was processed. // This includes command line options, transforms, etc., ideally inclusive enough @@ -225,6 +224,16 @@ enum ComputeDerivativeMode { LayoutDerivativeGroupLinear, // derivative_group_linearNV }; +// +// Status type on AST level. Some uncalled status or functions would be reset in call graph. +// Currently we will keep status set by explicitly declared layout or variable decl. +// +enum AstRefType { + AstRefTypeVar, // Status set by variable decl + AstRefTypeFunc, // Status set by function decl + AstRefTypeLayout, // Status set by layout decl +}; + class TIdMaps { public: TMap& operator[](long long i) { return maps[i]; } @@ -283,34 +292,38 @@ class TIntermediate { public: explicit TIntermediate(EShLanguage l, int v = 0, EProfile p = ENoProfile) : language(l), -#ifndef GLSLANG_ANGLE profile(p), version(v), -#endif - treeRoot(0), + treeRoot(nullptr), resources(TBuiltInResource{}), numEntryPoints(0), numErrors(0), numPushConstants(0), recursive(false), invertY(false), dxPositionW(false), + enhancedMsgs(false), + debugInfo(false), useStorageBuffer(false), invariantAll(false), nanMinMaxClamp(false), depthReplacing(false), + stencilReplacing(false), uniqueId(0), globalUniformBlockName(""), atomicCounterBlockName(""), globalUniformBlockSet(TQualifier::layoutSetEnd), globalUniformBlockBinding(TQualifier::layoutBindingEnd), - atomicCounterBlockSet(TQualifier::layoutSetEnd) -#ifndef GLSLANG_WEB - , + atomicCounterBlockSet(TQualifier::layoutSetEnd), implicitThisName("@this"), implicitCounterName("@count"), source(EShSourceNone), useVulkanMemoryModel(false), invocations(TQualifier::layoutNotSet), vertices(TQualifier::layoutNotSet), inputPrimitive(ElgNone), outputPrimitive(ElgNone), - pixelCenterInteger(false), originUpperLeft(false), + pixelCenterInteger(false), originUpperLeft(false),texCoordBuiltinRedeclared(false), vertexSpacing(EvsNone), vertexOrder(EvoNone), interlockOrdering(EioNone), pointMode(false), earlyFragmentTests(false), - postDepthCoverage(false), depthLayout(EldNone), + postDepthCoverage(false), earlyAndLateFragmentTestsAMD(false), + nonCoherentColorAttachmentReadEXT(false), + nonCoherentDepthAttachmentReadEXT(false), + nonCoherentStencilAttachmentReadEXT(false), + depthLayout(EldNone), + stencilLayout(ElsNone), hlslFunctionality1(false), blendEquations(0), xfbMode(false), multiStream(false), layoutOverrideCoverage(false), @@ -320,6 +333,7 @@ public: primitives(TQualifier::layoutNotSet), numTaskNVBlocks(0), layoutPrimitiveCulling(false), + numTaskEXTPayloads(0), autoMapBindings(false), autoMapLocations(false), flattenUniformArrays(false), @@ -331,11 +345,12 @@ public: needToLegalize(false), binaryDoubleOutput(false), subgroupUniformControlFlow(false), + maximallyReconverges(false), usePhysicalStorageBuffer(false), spirvRequirement(nullptr), spirvExecutionMode(nullptr), - uniformLocationBase(0) -#endif + uniformLocationBase(0), + quadDerivMode(false), reqFullQuadsMode(false) { localSize[0] = 1; localSize[1] = 1; @@ -346,23 +361,17 @@ public: localSizeSpecId[0] = TQualifier::layoutNotSet; localSizeSpecId[1] = TQualifier::layoutNotSet; localSizeSpecId[2] = TQualifier::layoutNotSet; -#ifndef GLSLANG_WEB xfbBuffers.resize(TQualifier::layoutXfbBufferEnd); shiftBinding.fill(0); -#endif } void setVersion(int v) { -#ifndef GLSLANG_ANGLE version = v; -#endif } void setProfile(EProfile p) { -#ifndef GLSLANG_ANGLE profile = p; -#endif } int getVersion() const { return version; } @@ -419,6 +428,9 @@ public: case EShTargetVulkan_1_2: processes.addProcess("target-env vulkan1.2"); break; + case EShTargetVulkan_1_3: + processes.addProcess("target-env vulkan1.3"); + break; default: processes.addProcess("target-env vulkanUnknown"); break; @@ -456,6 +468,12 @@ public: const std::string& getEntryPointName() const { return entryPointName; } const std::string& getEntryPointMangledName() const { return entryPointMangledName; } + void setDebugInfo(bool debuginfo) + { + debugInfo = debuginfo; + } + bool getDebugInfo() const { return debugInfo; } + void setInvertY(bool invert) { invertY = invert; @@ -466,12 +484,18 @@ public: void setDxPositionW(bool dxPosW) { - dxPositionW = dxPosW; - if (dxPositionW) - processes.addProcess("dx-position-w"); + dxPositionW = dxPosW; + if (dxPositionW) + processes.addProcess("dx-position-w"); } bool getDxPositionW() const { return dxPositionW; } + void setEnhancedMsgs() + { + enhancedMsgs = true; + } + bool getEnhancedMsgs() const { return enhancedMsgs && getSource() == EShSourceGlsl; } + #ifdef ENABLE_HLSL void setSource(EShSource s) { source = s; } EShSource getSource() const { return source; } @@ -506,6 +530,8 @@ public: TOperator mapTypeToConstructorOp(const TType&) const; TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right); TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); + TIntermAggregate* mergeAggregate(TIntermNode* left, TIntermNode* right); + TIntermAggregate* mergeAggregate(TIntermNode* left, TIntermNode* right, const TSourceLoc&); TIntermAggregate* makeAggregate(TIntermNode* node); TIntermAggregate* makeAggregate(TIntermNode* node, const TSourceLoc&); TIntermAggregate* makeAggregate(const TSourceLoc&); @@ -551,7 +577,8 @@ public: TIntermTyped* foldSwizzle(TIntermTyped* node, TSwizzleSelectors& fields, const TSourceLoc&); // Tree ops - static const TIntermTyped* findLValueBase(const TIntermTyped*, bool swizzleOkay , bool BufferReferenceOk = false); + static const TIntermTyped* traverseLValueBase(const TIntermTyped*, bool swizzleOkay, bool bufferReferenceOk = false, + std::function proc = {}); // Linkage related void addSymbolLinkageNodes(TIntermAggregate*& linkage, EShLanguage, TSymbolTable&); @@ -577,6 +604,8 @@ public: bool isInvariantAll() const { return invariantAll; } void setDepthReplacing() { depthReplacing = true; } bool isDepthReplacing() const { return depthReplacing; } + void setStencilReplacing() { stencilReplacing = true; } + bool isStencilReplacing() const { return stencilReplacing; } bool setLocalSize(int dim, int size) { if (localSizeNotDefault[dim]) @@ -606,34 +635,6 @@ public: localSizeSpecId[1] != TQualifier::layoutNotSet || localSizeSpecId[2] != TQualifier::layoutNotSet; } -#ifdef GLSLANG_WEB - void output(TInfoSink&, bool tree) { } - - bool isEsProfile() const { return false; } - bool getXfbMode() const { return false; } - bool isMultiStream() const { return false; } - TLayoutGeometry getOutputPrimitive() const { return ElgNone; } - bool getPostDepthCoverage() const { return false; } - bool getEarlyFragmentTests() const { return false; } - TLayoutDepth getDepth() const { return EldNone; } - bool getPixelCenterInteger() const { return false; } - void setOriginUpperLeft() { } - bool getOriginUpperLeft() const { return true; } - TInterlockOrdering getInterlockOrdering() const { return EioNone; } - - bool getAutoMapBindings() const { return false; } - bool getAutoMapLocations() const { return false; } - int getNumPushConstants() const { return 0; } - void addShaderRecordCount() { } - void addTaskNVCount() { } - void setUseVulkanMemoryModel() { } - bool usingVulkanMemoryModel() const { return false; } - bool usingPhysicalStorageBuffer() const { return false; } - bool usingVariablePointers() const { return false; } - unsigned getXfbStride(int buffer) const { return 0; } - bool hasLayoutDerivativeModeNone() const { return false; } - ComputeDerivativeMode getLayoutDerivativeModeNone() const { return LayoutDerivativeNone; } -#else void output(TInfoSink&, bool tree); bool isEsProfile() const { return profile == EEsProfile; } @@ -728,6 +729,65 @@ public: useVariablePointers = true; processes.addProcess("use-variable-pointers"); } + // Set the global flag for bindless texture + void setBindlessTextureMode(const TString& currentCaller, AstRefType type) + { + // When type is not func, currentCaller should be "" (empty string) + bindlessTextureModeCaller[currentCaller] = type; + } + + // Get the global flag for bindless texture + bool getBindlessTextureMode() const + { + return (bindlessTextureModeCaller.size() > 0); + } + + // Set the global flag for bindless image + void setBindlessImageMode(const TString& currentCaller, AstRefType type) + { + // When type is not func, currentCaller should be "" (empty string) + bindlessImageModeCaller[currentCaller] = type; + } + + // Get the global flag for bindless image + bool getBindlessImageMode() const + { + return (bindlessImageModeCaller.size() > 0); + } + + // Get the global flag for bindless texture + bool resetTopLevelUncalledStatus(const TString& deadCaller) + { + // For reflection collection purpose, currently uniform layout setting and some + // flags introduced by variables (IO, global, etc,.) won't be reset here. + // Remove each global status (AST top level) introduced by uncalled functions. + // If a status is set by several functions, keep those which in call graph. + bool result = false; + + // For two types of bindless mode flag, we would only reset which is set by an uncalled function. + // If one status flag's key in caller vec is empty, it should be come from a non-function setting. + if (!bindlessTextureModeCaller.empty()) { + auto caller = bindlessTextureModeCaller.find(deadCaller); + if (caller != bindlessTextureModeCaller.end() && bindlessTextureModeCaller[deadCaller] == AstRefTypeFunc) { + bindlessTextureModeCaller.erase(caller); + result = true; + } + } + if (!bindlessImageModeCaller.empty()) { + auto caller = bindlessImageModeCaller.find(deadCaller); + if (caller != bindlessImageModeCaller.end() && bindlessImageModeCaller[deadCaller] == AstRefTypeFunc) { + bindlessImageModeCaller.erase(caller); + result = true; + } + } + return result; + } + + bool getBindlessMode() const + { + return getBindlessTextureMode() || getBindlessImageMode(); + } + bool usingVariablePointers() const { return useVariablePointers; } #ifdef ENABLE_HLSL @@ -743,6 +803,7 @@ public: int getNumPushConstants() const { return numPushConstants; } void addShaderRecordCount() { ++numShaderRecordBlocks; } void addTaskNVCount() { ++numTaskNVBlocks; } + void addTaskPayloadEXTCount() { ++numTaskEXTPayloads; } bool setInvocations(int i) { @@ -798,6 +859,10 @@ public: void setXfbMode() { xfbMode = true; } bool getXfbMode() const { return xfbMode; } + void setQuadDerivMode(bool mode = true) { quadDerivMode = mode; } + bool getQuadDerivMode() const { return quadDerivMode; } + void setReqFullQuadsMode(bool mode = true) { reqFullQuadsMode = mode; } + bool getReqFullQuadsMode() const { return reqFullQuadsMode; } void setMultiStream() { multiStream = true; } bool isMultiStream() const { return multiStream; } bool setOutputPrimitive(TLayoutGeometry p) @@ -808,10 +873,18 @@ public: return true; } TLayoutGeometry getOutputPrimitive() const { return outputPrimitive; } + void setNonCoherentColorAttachmentReadEXT() { nonCoherentColorAttachmentReadEXT = true; } + bool getNonCoherentColorAttachmentReadEXT() const { return nonCoherentColorAttachmentReadEXT; } + void setNonCoherentDepthAttachmentReadEXT() { nonCoherentDepthAttachmentReadEXT = true; } + bool getNonCoherentDepthAttachmentReadEXT() const { return nonCoherentDepthAttachmentReadEXT; } + void setNonCoherentStencilAttachmentReadEXT() { nonCoherentStencilAttachmentReadEXT = true; } + bool getNonCoherentStencilAttachmentReadEXT() const { return nonCoherentStencilAttachmentReadEXT; } void setPostDepthCoverage() { postDepthCoverage = true; } bool getPostDepthCoverage() const { return postDepthCoverage; } void setEarlyFragmentTests() { earlyFragmentTests = true; } + void setEarlyAndLateFragmentTestsAMD() { earlyAndLateFragmentTestsAMD = true; } bool getEarlyFragmentTests() const { return earlyFragmentTests; } + bool getEarlyAndLateFragmentTestsAMD() const { return earlyAndLateFragmentTestsAMD; } bool setDepth(TLayoutDepth d) { if (depthLayout != EldNone) @@ -819,11 +892,21 @@ public: depthLayout = d; return true; } + bool setStencil(TLayoutStencil s) + { + if (stencilLayout != ElsNone) + return stencilLayout == s; + stencilLayout = s; + return true; + } TLayoutDepth getDepth() const { return depthLayout; } + TLayoutStencil getStencil() const { return stencilLayout; } void setOriginUpperLeft() { originUpperLeft = true; } bool getOriginUpperLeft() const { return originUpperLeft; } void setPixelCenterInteger() { pixelCenterInteger = true; } bool getPixelCenterInteger() const { return pixelCenterInteger; } + void setTexCoordRedeclared() { texCoordBuiltinRedeclared = true; } + bool getTexCoordRedeclared() const { return texCoordBuiltinRedeclared; } void addBlendEquation(TBlendEquationShift b) { blendEquations |= (1 << b); } unsigned int getBlendEquations() const { return blendEquations; } bool setXfbBufferStride(int buffer, unsigned stride) @@ -886,6 +969,9 @@ public: void setSubgroupUniformControlFlow() { subgroupUniformControlFlow = true; } bool getSubgroupUniformControlFlow() const { return subgroupUniformControlFlow; } + void setMaximallyReconverges() { maximallyReconverges = true; } + bool getMaximallyReconverges() const { return maximallyReconverges; } + // GL_EXT_spirv_intrinsics void insertSpirvRequirement(const TSpirvRequirement* spirvReq); bool hasSpirvRequirement() const { return spirvRequirement != nullptr; } @@ -894,7 +980,6 @@ public: void insertSpirvExecutionModeId(int executionMode, const TIntermAggregate* args); bool hasSpirvExecutionMode() const { return spirvExecutionMode != nullptr; } const TSpirvExecutionMode& getSpirvExecutionMode() const { return *spirvExecutionMode; } -#endif // GLSLANG_WEB void addBlockStorageOverride(const char* nameStr, TBlockStorageClass backing) { @@ -1001,12 +1086,6 @@ public: void setUniqueId(unsigned long long id) { uniqueId = id; } // Certain explicit conversions are allowed conditionally -#ifdef GLSLANG_WEB - bool getArithemeticInt8Enabled() const { return false; } - bool getArithemeticInt16Enabled() const { return false; } - bool getArithemeticFloat16Enabled() const { return false; } - void updateNumericFeature(TNumericFeatures::feature f, bool on) { } -#else bool getArithemeticInt8Enabled() const { return numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types) || numericFeatures.contains(TNumericFeatures::shader_explicit_arithmetic_types_int8); @@ -1024,12 +1103,11 @@ public: } void updateNumericFeature(TNumericFeatures::feature f, bool on) { on ? numericFeatures.insert(f) : numericFeatures.erase(f); } -#endif protected: TIntermSymbol* addSymbol(long long Id, const TString&, const TType&, const TConstUnionArray&, TIntermTyped* subtree, const TSourceLoc&); - void error(TInfoSink& infoSink, const char*); - void warn(TInfoSink& infoSink, const char*); + void error(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount); + void warn(TInfoSink& infoSink, const char*, EShLanguage unitStage = EShLangCount); void mergeCallGraphs(TInfoSink&, TIntermediate&); void mergeModes(TInfoSink&, TIntermediate&); void mergeTrees(TInfoSink&, TIntermediate&); @@ -1066,13 +1144,8 @@ protected: typedef std::list TGraph; TGraph callGraph; -#ifdef GLSLANG_ANGLE - const EProfile profile = ECoreProfile; - const int version = 450; -#else EProfile profile; // source profile int version; // source version -#endif SpvVersion spvVersion; TIntermNode* treeRoot; std::set requestedExtensions; // cumulation of all enabled or required extensions; not connected to what subset of the shader used them @@ -1083,10 +1156,13 @@ protected: bool recursive; bool invertY; bool dxPositionW; + bool enhancedMsgs; + bool debugInfo; bool useStorageBuffer; bool invariantAll; bool nanMinMaxClamp; // true if desiring min/max/clamp to favor non-NaN over NaN bool depthReplacing; + bool stencilReplacing; int localSize[3]; bool localSizeNotDefault[3]; int localSizeSpecId[3]; @@ -1098,7 +1174,6 @@ protected: unsigned int globalUniformBlockBinding; unsigned int atomicCounterBlockSet; -#ifndef GLSLANG_WEB public: const char* const implicitThisName; const char* const implicitCounterName; @@ -1111,13 +1186,19 @@ protected: TLayoutGeometry outputPrimitive; bool pixelCenterInteger; bool originUpperLeft; + bool texCoordBuiltinRedeclared; TVertexSpacing vertexSpacing; TVertexOrder vertexOrder; TInterlockOrdering interlockOrdering; bool pointMode; bool earlyFragmentTests; bool postDepthCoverage; + bool earlyAndLateFragmentTestsAMD; + bool nonCoherentColorAttachmentReadEXT; + bool nonCoherentDepthAttachmentReadEXT; + bool nonCoherentStencilAttachmentReadEXT; TLayoutDepth depthLayout; + TLayoutStencil stencilLayout; bool hlslFunctionality1; int blendEquations; // an 'or'ing of masks of shifts of TBlendEquationShift bool xfbMode; @@ -1130,6 +1211,7 @@ protected: int primitives; int numTaskNVBlocks; bool layoutPrimitiveCulling; + int numTaskEXTPayloads; // Base shift values std::array shiftBinding; @@ -1153,24 +1235,29 @@ protected: bool needToLegalize; bool binaryDoubleOutput; bool subgroupUniformControlFlow; + bool maximallyReconverges; bool usePhysicalStorageBuffer; TSpirvRequirement* spirvRequirement; TSpirvExecutionMode* spirvExecutionMode; - + std::map bindlessTextureModeCaller; + std::map bindlessImageModeCaller; std::unordered_map uniformLocationOverrides; int uniformLocationBase; + bool quadDerivMode; + bool reqFullQuadsMode; TNumericFeatures numericFeatures; -#endif std::unordered_map blockBackingOverrides; std::unordered_set usedConstantId; // specialization constant ids used std::vector usedAtomics; // sets of bindings used by atomic counters std::vector usedIo[4]; // sets of used locations, one for each of in, out, uniform, and buffers - std::vector usedIoRT[2]; // sets of used location, one for rayPayload/rayPayloadIN and other - // for callableData/callableDataIn + std::vector usedIoRT[4]; // sets of used location, one for rayPayload/rayPayloadIN, + // one for callableData/callableDataIn, one for hitObjectAttributeNV and + // one for shaderrecordhitobjectNV // set of names of statically read/written I/O that might need extra checking std::set ioAccessed; + // source code of shader, useful as part of debug information std::string sourceFile; std::string sourceText; diff --git a/src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp b/src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp index 6c182991f..835097234 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/parseConst.cpp @@ -198,7 +198,7 @@ void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) bool TIntermediate::parseConstTree(TIntermNode* root, TConstUnionArray unionArray, TOperator constructorType, const TType& t, bool singleConstantParam) { - if (root == 0) + if (root == nullptr) return false; TConstTraverser it(unionArray, singleConstantParam, constructorType, t); diff --git a/src/libraries/glslang/glslang/MachineIndependent/parseVersions.h b/src/libraries/glslang/glslang/MachineIndependent/parseVersions.h index 7248354e4..5c77e42ce 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/parseVersions.h +++ b/src/libraries/glslang/glslang/MachineIndependent/parseVersions.h @@ -58,72 +58,18 @@ public: const SpvVersion& spvVersion, EShLanguage language, TInfoSink& infoSink, bool forwardCompatible, EShMessages messages) : -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) forwardCompatible(forwardCompatible), profile(profile), -#endif infoSink(infoSink), version(version), language(language), spvVersion(spvVersion), - intermediate(interm), messages(messages), numErrors(0), currentScanner(0) { } + intermediate(interm), messages(messages), numErrors(0), currentScanner(nullptr) { } virtual ~TParseVersions() { } void requireStage(const TSourceLoc&, EShLanguageMask, const char* featureDesc); void requireStage(const TSourceLoc&, EShLanguage, const char* featureDesc); -#ifdef GLSLANG_WEB - const EProfile profile = EEsProfile; - bool isEsProfile() const { return true; } - void requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc) - { - if (! (EEsProfile & profileMask)) - error(loc, "not supported with this profile:", featureDesc, ProfileName(profile)); - } - void profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, - const char* const extensions[], const char* featureDesc) - { - if ((EEsProfile & profileMask) && (minVersion == 0 || version < minVersion)) - error(loc, "not supported for this version or the enabled extensions", featureDesc, ""); - } - void profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, const char* extension, - const char* featureDesc) - { - profileRequires(loc, profileMask, minVersion, extension ? 1 : 0, &extension, featureDesc); - } - void initializeExtensionBehavior() { } - void checkDeprecated(const TSourceLoc&, int queryProfiles, int depVersion, const char* featureDesc) { } - void requireNotRemoved(const TSourceLoc&, int queryProfiles, int removedVersion, const char* featureDesc) { } - void requireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], - const char* featureDesc) { } - void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], - const char* featureDesc) { } - TExtensionBehavior getExtensionBehavior(const char*) { return EBhMissing; } - bool extensionTurnedOn(const char* const extension) { return false; } - bool extensionsTurnedOn(int numExtensions, const char* const extensions[]) { return false; } - void updateExtensionBehavior(int line, const char* const extension, const char* behavior) { } - void updateExtensionBehavior(const char* const extension, TExtensionBehavior) { } - void checkExtensionStage(const TSourceLoc&, const char* const extension) { } - void extensionRequires(const TSourceLoc&, const char* const extension, const char* behavior) { } - void fullIntegerCheck(const TSourceLoc&, const char* op) { } - void doubleCheck(const TSourceLoc&, const char* op) { } - bool float16Arithmetic() { return false; } - void requireFloat16Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc) { } - bool int16Arithmetic() { return false; } - void requireInt16Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc) { } - bool int8Arithmetic() { return false; } - void requireInt8Arithmetic(const TSourceLoc& loc, const char* op, const char* featureDesc) { } - void int64Check(const TSourceLoc&, const char* op, bool builtIn = false) { } - void explicitFloat32Check(const TSourceLoc&, const char* op, bool builtIn = false) { } - void explicitFloat64Check(const TSourceLoc&, const char* op, bool builtIn = false) { } - bool relaxedErrors() const { return false; } - bool suppressWarnings() const { return true; } - bool isForwardCompatible() const { return false; } -#else -#ifdef GLSLANG_ANGLE - const bool forwardCompatible = true; - const EProfile profile = ECoreProfile; -#else + bool forwardCompatible; // true if errors are to be given for use of deprecated features EProfile profile; // the declared profile in the shader (core by default) -#endif bool isEsProfile() const { return profile == EEsProfile; } void requireProfile(const TSourceLoc& loc, int profileMask, const char* featureDesc); void profileRequires(const TSourceLoc& loc, int profileMask, int minVersion, int numExtensions, @@ -137,6 +83,11 @@ public: const char* featureDesc); virtual void ppRequireExtensions(const TSourceLoc&, int numExtensions, const char* const extensions[], const char* featureDesc); + template + constexpr void ppRequireExtensions(const TSourceLoc& loc, Container extensions, const char* featureDesc) { + ppRequireExtensions(loc, static_cast(extensions.size()), extensions.data(), featureDesc); + } + virtual TExtensionBehavior getExtensionBehavior(const char*); virtual bool extensionTurnedOn(const char* const extension); virtual bool extensionsTurnedOn(int numExtensions, const char* const extensions[]); @@ -167,29 +118,19 @@ public: virtual void explicitInt32Check(const TSourceLoc&, const char* op, bool builtIn = false); virtual void explicitFloat32Check(const TSourceLoc&, const char* op, bool builtIn = false); virtual void explicitFloat64Check(const TSourceLoc&, const char* op, bool builtIn = false); - virtual void fcoopmatCheck(const TSourceLoc&, const char* op, bool builtIn = false); - virtual void intcoopmatCheck(const TSourceLoc&, const char *op, bool builtIn = false); + virtual void fcoopmatCheckNV(const TSourceLoc&, const char* op, bool builtIn = false); + virtual void intcoopmatCheckNV(const TSourceLoc&, const char *op, bool builtIn = false); + virtual void coopmatCheck(const TSourceLoc&, const char* op, bool builtIn = false); bool relaxedErrors() const { return (messages & EShMsgRelaxedErrors) != 0; } bool suppressWarnings() const { return (messages & EShMsgSuppressWarnings) != 0; } bool isForwardCompatible() const { return forwardCompatible; } -#endif // GLSLANG_WEB + virtual void spvRemoved(const TSourceLoc&, const char* op); virtual void vulkanRemoved(const TSourceLoc&, const char* op); virtual void requireVulkan(const TSourceLoc&, const char* op); virtual void requireSpv(const TSourceLoc&, const char* op); virtual void requireSpv(const TSourceLoc&, const char *op, unsigned int version); - -#if defined(GLSLANG_WEB) && !defined(GLSLANG_WEB_DEVEL) - void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) { addError(); } - void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) { } - void C_DECL ppError(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) { addError(); } - void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, - const char* szExtraInfoFormat, ...) { } -#else virtual void C_DECL error(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...) = 0; virtual void C_DECL warn(const TSourceLoc&, const char* szReason, const char* szToken, @@ -198,7 +139,6 @@ public: const char* szExtraInfoFormat, ...) = 0; virtual void C_DECL ppWarn(const TSourceLoc&, const char* szReason, const char* szToken, const char* szExtraInfoFormat, ...) = 0; -#endif void addError() { ++numErrors; } int getNumErrors() const { return numErrors; } @@ -231,6 +171,7 @@ public: protected: TMap extensionBehavior; // for each extension string, what its current behavior is TMap extensionMinSpv; // for each extension string, store minimum spirv required + TVector spvUnsupportedExt; // for extensions reserved for spv usage. EShMessages messages; // errors/warnings/rule-sets int numErrors; // number of compile-time errors encountered TInputScanner* currentScanner; diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp index aa1e0d745..5f18c4e92 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/Pp.cpp @@ -378,8 +378,6 @@ namespace { int op_cmpl(int a) { return ~a; } int op_not(int a) { return !a; } -}; - struct TBinop { int token, precedence, (*op)(int, int); } binop[] = { @@ -412,6 +410,8 @@ struct TUnop { { '!', op_not }, }; +} // anonymous namespace + #define NUM_ELEMENTS(A) (sizeof(A) / sizeof(A[0])) int TPpContext::eval(int token, int precedence, bool shortCircuit, int& res, bool& err, TPpToken* ppToken) @@ -736,7 +736,6 @@ int TPpContext::CPPline(TPpToken* ppToken) parseContext.setCurrentLine(lineRes); if (token != '\n') { -#ifndef GLSLANG_WEB if (token == PpAtomConstString) { parseContext.ppRequireExtensions(directiveLoc, 1, &E_GL_GOOGLE_cpp_style_line_directive, "filename-based #line"); // We need to save a copy of the string instead of pointing @@ -746,9 +745,7 @@ int TPpContext::CPPline(TPpToken* ppToken) parseContext.setCurrentSourceName(sourceName); hasFile = true; token = scanToken(ppToken); - } else -#endif - { + } else { token = eval(token, MIN_PRECEDENCE, false, fileRes, fileErr, ppToken); if (! fileErr) { parseContext.setCurrentString(fileRes); @@ -974,17 +971,16 @@ int TPpContext::readCPPline(TPpToken* ppToken) case PpAtomLine: token = CPPline(ppToken); break; -#ifndef GLSLANG_WEB case PpAtomInclude: if(!parseContext.isReadingHLSL()) { - parseContext.ppRequireExtensions(ppToken->loc, 1, &E_GL_GOOGLE_include_directive, "#include"); + const std::array exts = { E_GL_GOOGLE_include_directive, E_GL_ARB_shading_language_include }; + parseContext.ppRequireExtensions(ppToken->loc, exts, "#include"); } token = CPPinclude(ppToken); break; case PpAtomPragma: token = CPPpragma(ppToken); break; -#endif case PpAtomUndef: token = CPPundef(ppToken); break; @@ -1126,9 +1122,6 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken) pasting = true; } - // HLSL does expand macros before concatenation - if (pasting && pp->parseContext.isReadingHLSL()) - pasting = false; // TODO: preprocessor: properly handle whitespace (or lack of it) between tokens when expanding if (token == PpAtomIdentifier) { @@ -1138,9 +1131,12 @@ int TPpContext::tMacroInput::scan(TPpToken* ppToken) break; if (i >= 0) { TokenStream* arg = expandedArgs[i]; - if (arg == nullptr || pasting) + bool expanded = !!arg && !pasting; + // HLSL does expand macros before concatenation + if (arg == nullptr || (pasting && !pp->parseContext.isReadingHLSL()) ) { arg = args[i]; - pp->pushTokenStreamInput(*arg, prepaste); + } + pp->pushTokenStreamInput(*arg, prepaste, expanded); return pp->scanToken(ppToken); } @@ -1183,6 +1179,9 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b { ppToken->space = false; int macroAtom = atomStrings.getAtom(ppToken->name); + if (ppToken->fullyExpanded) + return MacroExpandNotStarted; + switch (macroAtom) { case PpAtomLineMacro: // Arguments which are macro have been replaced in the first stage. @@ -1214,8 +1213,10 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b MacroSymbol* macro = macroAtom == 0 ? nullptr : lookupMacroDef(macroAtom); // no recursive expansions - if (macro != nullptr && macro->busy) + if (macro != nullptr && macro->busy) { + ppToken->fullyExpanded = true; return MacroExpandNotStarted; + } // not expanding undefined macros if ((macro == nullptr || macro->undef) && ! expandUndef) diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp index 1363ce2be..70f511978 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.cpp @@ -85,7 +85,7 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. namespace glslang { TPpContext::TPpContext(TParseContextBase& pc, const std::string& rootFileName, TShader::Includer& inclr) : - preamble(0), strings(0), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false), + preamble(nullptr), strings(nullptr), previous_token('\n'), parseContext(pc), includer(inclr), inComment(false), rootFileName(rootFileName), currentSourceFile(rootFileName), disableEscapeSequences(false) diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h index 714b5eadb..1ec30491c 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpContext.h @@ -86,11 +86,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "../ParseHelper.h" #include "PpTokens.h" -/* windows only pragma */ -#ifdef _MSC_VER - #pragma warning(disable : 4127) -#endif - namespace glslang { class TPpToken { @@ -102,6 +97,7 @@ public: i64val = 0; loc.init(); name[0] = 0; + fullyExpanded = false; } // Used for comparing macro definitions, so checks what is relevant for that. @@ -117,6 +113,8 @@ public: // True if a space (for white space or a removed comment) should also be // recognized, in front of the token returned: bool space; + + bool fullyExpanded; // Numeric value of the token: union { int ival; @@ -217,6 +215,7 @@ public: virtual bool peekContinuedPasting(int) { return false; } // true when non-spaced tokens can paste virtual bool endOfReplacementList() { return false; } // true when at the end of a macro replacement list (RHS of #define) virtual bool isMacroInput() { return false; } + virtual bool isStringInput() { return false; } // Will be called when we start reading tokens from this instance virtual void notifyActivated() {} @@ -357,7 +356,8 @@ protected: // Scanner data: int previous_token; TParseContextBase& parseContext; - + std::vector lastLineTokens; + std::vector lastLineTokenLocs; // Get the next token from *stack* of input sources, popping input sources // that are out of tokens, down until an input source is found that has a token. // Return EndOfInput when there are no more tokens to be found by doing this. @@ -371,7 +371,31 @@ protected: break; popInput(); } - + if (!inputStack.empty() && inputStack.back()->isStringInput()) { + if (token == '\n') { + bool seenNumSign = false; + for (int i = 0; i < (int)lastLineTokens.size() - 1;) { + int curPos = i; + int curToken = lastLineTokens[i++]; + if (curToken == '#' && lastLineTokens[i] == '#') { + curToken = PpAtomPaste; + i++; + } + if (curToken == '#') { + if (seenNumSign) { + parseContext.ppError(lastLineTokenLocs[curPos], "(#) can be preceded in its line only by spaces or horizontal tabs", "#", ""); + } else { + seenNumSign = true; + } + } + } + lastLineTokens.clear(); + lastLineTokenLocs.clear(); + } else { + lastLineTokens.push_back(token); + lastLineTokenLocs.push_back(ppToken->loc); + } + } return token; } int getChar() { return inputStack.back()->getch(); } @@ -475,16 +499,27 @@ protected: // // From PpTokens.cpp // - void pushTokenStreamInput(TokenStream&, bool pasting = false); + void pushTokenStreamInput(TokenStream&, bool pasting = false, bool expanded = false); void UngetToken(int token, TPpToken*); class tTokenInput : public tInput { public: - tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting) : + tTokenInput(TPpContext* pp, TokenStream* t, bool prepasting, bool expanded) : tInput(pp), tokens(t), - lastTokenPastes(prepasting) { } - virtual int scan(TPpToken *ppToken) override { return tokens->getToken(pp->parseContext, ppToken); } + lastTokenPastes(prepasting), + preExpanded(expanded) { } + virtual int scan(TPpToken *ppToken) override { + int token = tokens->getToken(pp->parseContext, ppToken); + ppToken->fullyExpanded = preExpanded; + if (tokens->atEnd() && token == PpAtomIdentifier) { + int macroAtom = pp->atomStrings.getAtom(ppToken->name); + MacroSymbol* macro = macroAtom == 0 ? nullptr : pp->lookupMacroDef(macroAtom); + if (macro && macro->functionLike) + ppToken->fullyExpanded = false; + } + return token; + } virtual int getch() override { assert(0); return EndOfInput; } virtual void ungetch() override { assert(0); } virtual bool peekPasting() override { return tokens->peekTokenizedPasting(lastTokenPastes); } @@ -492,6 +527,7 @@ protected: protected: TokenStream* tokens; bool lastTokenPastes; // true if the last token in the input is to be pasted, rather than consumed as a token + bool preExpanded; }; class tUngotTokenInput : public tInput { @@ -512,7 +548,7 @@ protected: public: tStringInput(TPpContext* pp, TInputScanner& i) : tInput(pp), input(&i) { } virtual int scan(TPpToken*) override; - + bool isStringInput() override { return true; } // Scanner used to get source stream characters. // - Escaped newlines are handled here, invisibly to the caller. // - All forms of newline are handled, and turned into just a '\n'. diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp index ad1179200..34dec2076 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpScanner.cpp @@ -3,6 +3,7 @@ // Copyright (C) 2013 LunarG, Inc. // Copyright (C) 2017 ARM Limited. // Copyright (C) 2015-2018 Google, Inc. +// Copyright (c) 2023, Mobica Limited // // All rights reserved. // @@ -259,7 +260,6 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) // Suffix: bool isDouble = false; bool isFloat16 = false; -#ifndef GLSLANG_WEB if (ch == 'l' || ch == 'L') { if (ifdepth == 0 && parseContext.intermediate.getSource() == EShSourceGlsl) parseContext.doubleCheck(ppToken->loc, "double floating-point suffix"); @@ -299,14 +299,11 @@ int TPpContext::lFloatConst(int len, int ch, TPpToken* ppToken) isFloat16 = true; } } else -#endif if (ch == 'f' || ch == 'F') { -#ifndef GLSLANG_WEB if (ifdepth == 0) parseContext.profileRequires(ppToken->loc, EEsProfile, 300, nullptr, "floating-point suffix"); if (ifdepth == 0 && !parseContext.relaxedErrors()) parseContext.profileRequires(ppToken->loc, ~EEsProfile, 120, nullptr, "floating-point suffix"); -#endif if (ifdepth == 0 && !hasDecimalOrExponent) parseContext.ppError(ppToken->loc, "float literal needs a decimal point or exponent", "", ""); saveName(ch); @@ -480,9 +477,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) E_GL_EXT_shader_explicit_arithmetic_types_int16 }; static const int Num_Int16_Extensions = sizeof(Int16_Extensions) / sizeof(Int16_Extensions[0]); - ppToken->ival = 0; - ppToken->i64val = 0; - ppToken->space = false; + ppToken->clear(); ch = getch(); for (;;) { while (ch == ' ' || ch == '\t') { @@ -551,7 +546,7 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ival = 0; do { - if (len < MaxTokenLength && ival <= 0x0fffffffffffffffull) { + if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) { ppToken->name[len++] = (char)ch; if (ch >= '0' && ch <= '9') { ii = ch - '0'; @@ -584,7 +579,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->name[len++] = (char)ch; isUnsigned = true; -#ifndef GLSLANG_WEB int nextCh = getch(); if (nextCh == 'l' || nextCh == 'L') { if (len < MaxTokenLength) @@ -610,7 +604,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt16 = true; -#endif } else ungetch(); ppToken->name[len] = '\0'; @@ -641,6 +634,108 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->ival = (int)ival; return isUnsigned ? PpAtomConstUint : PpAtomConstInt; } + } else if ((ch == 'b' || ch == 'B') && pp->parseContext.intermediate.getSource() == EShSourceHlsl) { + // must be binary + bool isUnsigned = false; + bool isInt64 = false; + bool isInt16 = false; + ppToken->name[len++] = (char)ch; + ch = getch(); + + // Check value + if ((ch == '0' || ch == '1')) + { + ival = 0; + do { + if (len < MaxTokenLength && ival <= 0x7fffffffffffffffull) { + ppToken->name[len++] = (char)ch; + if (ch == '0' || ch == '1') { + ii = ch - '0'; + } else { + pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", ""); + } + ival = (ival << 1) | ii; + } + else + { + if (! AlreadyComplained) { + if(len < MaxTokenLength) + pp->parseContext.ppError(ppToken->loc, "binary literal too big", "", ""); + else + pp->parseContext.ppError(ppToken->loc, "binary literal too long", "", ""); + AlreadyComplained = 1; + } + ival = 0xffffffffffffffffull; + } + ch = getch(); + } while (ch == '0' || ch == '1'); + } + else + { + pp->parseContext.ppError(ppToken->loc, "bad digit in binary literal", "", ""); + } + + // check type + if (ch == 'u' || ch == 'U') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isUnsigned = true; + + int nextCh = getch(); + if (nextCh == 'l' || nextCh == 'L') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt64 = true; + } else + ungetch(); + + nextCh = getch(); + if ((nextCh == 's' || nextCh == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)nextCh; + isInt16 = true; + } else + ungetch(); + } else if (ch == 'l' || ch == 'L') { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isInt64 = true; + } else if ((ch == 's' || ch == 'S') && + pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (len < MaxTokenLength) + ppToken->name[len++] = (char)ch; + isInt16 = true; + } else { + ungetch(); + } + ppToken->name[len] = '\0'; + + // Assign value + if (isInt64 && pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + if (pp->ifdepth == 0) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "64-bit binary literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int64_Extensions, Int64_Extensions, "64-bit binary literal"); + } + ppToken->i64val = ival; + return isUnsigned ? PpAtomConstUint64 : PpAtomConstInt64; + } else if (isInt16) { + if (pp->ifdepth == 0) { + if (pp->parseContext.intermediate.getSource() == EShSourceGlsl) { + pp->parseContext.requireProfile(ppToken->loc, ~EEsProfile, + "16-bit binary literal"); + pp->parseContext.profileRequires(ppToken->loc, ~EEsProfile, 0, + Num_Int16_Extensions, Int16_Extensions, "16-bit binary literal"); + } + } + ppToken->ival = (int)ival; + return isUnsigned ? PpAtomConstUint16 : PpAtomConstInt16; + } else { + ppToken->ival = (int)ival; + return isUnsigned ? PpAtomConstUint : PpAtomConstInt; + } } else { // could be octal integer or floating point, speculative pursue octal until it must be floating point @@ -692,7 +787,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->name[len++] = (char)ch; isUnsigned = true; -#ifndef GLSLANG_WEB int nextCh = getch(); if (nextCh == 'l' || nextCh == 'L') { if (len < MaxTokenLength) @@ -718,7 +812,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt16 = true; -#endif } else ungetch(); ppToken->name[len] = '\0'; @@ -781,7 +874,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) ppToken->name[len++] = (char)ch; isUnsigned = true; -#ifndef GLSLANG_WEB int nextCh = getch(); if (nextCh == 'l' || nextCh == 'L') { if (len < MaxTokenLength) @@ -807,7 +899,6 @@ int TPpContext::tStringInput::scan(TPpToken* ppToken) if (len < MaxTokenLength) ppToken->name[len++] = (char)ch; isInt16 = true; -#endif } else ungetch(); diff --git a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp index 7ed58703f..e6ee64cf9 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/preprocessor/PpTokens.cpp @@ -85,9 +85,6 @@ NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif -#if (defined(_MSC_VER) && _MSC_VER < 1900 /*vs2015*/) -#define snprintf sprintf_s -#endif #include #include @@ -116,17 +113,15 @@ int TPpContext::TokenStream::getToken(TParseContextBase& parseContext, TPpToken int atom = stream[currentPos++].get(*ppToken); ppToken->loc = parseContext.getCurrentLoc(); -#ifndef GLSLANG_WEB // Check for ##, unless the current # is the last character if (atom == '#') { if (peekToken('#')) { parseContext.requireProfile(ppToken->loc, ~EEsProfile, "token pasting (##)"); - parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, 0, "token pasting (##)"); + parseContext.profileRequires(ppToken->loc, ~EEsProfile, 130, nullptr, "token pasting (##)"); currentPos++; atom = PpAtomPaste; } } -#endif return atom; } @@ -195,9 +190,9 @@ bool TPpContext::TokenStream::peekUntokenizedPasting() return pasting; } -void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting) +void TPpContext::pushTokenStreamInput(TokenStream& ts, bool prepasting, bool expanded) { - pushInput(new tTokenInput(this, &ts, prepasting)); + pushInput(new tTokenInput(this, &ts, prepasting, expanded)); ts.reset(); } diff --git a/src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp b/src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp index 9def592ba..7b5cd03fa 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/propagateNoContraction.cpp @@ -37,8 +37,6 @@ // propagate the 'noContraction' qualifier. // -#ifndef GLSLANG_WEB - #include "propagateNoContraction.h" #include @@ -423,7 +421,7 @@ getSymbolToDefinitionMappingAndPreciseSymbolIDs(const glslang::TIntermediate& in ReturnBranchNodeSet()); TIntermNode* root = intermediate.getTreeRoot(); - if (root == 0) + if (root == nullptr) return result_tuple; NodeMapping& symbol_definition_mapping = std::get<0>(result_tuple); @@ -865,6 +863,4 @@ void PropagateNoContraction(const glslang::TIntermediate& intermediate) precise_object_accesschains.erase(precise_object_accesschain); } } -}; - -#endif // GLSLANG_WEB +} diff --git a/src/libraries/glslang/glslang/MachineIndependent/reflection.cpp b/src/libraries/glslang/glslang/MachineIndependent/reflection.cpp index c76d9c6e2..7aebd6bf9 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/reflection.cpp +++ b/src/libraries/glslang/glslang/MachineIndependent/reflection.cpp @@ -33,8 +33,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #include "../Include/Common.h" #include "reflection.h" #include "LiveTraverser.h" @@ -251,7 +249,7 @@ public: void blowUpActiveAggregate(const TType& baseType, const TString& baseName, const TList& derefs, TList::const_iterator deref, int offset, int blockIndex, int arraySize, int topLevelArraySize, int topLevelArrayStride, TStorageQualifier baseStorage, bool active, - const TConstUnionArray* constArray = nullptr) + const TConstUnionArray* constArray = nullptr) { // when strictArraySuffix is enabled, we closely follow the rules from ARB_program_interface_query. // Broadly: @@ -266,18 +264,18 @@ public: // process the part of the dereference chain that was explicit in the shader TString name = baseName; const TType* terminalType = &baseType; - const TConstUnionArray* terminalConstArray = constArray; + const TConstUnionArray* terminalConstArray = constArray; for (; deref != derefs.end(); ++deref) { TIntermBinary* visitNode = *deref; terminalType = &visitNode->getType(); - if (visitNode->getAsSymbolNode()) - terminalConstArray = &visitNode->getAsSymbolNode()->getConstArray(); - else if (visitNode->getAsConstantUnion()) - terminalConstArray = &visitNode->getAsConstantUnion()->getConstArray(); - else if (visitNode->getLeft() != nullptr && visitNode->getLeft()->getAsSymbolNode()) - terminalConstArray = &visitNode->getLeft()->getAsSymbolNode()->getConstArray(); - else - terminalConstArray = nullptr; + if (visitNode->getAsSymbolNode()) + terminalConstArray = &visitNode->getAsSymbolNode()->getConstArray(); + else if (visitNode->getAsConstantUnion()) + terminalConstArray = &visitNode->getAsConstantUnion()->getConstArray(); + else if (visitNode->getLeft() != nullptr && visitNode->getLeft()->getAsSymbolNode()) + terminalConstArray = &visitNode->getLeft()->getAsSymbolNode()->getConstArray(); + else + terminalConstArray = nullptr; int index; switch (visitNode->getOp()) { case EOpIndexIndirect: { @@ -692,7 +690,7 @@ public: } // For a binary operation indexing into an aggregate, chase down the base of the aggregate. - // Return 0 if the topology does not fit this situation. + // Return nullptr if the topology does not fit this situation. TIntermSymbol* findBase(const TIntermBinary* node) { TIntermSymbol *base = node->getLeft()->getAsSymbolNode(); @@ -716,69 +714,73 @@ public: case EbtFloat: switch ((int)sampler.dim) { case Esd1D: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D; - case true: return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW; - } + if (sampler.shadow) + return sampler.arrayed ? GL_SAMPLER_1D_ARRAY_SHADOW : GL_SAMPLER_1D_SHADOW; + else + return sampler.arrayed ? GL_SAMPLER_1D_ARRAY : GL_SAMPLER_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D; - case true: return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW; - } - case true: return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE; + if (sampler.ms) { + return sampler.arrayed ? GL_SAMPLER_2D_MULTISAMPLE_ARRAY : GL_SAMPLER_2D_MULTISAMPLE; + } else { + if (sampler.shadow) + return sampler.arrayed ? GL_SAMPLER_2D_ARRAY_SHADOW : GL_SAMPLER_2D_SHADOW; + else + return sampler.arrayed ? GL_SAMPLER_2D_ARRAY : GL_SAMPLER_2D; } case Esd3D: return GL_SAMPLER_3D; case EsdCube: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE; - case true: return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW; - } + if (sampler.shadow) + return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW : GL_SAMPLER_CUBE_SHADOW; + else + return sampler.arrayed ? GL_SAMPLER_CUBE_MAP_ARRAY : GL_SAMPLER_CUBE; case EsdRect: return sampler.shadow ? GL_SAMPLER_2D_RECT_SHADOW : GL_SAMPLER_2D_RECT; case EsdBuffer: return GL_SAMPLER_BUFFER; + default: + return 0; } case EbtFloat16: switch ((int)sampler.dim) { case Esd1D: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD; - case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD; - } + if (sampler.shadow) + return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_1D_SHADOW_AMD; + else + return sampler.arrayed ? GL_FLOAT16_SAMPLER_1D_ARRAY_AMD : GL_FLOAT16_SAMPLER_1D_AMD; case Esd2D: - switch ((int)sampler.ms) { - case false: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD; - case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD; - } - case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD; + if (sampler.ms) { + return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_MULTISAMPLE_AMD; + } else { + if (sampler.shadow) + return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_SHADOW_AMD; + else + return sampler.arrayed ? GL_FLOAT16_SAMPLER_2D_ARRAY_AMD : GL_FLOAT16_SAMPLER_2D_AMD; } case Esd3D: return GL_FLOAT16_SAMPLER_3D_AMD; case EsdCube: - switch ((int)sampler.shadow) { - case false: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD; - case true: return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD; - } + if (sampler.shadow) + return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_SHADOW_AMD : GL_FLOAT16_SAMPLER_CUBE_SHADOW_AMD; + else + return sampler.arrayed ? GL_FLOAT16_SAMPLER_CUBE_MAP_ARRAY_AMD : GL_FLOAT16_SAMPLER_CUBE_AMD; case EsdRect: return sampler.shadow ? GL_FLOAT16_SAMPLER_2D_RECT_SHADOW_AMD : GL_FLOAT16_SAMPLER_2D_RECT_AMD; case EsdBuffer: return GL_FLOAT16_SAMPLER_BUFFER_AMD; + default: + return 0; } case EbtInt: switch ((int)sampler.dim) { case Esd1D: return sampler.arrayed ? GL_INT_SAMPLER_1D_ARRAY : GL_INT_SAMPLER_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D; - case true: return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY - : GL_INT_SAMPLER_2D_MULTISAMPLE; - } + if (sampler.ms) + return sampler.arrayed ? GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + : GL_INT_SAMPLER_2D_MULTISAMPLE; + else + return sampler.arrayed ? GL_INT_SAMPLER_2D_ARRAY : GL_INT_SAMPLER_2D; case Esd3D: return GL_INT_SAMPLER_3D; case EsdCube: @@ -787,17 +789,19 @@ public: return GL_INT_SAMPLER_2D_RECT; case EsdBuffer: return GL_INT_SAMPLER_BUFFER; + default: + return 0; } case EbtUint: switch ((int)sampler.dim) { case Esd1D: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_1D_ARRAY : GL_UNSIGNED_INT_SAMPLER_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D; - case true: return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY - : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; - } + if (sampler.ms) + return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY + : GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE; + else + return sampler.arrayed ? GL_UNSIGNED_INT_SAMPLER_2D_ARRAY : GL_UNSIGNED_INT_SAMPLER_2D; case Esd3D: return GL_UNSIGNED_INT_SAMPLER_3D; case EsdCube: @@ -806,6 +810,8 @@ public: return GL_UNSIGNED_INT_SAMPLER_2D_RECT; case EsdBuffer: return GL_UNSIGNED_INT_SAMPLER_BUFFER; + default: + return 0; } default: return 0; @@ -818,10 +824,10 @@ public: case Esd1D: return sampler.arrayed ? GL_IMAGE_1D_ARRAY : GL_IMAGE_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D; - case true: return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE; - } + if (sampler.ms) + return sampler.arrayed ? GL_IMAGE_2D_MULTISAMPLE_ARRAY : GL_IMAGE_2D_MULTISAMPLE; + else + return sampler.arrayed ? GL_IMAGE_2D_ARRAY : GL_IMAGE_2D; case Esd3D: return GL_IMAGE_3D; case EsdCube: @@ -830,16 +836,18 @@ public: return GL_IMAGE_2D_RECT; case EsdBuffer: return GL_IMAGE_BUFFER; + default: + return 0; } case EbtFloat16: switch ((int)sampler.dim) { case Esd1D: return sampler.arrayed ? GL_FLOAT16_IMAGE_1D_ARRAY_AMD : GL_FLOAT16_IMAGE_1D_AMD; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD; - case true: return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD; - } + if (sampler.ms) + return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_MULTISAMPLE_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_MULTISAMPLE_AMD; + else + return sampler.arrayed ? GL_FLOAT16_IMAGE_2D_ARRAY_AMD : GL_FLOAT16_IMAGE_2D_AMD; case Esd3D: return GL_FLOAT16_IMAGE_3D_AMD; case EsdCube: @@ -848,16 +856,18 @@ public: return GL_FLOAT16_IMAGE_2D_RECT_AMD; case EsdBuffer: return GL_FLOAT16_IMAGE_BUFFER_AMD; + default: + return 0; } case EbtInt: switch ((int)sampler.dim) { case Esd1D: return sampler.arrayed ? GL_INT_IMAGE_1D_ARRAY : GL_INT_IMAGE_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D; - case true: return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE; - } + if (sampler.ms) + return sampler.arrayed ? GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY : GL_INT_IMAGE_2D_MULTISAMPLE; + else + return sampler.arrayed ? GL_INT_IMAGE_2D_ARRAY : GL_INT_IMAGE_2D; case Esd3D: return GL_INT_IMAGE_3D; case EsdCube: @@ -866,17 +876,19 @@ public: return GL_INT_IMAGE_2D_RECT; case EsdBuffer: return GL_INT_IMAGE_BUFFER; + default: + return 0; } case EbtUint: switch ((int)sampler.dim) { case Esd1D: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_1D_ARRAY : GL_UNSIGNED_INT_IMAGE_1D; case Esd2D: - switch ((int)sampler.ms) { - case false: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D; - case true: return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY - : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE; - } + if (sampler.ms) + return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY + : GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE; + else + return sampler.arrayed ? GL_UNSIGNED_INT_IMAGE_2D_ARRAY : GL_UNSIGNED_INT_IMAGE_2D; case Esd3D: return GL_UNSIGNED_INT_IMAGE_3D; case EsdCube: @@ -885,6 +897,8 @@ public: return GL_UNSIGNED_INT_IMAGE_2D_RECT; case EsdBuffer: return GL_UNSIGNED_INT_IMAGE_BUFFER; + default: + return 0; } default: return 0; @@ -949,6 +963,7 @@ public: case 4: return GL_FLOAT_MAT4; default: return 0; } + default: return 0; } case EbtDouble: switch (type.getMatrixCols()) { @@ -973,6 +988,7 @@ public: case 4: return GL_DOUBLE_MAT4; default: return 0; } + default: return 0; } case EbtFloat16: switch (type.getMatrixCols()) { @@ -997,6 +1013,7 @@ public: case 4: return GL_FLOAT16_MAT4_AMD; default: return 0; } + default: return 0; } default: return 0; @@ -1280,5 +1297,3 @@ void TReflection::dump() } } // end namespace glslang - -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/src/libraries/glslang/glslang/MachineIndependent/reflection.h b/src/libraries/glslang/glslang/MachineIndependent/reflection.h index 5af4467c1..221d93f8b 100644 --- a/src/libraries/glslang/glslang/MachineIndependent/reflection.h +++ b/src/libraries/glslang/glslang/MachineIndependent/reflection.h @@ -33,8 +33,6 @@ // POSSIBILITY OF SUCH DAMAGE. // -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - #ifndef _REFLECTION_INCLUDED #define _REFLECTION_INCLUDED @@ -219,5 +217,3 @@ protected: } // end namespace glslang #endif // _REFLECTION_INCLUDED - -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE diff --git a/src/libraries/glslang/glslang/MachineIndependent/span.h b/src/libraries/glslang/glslang/MachineIndependent/span.h new file mode 100644 index 000000000..bd705fead --- /dev/null +++ b/src/libraries/glslang/glslang/MachineIndependent/span.h @@ -0,0 +1,92 @@ +#pragma once + +// +// Copyright (C) 2023 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. +// + +// Partial implementation of std::span for C++11 +// Replace with std::span if repo standard is bumped to C++20 +// +// This code was copied from https://github.com/KhronosGroup/Vulkan-ValidationLayers/blob/main/layers/containers/custom_containers.h +template +class span { + public: + using pointer = T *; + using const_pointer = T const *; + using iterator = pointer; + using const_iterator = const_pointer; + + span() = default; + span(pointer start, size_t n) : data_(start), count_(n) {} + template + span(Iterator start, Iterator end) : data_(&(*start)), count_(end - start) {} + template + span(Container &c) : data_(c.data()), count_(c.size()) {} + + iterator begin() { return data_; } + const_iterator begin() const { return data_; } + + iterator end() { return data_ + count_; } + const_iterator end() const { return data_ + count_; } + + T &operator[](int i) { return data_[i]; } + const T &operator[](int i) const { return data_[i]; } + + T &front() { return *data_; } + const T &front() const { return *data_; } + + T &back() { return *(data_ + (count_ - 1)); } + const T &back() const { return *(data_ + (count_ - 1)); } + + size_t size() const { return count_; } + bool empty() const { return count_ == 0; } + + pointer data() { return data_; } + const_pointer data() const { return data_; } + + private: + pointer data_ = {}; + size_t count_ = 0; +}; + +// +// Allow type inference that using the constructor doesn't allow in C++11 +template +span make_span(T *begin, size_t count) { + return span(begin, count); +} +template +span make_span(T *begin, T *end) { + return make_span(begin, end); +} diff --git a/src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp b/src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp index 81da99c2c..fbb51f7bd 100644 --- a/src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp +++ b/src/libraries/glslang/glslang/OSDependent/Unix/ossource.cpp @@ -36,15 +36,8 @@ // This file contains the Linux-specific functions // #include "../osinclude.h" -#include "../../../OGLCompilersDLL/InitializeDll.h" -#include -#include -#include -#include -#include #include -#include #if !defined(__Fuchsia__) #include @@ -52,150 +45,6 @@ namespace glslang { -// -// Thread cleanup -// - -// -// Wrapper for Linux call to DetachThread. This is required as pthread_cleanup_push() expects -// the cleanup routine to return void. -// -static void DetachThreadLinux(void *) -{ - DetachThread(); -} - -// -// Registers cleanup handler, sets cancel type and state, and executes the thread specific -// cleanup handler. This function will be called in the Standalone.cpp for regression -// testing. When OpenGL applications are run with the driver code, Linux OS does the -// thread cleanup. -// -void OS_CleanupThreadData(void) -{ -#if defined(__ANDROID__) || defined(__Fuchsia__) - DetachThreadLinux(NULL); -#else - int old_cancel_state, old_cancel_type; - void *cleanupArg = NULL; - - // - // Set thread cancel state and push cleanup handler. - // - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancel_state); - pthread_cleanup_push(DetachThreadLinux, (void *) cleanupArg); - - // - // Put the thread in deferred cancellation mode. - // - pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &old_cancel_type); - - // - // Pop cleanup handler and execute it prior to unregistering the cleanup handler. - // - pthread_cleanup_pop(1); - - // - // Restore the thread's previous cancellation mode. - // - pthread_setcanceltype(old_cancel_state, NULL); -#endif -} - -// -// Thread Local Storage Operations -// -inline OS_TLSIndex PthreadKeyToTLSIndex(pthread_key_t key) -{ - return (OS_TLSIndex)((uintptr_t)key + 1); -} - -inline pthread_key_t TLSIndexToPthreadKey(OS_TLSIndex nIndex) -{ - return (pthread_key_t)((uintptr_t)nIndex - 1); -} - -OS_TLSIndex OS_AllocTLSIndex() -{ - pthread_key_t pPoolIndex; - - // - // Create global pool key. - // - if ((pthread_key_create(&pPoolIndex, NULL)) != 0) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return OS_INVALID_TLS_INDEX; - } - else - return PthreadKeyToTLSIndex(pPoolIndex); -} - -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (pthread_setspecific(TLSIndexToPthreadKey(nIndex), lpvValue) == 0) - return true; - else - return false; -} - -void* OS_GetTLSValue(OS_TLSIndex nIndex) -{ - // - // This function should return 0 if nIndex is invalid. - // - assert(nIndex != OS_INVALID_TLS_INDEX); - return pthread_getspecific(TLSIndexToPthreadKey(nIndex)); -} - -bool OS_FreeTLSIndex(OS_TLSIndex nIndex) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - // - // Delete the global pool key. - // - if (pthread_key_delete(TLSIndexToPthreadKey(nIndex)) == 0) - return true; - else - return false; -} - -namespace { - pthread_mutex_t gMutex; -} - -static void InitMutex(void) -{ - pthread_mutexattr_t mutexattr; - pthread_mutexattr_init(&mutexattr); - pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&gMutex, &mutexattr); -} - -void InitGlobalLock() -{ - static pthread_once_t once = PTHREAD_ONCE_INIT; - pthread_once(&once, InitMutex); -} - -void GetGlobalLock() -{ - pthread_mutex_lock(&gMutex); -} - -void ReleaseGlobalLock() -{ - pthread_mutex_unlock(&gMutex); -} - // #define DUMP_COUNTERS void OS_DumpMemoryCounters() diff --git a/src/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp b/src/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp index f2306a609..c820da6aa 100644 --- a/src/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp +++ b/src/libraries/glslang/glslang/OSDependent/Web/glslang.js.cpp @@ -141,6 +141,15 @@ const TBuiltInResource DefaultTBuiltInResource = { /* .maxTaskWorkGroupSizeY_NV = */ 1, /* .maxTaskWorkGroupSizeZ_NV = */ 1, /* .maxMeshViewCountNV = */ 4, + /* .maxMeshOutputVerticesEXT = */ 256, + /* .maxMeshOutputPrimitivesEXT = */ 512, + /* .maxMeshWorkGroupSizeX_EXT = */ 32, + /* .maxMeshWorkGroupSizeY_EXT = */ 1, + /* .maxMeshWorkGroupSizeZ_EXT = */ 1, + /* .maxTaskWorkGroupSizeX_EXT = */ 32, + /* .maxTaskWorkGroupSizeY_EXT = */ 1, + /* .maxTaskWorkGroupSizeZ_EXT = */ 1, + /* .maxMeshViewCountEXT = */ 4, /* .maxDualSourceDrawBuffersEXT = */ 1, /* .limits = */ { diff --git a/src/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js b/src/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js index 46a569506..390390e99 100644 --- a/src/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js +++ b/src/libraries/glslang/glslang/OSDependent/Web/glslang.pre.js @@ -25,7 +25,7 @@ Module['compileGLSLZeroCopy'] = function(glsl, shader_stage, gen_debug, spirv_ve var p_output = Module['_malloc'](4); var p_output_len = Module['_malloc'](4); - var id = ccall('convert_glsl_to_spirv', + var id = Module['ccall']('convert_glsl_to_spirv', 'number', ['string', 'number', 'boolean', 'number', 'number', 'number'], [glsl, shader_stage_int, gen_debug, spirv_version_int, p_output, p_output_len]); diff --git a/src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp b/src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp index 870840c56..d7f89f71b 100644 --- a/src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp +++ b/src/libraries/glslang/glslang/OSDependent/Windows/ossource.cpp @@ -37,11 +37,9 @@ #define STRICT #define VC_EXTRALEAN 1 #include -#include #include #include #include -#include // // This file contains the Window-OS-specific functions @@ -53,84 +51,6 @@ namespace glslang { -inline OS_TLSIndex ToGenericTLSIndex (DWORD handle) -{ - return (OS_TLSIndex)((uintptr_t)handle + 1); -} - -inline DWORD ToNativeTLSIndex (OS_TLSIndex nIndex) -{ - return (DWORD)((uintptr_t)nIndex - 1); -} - -// -// Thread Local Storage Operations -// -OS_TLSIndex OS_AllocTLSIndex() -{ - DWORD dwIndex = TlsAlloc(); - if (dwIndex == TLS_OUT_OF_INDEXES) { - assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); - return OS_INVALID_TLS_INDEX; - } - - return ToGenericTLSIndex(dwIndex); -} - -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (TlsSetValue(ToNativeTLSIndex(nIndex), lpvValue)) - return true; - else - return false; -} - -void* OS_GetTLSValue(OS_TLSIndex nIndex) -{ - assert(nIndex != OS_INVALID_TLS_INDEX); - return TlsGetValue(ToNativeTLSIndex(nIndex)); -} - -bool OS_FreeTLSIndex(OS_TLSIndex nIndex) -{ - if (nIndex == OS_INVALID_TLS_INDEX) { - assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); - return false; - } - - if (TlsFree(ToNativeTLSIndex(nIndex))) - return true; - else - return false; -} - -HANDLE GlobalLock; - -void InitGlobalLock() -{ - GlobalLock = CreateMutex(0, false, 0); -} - -void GetGlobalLock() -{ - WaitForSingleObject(GlobalLock, INFINITE); -} - -void ReleaseGlobalLock() -{ - ReleaseMutex(GlobalLock); -} - -unsigned int __stdcall EnterGenericThread (void* entry) -{ - return ((TThreadEntrypoint)entry)(0); -} - //#define DUMP_COUNTERS void OS_DumpMemoryCounters() diff --git a/src/libraries/glslang/glslang/OSDependent/osinclude.h b/src/libraries/glslang/glslang/OSDependent/osinclude.h index 218abe4f2..0d677e4af 100644 --- a/src/libraries/glslang/glslang/OSDependent/osinclude.h +++ b/src/libraries/glslang/glslang/OSDependent/osinclude.h @@ -37,25 +37,6 @@ namespace glslang { -// -// Thread Local Storage Operations -// -typedef void* OS_TLSIndex; -#define OS_INVALID_TLS_INDEX ((void*)0) - -OS_TLSIndex OS_AllocTLSIndex(); -bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); -bool OS_FreeTLSIndex(OS_TLSIndex nIndex); -void* OS_GetTLSValue(OS_TLSIndex nIndex); - -void InitGlobalLock(); -void GetGlobalLock(); -void ReleaseGlobalLock(); - -typedef unsigned int (*TThreadEntrypoint)(void*); - -void OS_CleanupThreadData(void); - void OS_DumpMemoryCounters(); } // end namespace glslang diff --git a/src/libraries/glslang/glslang/OSDependent/Windows/main.cpp b/src/libraries/glslang/glslang/Public/ResourceLimits.h similarity index 61% rename from src/libraries/glslang/glslang/OSDependent/Windows/main.cpp rename to src/libraries/glslang/glslang/Public/ResourceLimits.h index 0217e0a64..f70be8172 100644 --- a/src/libraries/glslang/glslang/OSDependent/Windows/main.cpp +++ b/src/libraries/glslang/glslang/Public/ResourceLimits.h @@ -1,5 +1,6 @@ // -// Copyright (C) 2002-2005 3Dlabs Inc. Ltd. +// Copyright (C) 2016 Google, Inc. +// // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -14,7 +15,7 @@ // disclaimer in the documentation and/or other materials provided // with the distribution. // -// Neither the name of 3Dlabs Inc. Ltd. nor the names of its +// 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. // @@ -30,45 +31,27 @@ // 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 "glslang/OGLCompilersDLL/InitializeDll.h" +#ifndef _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_ +#define _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_ -#define STRICT -#define VC_EXTRALEAN 1 -#include -#include +#include -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - switch (fdwReason) - { - case DLL_PROCESS_ATTACH: +#include "../Include/ResourceLimits.h" - if (! glslang::InitProcess()) - return FALSE; - break; - case DLL_THREAD_ATTACH: +// Return pointer to user-writable Resource to pass through API in +// future-proof way. +extern TBuiltInResource* GetResources(); - if (! glslang::InitThread()) - return FALSE; - break; +// 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* GetDefaultResources(); - case DLL_THREAD_DETACH: +// Returns the DefaultTBuiltInResource as a human-readable string. +std::string GetDefaultTBuiltInResourceString(); - if (! glslang::DetachThread()) - return FALSE; - break; +// Decodes the resource limits from |config| to |resources|. +void DecodeResourceLimits(TBuiltInResource* resources, char* config); - case DLL_PROCESS_DETACH: - - glslang::DetachProcess(); - break; - - default: - assert(0 && "DllMain(): Reason for calling DLL Main is unknown"); - return FALSE; - } - - return TRUE; -} +#endif // _STAND_ALONE_RESOURCE_LIMITS_INCLUDED_ diff --git a/src/libraries/glslang/glslang/Public/ShaderLang.h b/src/libraries/glslang/glslang/Public/ShaderLang.h index 1fd692c7c..a6eb53b20 100644 --- a/src/libraries/glslang/glslang/Public/ShaderLang.h +++ b/src/libraries/glslang/glslang/Public/ShaderLang.h @@ -108,8 +108,10 @@ typedef enum { EShLangMissNV = EShLangMiss, EShLangCallable, EShLangCallableNV = EShLangCallable, - EShLangTaskNV, - EShLangMeshNV, + EShLangTask, + EShLangTaskNV = EShLangTask, + EShLangMesh, + EShLangMeshNV = EShLangMesh, LAST_ELEMENT_MARKER(EShLangCount), } EShLanguage; // would be better as stage, but this is ancient now @@ -132,8 +134,10 @@ typedef enum : unsigned { EShLangMissNVMask = EShLangMissMask, EShLangCallableMask = (1 << EShLangCallable), EShLangCallableNVMask = EShLangCallableMask, - EShLangTaskNVMask = (1 << EShLangTaskNV), - EShLangMeshNVMask = (1 << EShLangMeshNV), + EShLangTaskMask = (1 << EShLangTask), + EShLangTaskNVMask = EShLangTaskMask, + EShLangMeshMask = (1 << EShLangMesh), + EShLangMeshNVMask = EShLangMeshMask, LAST_ELEMENT_MARKER(EShLanguageMaskCount), } EShLanguageMask; @@ -151,8 +155,8 @@ typedef enum { typedef enum { EShClientNone, // use when there is no client, e.g. for validation - EShClientVulkan, - EShClientOpenGL, + EShClientVulkan, // as GLSL dialect, specifies KHR_vulkan_glsl extension + EShClientOpenGL, // as GLSL dialect, specifies ARB_gl_spirv extension LAST_ELEMENT_MARKER(EShClientCount), } EShClient; @@ -164,12 +168,12 @@ typedef enum { } EShTargetLanguage; typedef enum { - EShTargetUniversal = 0, // Universal EShTargetVulkan_1_0 = (1 << 22), // Vulkan 1.0 EShTargetVulkan_1_1 = (1 << 22) | (1 << 12), // Vulkan 1.1 EShTargetVulkan_1_2 = (1 << 22) | (2 << 12), // Vulkan 1.2 + EShTargetVulkan_1_3 = (1 << 22) | (3 << 12), // Vulkan 1.3 EShTargetOpenGL_450 = 450, // OpenGL - LAST_ELEMENT_MARKER(EShTargetClientVersionCount = 4), + LAST_ELEMENT_MARKER(EShTargetClientVersionCount = 5), } EShTargetClientVersion; typedef EShTargetClientVersion EshTargetClientVersion; @@ -249,22 +253,24 @@ typedef enum { // Message choices for what errors and warnings are given. // enum EShMessages : unsigned { - EShMsgDefault = 0, // default is to give all required errors and extra warnings - EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input - EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification - EShMsgAST = (1 << 2), // print the AST intermediate representation - EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation - EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V - EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor - EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics - EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit - EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions - EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules - EShMsgDebugInfo = (1 << 10), // save debug information - EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL - EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages - EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (for samplers and semantics) - EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table + EShMsgDefault = 0, // default is to give all required errors and extra warnings + EShMsgRelaxedErrors = (1 << 0), // be liberal in accepting input + EShMsgSuppressWarnings = (1 << 1), // suppress all warnings, except those required by the specification + EShMsgAST = (1 << 2), // print the AST intermediate representation + EShMsgSpvRules = (1 << 3), // issue messages for SPIR-V generation + EShMsgVulkanRules = (1 << 4), // issue messages for Vulkan-requirements of GLSL for SPIR-V + EShMsgOnlyPreprocessor = (1 << 5), // only print out errors produced by the preprocessor + EShMsgReadHlsl = (1 << 6), // use HLSL parsing rules and semantics + EShMsgCascadingErrors = (1 << 7), // get cascading errors; risks error-recovery issues, instead of an early exit + EShMsgKeepUncalled = (1 << 8), // for testing, don't eliminate uncalled functions + EShMsgHlslOffsets = (1 << 9), // allow block offsets to follow HLSL rules instead of GLSL rules + EShMsgDebugInfo = (1 << 10), // save debug information + EShMsgHlslEnable16BitTypes = (1 << 11), // enable use of 16-bit types in SPIR-V for HLSL + EShMsgHlslLegalization = (1 << 12), // enable HLSL Legalization messages + EShMsgHlslDX9Compatible = (1 << 13), // enable HLSL DX9 compatible mode (for samplers and semantics) + EShMsgBuiltinSymbolTable = (1 << 14), // print the builtin symbol table + EShMsgEnhanced = (1 << 15), // enhanced message readability + EShMsgAbsolutePath = (1 << 16), // Output Absolute path for messages LAST_ELEMENT_MARKER(EShMsgCount), }; @@ -301,7 +307,7 @@ typedef struct { // // ShHandle held by but opaque to the driver. It is allocated, -// managed, and de-allocated by the compiler/linker. It's contents +// managed, and de-allocated by the compiler/linker. Its contents // are defined by and used by the compiler and linker. For example, // symbol table information and object code passed from the compiler // to the linker can be stored where ShHandle points. @@ -314,8 +320,8 @@ typedef void* ShHandle; // Driver calls these to create and destroy compiler/linker // objects. // -GLSLANG_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader -GLSLANG_EXPORT ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair +GLSLANG_EXPORT ShHandle ShConstructCompiler(const EShLanguage, int /*debugOptions unused*/); // one per shader +GLSLANG_EXPORT ShHandle ShConstructLinker(const EShExecutable, int /*debugOptions unused*/); // one per shader pair GLSLANG_EXPORT ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object) GLSLANG_EXPORT void ShDestruct(ShHandle); @@ -326,18 +332,14 @@ GLSLANG_EXPORT void ShDestruct(ShHandle); // The info-log should be written by ShCompile into // ShHandle, so it can answer future queries. // -GLSLANG_EXPORT int ShCompile( - const ShHandle, - const char* const shaderStrings[], - const int numStrings, - const int* lengths, - const EShOptimizationLevel, - const TBuiltInResource *resources, - int debugOptions, - int defaultVersion = 110, // use 100 for ES environment, overridden by #version in shader - bool forwardCompatible = false, // give errors for use of deprecated features - EShMessages messages = EShMsgDefault // warnings and errors - ); +GLSLANG_EXPORT int ShCompile(const ShHandle, const char* const shaderStrings[], const int numStrings, + const int* lengths, const EShOptimizationLevel, const TBuiltInResource* resources, + int, // debugOptions unused + int defaultVersion = 110, // use 100 for ES environment, overridden by #version in shader + bool forwardCompatible = false, // give errors for use of deprecated features + EShMessages messages = EShMsgDefault, // warnings and errors + const char* fileName = nullptr +); GLSLANG_EXPORT int ShLinkExt( const ShHandle, // linker object @@ -471,6 +473,8 @@ public: GLSLANG_EXPORT void setSourceEntryPoint(const char* sourceEntryPointName); GLSLANG_EXPORT void addProcesses(const std::vector&); GLSLANG_EXPORT void setUniqueId(unsigned long long id); + GLSLANG_EXPORT void setOverrideVersion(int version); + GLSLANG_EXPORT void setDebugInfo(bool debugInfo); // IO resolver binding data: see comments in ShaderLang.cpp GLSLANG_EXPORT void setShiftBinding(TResourceType res, unsigned int base); @@ -489,6 +493,7 @@ public: GLSLANG_EXPORT void setUniformLocationBase(int base); GLSLANG_EXPORT void setInvertY(bool invert); GLSLANG_EXPORT void setDxPositionW(bool dxPosW); + GLSLANG_EXPORT void setEnhancedMsgs(); #ifdef ENABLE_HLSL GLSLANG_EXPORT void setHlslIoMapping(bool hlslIoMap); GLSLANG_EXPORT void setFlattenUniformArrays(bool flatten); @@ -516,11 +521,14 @@ public: // use EShClientNone and version of 0, e.g. for validation mode. // Note 'version' does not describe the target environment, // just the version of the source dialect to compile under. + // For example, to choose the Vulkan dialect of GLSL defined by + // version 100 of the KHR_vulkan_glsl extension: lang = EShSourceGlsl, + // dialect = EShClientVulkan, and version = 100. // // See the definitions of TEnvironment, EShSource, EShLanguage, // and EShClient for choices and more detail. // - // setEnvClient: The client that will be hosting the execution, and it's version. + // setEnvClient: The client that will be hosting the execution, and its version. // Note 'version' is not the version of the languages involved, but // the version of the client environment. // Use EShClientNone and version of 0 if there is no client, e.g. @@ -563,6 +571,9 @@ public: void setEnvInputVulkanRulesRelaxed() { environment.input.vulkanRulesRelaxed = true; } bool getEnvInputVulkanRulesRelaxed() const { return environment.input.vulkanRulesRelaxed; } + void setCompileOnly() { compileOnly = true; } + bool getCompileOnly() const { return compileOnly; } + // Interface to #include handlers. // // To support #include, a client of Glslang does the following: @@ -707,16 +718,20 @@ protected: // a function in the source string can be renamed FROM this TO the name given in setEntryPoint. std::string sourceEntryPointName; + // overrides #version in shader source or default version if #version isn't present + int overrideVersion; + TEnvironment environment; + // Indicates this shader is meant to be used without linking + bool compileOnly = false; + friend class TProgram; private: TShader& operator=(TShader&); }; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - // // A reflection database and its interface, consistent with the OpenGL API reflection queries. // @@ -727,7 +742,7 @@ public: GLSLANG_EXPORT TObjectReflection(const std::string& pName, const TType& pType, int pOffset, int pGLDefineType, int pSize, int pIndex, const TConstUnionArray* pConstArray = nullptr); const TType* getType() const { return type; } - const TConstUnionArray* getConstArray() const { return constArray; } + const TConstUnionArray* getConstArray() const { return constArray; } GLSLANG_EXPORT int getBinding() const; GLSLANG_EXPORT void dump() const; static TObjectReflection badReflection() { return TObjectReflection(); } @@ -752,7 +767,7 @@ protected: } const TType* type; - const TConstUnionArray* constArray; + const TConstUnionArray* constArray; }; class TReflection; @@ -835,8 +850,6 @@ public: virtual void addStage(EShLanguage stage, TIntermediate& stageIntermediate) = 0; }; -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE - // Make one TProgram per set of shaders that will get linked together. Add all // the shaders that are to be linked together. After calling shader.parse() // for all shaders, call link(). @@ -856,8 +869,6 @@ public: TIntermediate* getIntermediate(EShLanguage stage) const { return intermediate[stage]; } -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) - // Reflection Interface // call first, to do liveness analysis, index mapping, etc.; returns false on failure @@ -950,7 +961,6 @@ public: // If resolver is not provided it uses the previous approach // and respects auto assignment and offsets. GLSLANG_EXPORT bool mapIO(TIoMapResolver* pResolver = nullptr, TIoMapper* pIoMapper = nullptr); -#endif // !GLSLANG_WEB && !GLSLANG_ANGLE protected: GLSLANG_EXPORT bool linkStage(EShLanguage, EShMessages); @@ -961,9 +971,7 @@ protected: TIntermediate* intermediate[EShLangCount]; bool newedIntermediate[EShLangCount]; // track which intermediate were "new" versus reusing a singleton unit in a stage TInfoSink* infoSink; -#if !defined(GLSLANG_WEB) && !defined(GLSLANG_ANGLE) TReflection* reflection; -#endif bool linked; private: diff --git a/src/libraries/glslang/glslang/ResourceLimits/ResourceLimits.cpp b/src/libraries/glslang/glslang/ResourceLimits/ResourceLimits.cpp new file mode 100644 index 000000000..c255604b9 --- /dev/null +++ b/src/libraries/glslang/glslang/ResourceLimits/ResourceLimits.cpp @@ -0,0 +1,542 @@ +// +// 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 +#include +#include +#include + +#include "../../glslang/Public/ResourceLimits.h" + +TBuiltInResource Resources; + +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, + /* .maxMeshOutputVerticesEXT = */ 256, + /* .maxMeshOutputPrimitivesEXT = */ 256, + /* .maxMeshWorkGroupSizeX_EXT = */ 128, + /* .maxMeshWorkGroupSizeY_EXT = */ 128, + /* .maxMeshWorkGroupSizeZ_EXT = */ 128, + /* .maxTaskWorkGroupSizeX_EXT = */ 128, + /* .maxTaskWorkGroupSizeY_EXT = */ 128, + /* .maxTaskWorkGroupSizeZ_EXT = */ 128, + /* .maxMeshViewCountEXT = */ 4, + /* .maxDualSourceDrawBuffersEXT = */ 1, + + /* .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" + << "MaxMeshOutputVerticesEXT " << DefaultTBuiltInResource.maxMeshOutputVerticesEXT << "\n" + << "MaxMeshOutputPrimitivesEXT " << DefaultTBuiltInResource.maxMeshOutputPrimitivesEXT << "\n" + << "MaxMeshWorkGroupSizeX_EXT " << DefaultTBuiltInResource.maxMeshWorkGroupSizeX_EXT << "\n" + << "MaxMeshWorkGroupSizeY_EXT " << DefaultTBuiltInResource.maxMeshWorkGroupSizeY_EXT << "\n" + << "MaxMeshWorkGroupSizeZ_EXT " << DefaultTBuiltInResource.maxMeshWorkGroupSizeZ_EXT << "\n" + << "MaxTaskWorkGroupSizeX_EXT " << DefaultTBuiltInResource.maxTaskWorkGroupSizeX_EXT << "\n" + << "MaxTaskWorkGroupSizeY_EXT " << DefaultTBuiltInResource.maxTaskWorkGroupSizeY_EXT << "\n" + << "MaxTaskWorkGroupSizeZ_EXT " << DefaultTBuiltInResource.maxTaskWorkGroupSizeZ_EXT << "\n" + << "MaxMeshViewCountEXT " << DefaultTBuiltInResource.maxMeshViewCountEXT << "\n" + << "MaxDualSourceDrawBuffersEXT " << DefaultTBuiltInResource.maxDualSourceDrawBuffersEXT << "\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 == "MaxMeshOutputVerticesEXT") + resources->maxMeshOutputVerticesEXT = value; + else if (tokenStr == "MaxMeshOutputPrimitivesEXT") + resources->maxMeshOutputPrimitivesEXT = value; + else if (tokenStr == "MaxMeshWorkGroupSizeX_EXT") + resources->maxMeshWorkGroupSizeX_EXT = value; + else if (tokenStr == "MaxMeshWorkGroupSizeY_EXT") + resources->maxMeshWorkGroupSizeY_EXT = value; + else if (tokenStr == "MaxMeshWorkGroupSizeZ_EXT") + resources->maxMeshWorkGroupSizeZ_EXT = value; + else if (tokenStr == "MaxTaskWorkGroupSizeX_EXT") + resources->maxTaskWorkGroupSizeX_EXT = value; + else if (tokenStr == "MaxTaskWorkGroupSizeY_EXT") + resources->maxTaskWorkGroupSizeY_EXT = value; + else if (tokenStr == "MaxTaskWorkGroupSizeZ_EXT") + resources->maxTaskWorkGroupSizeZ_EXT = value; + else if (tokenStr == "MaxMeshViewCountEXT") + resources->maxMeshViewCountEXT = value; + else if (tokenStr == "MaxDualSourceDrawBuffersEXT") + resources->maxDualSourceDrawBuffersEXT = 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()); + + } +} + +TBuiltInResource* GetResources() +{ + return &Resources; +} + +const TBuiltInResource* GetDefaultResources() +{ + return &DefaultTBuiltInResource; +} diff --git a/src/libraries/glslang/glslang/build_info.h b/src/libraries/glslang/glslang/build_info.h index 319bfa5f7..ffb33ca0d 100644 --- a/src/libraries/glslang/glslang/build_info.h +++ b/src/libraries/glslang/glslang/build_info.h @@ -34,29 +34,29 @@ #ifndef GLSLANG_BUILD_INFO #define GLSLANG_BUILD_INFO -#define GLSLANG_VERSION_MAJOR 11 +#define GLSLANG_VERSION_MAJOR 14 #define GLSLANG_VERSION_MINOR 0 #define GLSLANG_VERSION_PATCH 0 #define GLSLANG_VERSION_FLAVOR "" #define GLSLANG_VERSION_GREATER_THAN(major, minor, patch) \ - (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ - (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ - ((patch) > GLSLANG_VERSION_PATCH))))) + ((GLSLANG_VERSION_MAJOR) > (major) || ((major) == GLSLANG_VERSION_MAJOR && \ + ((GLSLANG_VERSION_MINOR) > (minor) || ((minor) == GLSLANG_VERSION_MINOR && \ + (GLSLANG_VERSION_PATCH) > (patch))))) #define GLSLANG_VERSION_GREATER_OR_EQUAL_TO(major, minor, patch) \ - (((major) > GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ - (((minor) > GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ - ((patch) >= GLSLANG_VERSION_PATCH))))) + ((GLSLANG_VERSION_MAJOR) > (major) || ((major) == GLSLANG_VERSION_MAJOR && \ + ((GLSLANG_VERSION_MINOR) > (minor) || ((minor) == GLSLANG_VERSION_MINOR && \ + (GLSLANG_VERSION_PATCH >= (patch)))))) #define GLSLANG_VERSION_LESS_THAN(major, minor, patch) \ - (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ - (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ - ((patch) < GLSLANG_VERSION_PATCH))))) + ((GLSLANG_VERSION_MAJOR) < (major) || ((major) == GLSLANG_VERSION_MAJOR && \ + ((GLSLANG_VERSION_MINOR) < (minor) || ((minor) == GLSLANG_VERSION_MINOR && \ + (GLSLANG_VERSION_PATCH) < (patch))))) #define GLSLANG_VERSION_LESS_OR_EQUAL_TO(major, minor, patch) \ - (((major) < GLSLANG_VERSION_MAJOR) || ((major) == GLSLANG_VERSION_MAJOR && \ - (((minor) < GLSLANG_VERSION_MINOR) || ((minor) == GLSLANG_VERSION_MINOR && \ - ((patch) <= GLSLANG_VERSION_PATCH))))) + ((GLSLANG_VERSION_MAJOR) < (major) || ((major) == GLSLANG_VERSION_MAJOR && \ + ((GLSLANG_VERSION_MINOR) < (minor) || ((minor) == GLSLANG_VERSION_MINOR && \ + (GLSLANG_VERSION_PATCH <= (patch)))))) #endif // GLSLANG_BUILD_INFO diff --git a/src/libraries/luahttps/src/android/AndroidClient.cpp b/src/libraries/luahttps/src/android/AndroidClient.cpp index 24cbb1d0e..a5994e24b 100644 --- a/src/libraries/luahttps/src/android/AndroidClient.cpp +++ b/src/libraries/luahttps/src/android/AndroidClient.cpp @@ -7,6 +7,10 @@ #include +// We want std::string that contains null byte, hence length of 1. +// NOLINTNEXTLINE +static std::string null("", 1); + static std::string replace(const std::string &str, const std::string &from, const std::string &to) { std::stringstream ss; @@ -31,9 +35,6 @@ static std::string replace(const std::string &str, const std::string &from, cons static jstring newStringUTF(JNIEnv *env, const std::string &str) { - // We want std::string that contains null byte, hence length of 1. - static std::string null("", 1); - std::string newStr = replace(str, null, "\xC0\x80"); jstring jstr = env->NewStringUTF(newStr.c_str()); return jstr; @@ -41,9 +42,6 @@ static jstring newStringUTF(JNIEnv *env, const std::string &str) static std::string getStringUTF(JNIEnv *env, jstring str) { - // We want std::string that contains null byte, hence length of 1. - static std::string null("", 1); - const char *c = env->GetStringUTFChars(str, nullptr); std::string result = replace(c, "\xC0\x80", null); @@ -53,7 +51,6 @@ static std::string getStringUTF(JNIEnv *env, jstring str) AndroidClient::AndroidClient() : HTTPSClient() -, SDL_AndroidGetJNIEnv(nullptr) { // Look for SDL_AndroidGetJNIEnv SDL_AndroidGetJNIEnv = (decltype(SDL_AndroidGetJNIEnv)) dlsym(RTLD_DEFAULT, "SDL_AndroidGetJNIEnv"); @@ -116,12 +113,14 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req) env->DeleteLocalRef(method); // Set post data - if (req.postdata.size() > 0) + if (!req.postdata.empty()) { jmethodID setPostData = env->GetMethodID(httpsClass, "setPostData", "([B)V"); jbyteArray byteArray = env->NewByteArray((jsize) req.postdata.length()); jbyte *byteArrayData = env->GetByteArrayElements(byteArray, nullptr); + // The usage of memcpy is intentional. + // NOLINTNEXTLINE memcpy(byteArrayData, req.postdata.data(), req.postdata.length()); env->ReleaseByteArrayElements(byteArray, byteArrayData, 0); @@ -156,9 +155,9 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req) { // Get headers jobjectArray interleavedHeaders = (jobjectArray) env->CallObjectMethod(httpsObject, getInterleavedHeaders); - int len = env->GetArrayLength(interleavedHeaders); + int headerLen = env->GetArrayLength(interleavedHeaders); - for (int i = 0; i < len; i += 2) + for (int i = 0; i < headerLen; i += 2) { jstring key = (jstring) env->GetObjectArrayElement(interleavedHeaders, i); jstring value = (jstring) env->GetObjectArrayElement(interleavedHeaders, i + 1); @@ -176,15 +175,17 @@ HTTPSClient::Reply AndroidClient::request(const HTTPSClient::Request &req) if (responseData) { - int len = env->GetArrayLength(responseData); + int responseLen = env->GetArrayLength(responseData); jbyte *responseByte = env->GetByteArrayElements(responseData, nullptr); - response.body = std::string((char *) responseByte, len); + response.body = std::string((char *) responseByte, responseLen); env->DeleteLocalRef(responseData); } } + env->DeleteLocalRef(httpsObject); + return response; } diff --git a/src/libraries/luahttps/src/common/config.h b/src/libraries/luahttps/src/common/config.h index e55c3fe3f..4068e9b63 100644 --- a/src/libraries/luahttps/src/common/config.h +++ b/src/libraries/luahttps/src/common/config.h @@ -1,5 +1,10 @@ #pragma once +// MSVC warnings +#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS +#endif + #if defined(HTTPS_HAVE_CONFIG_GENERATED_H) #include "common/config-generated.h" #elif defined(WIN32) || defined(_WIN32) @@ -10,6 +15,12 @@ // WinINet is only supported on desktop. #define HTTPS_BACKEND_WININET #endif + // Visual Studio 2017 supports __has_include + #if defined __has_include + #if __has_include() + #define HTTPS_BACKEND_CURL + #endif + #endif #elif defined(__ANDROID__) #define HTTPS_BACKEND_ANDROID #elif defined(__APPLE__) diff --git a/src/libraries/luasocket/libluasocket/ftp.lua.h b/src/libraries/luasocket/libluasocket/ftp.lua.h index affb67c4f..6d6b2cfa0 100644 --- a/src/libraries/luasocket/libluasocket/ftp.lua.h +++ b/src/libraries/luasocket/libluasocket/ftp.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/headers.lua.h b/src/libraries/luasocket/libluasocket/headers.lua.h index b09fafa6d..7764f796d 100644 --- a/src/libraries/luasocket/libluasocket/headers.lua.h +++ b/src/libraries/luasocket/libluasocket/headers.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/http.lua b/src/libraries/luasocket/libluasocket/http.lua index 1330355f4..259eb2b5d 100644 --- a/src/libraries/luasocket/libluasocket/http.lua +++ b/src/libraries/luasocket/libluasocket/http.lua @@ -54,7 +54,7 @@ local function receiveheaders(sock, headers) while line ~= "" do -- get field-name and value name, value = socket.skip(2, string.find(line, "^(.-):%s*(.*)")) - if not (name and value) then return nil, "malformed reponse headers" end + if not (name and value) then return nil, "malformed response headers" end name = string.lower(name) -- get next line (value might be folded) line, err = sock:receive() @@ -62,7 +62,7 @@ local function receiveheaders(sock, headers) -- unfold any folded values while string.find(line, "^%s") do value = value .. line - line = sock:receive() + line, err = sock:receive() if err then return nil, err end end -- save pair in table @@ -81,7 +81,7 @@ socket.sourcet["http-chunked"] = function(sock, headers) dirty = function() return sock:dirty() end }, { __call = function() - -- get chunk size, skip extention + -- get chunk size, skip extension local line, err = sock:receive() if err then return nil, err end local size = base.tonumber(string.gsub(line, ";.*", ""), 16) @@ -219,9 +219,11 @@ local function adjustproxy(reqt) local proxy = reqt.proxy or _M.PROXY if proxy then proxy = url.parse(proxy) - return proxy.host, proxy.port or 3128 + proxy.port = proxy.port or 3128 + proxy.create = SCHEMES[proxy.scheme].create(reqt) + return proxy.host, proxy.port, proxy.create else - return reqt.host, reqt.port + return reqt.host, reqt.port, reqt.create end end @@ -279,7 +281,7 @@ local function adjustrequest(reqt) if not (host and host ~= "") then socket.try(nil, "invalid host '" .. base.tostring(nreqt.host) .. "'") end - -- compute uri if user hasn't overriden + -- compute uri if user hasn't overridden nreqt.uri = reqt.uri or adjusturi(nreqt) -- adjust headers in request nreqt.headers = adjustheaders(nreqt) @@ -291,7 +293,10 @@ local function adjustrequest(reqt) end -- ajust host and port if there is a proxy - nreqt.host, nreqt.port = adjustproxy(nreqt) + local proxy_create + nreqt.host, nreqt.port, proxy_create = adjustproxy(nreqt) + if not reqt.create then nreqt.create = proxy_create end + return nreqt end @@ -300,6 +305,8 @@ local function shouldredirect(reqt, code, headers) if not location then return false end location = string.gsub(location, "%s", "") if location == "" then return false end + -- the RFC says the redirect URL may be relative + location = url.absolute(reqt.url, location) local scheme = url.parse(location).scheme if scheme and (not SCHEMES[scheme]) then return false end -- avoid https downgrades @@ -323,8 +330,7 @@ end local trequest, tredirect --[[local]] function tredirect(reqt, location) - -- the RFC says the redirect URL has to be absolute, but some - -- servers do not respect that + -- the RFC says the redirect URL may be relative local newurl = url.absolute(reqt.url, location) -- if switching schemes, reset port and create function if url.parse(newurl).scheme ~= reqt.scheme then diff --git a/src/libraries/luasocket/libluasocket/http.lua.h b/src/libraries/luasocket/libluasocket/http.lua.h index 2807690a0..70620ec39 100644 --- a/src/libraries/luasocket/libluasocket/http.lua.h +++ b/src/libraries/luasocket/libluasocket/http.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -167,8 +167,8 @@ const unsigned char http_lua[] = 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x22, 0x6d, 0x61, 0x6c, 0x66, - 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x20, 0x72, 0x65, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x68, 0x65, 0x61, 0x64, - 0x65, 0x72, 0x73, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x20, 0x68, 0x65, 0x61, + 0x64, 0x65, 0x72, 0x73, 0x22, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x28, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x6e, 0x65, 0x78, @@ -186,8 +186,9 @@ const unsigned char http_lua[] = 0x22, 0x29, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x3d, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x20, 0x2e, 0x2e, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x3d, - 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x2c, 0x20, + 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, + 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x72, 0x72, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x69, 0x6c, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x65, 0x6e, 0x64, 0x0a, @@ -235,7 +236,7 @@ const unsigned char http_lua[] = 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x63, 0x68, 0x75, 0x6e, 0x6b, 0x20, 0x73, 0x69, 0x7a, 0x65, 0x2c, 0x20, 0x73, 0x6b, 0x69, 0x70, 0x20, - 0x65, 0x78, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x0a, + 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x69, 0x6e, 0x65, 0x2c, 0x20, 0x65, 0x72, 0x72, 0x20, 0x3d, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x3a, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x28, 0x29, 0x0a, @@ -570,12 +571,20 @@ const unsigned char http_lua[] = 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x70, 0x6f, 0x72, 0x74, + 0x20, 0x3d, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x33, + 0x31, 0x32, 0x38, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x20, 0x3d, 0x20, 0x53, 0x43, 0x48, 0x45, 0x4d, 0x45, 0x53, 0x5b, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x5d, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x28, 0x72, 0x65, + 0x71, 0x74, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x70, 0x6f, 0x72, - 0x74, 0x20, 0x6f, 0x72, 0x20, 0x33, 0x31, 0x32, 0x38, 0x0a, + 0x74, 0x2c, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x72, 0x65, 0x71, - 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x0a, + 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x2c, + 0x20, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, @@ -710,7 +719,7 @@ const unsigned char http_lua[] = 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x20, 0x75, 0x72, 0x69, 0x20, 0x69, 0x66, 0x20, 0x75, 0x73, 0x65, 0x72, 0x20, 0x68, 0x61, 0x73, 0x6e, 0x27, 0x74, 0x20, 0x6f, 0x76, - 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x6e, 0x0a, + 0x65, 0x72, 0x72, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x75, 0x72, 0x69, 0x20, 0x3d, 0x20, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x75, 0x72, 0x69, 0x20, 0x6f, 0x72, 0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x75, 0x72, 0x69, 0x28, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x29, 0x0a, @@ -736,9 +745,17 @@ const unsigned char http_lua[] = 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x61, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x69, 0x66, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x61, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x2c, 0x20, 0x6e, 0x72, - 0x65, 0x71, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x70, - 0x72, 0x6f, 0x78, 0x79, 0x28, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x29, 0x0a, + 0x65, 0x71, 0x74, 0x2e, 0x70, 0x6f, 0x72, 0x74, 0x2c, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x61, 0x64, 0x6a, 0x75, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x78, 0x79, + 0x28, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x5f, 0x63, 0x72, 0x65, 0x61, 0x74, + 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6e, 0x72, 0x65, 0x71, 0x74, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, @@ -757,6 +774,12 @@ const unsigned char http_lua[] = 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x73, 0x61, 0x79, + 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x55, 0x52, 0x4c, + 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, + 0x2e, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x28, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x75, 0x72, 0x6c, + 0x2c, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x0a, @@ -820,10 +843,7 @@ const unsigned char http_lua[] = 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x46, 0x43, 0x20, 0x73, 0x61, 0x79, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x20, 0x55, 0x52, 0x4c, - 0x20, 0x68, 0x61, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x62, 0x65, 0x20, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, - 0x65, 0x2c, 0x20, 0x62, 0x75, 0x74, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x20, 0x64, 0x6f, 0x20, - 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63, 0x74, 0x20, 0x74, 0x68, 0x61, 0x74, 0x0a, + 0x20, 0x6d, 0x61, 0x79, 0x20, 0x62, 0x65, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x6e, 0x65, 0x77, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x75, 0x72, 0x6c, 0x2e, 0x61, 0x62, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x28, 0x72, 0x65, 0x71, 0x74, 0x2e, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x29, 0x0a, diff --git a/src/libraries/luasocket/libluasocket/inet.c b/src/libraries/luasocket/libluasocket/inet.c index 138c9abe8..afef5f45b 100644 --- a/src/libraries/luasocket/libluasocket/inet.c +++ b/src/libraries/luasocket/libluasocket/inet.c @@ -290,7 +290,7 @@ int inet_meth_getsockname(lua_State *L, p_socket ps, int family) return 2; } lua_pushstring(L, name); - lua_pushstring(L, port); + lua_pushinteger(L, (int) strtol(port, (char **) NULL, 10)); switch (family) { case AF_INET: lua_pushliteral(L, "inet"); break; case AF_INET6: lua_pushliteral(L, "inet6"); break; diff --git a/src/libraries/luasocket/libluasocket/ltn12.lua.h b/src/libraries/luasocket/libluasocket/ltn12.lua.h index 659ad726c..46a417b64 100644 --- a/src/libraries/luasocket/libluasocket/ltn12.lua.h +++ b/src/libraries/luasocket/libluasocket/ltn12.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/luasocket.h b/src/libraries/luasocket/libluasocket/luasocket.h index 1017fbaab..1e3d3588c 100644 --- a/src/libraries/luasocket/libluasocket/luasocket.h +++ b/src/libraries/luasocket/libluasocket/luasocket.h @@ -10,7 +10,7 @@ /*-------------------------------------------------------------------------* \ * Current socket library version \*-------------------------------------------------------------------------*/ -#define LUASOCKET_VERSION "LuaSocket 3.0.0" +#define LUASOCKET_VERSION "LuaSocket 3.1.0" #define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" /*-------------------------------------------------------------------------*\ diff --git a/src/libraries/luasocket/libluasocket/makefile b/src/libraries/luasocket/libluasocket/makefile index 06f4d1927..25b293c72 100644 --- a/src/libraries/luasocket/libluasocket/makefile +++ b/src/libraries/luasocket/libluasocket/makefile @@ -1,6 +1,6 @@ # luasocket src/makefile # -# Definitions in this section can be overriden on the command line or in the +# Definitions in this section can be overridden on the command line or in the # environment. # # These are equivalent: @@ -272,7 +272,7 @@ SOCKET_win64=wsocket.obj # SO=$(SO_$(PLAT)) O=$(O_$(PLAT)) -SOCKET_V=3.0.0 +SOCKET_V=3.1.0 MIME_V=1.0.3 SOCKET_SO=socket-$(SOCKET_V).$(SO) MIME_SO=mime-$(MIME_V).$(SO) diff --git a/src/libraries/luasocket/libluasocket/mbox.lua.h b/src/libraries/luasocket/libluasocket/mbox.lua.h index 6af5c4de6..d11b4a063 100644 --- a/src/libraries/luasocket/libluasocket/mbox.lua.h +++ b/src/libraries/luasocket/libluasocket/mbox.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/mime.lua.h b/src/libraries/luasocket/libluasocket/mime.lua.h index 222efa219..27daf0d2c 100644 --- a/src/libraries/luasocket/libluasocket/mime.lua.h +++ b/src/libraries/luasocket/libluasocket/mime.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/options.c b/src/libraries/luasocket/libluasocket/options.c index 3280c51d7..9dea6bda2 100644 --- a/src/libraries/luasocket/libluasocket/options.c +++ b/src/libraries/luasocket/libluasocket/options.c @@ -54,6 +54,33 @@ int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps) return opt->func(L, ps); } +/*------------------------------------------------------*/ +/* binds socket to network interface */ +int opt_set_bindtodevice(lua_State *L, p_socket ps) +{ +#ifndef SO_BINDTODEVICE + return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system"); +#else + const char *dev = luaL_checkstring(L, 3); + return opt_set(L, ps, SOL_SOCKET, SO_BINDTODEVICE, (char*)dev, strlen(dev)+1); +#endif +} + +int opt_get_bindtodevice(lua_State *L, p_socket ps) +{ +#ifndef SO_BINDTODEVICE + return luaL_error(L, "SO_BINDTODEVICE is not supported on this operating system"); +#else + char dev[IFNAMSIZ]; + int len = sizeof(dev); + int err = opt_get(L, ps, SOL_SOCKET, SO_BINDTODEVICE, &dev, &len); + if (err) + return err; + lua_pushstring(L, dev); + return 1; +#endif +} + /*------------------------------------------------------*/ /* enables reuse of local address */ int opt_set_reuseaddr(lua_State *L, p_socket ps) @@ -190,7 +217,7 @@ int opt_set_send_buf_size(lua_State *L, p_socket ps) return opt_setint(L, ps, SOL_SOCKET, SO_SNDBUF); } -// /*------------------------------------------------------*/ +/*------------------------------------------------------*/ #ifdef TCP_FASTOPEN int opt_set_tcp_fastopen(lua_State *L, p_socket ps) diff --git a/src/libraries/luasocket/libluasocket/options.h b/src/libraries/luasocket/libluasocket/options.h index 456eeb5f4..26d6f0250 100644 --- a/src/libraries/luasocket/libluasocket/options.h +++ b/src/libraries/luasocket/libluasocket/options.h @@ -53,6 +53,9 @@ int opt_get_tcp_keepintvl(lua_State *L, p_socket ps); int opt_set_tcp_defer_accept(lua_State *L, p_socket ps); #endif +int opt_set_bindtodevice(lua_State *L, p_socket ps); +int opt_get_bindtodevice(lua_State *L, p_socket ps); + int opt_set_keepalive(lua_State *L, p_socket ps); int opt_get_keepalive(lua_State *L, p_socket ps); diff --git a/src/libraries/luasocket/libluasocket/smtp.lua b/src/libraries/luasocket/libluasocket/smtp.lua index b113d0067..c26ce44f4 100644 --- a/src/libraries/luasocket/libluasocket/smtp.lua +++ b/src/libraries/luasocket/libluasocket/smtp.lua @@ -225,7 +225,7 @@ local function adjust_headers(mesgt) lower["date"] = lower["date"] or os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE) lower["x-mailer"] = lower["x-mailer"] or socket._VERSION - -- this can't be overriden + -- this can't be overridden lower["mime-version"] = "1.0" return lower end @@ -253,4 +253,4 @@ _M.send = socket.protect(function(mailt) return s:close() end) -return _M \ No newline at end of file +return _M diff --git a/src/libraries/luasocket/libluasocket/smtp.lua.h b/src/libraries/luasocket/libluasocket/smtp.lua.h index 2f9929ad3..6bb022090 100644 --- a/src/libraries/luasocket/libluasocket/smtp.lua.h +++ b/src/libraries/luasocket/libluasocket/smtp.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -543,7 +543,7 @@ const unsigned char smtp_lua[] = 0x6c, 0x65, 0x72, 0x22, 0x5d, 0x20, 0x6f, 0x72, 0x20, 0x73, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x5f, 0x56, 0x45, 0x52, 0x53, 0x49, 0x4f, 0x4e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x63, 0x61, 0x6e, 0x27, 0x74, 0x20, - 0x62, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x6e, 0x0a, + 0x62, 0x65, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x64, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x5b, 0x22, 0x6d, 0x69, 0x6d, 0x65, 0x2d, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x20, 0x3d, 0x20, 0x22, 0x31, 0x2e, 0x30, 0x22, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x6f, 0x77, 0x65, 0x72, 0x0a, diff --git a/src/libraries/luasocket/libluasocket/socket.lua.h b/src/libraries/luasocket/libluasocket/socket.lua.h index b6986c743..f3f22f20a 100644 --- a/src/libraries/luasocket/libluasocket/socket.lua.h +++ b/src/libraries/luasocket/libluasocket/socket.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/tcp.c b/src/libraries/luasocket/libluasocket/tcp.c index e84db8454..f00120640 100644 --- a/src/libraries/luasocket/libluasocket/tcp.c +++ b/src/libraries/luasocket/libluasocket/tcp.c @@ -71,6 +71,7 @@ static luaL_Reg tcp_methods[] = { /* socket option handlers */ static t_opt optget[] = { + {"bindtodevice", opt_get_bindtodevice}, {"keepalive", opt_get_keepalive}, {"reuseaddr", opt_get_reuseaddr}, {"reuseport", opt_get_reuseport}, @@ -92,6 +93,7 @@ static t_opt optget[] = { }; static t_opt optset[] = { + {"bindtodevice", opt_set_bindtodevice}, {"keepalive", opt_set_keepalive}, {"reuseaddr", opt_set_reuseaddr}, {"reuseport", opt_set_reuseport}, diff --git a/src/libraries/luasocket/libluasocket/tp.lua.h b/src/libraries/luasocket/libluasocket/tp.lua.h index 2514af0ac..85b1e2c7f 100644 --- a/src/libraries/luasocket/libluasocket/tp.lua.h +++ b/src/libraries/luasocket/libluasocket/tp.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/libluasocket/url.lua b/src/libraries/luasocket/libluasocket/url.lua index 8e0dc5ceb..aef16984c 100644 --- a/src/libraries/luasocket/libluasocket/url.lua +++ b/src/libraries/luasocket/libluasocket/url.lua @@ -152,7 +152,7 @@ function _M.parse(url, default) url = string.gsub(url, "^([%w][%w%+%-%.]*)%:", function(s) parsed.scheme = s; return "" end) -- get authority - url = string.gsub(url, "^//([^/]*)", function(n) + url = string.gsub(url, "^//([^/%?#]*)", function(n) parsed.authority = n return "" end) diff --git a/src/libraries/luasocket/libluasocket/url.lua.h b/src/libraries/luasocket/libluasocket/url.lua.h index b0e2ca092..7db3e665c 100644 --- a/src/libraries/luasocket/libluasocket/url.lua.h +++ b/src/libraries/luasocket/libluasocket/url.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -402,8 +402,9 @@ const unsigned char url_lua[] = 0x20, 0x20, 0x20, 0x20, 0x2d, 0x2d, 0x20, 0x67, 0x65, 0x74, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x75, 0x72, 0x6c, 0x20, 0x3d, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x67, - 0x73, 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x22, 0x5e, 0x2f, 0x2f, 0x28, 0x5b, 0x5e, 0x2f, 0x5d, - 0x2a, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, 0x29, 0x0a, + 0x73, 0x75, 0x62, 0x28, 0x75, 0x72, 0x6c, 0x2c, 0x20, 0x22, 0x5e, 0x2f, 0x2f, 0x28, 0x5b, 0x5e, 0x2f, 0x25, + 0x3f, 0x23, 0x5d, 0x2a, 0x29, 0x22, 0x2c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6e, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70, 0x61, 0x72, 0x73, 0x65, 0x64, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x20, 0x3d, 0x20, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x22, 0x22, 0x0a, diff --git a/src/libraries/luasocket/libluasocket/usocket.c b/src/libraries/luasocket/libluasocket/usocket.c index 69635daa6..7965db6c4 100644 --- a/src/libraries/luasocket/libluasocket/usocket.c +++ b/src/libraries/luasocket/libluasocket/usocket.c @@ -236,7 +236,7 @@ int socket_sendto(p_socket ps, const char *data, size_t count, size_t *sent, *sent = 0; if (*ps == SOCKET_INVALID) return IO_CLOSED; for ( ;; ) { - long put = (long) sendto(*ps, data, count, 0, addr, len); + long put = (long) sendto(*ps, data, count, 0, addr, len); if (put >= 0) { *sent = put; return IO_DONE; diff --git a/src/libraries/luasocket/libluasocket/wsocket.c b/src/libraries/luasocket/libluasocket/wsocket.c index 6cb1e415c..d3af9d4a1 100644 --- a/src/libraries/luasocket/libluasocket/wsocket.c +++ b/src/libraries/luasocket/libluasocket/wsocket.c @@ -262,6 +262,7 @@ int socket_recv(p_socket ps, char *data, size_t count, size_t *got, if (err != WSAEWOULDBLOCK) { if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; prev = err; + continue; } if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } @@ -291,6 +292,7 @@ int socket_recvfrom(p_socket ps, char *data, size_t count, size_t *got, if (err != WSAEWOULDBLOCK) { if (err != WSAECONNRESET || prev == WSAECONNRESET) return err; prev = err; + continue; } if ((err = socket_waitfd(ps, WAITFD_R, tm)) != IO_DONE) return err; } diff --git a/src/libraries/luasocket/luasocket.cpp b/src/libraries/luasocket/luasocket.cpp index e1aa845cf..d5cd26ed4 100644 --- a/src/libraries/luasocket/luasocket.cpp +++ b/src/libraries/luasocket/luasocket.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/luasocket/luasocket.h b/src/libraries/luasocket/luasocket.h index 26865bb07..b6225dd3f 100644 --- a/src/libraries/luasocket/luasocket.h +++ b/src/libraries/luasocket/luasocket.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/libraries/physfs/physfs_platform_windows.c b/src/libraries/physfs/physfs_platform_windows.c index 652300c9a..b95b06472 100644 --- a/src/libraries/physfs/physfs_platform_windows.c +++ b/src/libraries/physfs/physfs_platform_windows.c @@ -123,7 +123,7 @@ static inline HANDLE winCreateFileW(const WCHAR *wfname, const DWORD mode, const DWORD creation) { const DWORD share = FILE_SHARE_READ | FILE_SHARE_WRITE; - #if defined(PHYSFS_PLATFORM_WINRT) || (_WIN32_WINNT >= 0x0602) // Windows 8+ + #if defined(PHYSFS_PLATFORM_WINRT) /*|| (_WIN32_WINNT >= 0x0602)*/ // Windows 8+ return CreateFile2(wfname, mode, share, creation, NULL); #else return CreateFileW(wfname, mode, share, NULL, creation, diff --git a/src/libraries/spirv_cross/spirv.h b/src/libraries/spirv_cross/spirv.h deleted file mode 100644 index 949f1980e..000000000 --- a/src/libraries/spirv_cross/spirv.h +++ /dev/null @@ -1,2192 +0,0 @@ -/* -** Copyright (c) 2014-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. -*/ - -/* -** This header is automatically generated by the same tool that creates -** the Binary Section of the SPIR-V specification. -*/ - -/* -** Enumeration tokens for SPIR-V, in various styles: -** C, C++, C++11, JSON, Lua, Python, C#, D -** -** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL -** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL -** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL -** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL -** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL'] -** - C# will use enum classes in the Specification class located in the "Spv" namespace, -** e.g.: Spv.Specification.SourceLanguage.GLSL -** - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL -** -** Some tokens act like mask values, which can be OR'd together, -** while others are mutually exclusive. The mask-like ones have -** "Mask" in their name, and a parallel enum that has the shift -** amount (1 << x) for each corresponding enumerant. -*/ - -#ifndef spirv_H -#define spirv_H - -typedef unsigned int SpvId; - -#define SPV_VERSION 0x10500 -#define SPV_REVISION 4 - -static const unsigned int SpvMagicNumber = 0x07230203; -static const unsigned int SpvVersion = 0x00010500; -static const unsigned int SpvRevision = 4; -static const unsigned int SpvOpCodeMask = 0xffff; -static const unsigned int SpvWordCountShift = 16; - -typedef enum SpvSourceLanguage_ { - SpvSourceLanguageUnknown = 0, - SpvSourceLanguageESSL = 1, - SpvSourceLanguageGLSL = 2, - SpvSourceLanguageOpenCL_C = 3, - SpvSourceLanguageOpenCL_CPP = 4, - SpvSourceLanguageHLSL = 5, - SpvSourceLanguageMax = 0x7fffffff, -} SpvSourceLanguage; - -typedef enum SpvExecutionModel_ { - SpvExecutionModelVertex = 0, - SpvExecutionModelTessellationControl = 1, - SpvExecutionModelTessellationEvaluation = 2, - SpvExecutionModelGeometry = 3, - SpvExecutionModelFragment = 4, - SpvExecutionModelGLCompute = 5, - SpvExecutionModelKernel = 6, - SpvExecutionModelTaskNV = 5267, - SpvExecutionModelMeshNV = 5268, - SpvExecutionModelRayGenerationKHR = 5313, - SpvExecutionModelRayGenerationNV = 5313, - SpvExecutionModelIntersectionKHR = 5314, - SpvExecutionModelIntersectionNV = 5314, - SpvExecutionModelAnyHitKHR = 5315, - SpvExecutionModelAnyHitNV = 5315, - SpvExecutionModelClosestHitKHR = 5316, - SpvExecutionModelClosestHitNV = 5316, - SpvExecutionModelMissKHR = 5317, - SpvExecutionModelMissNV = 5317, - SpvExecutionModelCallableKHR = 5318, - SpvExecutionModelCallableNV = 5318, - SpvExecutionModelMax = 0x7fffffff, -} SpvExecutionModel; - -typedef enum SpvAddressingModel_ { - SpvAddressingModelLogical = 0, - SpvAddressingModelPhysical32 = 1, - SpvAddressingModelPhysical64 = 2, - SpvAddressingModelPhysicalStorageBuffer64 = 5348, - SpvAddressingModelPhysicalStorageBuffer64EXT = 5348, - SpvAddressingModelMax = 0x7fffffff, -} SpvAddressingModel; - -typedef enum SpvMemoryModel_ { - SpvMemoryModelSimple = 0, - SpvMemoryModelGLSL450 = 1, - SpvMemoryModelOpenCL = 2, - SpvMemoryModelVulkan = 3, - SpvMemoryModelVulkanKHR = 3, - SpvMemoryModelMax = 0x7fffffff, -} SpvMemoryModel; - -typedef enum SpvExecutionMode_ { - SpvExecutionModeInvocations = 0, - SpvExecutionModeSpacingEqual = 1, - SpvExecutionModeSpacingFractionalEven = 2, - SpvExecutionModeSpacingFractionalOdd = 3, - SpvExecutionModeVertexOrderCw = 4, - SpvExecutionModeVertexOrderCcw = 5, - SpvExecutionModePixelCenterInteger = 6, - SpvExecutionModeOriginUpperLeft = 7, - SpvExecutionModeOriginLowerLeft = 8, - SpvExecutionModeEarlyFragmentTests = 9, - SpvExecutionModePointMode = 10, - SpvExecutionModeXfb = 11, - SpvExecutionModeDepthReplacing = 12, - SpvExecutionModeDepthGreater = 14, - SpvExecutionModeDepthLess = 15, - SpvExecutionModeDepthUnchanged = 16, - SpvExecutionModeLocalSize = 17, - SpvExecutionModeLocalSizeHint = 18, - SpvExecutionModeInputPoints = 19, - SpvExecutionModeInputLines = 20, - SpvExecutionModeInputLinesAdjacency = 21, - SpvExecutionModeTriangles = 22, - SpvExecutionModeInputTrianglesAdjacency = 23, - SpvExecutionModeQuads = 24, - SpvExecutionModeIsolines = 25, - SpvExecutionModeOutputVertices = 26, - SpvExecutionModeOutputPoints = 27, - SpvExecutionModeOutputLineStrip = 28, - SpvExecutionModeOutputTriangleStrip = 29, - SpvExecutionModeVecTypeHint = 30, - SpvExecutionModeContractionOff = 31, - SpvExecutionModeInitializer = 33, - SpvExecutionModeFinalizer = 34, - SpvExecutionModeSubgroupSize = 35, - SpvExecutionModeSubgroupsPerWorkgroup = 36, - SpvExecutionModeSubgroupsPerWorkgroupId = 37, - SpvExecutionModeLocalSizeId = 38, - SpvExecutionModeLocalSizeHintId = 39, - SpvExecutionModePostDepthCoverage = 4446, - SpvExecutionModeDenormPreserve = 4459, - SpvExecutionModeDenormFlushToZero = 4460, - SpvExecutionModeSignedZeroInfNanPreserve = 4461, - SpvExecutionModeRoundingModeRTE = 4462, - SpvExecutionModeRoundingModeRTZ = 4463, - SpvExecutionModeStencilRefReplacingEXT = 5027, - SpvExecutionModeOutputLinesNV = 5269, - SpvExecutionModeOutputPrimitivesNV = 5270, - SpvExecutionModeDerivativeGroupQuadsNV = 5289, - SpvExecutionModeDerivativeGroupLinearNV = 5290, - SpvExecutionModeOutputTrianglesNV = 5298, - SpvExecutionModePixelInterlockOrderedEXT = 5366, - SpvExecutionModePixelInterlockUnorderedEXT = 5367, - SpvExecutionModeSampleInterlockOrderedEXT = 5368, - SpvExecutionModeSampleInterlockUnorderedEXT = 5369, - SpvExecutionModeShadingRateInterlockOrderedEXT = 5370, - SpvExecutionModeShadingRateInterlockUnorderedEXT = 5371, - SpvExecutionModeMaxWorkgroupSizeINTEL = 5893, - SpvExecutionModeMaxWorkDimINTEL = 5894, - SpvExecutionModeNoGlobalOffsetINTEL = 5895, - SpvExecutionModeNumSIMDWorkitemsINTEL = 5896, - SpvExecutionModeMax = 0x7fffffff, -} SpvExecutionMode; - -typedef enum SpvStorageClass_ { - SpvStorageClassUniformConstant = 0, - SpvStorageClassInput = 1, - SpvStorageClassUniform = 2, - SpvStorageClassOutput = 3, - SpvStorageClassWorkgroup = 4, - SpvStorageClassCrossWorkgroup = 5, - SpvStorageClassPrivate = 6, - SpvStorageClassFunction = 7, - SpvStorageClassGeneric = 8, - SpvStorageClassPushConstant = 9, - SpvStorageClassAtomicCounter = 10, - SpvStorageClassImage = 11, - SpvStorageClassStorageBuffer = 12, - SpvStorageClassCallableDataKHR = 5328, - SpvStorageClassCallableDataNV = 5328, - SpvStorageClassIncomingCallableDataKHR = 5329, - SpvStorageClassIncomingCallableDataNV = 5329, - SpvStorageClassRayPayloadKHR = 5338, - SpvStorageClassRayPayloadNV = 5338, - SpvStorageClassHitAttributeKHR = 5339, - SpvStorageClassHitAttributeNV = 5339, - SpvStorageClassIncomingRayPayloadKHR = 5342, - SpvStorageClassIncomingRayPayloadNV = 5342, - SpvStorageClassShaderRecordBufferKHR = 5343, - SpvStorageClassShaderRecordBufferNV = 5343, - SpvStorageClassPhysicalStorageBuffer = 5349, - SpvStorageClassPhysicalStorageBufferEXT = 5349, - SpvStorageClassCodeSectionINTEL = 5605, - SpvStorageClassMax = 0x7fffffff, -} SpvStorageClass; - -typedef enum SpvDim_ { - SpvDim1D = 0, - SpvDim2D = 1, - SpvDim3D = 2, - SpvDimCube = 3, - SpvDimRect = 4, - SpvDimBuffer = 5, - SpvDimSubpassData = 6, - SpvDimMax = 0x7fffffff, -} SpvDim; - -typedef enum SpvSamplerAddressingMode_ { - SpvSamplerAddressingModeNone = 0, - SpvSamplerAddressingModeClampToEdge = 1, - SpvSamplerAddressingModeClamp = 2, - SpvSamplerAddressingModeRepeat = 3, - SpvSamplerAddressingModeRepeatMirrored = 4, - SpvSamplerAddressingModeMax = 0x7fffffff, -} SpvSamplerAddressingMode; - -typedef enum SpvSamplerFilterMode_ { - SpvSamplerFilterModeNearest = 0, - SpvSamplerFilterModeLinear = 1, - SpvSamplerFilterModeMax = 0x7fffffff, -} SpvSamplerFilterMode; - -typedef enum SpvImageFormat_ { - SpvImageFormatUnknown = 0, - SpvImageFormatRgba32f = 1, - SpvImageFormatRgba16f = 2, - SpvImageFormatR32f = 3, - SpvImageFormatRgba8 = 4, - SpvImageFormatRgba8Snorm = 5, - SpvImageFormatRg32f = 6, - SpvImageFormatRg16f = 7, - SpvImageFormatR11fG11fB10f = 8, - SpvImageFormatR16f = 9, - SpvImageFormatRgba16 = 10, - SpvImageFormatRgb10A2 = 11, - SpvImageFormatRg16 = 12, - SpvImageFormatRg8 = 13, - SpvImageFormatR16 = 14, - SpvImageFormatR8 = 15, - SpvImageFormatRgba16Snorm = 16, - SpvImageFormatRg16Snorm = 17, - SpvImageFormatRg8Snorm = 18, - SpvImageFormatR16Snorm = 19, - SpvImageFormatR8Snorm = 20, - SpvImageFormatRgba32i = 21, - SpvImageFormatRgba16i = 22, - SpvImageFormatRgba8i = 23, - SpvImageFormatR32i = 24, - SpvImageFormatRg32i = 25, - SpvImageFormatRg16i = 26, - SpvImageFormatRg8i = 27, - SpvImageFormatR16i = 28, - SpvImageFormatR8i = 29, - SpvImageFormatRgba32ui = 30, - SpvImageFormatRgba16ui = 31, - SpvImageFormatRgba8ui = 32, - SpvImageFormatR32ui = 33, - SpvImageFormatRgb10a2ui = 34, - SpvImageFormatRg32ui = 35, - SpvImageFormatRg16ui = 36, - SpvImageFormatRg8ui = 37, - SpvImageFormatR16ui = 38, - SpvImageFormatR8ui = 39, - SpvImageFormatR64ui = 40, - SpvImageFormatR64i = 41, - SpvImageFormatMax = 0x7fffffff, -} SpvImageFormat; - -typedef enum SpvImageChannelOrder_ { - SpvImageChannelOrderR = 0, - SpvImageChannelOrderA = 1, - SpvImageChannelOrderRG = 2, - SpvImageChannelOrderRA = 3, - SpvImageChannelOrderRGB = 4, - SpvImageChannelOrderRGBA = 5, - SpvImageChannelOrderBGRA = 6, - SpvImageChannelOrderARGB = 7, - SpvImageChannelOrderIntensity = 8, - SpvImageChannelOrderLuminance = 9, - SpvImageChannelOrderRx = 10, - SpvImageChannelOrderRGx = 11, - SpvImageChannelOrderRGBx = 12, - SpvImageChannelOrderDepth = 13, - SpvImageChannelOrderDepthStencil = 14, - SpvImageChannelOrdersRGB = 15, - SpvImageChannelOrdersRGBx = 16, - SpvImageChannelOrdersRGBA = 17, - SpvImageChannelOrdersBGRA = 18, - SpvImageChannelOrderABGR = 19, - SpvImageChannelOrderMax = 0x7fffffff, -} SpvImageChannelOrder; - -typedef enum SpvImageChannelDataType_ { - SpvImageChannelDataTypeSnormInt8 = 0, - SpvImageChannelDataTypeSnormInt16 = 1, - SpvImageChannelDataTypeUnormInt8 = 2, - SpvImageChannelDataTypeUnormInt16 = 3, - SpvImageChannelDataTypeUnormShort565 = 4, - SpvImageChannelDataTypeUnormShort555 = 5, - SpvImageChannelDataTypeUnormInt101010 = 6, - SpvImageChannelDataTypeSignedInt8 = 7, - SpvImageChannelDataTypeSignedInt16 = 8, - SpvImageChannelDataTypeSignedInt32 = 9, - SpvImageChannelDataTypeUnsignedInt8 = 10, - SpvImageChannelDataTypeUnsignedInt16 = 11, - SpvImageChannelDataTypeUnsignedInt32 = 12, - SpvImageChannelDataTypeHalfFloat = 13, - SpvImageChannelDataTypeFloat = 14, - SpvImageChannelDataTypeUnormInt24 = 15, - SpvImageChannelDataTypeUnormInt101010_2 = 16, - SpvImageChannelDataTypeMax = 0x7fffffff, -} SpvImageChannelDataType; - -typedef enum SpvImageOperandsShift_ { - SpvImageOperandsBiasShift = 0, - SpvImageOperandsLodShift = 1, - SpvImageOperandsGradShift = 2, - SpvImageOperandsConstOffsetShift = 3, - SpvImageOperandsOffsetShift = 4, - SpvImageOperandsConstOffsetsShift = 5, - SpvImageOperandsSampleShift = 6, - SpvImageOperandsMinLodShift = 7, - SpvImageOperandsMakeTexelAvailableShift = 8, - SpvImageOperandsMakeTexelAvailableKHRShift = 8, - SpvImageOperandsMakeTexelVisibleShift = 9, - SpvImageOperandsMakeTexelVisibleKHRShift = 9, - SpvImageOperandsNonPrivateTexelShift = 10, - SpvImageOperandsNonPrivateTexelKHRShift = 10, - SpvImageOperandsVolatileTexelShift = 11, - SpvImageOperandsVolatileTexelKHRShift = 11, - SpvImageOperandsSignExtendShift = 12, - SpvImageOperandsZeroExtendShift = 13, - SpvImageOperandsMax = 0x7fffffff, -} SpvImageOperandsShift; - -typedef enum SpvImageOperandsMask_ { - SpvImageOperandsMaskNone = 0, - SpvImageOperandsBiasMask = 0x00000001, - SpvImageOperandsLodMask = 0x00000002, - SpvImageOperandsGradMask = 0x00000004, - SpvImageOperandsConstOffsetMask = 0x00000008, - SpvImageOperandsOffsetMask = 0x00000010, - SpvImageOperandsConstOffsetsMask = 0x00000020, - SpvImageOperandsSampleMask = 0x00000040, - SpvImageOperandsMinLodMask = 0x00000080, - SpvImageOperandsMakeTexelAvailableMask = 0x00000100, - SpvImageOperandsMakeTexelAvailableKHRMask = 0x00000100, - SpvImageOperandsMakeTexelVisibleMask = 0x00000200, - SpvImageOperandsMakeTexelVisibleKHRMask = 0x00000200, - SpvImageOperandsNonPrivateTexelMask = 0x00000400, - SpvImageOperandsNonPrivateTexelKHRMask = 0x00000400, - SpvImageOperandsVolatileTexelMask = 0x00000800, - SpvImageOperandsVolatileTexelKHRMask = 0x00000800, - SpvImageOperandsSignExtendMask = 0x00001000, - SpvImageOperandsZeroExtendMask = 0x00002000, -} SpvImageOperandsMask; - -typedef enum SpvFPFastMathModeShift_ { - SpvFPFastMathModeNotNaNShift = 0, - SpvFPFastMathModeNotInfShift = 1, - SpvFPFastMathModeNSZShift = 2, - SpvFPFastMathModeAllowRecipShift = 3, - SpvFPFastMathModeFastShift = 4, - SpvFPFastMathModeMax = 0x7fffffff, -} SpvFPFastMathModeShift; - -typedef enum SpvFPFastMathModeMask_ { - SpvFPFastMathModeMaskNone = 0, - SpvFPFastMathModeNotNaNMask = 0x00000001, - SpvFPFastMathModeNotInfMask = 0x00000002, - SpvFPFastMathModeNSZMask = 0x00000004, - SpvFPFastMathModeAllowRecipMask = 0x00000008, - SpvFPFastMathModeFastMask = 0x00000010, -} SpvFPFastMathModeMask; - -typedef enum SpvFPRoundingMode_ { - SpvFPRoundingModeRTE = 0, - SpvFPRoundingModeRTZ = 1, - SpvFPRoundingModeRTP = 2, - SpvFPRoundingModeRTN = 3, - SpvFPRoundingModeMax = 0x7fffffff, -} SpvFPRoundingMode; - -typedef enum SpvLinkageType_ { - SpvLinkageTypeExport = 0, - SpvLinkageTypeImport = 1, - SpvLinkageTypeMax = 0x7fffffff, -} SpvLinkageType; - -typedef enum SpvAccessQualifier_ { - SpvAccessQualifierReadOnly = 0, - SpvAccessQualifierWriteOnly = 1, - SpvAccessQualifierReadWrite = 2, - SpvAccessQualifierMax = 0x7fffffff, -} SpvAccessQualifier; - -typedef enum SpvFunctionParameterAttribute_ { - SpvFunctionParameterAttributeZext = 0, - SpvFunctionParameterAttributeSext = 1, - SpvFunctionParameterAttributeByVal = 2, - SpvFunctionParameterAttributeSret = 3, - SpvFunctionParameterAttributeNoAlias = 4, - SpvFunctionParameterAttributeNoCapture = 5, - SpvFunctionParameterAttributeNoWrite = 6, - SpvFunctionParameterAttributeNoReadWrite = 7, - SpvFunctionParameterAttributeMax = 0x7fffffff, -} SpvFunctionParameterAttribute; - -typedef enum SpvDecoration_ { - SpvDecorationRelaxedPrecision = 0, - SpvDecorationSpecId = 1, - SpvDecorationBlock = 2, - SpvDecorationBufferBlock = 3, - SpvDecorationRowMajor = 4, - SpvDecorationColMajor = 5, - SpvDecorationArrayStride = 6, - SpvDecorationMatrixStride = 7, - SpvDecorationGLSLShared = 8, - SpvDecorationGLSLPacked = 9, - SpvDecorationCPacked = 10, - SpvDecorationBuiltIn = 11, - SpvDecorationNoPerspective = 13, - SpvDecorationFlat = 14, - SpvDecorationPatch = 15, - SpvDecorationCentroid = 16, - SpvDecorationSample = 17, - SpvDecorationInvariant = 18, - SpvDecorationRestrict = 19, - SpvDecorationAliased = 20, - SpvDecorationVolatile = 21, - SpvDecorationConstant = 22, - SpvDecorationCoherent = 23, - SpvDecorationNonWritable = 24, - SpvDecorationNonReadable = 25, - SpvDecorationUniform = 26, - SpvDecorationUniformId = 27, - SpvDecorationSaturatedConversion = 28, - SpvDecorationStream = 29, - SpvDecorationLocation = 30, - SpvDecorationComponent = 31, - SpvDecorationIndex = 32, - SpvDecorationBinding = 33, - SpvDecorationDescriptorSet = 34, - SpvDecorationOffset = 35, - SpvDecorationXfbBuffer = 36, - SpvDecorationXfbStride = 37, - SpvDecorationFuncParamAttr = 38, - SpvDecorationFPRoundingMode = 39, - SpvDecorationFPFastMathMode = 40, - SpvDecorationLinkageAttributes = 41, - SpvDecorationNoContraction = 42, - SpvDecorationInputAttachmentIndex = 43, - SpvDecorationAlignment = 44, - SpvDecorationMaxByteOffset = 45, - SpvDecorationAlignmentId = 46, - SpvDecorationMaxByteOffsetId = 47, - SpvDecorationNoSignedWrap = 4469, - SpvDecorationNoUnsignedWrap = 4470, - SpvDecorationExplicitInterpAMD = 4999, - SpvDecorationOverrideCoverageNV = 5248, - SpvDecorationPassthroughNV = 5250, - SpvDecorationViewportRelativeNV = 5252, - SpvDecorationSecondaryViewportRelativeNV = 5256, - SpvDecorationPerPrimitiveNV = 5271, - SpvDecorationPerViewNV = 5272, - SpvDecorationPerTaskNV = 5273, - SpvDecorationPerVertexNV = 5285, - SpvDecorationNonUniform = 5300, - SpvDecorationNonUniformEXT = 5300, - SpvDecorationRestrictPointer = 5355, - SpvDecorationRestrictPointerEXT = 5355, - SpvDecorationAliasedPointer = 5356, - SpvDecorationAliasedPointerEXT = 5356, - SpvDecorationReferencedIndirectlyINTEL = 5602, - SpvDecorationCounterBuffer = 5634, - SpvDecorationHlslCounterBufferGOOGLE = 5634, - SpvDecorationHlslSemanticGOOGLE = 5635, - SpvDecorationUserSemantic = 5635, - SpvDecorationUserTypeGOOGLE = 5636, - SpvDecorationRegisterINTEL = 5825, - SpvDecorationMemoryINTEL = 5826, - SpvDecorationNumbanksINTEL = 5827, - SpvDecorationBankwidthINTEL = 5828, - SpvDecorationMaxPrivateCopiesINTEL = 5829, - SpvDecorationSinglepumpINTEL = 5830, - SpvDecorationDoublepumpINTEL = 5831, - SpvDecorationMaxReplicatesINTEL = 5832, - SpvDecorationSimpleDualPortINTEL = 5833, - SpvDecorationMergeINTEL = 5834, - SpvDecorationBankBitsINTEL = 5835, - SpvDecorationForcePow2DepthINTEL = 5836, - SpvDecorationMax = 0x7fffffff, -} SpvDecoration; - -typedef enum SpvBuiltIn_ { - SpvBuiltInPosition = 0, - SpvBuiltInPointSize = 1, - SpvBuiltInClipDistance = 3, - SpvBuiltInCullDistance = 4, - SpvBuiltInVertexId = 5, - SpvBuiltInInstanceId = 6, - SpvBuiltInPrimitiveId = 7, - SpvBuiltInInvocationId = 8, - SpvBuiltInLayer = 9, - SpvBuiltInViewportIndex = 10, - SpvBuiltInTessLevelOuter = 11, - SpvBuiltInTessLevelInner = 12, - SpvBuiltInTessCoord = 13, - SpvBuiltInPatchVertices = 14, - SpvBuiltInFragCoord = 15, - SpvBuiltInPointCoord = 16, - SpvBuiltInFrontFacing = 17, - SpvBuiltInSampleId = 18, - SpvBuiltInSamplePosition = 19, - SpvBuiltInSampleMask = 20, - SpvBuiltInFragDepth = 22, - SpvBuiltInHelperInvocation = 23, - SpvBuiltInNumWorkgroups = 24, - SpvBuiltInWorkgroupSize = 25, - SpvBuiltInWorkgroupId = 26, - SpvBuiltInLocalInvocationId = 27, - SpvBuiltInGlobalInvocationId = 28, - SpvBuiltInLocalInvocationIndex = 29, - SpvBuiltInWorkDim = 30, - SpvBuiltInGlobalSize = 31, - SpvBuiltInEnqueuedWorkgroupSize = 32, - SpvBuiltInGlobalOffset = 33, - SpvBuiltInGlobalLinearId = 34, - SpvBuiltInSubgroupSize = 36, - SpvBuiltInSubgroupMaxSize = 37, - SpvBuiltInNumSubgroups = 38, - SpvBuiltInNumEnqueuedSubgroups = 39, - SpvBuiltInSubgroupId = 40, - SpvBuiltInSubgroupLocalInvocationId = 41, - SpvBuiltInVertexIndex = 42, - SpvBuiltInInstanceIndex = 43, - SpvBuiltInSubgroupEqMask = 4416, - SpvBuiltInSubgroupEqMaskKHR = 4416, - SpvBuiltInSubgroupGeMask = 4417, - SpvBuiltInSubgroupGeMaskKHR = 4417, - SpvBuiltInSubgroupGtMask = 4418, - SpvBuiltInSubgroupGtMaskKHR = 4418, - SpvBuiltInSubgroupLeMask = 4419, - SpvBuiltInSubgroupLeMaskKHR = 4419, - SpvBuiltInSubgroupLtMask = 4420, - SpvBuiltInSubgroupLtMaskKHR = 4420, - SpvBuiltInBaseVertex = 4424, - SpvBuiltInBaseInstance = 4425, - SpvBuiltInDrawIndex = 4426, - SpvBuiltInPrimitiveShadingRateKHR = 4432, - SpvBuiltInDeviceIndex = 4438, - SpvBuiltInViewIndex = 4440, - SpvBuiltInShadingRateKHR = 4444, - SpvBuiltInBaryCoordNoPerspAMD = 4992, - SpvBuiltInBaryCoordNoPerspCentroidAMD = 4993, - SpvBuiltInBaryCoordNoPerspSampleAMD = 4994, - SpvBuiltInBaryCoordSmoothAMD = 4995, - SpvBuiltInBaryCoordSmoothCentroidAMD = 4996, - SpvBuiltInBaryCoordSmoothSampleAMD = 4997, - SpvBuiltInBaryCoordPullModelAMD = 4998, - SpvBuiltInFragStencilRefEXT = 5014, - SpvBuiltInViewportMaskNV = 5253, - SpvBuiltInSecondaryPositionNV = 5257, - SpvBuiltInSecondaryViewportMaskNV = 5258, - SpvBuiltInPositionPerViewNV = 5261, - SpvBuiltInViewportMaskPerViewNV = 5262, - SpvBuiltInFullyCoveredEXT = 5264, - SpvBuiltInTaskCountNV = 5274, - SpvBuiltInPrimitiveCountNV = 5275, - SpvBuiltInPrimitiveIndicesNV = 5276, - SpvBuiltInClipDistancePerViewNV = 5277, - SpvBuiltInCullDistancePerViewNV = 5278, - SpvBuiltInLayerPerViewNV = 5279, - SpvBuiltInMeshViewCountNV = 5280, - SpvBuiltInMeshViewIndicesNV = 5281, - SpvBuiltInBaryCoordNV = 5286, - SpvBuiltInBaryCoordNoPerspNV = 5287, - SpvBuiltInFragSizeEXT = 5292, - SpvBuiltInFragmentSizeNV = 5292, - SpvBuiltInFragInvocationCountEXT = 5293, - SpvBuiltInInvocationsPerPixelNV = 5293, - SpvBuiltInLaunchIdKHR = 5319, - SpvBuiltInLaunchIdNV = 5319, - SpvBuiltInLaunchSizeKHR = 5320, - SpvBuiltInLaunchSizeNV = 5320, - SpvBuiltInWorldRayOriginKHR = 5321, - SpvBuiltInWorldRayOriginNV = 5321, - SpvBuiltInWorldRayDirectionKHR = 5322, - SpvBuiltInWorldRayDirectionNV = 5322, - SpvBuiltInObjectRayOriginKHR = 5323, - SpvBuiltInObjectRayOriginNV = 5323, - SpvBuiltInObjectRayDirectionKHR = 5324, - SpvBuiltInObjectRayDirectionNV = 5324, - SpvBuiltInRayTminKHR = 5325, - SpvBuiltInRayTminNV = 5325, - SpvBuiltInRayTmaxKHR = 5326, - SpvBuiltInRayTmaxNV = 5326, - SpvBuiltInInstanceCustomIndexKHR = 5327, - SpvBuiltInInstanceCustomIndexNV = 5327, - SpvBuiltInObjectToWorldKHR = 5330, - SpvBuiltInObjectToWorldNV = 5330, - SpvBuiltInWorldToObjectKHR = 5331, - SpvBuiltInWorldToObjectNV = 5331, - SpvBuiltInHitTNV = 5332, - SpvBuiltInHitKindKHR = 5333, - SpvBuiltInHitKindNV = 5333, - SpvBuiltInIncomingRayFlagsKHR = 5351, - SpvBuiltInIncomingRayFlagsNV = 5351, - SpvBuiltInRayGeometryIndexKHR = 5352, - SpvBuiltInWarpsPerSMNV = 5374, - SpvBuiltInSMCountNV = 5375, - SpvBuiltInWarpIDNV = 5376, - SpvBuiltInSMIDNV = 5377, - SpvBuiltInMax = 0x7fffffff, -} SpvBuiltIn; - -typedef enum SpvSelectionControlShift_ { - SpvSelectionControlFlattenShift = 0, - SpvSelectionControlDontFlattenShift = 1, - SpvSelectionControlMax = 0x7fffffff, -} SpvSelectionControlShift; - -typedef enum SpvSelectionControlMask_ { - SpvSelectionControlMaskNone = 0, - SpvSelectionControlFlattenMask = 0x00000001, - SpvSelectionControlDontFlattenMask = 0x00000002, -} SpvSelectionControlMask; - -typedef enum SpvLoopControlShift_ { - SpvLoopControlUnrollShift = 0, - SpvLoopControlDontUnrollShift = 1, - SpvLoopControlDependencyInfiniteShift = 2, - SpvLoopControlDependencyLengthShift = 3, - SpvLoopControlMinIterationsShift = 4, - SpvLoopControlMaxIterationsShift = 5, - SpvLoopControlIterationMultipleShift = 6, - SpvLoopControlPeelCountShift = 7, - SpvLoopControlPartialCountShift = 8, - SpvLoopControlInitiationIntervalINTELShift = 16, - SpvLoopControlMaxConcurrencyINTELShift = 17, - SpvLoopControlDependencyArrayINTELShift = 18, - SpvLoopControlPipelineEnableINTELShift = 19, - SpvLoopControlLoopCoalesceINTELShift = 20, - SpvLoopControlMaxInterleavingINTELShift = 21, - SpvLoopControlSpeculatedIterationsINTELShift = 22, - SpvLoopControlMax = 0x7fffffff, -} SpvLoopControlShift; - -typedef enum SpvLoopControlMask_ { - SpvLoopControlMaskNone = 0, - SpvLoopControlUnrollMask = 0x00000001, - SpvLoopControlDontUnrollMask = 0x00000002, - SpvLoopControlDependencyInfiniteMask = 0x00000004, - SpvLoopControlDependencyLengthMask = 0x00000008, - SpvLoopControlMinIterationsMask = 0x00000010, - SpvLoopControlMaxIterationsMask = 0x00000020, - SpvLoopControlIterationMultipleMask = 0x00000040, - SpvLoopControlPeelCountMask = 0x00000080, - SpvLoopControlPartialCountMask = 0x00000100, - SpvLoopControlInitiationIntervalINTELMask = 0x00010000, - SpvLoopControlMaxConcurrencyINTELMask = 0x00020000, - SpvLoopControlDependencyArrayINTELMask = 0x00040000, - SpvLoopControlPipelineEnableINTELMask = 0x00080000, - SpvLoopControlLoopCoalesceINTELMask = 0x00100000, - SpvLoopControlMaxInterleavingINTELMask = 0x00200000, - SpvLoopControlSpeculatedIterationsINTELMask = 0x00400000, -} SpvLoopControlMask; - -typedef enum SpvFunctionControlShift_ { - SpvFunctionControlInlineShift = 0, - SpvFunctionControlDontInlineShift = 1, - SpvFunctionControlPureShift = 2, - SpvFunctionControlConstShift = 3, - SpvFunctionControlMax = 0x7fffffff, -} SpvFunctionControlShift; - -typedef enum SpvFunctionControlMask_ { - SpvFunctionControlMaskNone = 0, - SpvFunctionControlInlineMask = 0x00000001, - SpvFunctionControlDontInlineMask = 0x00000002, - SpvFunctionControlPureMask = 0x00000004, - SpvFunctionControlConstMask = 0x00000008, -} SpvFunctionControlMask; - -typedef enum SpvMemorySemanticsShift_ { - SpvMemorySemanticsAcquireShift = 1, - SpvMemorySemanticsReleaseShift = 2, - SpvMemorySemanticsAcquireReleaseShift = 3, - SpvMemorySemanticsSequentiallyConsistentShift = 4, - SpvMemorySemanticsUniformMemoryShift = 6, - SpvMemorySemanticsSubgroupMemoryShift = 7, - SpvMemorySemanticsWorkgroupMemoryShift = 8, - SpvMemorySemanticsCrossWorkgroupMemoryShift = 9, - SpvMemorySemanticsAtomicCounterMemoryShift = 10, - SpvMemorySemanticsImageMemoryShift = 11, - SpvMemorySemanticsOutputMemoryShift = 12, - SpvMemorySemanticsOutputMemoryKHRShift = 12, - SpvMemorySemanticsMakeAvailableShift = 13, - SpvMemorySemanticsMakeAvailableKHRShift = 13, - SpvMemorySemanticsMakeVisibleShift = 14, - SpvMemorySemanticsMakeVisibleKHRShift = 14, - SpvMemorySemanticsVolatileShift = 15, - SpvMemorySemanticsMax = 0x7fffffff, -} SpvMemorySemanticsShift; - -typedef enum SpvMemorySemanticsMask_ { - SpvMemorySemanticsMaskNone = 0, - SpvMemorySemanticsAcquireMask = 0x00000002, - SpvMemorySemanticsReleaseMask = 0x00000004, - SpvMemorySemanticsAcquireReleaseMask = 0x00000008, - SpvMemorySemanticsSequentiallyConsistentMask = 0x00000010, - SpvMemorySemanticsUniformMemoryMask = 0x00000040, - SpvMemorySemanticsSubgroupMemoryMask = 0x00000080, - SpvMemorySemanticsWorkgroupMemoryMask = 0x00000100, - SpvMemorySemanticsCrossWorkgroupMemoryMask = 0x00000200, - SpvMemorySemanticsAtomicCounterMemoryMask = 0x00000400, - SpvMemorySemanticsImageMemoryMask = 0x00000800, - SpvMemorySemanticsOutputMemoryMask = 0x00001000, - SpvMemorySemanticsOutputMemoryKHRMask = 0x00001000, - SpvMemorySemanticsMakeAvailableMask = 0x00002000, - SpvMemorySemanticsMakeAvailableKHRMask = 0x00002000, - SpvMemorySemanticsMakeVisibleMask = 0x00004000, - SpvMemorySemanticsMakeVisibleKHRMask = 0x00004000, - SpvMemorySemanticsVolatileMask = 0x00008000, -} SpvMemorySemanticsMask; - -typedef enum SpvMemoryAccessShift_ { - SpvMemoryAccessVolatileShift = 0, - SpvMemoryAccessAlignedShift = 1, - SpvMemoryAccessNontemporalShift = 2, - SpvMemoryAccessMakePointerAvailableShift = 3, - SpvMemoryAccessMakePointerAvailableKHRShift = 3, - SpvMemoryAccessMakePointerVisibleShift = 4, - SpvMemoryAccessMakePointerVisibleKHRShift = 4, - SpvMemoryAccessNonPrivatePointerShift = 5, - SpvMemoryAccessNonPrivatePointerKHRShift = 5, - SpvMemoryAccessMax = 0x7fffffff, -} SpvMemoryAccessShift; - -typedef enum SpvMemoryAccessMask_ { - SpvMemoryAccessMaskNone = 0, - SpvMemoryAccessVolatileMask = 0x00000001, - SpvMemoryAccessAlignedMask = 0x00000002, - SpvMemoryAccessNontemporalMask = 0x00000004, - SpvMemoryAccessMakePointerAvailableMask = 0x00000008, - SpvMemoryAccessMakePointerAvailableKHRMask = 0x00000008, - SpvMemoryAccessMakePointerVisibleMask = 0x00000010, - SpvMemoryAccessMakePointerVisibleKHRMask = 0x00000010, - SpvMemoryAccessNonPrivatePointerMask = 0x00000020, - SpvMemoryAccessNonPrivatePointerKHRMask = 0x00000020, -} SpvMemoryAccessMask; - -typedef enum SpvScope_ { - SpvScopeCrossDevice = 0, - SpvScopeDevice = 1, - SpvScopeWorkgroup = 2, - SpvScopeSubgroup = 3, - SpvScopeInvocation = 4, - SpvScopeQueueFamily = 5, - SpvScopeQueueFamilyKHR = 5, - SpvScopeShaderCallKHR = 6, - SpvScopeMax = 0x7fffffff, -} SpvScope; - -typedef enum SpvGroupOperation_ { - SpvGroupOperationReduce = 0, - SpvGroupOperationInclusiveScan = 1, - SpvGroupOperationExclusiveScan = 2, - SpvGroupOperationClusteredReduce = 3, - SpvGroupOperationPartitionedReduceNV = 6, - SpvGroupOperationPartitionedInclusiveScanNV = 7, - SpvGroupOperationPartitionedExclusiveScanNV = 8, - SpvGroupOperationMax = 0x7fffffff, -} SpvGroupOperation; - -typedef enum SpvKernelEnqueueFlags_ { - SpvKernelEnqueueFlagsNoWait = 0, - SpvKernelEnqueueFlagsWaitKernel = 1, - SpvKernelEnqueueFlagsWaitWorkGroup = 2, - SpvKernelEnqueueFlagsMax = 0x7fffffff, -} SpvKernelEnqueueFlags; - -typedef enum SpvKernelProfilingInfoShift_ { - SpvKernelProfilingInfoCmdExecTimeShift = 0, - SpvKernelProfilingInfoMax = 0x7fffffff, -} SpvKernelProfilingInfoShift; - -typedef enum SpvKernelProfilingInfoMask_ { - SpvKernelProfilingInfoMaskNone = 0, - SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001, -} SpvKernelProfilingInfoMask; - -typedef enum SpvCapability_ { - SpvCapabilityMatrix = 0, - SpvCapabilityShader = 1, - SpvCapabilityGeometry = 2, - SpvCapabilityTessellation = 3, - SpvCapabilityAddresses = 4, - SpvCapabilityLinkage = 5, - SpvCapabilityKernel = 6, - SpvCapabilityVector16 = 7, - SpvCapabilityFloat16Buffer = 8, - SpvCapabilityFloat16 = 9, - SpvCapabilityFloat64 = 10, - SpvCapabilityInt64 = 11, - SpvCapabilityInt64Atomics = 12, - SpvCapabilityImageBasic = 13, - SpvCapabilityImageReadWrite = 14, - SpvCapabilityImageMipmap = 15, - SpvCapabilityPipes = 17, - SpvCapabilityGroups = 18, - SpvCapabilityDeviceEnqueue = 19, - SpvCapabilityLiteralSampler = 20, - SpvCapabilityAtomicStorage = 21, - SpvCapabilityInt16 = 22, - SpvCapabilityTessellationPointSize = 23, - SpvCapabilityGeometryPointSize = 24, - SpvCapabilityImageGatherExtended = 25, - SpvCapabilityStorageImageMultisample = 27, - SpvCapabilityUniformBufferArrayDynamicIndexing = 28, - SpvCapabilitySampledImageArrayDynamicIndexing = 29, - SpvCapabilityStorageBufferArrayDynamicIndexing = 30, - SpvCapabilityStorageImageArrayDynamicIndexing = 31, - SpvCapabilityClipDistance = 32, - SpvCapabilityCullDistance = 33, - SpvCapabilityImageCubeArray = 34, - SpvCapabilitySampleRateShading = 35, - SpvCapabilityImageRect = 36, - SpvCapabilitySampledRect = 37, - SpvCapabilityGenericPointer = 38, - SpvCapabilityInt8 = 39, - SpvCapabilityInputAttachment = 40, - SpvCapabilitySparseResidency = 41, - SpvCapabilityMinLod = 42, - SpvCapabilitySampled1D = 43, - SpvCapabilityImage1D = 44, - SpvCapabilitySampledCubeArray = 45, - SpvCapabilitySampledBuffer = 46, - SpvCapabilityImageBuffer = 47, - SpvCapabilityImageMSArray = 48, - SpvCapabilityStorageImageExtendedFormats = 49, - SpvCapabilityImageQuery = 50, - SpvCapabilityDerivativeControl = 51, - SpvCapabilityInterpolationFunction = 52, - SpvCapabilityTransformFeedback = 53, - SpvCapabilityGeometryStreams = 54, - SpvCapabilityStorageImageReadWithoutFormat = 55, - SpvCapabilityStorageImageWriteWithoutFormat = 56, - SpvCapabilityMultiViewport = 57, - SpvCapabilitySubgroupDispatch = 58, - SpvCapabilityNamedBarrier = 59, - SpvCapabilityPipeStorage = 60, - SpvCapabilityGroupNonUniform = 61, - SpvCapabilityGroupNonUniformVote = 62, - SpvCapabilityGroupNonUniformArithmetic = 63, - SpvCapabilityGroupNonUniformBallot = 64, - SpvCapabilityGroupNonUniformShuffle = 65, - SpvCapabilityGroupNonUniformShuffleRelative = 66, - SpvCapabilityGroupNonUniformClustered = 67, - SpvCapabilityGroupNonUniformQuad = 68, - SpvCapabilityShaderLayer = 69, - SpvCapabilityShaderViewportIndex = 70, - SpvCapabilityFragmentShadingRateKHR = 4422, - SpvCapabilitySubgroupBallotKHR = 4423, - SpvCapabilityDrawParameters = 4427, - SpvCapabilitySubgroupVoteKHR = 4431, - SpvCapabilityStorageBuffer16BitAccess = 4433, - SpvCapabilityStorageUniformBufferBlock16 = 4433, - SpvCapabilityStorageUniform16 = 4434, - SpvCapabilityUniformAndStorageBuffer16BitAccess = 4434, - SpvCapabilityStoragePushConstant16 = 4435, - SpvCapabilityStorageInputOutput16 = 4436, - SpvCapabilityDeviceGroup = 4437, - SpvCapabilityMultiView = 4439, - SpvCapabilityVariablePointersStorageBuffer = 4441, - SpvCapabilityVariablePointers = 4442, - SpvCapabilityAtomicStorageOps = 4445, - SpvCapabilitySampleMaskPostDepthCoverage = 4447, - SpvCapabilityStorageBuffer8BitAccess = 4448, - SpvCapabilityUniformAndStorageBuffer8BitAccess = 4449, - SpvCapabilityStoragePushConstant8 = 4450, - SpvCapabilityDenormPreserve = 4464, - SpvCapabilityDenormFlushToZero = 4465, - SpvCapabilitySignedZeroInfNanPreserve = 4466, - SpvCapabilityRoundingModeRTE = 4467, - SpvCapabilityRoundingModeRTZ = 4468, - SpvCapabilityRayQueryProvisionalKHR = 4471, - SpvCapabilityRayQueryKHR = 4472, - SpvCapabilityRayTraversalPrimitiveCullingKHR = 4478, - SpvCapabilityRayTracingKHR = 4479, - SpvCapabilityFloat16ImageAMD = 5008, - SpvCapabilityImageGatherBiasLodAMD = 5009, - SpvCapabilityFragmentMaskAMD = 5010, - SpvCapabilityStencilExportEXT = 5013, - SpvCapabilityImageReadWriteLodAMD = 5015, - SpvCapabilityInt64ImageEXT = 5016, - SpvCapabilityShaderClockKHR = 5055, - SpvCapabilitySampleMaskOverrideCoverageNV = 5249, - SpvCapabilityGeometryShaderPassthroughNV = 5251, - SpvCapabilityShaderViewportIndexLayerEXT = 5254, - SpvCapabilityShaderViewportIndexLayerNV = 5254, - SpvCapabilityShaderViewportMaskNV = 5255, - SpvCapabilityShaderStereoViewNV = 5259, - SpvCapabilityPerViewAttributesNV = 5260, - SpvCapabilityFragmentFullyCoveredEXT = 5265, - SpvCapabilityMeshShadingNV = 5266, - SpvCapabilityImageFootprintNV = 5282, - SpvCapabilityFragmentBarycentricNV = 5284, - SpvCapabilityComputeDerivativeGroupQuadsNV = 5288, - SpvCapabilityFragmentDensityEXT = 5291, - SpvCapabilityShadingRateNV = 5291, - SpvCapabilityGroupNonUniformPartitionedNV = 5297, - SpvCapabilityShaderNonUniform = 5301, - SpvCapabilityShaderNonUniformEXT = 5301, - SpvCapabilityRuntimeDescriptorArray = 5302, - SpvCapabilityRuntimeDescriptorArrayEXT = 5302, - SpvCapabilityInputAttachmentArrayDynamicIndexing = 5303, - SpvCapabilityInputAttachmentArrayDynamicIndexingEXT = 5303, - SpvCapabilityUniformTexelBufferArrayDynamicIndexing = 5304, - SpvCapabilityUniformTexelBufferArrayDynamicIndexingEXT = 5304, - SpvCapabilityStorageTexelBufferArrayDynamicIndexing = 5305, - SpvCapabilityStorageTexelBufferArrayDynamicIndexingEXT = 5305, - SpvCapabilityUniformBufferArrayNonUniformIndexing = 5306, - SpvCapabilityUniformBufferArrayNonUniformIndexingEXT = 5306, - SpvCapabilitySampledImageArrayNonUniformIndexing = 5307, - SpvCapabilitySampledImageArrayNonUniformIndexingEXT = 5307, - SpvCapabilityStorageBufferArrayNonUniformIndexing = 5308, - SpvCapabilityStorageBufferArrayNonUniformIndexingEXT = 5308, - SpvCapabilityStorageImageArrayNonUniformIndexing = 5309, - SpvCapabilityStorageImageArrayNonUniformIndexingEXT = 5309, - SpvCapabilityInputAttachmentArrayNonUniformIndexing = 5310, - SpvCapabilityInputAttachmentArrayNonUniformIndexingEXT = 5310, - SpvCapabilityUniformTexelBufferArrayNonUniformIndexing = 5311, - SpvCapabilityUniformTexelBufferArrayNonUniformIndexingEXT = 5311, - SpvCapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, - SpvCapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, - SpvCapabilityRayTracingNV = 5340, - SpvCapabilityVulkanMemoryModel = 5345, - SpvCapabilityVulkanMemoryModelKHR = 5345, - SpvCapabilityVulkanMemoryModelDeviceScope = 5346, - SpvCapabilityVulkanMemoryModelDeviceScopeKHR = 5346, - SpvCapabilityPhysicalStorageBufferAddresses = 5347, - SpvCapabilityPhysicalStorageBufferAddressesEXT = 5347, - SpvCapabilityComputeDerivativeGroupLinearNV = 5350, - SpvCapabilityRayTracingProvisionalKHR = 5353, - SpvCapabilityCooperativeMatrixNV = 5357, - SpvCapabilityFragmentShaderSampleInterlockEXT = 5363, - SpvCapabilityFragmentShaderShadingRateInterlockEXT = 5372, - SpvCapabilityShaderSMBuiltinsNV = 5373, - SpvCapabilityFragmentShaderPixelInterlockEXT = 5378, - SpvCapabilityDemoteToHelperInvocationEXT = 5379, - SpvCapabilitySubgroupShuffleINTEL = 5568, - SpvCapabilitySubgroupBufferBlockIOINTEL = 5569, - SpvCapabilitySubgroupImageBlockIOINTEL = 5570, - SpvCapabilitySubgroupImageMediaBlockIOINTEL = 5579, - SpvCapabilityIntegerFunctions2INTEL = 5584, - SpvCapabilityFunctionPointersINTEL = 5603, - SpvCapabilityIndirectReferencesINTEL = 5604, - SpvCapabilitySubgroupAvcMotionEstimationINTEL = 5696, - SpvCapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, - SpvCapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, - SpvCapabilityFPGAMemoryAttributesINTEL = 5824, - SpvCapabilityUnstructuredLoopControlsINTEL = 5886, - SpvCapabilityFPGALoopControlsINTEL = 5888, - SpvCapabilityKernelAttributesINTEL = 5892, - SpvCapabilityFPGAKernelAttributesINTEL = 5897, - SpvCapabilityBlockingPipesINTEL = 5945, - SpvCapabilityFPGARegINTEL = 5948, - SpvCapabilityAtomicFloat32AddEXT = 6033, - SpvCapabilityAtomicFloat64AddEXT = 6034, - SpvCapabilityMax = 0x7fffffff, -} SpvCapability; - -typedef enum SpvRayFlagsShift_ { - SpvRayFlagsOpaqueKHRShift = 0, - SpvRayFlagsNoOpaqueKHRShift = 1, - SpvRayFlagsTerminateOnFirstHitKHRShift = 2, - SpvRayFlagsSkipClosestHitShaderKHRShift = 3, - SpvRayFlagsCullBackFacingTrianglesKHRShift = 4, - SpvRayFlagsCullFrontFacingTrianglesKHRShift = 5, - SpvRayFlagsCullOpaqueKHRShift = 6, - SpvRayFlagsCullNoOpaqueKHRShift = 7, - SpvRayFlagsSkipTrianglesKHRShift = 8, - SpvRayFlagsSkipAABBsKHRShift = 9, - SpvRayFlagsMax = 0x7fffffff, -} SpvRayFlagsShift; - -typedef enum SpvRayFlagsMask_ { - SpvRayFlagsMaskNone = 0, - SpvRayFlagsOpaqueKHRMask = 0x00000001, - SpvRayFlagsNoOpaqueKHRMask = 0x00000002, - SpvRayFlagsTerminateOnFirstHitKHRMask = 0x00000004, - SpvRayFlagsSkipClosestHitShaderKHRMask = 0x00000008, - SpvRayFlagsCullBackFacingTrianglesKHRMask = 0x00000010, - SpvRayFlagsCullFrontFacingTrianglesKHRMask = 0x00000020, - SpvRayFlagsCullOpaqueKHRMask = 0x00000040, - SpvRayFlagsCullNoOpaqueKHRMask = 0x00000080, - SpvRayFlagsSkipTrianglesKHRMask = 0x00000100, - SpvRayFlagsSkipAABBsKHRMask = 0x00000200, -} SpvRayFlagsMask; - -typedef enum SpvRayQueryIntersection_ { - SpvRayQueryIntersectionRayQueryCandidateIntersectionKHR = 0, - SpvRayQueryIntersectionRayQueryCommittedIntersectionKHR = 1, - SpvRayQueryIntersectionMax = 0x7fffffff, -} SpvRayQueryIntersection; - -typedef enum SpvRayQueryCommittedIntersectionType_ { - SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionNoneKHR = 0, - SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionTriangleKHR = 1, - SpvRayQueryCommittedIntersectionTypeRayQueryCommittedIntersectionGeneratedKHR = 2, - SpvRayQueryCommittedIntersectionTypeMax = 0x7fffffff, -} SpvRayQueryCommittedIntersectionType; - -typedef enum SpvRayQueryCandidateIntersectionType_ { - SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionTriangleKHR = 0, - SpvRayQueryCandidateIntersectionTypeRayQueryCandidateIntersectionAABBKHR = 1, - SpvRayQueryCandidateIntersectionTypeMax = 0x7fffffff, -} SpvRayQueryCandidateIntersectionType; - -typedef enum SpvFragmentShadingRateShift_ { - SpvFragmentShadingRateVertical2PixelsShift = 0, - SpvFragmentShadingRateVertical4PixelsShift = 1, - SpvFragmentShadingRateHorizontal2PixelsShift = 2, - SpvFragmentShadingRateHorizontal4PixelsShift = 3, - SpvFragmentShadingRateMax = 0x7fffffff, -} SpvFragmentShadingRateShift; - -typedef enum SpvFragmentShadingRateMask_ { - SpvFragmentShadingRateMaskNone = 0, - SpvFragmentShadingRateVertical2PixelsMask = 0x00000001, - SpvFragmentShadingRateVertical4PixelsMask = 0x00000002, - SpvFragmentShadingRateHorizontal2PixelsMask = 0x00000004, - SpvFragmentShadingRateHorizontal4PixelsMask = 0x00000008, -} SpvFragmentShadingRateMask; - -typedef enum SpvOp_ { - SpvOpNop = 0, - SpvOpUndef = 1, - SpvOpSourceContinued = 2, - SpvOpSource = 3, - SpvOpSourceExtension = 4, - SpvOpName = 5, - SpvOpMemberName = 6, - SpvOpString = 7, - SpvOpLine = 8, - SpvOpExtension = 10, - SpvOpExtInstImport = 11, - SpvOpExtInst = 12, - SpvOpMemoryModel = 14, - SpvOpEntryPoint = 15, - SpvOpExecutionMode = 16, - SpvOpCapability = 17, - SpvOpTypeVoid = 19, - SpvOpTypeBool = 20, - SpvOpTypeInt = 21, - SpvOpTypeFloat = 22, - SpvOpTypeVector = 23, - SpvOpTypeMatrix = 24, - SpvOpTypeImage = 25, - SpvOpTypeSampler = 26, - SpvOpTypeSampledImage = 27, - SpvOpTypeArray = 28, - SpvOpTypeRuntimeArray = 29, - SpvOpTypeStruct = 30, - SpvOpTypeOpaque = 31, - SpvOpTypePointer = 32, - SpvOpTypeFunction = 33, - SpvOpTypeEvent = 34, - SpvOpTypeDeviceEvent = 35, - SpvOpTypeReserveId = 36, - SpvOpTypeQueue = 37, - SpvOpTypePipe = 38, - SpvOpTypeForwardPointer = 39, - SpvOpConstantTrue = 41, - SpvOpConstantFalse = 42, - SpvOpConstant = 43, - SpvOpConstantComposite = 44, - SpvOpConstantSampler = 45, - SpvOpConstantNull = 46, - SpvOpSpecConstantTrue = 48, - SpvOpSpecConstantFalse = 49, - SpvOpSpecConstant = 50, - SpvOpSpecConstantComposite = 51, - SpvOpSpecConstantOp = 52, - SpvOpFunction = 54, - SpvOpFunctionParameter = 55, - SpvOpFunctionEnd = 56, - SpvOpFunctionCall = 57, - SpvOpVariable = 59, - SpvOpImageTexelPointer = 60, - SpvOpLoad = 61, - SpvOpStore = 62, - SpvOpCopyMemory = 63, - SpvOpCopyMemorySized = 64, - SpvOpAccessChain = 65, - SpvOpInBoundsAccessChain = 66, - SpvOpPtrAccessChain = 67, - SpvOpArrayLength = 68, - SpvOpGenericPtrMemSemantics = 69, - SpvOpInBoundsPtrAccessChain = 70, - SpvOpDecorate = 71, - SpvOpMemberDecorate = 72, - SpvOpDecorationGroup = 73, - SpvOpGroupDecorate = 74, - SpvOpGroupMemberDecorate = 75, - SpvOpVectorExtractDynamic = 77, - SpvOpVectorInsertDynamic = 78, - SpvOpVectorShuffle = 79, - SpvOpCompositeConstruct = 80, - SpvOpCompositeExtract = 81, - SpvOpCompositeInsert = 82, - SpvOpCopyObject = 83, - SpvOpTranspose = 84, - SpvOpSampledImage = 86, - SpvOpImageSampleImplicitLod = 87, - SpvOpImageSampleExplicitLod = 88, - SpvOpImageSampleDrefImplicitLod = 89, - SpvOpImageSampleDrefExplicitLod = 90, - SpvOpImageSampleProjImplicitLod = 91, - SpvOpImageSampleProjExplicitLod = 92, - SpvOpImageSampleProjDrefImplicitLod = 93, - SpvOpImageSampleProjDrefExplicitLod = 94, - SpvOpImageFetch = 95, - SpvOpImageGather = 96, - SpvOpImageDrefGather = 97, - SpvOpImageRead = 98, - SpvOpImageWrite = 99, - SpvOpImage = 100, - SpvOpImageQueryFormat = 101, - SpvOpImageQueryOrder = 102, - SpvOpImageQuerySizeLod = 103, - SpvOpImageQuerySize = 104, - SpvOpImageQueryLod = 105, - SpvOpImageQueryLevels = 106, - SpvOpImageQuerySamples = 107, - SpvOpConvertFToU = 109, - SpvOpConvertFToS = 110, - SpvOpConvertSToF = 111, - SpvOpConvertUToF = 112, - SpvOpUConvert = 113, - SpvOpSConvert = 114, - SpvOpFConvert = 115, - SpvOpQuantizeToF16 = 116, - SpvOpConvertPtrToU = 117, - SpvOpSatConvertSToU = 118, - SpvOpSatConvertUToS = 119, - SpvOpConvertUToPtr = 120, - SpvOpPtrCastToGeneric = 121, - SpvOpGenericCastToPtr = 122, - SpvOpGenericCastToPtrExplicit = 123, - SpvOpBitcast = 124, - SpvOpSNegate = 126, - SpvOpFNegate = 127, - SpvOpIAdd = 128, - SpvOpFAdd = 129, - SpvOpISub = 130, - SpvOpFSub = 131, - SpvOpIMul = 132, - SpvOpFMul = 133, - SpvOpUDiv = 134, - SpvOpSDiv = 135, - SpvOpFDiv = 136, - SpvOpUMod = 137, - SpvOpSRem = 138, - SpvOpSMod = 139, - SpvOpFRem = 140, - SpvOpFMod = 141, - SpvOpVectorTimesScalar = 142, - SpvOpMatrixTimesScalar = 143, - SpvOpVectorTimesMatrix = 144, - SpvOpMatrixTimesVector = 145, - SpvOpMatrixTimesMatrix = 146, - SpvOpOuterProduct = 147, - SpvOpDot = 148, - SpvOpIAddCarry = 149, - SpvOpISubBorrow = 150, - SpvOpUMulExtended = 151, - SpvOpSMulExtended = 152, - SpvOpAny = 154, - SpvOpAll = 155, - SpvOpIsNan = 156, - SpvOpIsInf = 157, - SpvOpIsFinite = 158, - SpvOpIsNormal = 159, - SpvOpSignBitSet = 160, - SpvOpLessOrGreater = 161, - SpvOpOrdered = 162, - SpvOpUnordered = 163, - SpvOpLogicalEqual = 164, - SpvOpLogicalNotEqual = 165, - SpvOpLogicalOr = 166, - SpvOpLogicalAnd = 167, - SpvOpLogicalNot = 168, - SpvOpSelect = 169, - SpvOpIEqual = 170, - SpvOpINotEqual = 171, - SpvOpUGreaterThan = 172, - SpvOpSGreaterThan = 173, - SpvOpUGreaterThanEqual = 174, - SpvOpSGreaterThanEqual = 175, - SpvOpULessThan = 176, - SpvOpSLessThan = 177, - SpvOpULessThanEqual = 178, - SpvOpSLessThanEqual = 179, - SpvOpFOrdEqual = 180, - SpvOpFUnordEqual = 181, - SpvOpFOrdNotEqual = 182, - SpvOpFUnordNotEqual = 183, - SpvOpFOrdLessThan = 184, - SpvOpFUnordLessThan = 185, - SpvOpFOrdGreaterThan = 186, - SpvOpFUnordGreaterThan = 187, - SpvOpFOrdLessThanEqual = 188, - SpvOpFUnordLessThanEqual = 189, - SpvOpFOrdGreaterThanEqual = 190, - SpvOpFUnordGreaterThanEqual = 191, - SpvOpShiftRightLogical = 194, - SpvOpShiftRightArithmetic = 195, - SpvOpShiftLeftLogical = 196, - SpvOpBitwiseOr = 197, - SpvOpBitwiseXor = 198, - SpvOpBitwiseAnd = 199, - SpvOpNot = 200, - SpvOpBitFieldInsert = 201, - SpvOpBitFieldSExtract = 202, - SpvOpBitFieldUExtract = 203, - SpvOpBitReverse = 204, - SpvOpBitCount = 205, - SpvOpDPdx = 207, - SpvOpDPdy = 208, - SpvOpFwidth = 209, - SpvOpDPdxFine = 210, - SpvOpDPdyFine = 211, - SpvOpFwidthFine = 212, - SpvOpDPdxCoarse = 213, - SpvOpDPdyCoarse = 214, - SpvOpFwidthCoarse = 215, - SpvOpEmitVertex = 218, - SpvOpEndPrimitive = 219, - SpvOpEmitStreamVertex = 220, - SpvOpEndStreamPrimitive = 221, - SpvOpControlBarrier = 224, - SpvOpMemoryBarrier = 225, - SpvOpAtomicLoad = 227, - SpvOpAtomicStore = 228, - SpvOpAtomicExchange = 229, - SpvOpAtomicCompareExchange = 230, - SpvOpAtomicCompareExchangeWeak = 231, - SpvOpAtomicIIncrement = 232, - SpvOpAtomicIDecrement = 233, - SpvOpAtomicIAdd = 234, - SpvOpAtomicISub = 235, - SpvOpAtomicSMin = 236, - SpvOpAtomicUMin = 237, - SpvOpAtomicSMax = 238, - SpvOpAtomicUMax = 239, - SpvOpAtomicAnd = 240, - SpvOpAtomicOr = 241, - SpvOpAtomicXor = 242, - SpvOpPhi = 245, - SpvOpLoopMerge = 246, - SpvOpSelectionMerge = 247, - SpvOpLabel = 248, - SpvOpBranch = 249, - SpvOpBranchConditional = 250, - SpvOpSwitch = 251, - SpvOpKill = 252, - SpvOpReturn = 253, - SpvOpReturnValue = 254, - SpvOpUnreachable = 255, - SpvOpLifetimeStart = 256, - SpvOpLifetimeStop = 257, - SpvOpGroupAsyncCopy = 259, - SpvOpGroupWaitEvents = 260, - SpvOpGroupAll = 261, - SpvOpGroupAny = 262, - SpvOpGroupBroadcast = 263, - SpvOpGroupIAdd = 264, - SpvOpGroupFAdd = 265, - SpvOpGroupFMin = 266, - SpvOpGroupUMin = 267, - SpvOpGroupSMin = 268, - SpvOpGroupFMax = 269, - SpvOpGroupUMax = 270, - SpvOpGroupSMax = 271, - SpvOpReadPipe = 274, - SpvOpWritePipe = 275, - SpvOpReservedReadPipe = 276, - SpvOpReservedWritePipe = 277, - SpvOpReserveReadPipePackets = 278, - SpvOpReserveWritePipePackets = 279, - SpvOpCommitReadPipe = 280, - SpvOpCommitWritePipe = 281, - SpvOpIsValidReserveId = 282, - SpvOpGetNumPipePackets = 283, - SpvOpGetMaxPipePackets = 284, - SpvOpGroupReserveReadPipePackets = 285, - SpvOpGroupReserveWritePipePackets = 286, - SpvOpGroupCommitReadPipe = 287, - SpvOpGroupCommitWritePipe = 288, - SpvOpEnqueueMarker = 291, - SpvOpEnqueueKernel = 292, - SpvOpGetKernelNDrangeSubGroupCount = 293, - SpvOpGetKernelNDrangeMaxSubGroupSize = 294, - SpvOpGetKernelWorkGroupSize = 295, - SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296, - SpvOpRetainEvent = 297, - SpvOpReleaseEvent = 298, - SpvOpCreateUserEvent = 299, - SpvOpIsValidEvent = 300, - SpvOpSetUserEventStatus = 301, - SpvOpCaptureEventProfilingInfo = 302, - SpvOpGetDefaultQueue = 303, - SpvOpBuildNDRange = 304, - SpvOpImageSparseSampleImplicitLod = 305, - SpvOpImageSparseSampleExplicitLod = 306, - SpvOpImageSparseSampleDrefImplicitLod = 307, - SpvOpImageSparseSampleDrefExplicitLod = 308, - SpvOpImageSparseSampleProjImplicitLod = 309, - SpvOpImageSparseSampleProjExplicitLod = 310, - SpvOpImageSparseSampleProjDrefImplicitLod = 311, - SpvOpImageSparseSampleProjDrefExplicitLod = 312, - SpvOpImageSparseFetch = 313, - SpvOpImageSparseGather = 314, - SpvOpImageSparseDrefGather = 315, - SpvOpImageSparseTexelsResident = 316, - SpvOpNoLine = 317, - SpvOpAtomicFlagTestAndSet = 318, - SpvOpAtomicFlagClear = 319, - SpvOpImageSparseRead = 320, - SpvOpSizeOf = 321, - SpvOpTypePipeStorage = 322, - SpvOpConstantPipeStorage = 323, - SpvOpCreatePipeFromPipeStorage = 324, - SpvOpGetKernelLocalSizeForSubgroupCount = 325, - SpvOpGetKernelMaxNumSubgroups = 326, - SpvOpTypeNamedBarrier = 327, - SpvOpNamedBarrierInitialize = 328, - SpvOpMemoryNamedBarrier = 329, - SpvOpModuleProcessed = 330, - SpvOpExecutionModeId = 331, - SpvOpDecorateId = 332, - SpvOpGroupNonUniformElect = 333, - SpvOpGroupNonUniformAll = 334, - SpvOpGroupNonUniformAny = 335, - SpvOpGroupNonUniformAllEqual = 336, - SpvOpGroupNonUniformBroadcast = 337, - SpvOpGroupNonUniformBroadcastFirst = 338, - SpvOpGroupNonUniformBallot = 339, - SpvOpGroupNonUniformInverseBallot = 340, - SpvOpGroupNonUniformBallotBitExtract = 341, - SpvOpGroupNonUniformBallotBitCount = 342, - SpvOpGroupNonUniformBallotFindLSB = 343, - SpvOpGroupNonUniformBallotFindMSB = 344, - SpvOpGroupNonUniformShuffle = 345, - SpvOpGroupNonUniformShuffleXor = 346, - SpvOpGroupNonUniformShuffleUp = 347, - SpvOpGroupNonUniformShuffleDown = 348, - SpvOpGroupNonUniformIAdd = 349, - SpvOpGroupNonUniformFAdd = 350, - SpvOpGroupNonUniformIMul = 351, - SpvOpGroupNonUniformFMul = 352, - SpvOpGroupNonUniformSMin = 353, - SpvOpGroupNonUniformUMin = 354, - SpvOpGroupNonUniformFMin = 355, - SpvOpGroupNonUniformSMax = 356, - SpvOpGroupNonUniformUMax = 357, - SpvOpGroupNonUniformFMax = 358, - SpvOpGroupNonUniformBitwiseAnd = 359, - SpvOpGroupNonUniformBitwiseOr = 360, - SpvOpGroupNonUniformBitwiseXor = 361, - SpvOpGroupNonUniformLogicalAnd = 362, - SpvOpGroupNonUniformLogicalOr = 363, - SpvOpGroupNonUniformLogicalXor = 364, - SpvOpGroupNonUniformQuadBroadcast = 365, - SpvOpGroupNonUniformQuadSwap = 366, - SpvOpCopyLogical = 400, - SpvOpPtrEqual = 401, - SpvOpPtrNotEqual = 402, - SpvOpPtrDiff = 403, - SpvOpTerminateInvocation = 4416, - SpvOpSubgroupBallotKHR = 4421, - SpvOpSubgroupFirstInvocationKHR = 4422, - SpvOpSubgroupAllKHR = 4428, - SpvOpSubgroupAnyKHR = 4429, - SpvOpSubgroupAllEqualKHR = 4430, - SpvOpSubgroupReadInvocationKHR = 4432, - SpvOpTraceRayKHR = 4445, - SpvOpExecuteCallableKHR = 4446, - SpvOpConvertUToAccelerationStructureKHR = 4447, - SpvOpIgnoreIntersectionKHR = 4448, - SpvOpTerminateRayKHR = 4449, - SpvOpTypeRayQueryKHR = 4472, - SpvOpRayQueryInitializeKHR = 4473, - SpvOpRayQueryTerminateKHR = 4474, - SpvOpRayQueryGenerateIntersectionKHR = 4475, - SpvOpRayQueryConfirmIntersectionKHR = 4476, - SpvOpRayQueryProceedKHR = 4477, - SpvOpRayQueryGetIntersectionTypeKHR = 4479, - SpvOpGroupIAddNonUniformAMD = 5000, - SpvOpGroupFAddNonUniformAMD = 5001, - SpvOpGroupFMinNonUniformAMD = 5002, - SpvOpGroupUMinNonUniformAMD = 5003, - SpvOpGroupSMinNonUniformAMD = 5004, - SpvOpGroupFMaxNonUniformAMD = 5005, - SpvOpGroupUMaxNonUniformAMD = 5006, - SpvOpGroupSMaxNonUniformAMD = 5007, - SpvOpFragmentMaskFetchAMD = 5011, - SpvOpFragmentFetchAMD = 5012, - SpvOpReadClockKHR = 5056, - SpvOpImageSampleFootprintNV = 5283, - SpvOpGroupNonUniformPartitionNV = 5296, - SpvOpWritePackedPrimitiveIndices4x8NV = 5299, - SpvOpReportIntersectionKHR = 5334, - SpvOpReportIntersectionNV = 5334, - SpvOpIgnoreIntersectionNV = 5335, - SpvOpTerminateRayNV = 5336, - SpvOpTraceNV = 5337, - SpvOpTypeAccelerationStructureKHR = 5341, - SpvOpTypeAccelerationStructureNV = 5341, - SpvOpExecuteCallableNV = 5344, - SpvOpTypeCooperativeMatrixNV = 5358, - SpvOpCooperativeMatrixLoadNV = 5359, - SpvOpCooperativeMatrixStoreNV = 5360, - SpvOpCooperativeMatrixMulAddNV = 5361, - SpvOpCooperativeMatrixLengthNV = 5362, - SpvOpBeginInvocationInterlockEXT = 5364, - SpvOpEndInvocationInterlockEXT = 5365, - SpvOpDemoteToHelperInvocationEXT = 5380, - SpvOpIsHelperInvocationEXT = 5381, - SpvOpSubgroupShuffleINTEL = 5571, - SpvOpSubgroupShuffleDownINTEL = 5572, - SpvOpSubgroupShuffleUpINTEL = 5573, - SpvOpSubgroupShuffleXorINTEL = 5574, - SpvOpSubgroupBlockReadINTEL = 5575, - SpvOpSubgroupBlockWriteINTEL = 5576, - SpvOpSubgroupImageBlockReadINTEL = 5577, - SpvOpSubgroupImageBlockWriteINTEL = 5578, - SpvOpSubgroupImageMediaBlockReadINTEL = 5580, - SpvOpSubgroupImageMediaBlockWriteINTEL = 5581, - SpvOpUCountLeadingZerosINTEL = 5585, - SpvOpUCountTrailingZerosINTEL = 5586, - SpvOpAbsISubINTEL = 5587, - SpvOpAbsUSubINTEL = 5588, - SpvOpIAddSatINTEL = 5589, - SpvOpUAddSatINTEL = 5590, - SpvOpIAverageINTEL = 5591, - SpvOpUAverageINTEL = 5592, - SpvOpIAverageRoundedINTEL = 5593, - SpvOpUAverageRoundedINTEL = 5594, - SpvOpISubSatINTEL = 5595, - SpvOpUSubSatINTEL = 5596, - SpvOpIMul32x16INTEL = 5597, - SpvOpUMul32x16INTEL = 5598, - SpvOpFunctionPointerINTEL = 5600, - SpvOpFunctionPointerCallINTEL = 5601, - SpvOpDecorateString = 5632, - SpvOpDecorateStringGOOGLE = 5632, - SpvOpMemberDecorateString = 5633, - SpvOpMemberDecorateStringGOOGLE = 5633, - SpvOpVmeImageINTEL = 5699, - SpvOpTypeVmeImageINTEL = 5700, - SpvOpTypeAvcImePayloadINTEL = 5701, - SpvOpTypeAvcRefPayloadINTEL = 5702, - SpvOpTypeAvcSicPayloadINTEL = 5703, - SpvOpTypeAvcMcePayloadINTEL = 5704, - SpvOpTypeAvcMceResultINTEL = 5705, - SpvOpTypeAvcImeResultINTEL = 5706, - SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL = 5707, - SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL = 5708, - SpvOpTypeAvcImeSingleReferenceStreaminINTEL = 5709, - SpvOpTypeAvcImeDualReferenceStreaminINTEL = 5710, - SpvOpTypeAvcRefResultINTEL = 5711, - SpvOpTypeAvcSicResultINTEL = 5712, - SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL = 5713, - SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL = 5714, - SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL = 5715, - SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL = 5716, - SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL = 5717, - SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL = 5718, - SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL = 5719, - SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL = 5720, - SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL = 5721, - SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL = 5722, - SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL = 5723, - SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL = 5724, - SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL = 5725, - SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL = 5726, - SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL = 5727, - SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL = 5728, - SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL = 5729, - SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL = 5730, - SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL = 5731, - SpvOpSubgroupAvcMceConvertToImePayloadINTEL = 5732, - SpvOpSubgroupAvcMceConvertToImeResultINTEL = 5733, - SpvOpSubgroupAvcMceConvertToRefPayloadINTEL = 5734, - SpvOpSubgroupAvcMceConvertToRefResultINTEL = 5735, - SpvOpSubgroupAvcMceConvertToSicPayloadINTEL = 5736, - SpvOpSubgroupAvcMceConvertToSicResultINTEL = 5737, - SpvOpSubgroupAvcMceGetMotionVectorsINTEL = 5738, - SpvOpSubgroupAvcMceGetInterDistortionsINTEL = 5739, - SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL = 5740, - SpvOpSubgroupAvcMceGetInterMajorShapeINTEL = 5741, - SpvOpSubgroupAvcMceGetInterMinorShapeINTEL = 5742, - SpvOpSubgroupAvcMceGetInterDirectionsINTEL = 5743, - SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL = 5744, - SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL = 5745, - SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL = 5746, - SpvOpSubgroupAvcImeInitializeINTEL = 5747, - SpvOpSubgroupAvcImeSetSingleReferenceINTEL = 5748, - SpvOpSubgroupAvcImeSetDualReferenceINTEL = 5749, - SpvOpSubgroupAvcImeRefWindowSizeINTEL = 5750, - SpvOpSubgroupAvcImeAdjustRefOffsetINTEL = 5751, - SpvOpSubgroupAvcImeConvertToMcePayloadINTEL = 5752, - SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL = 5753, - SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL = 5754, - SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL = 5755, - SpvOpSubgroupAvcImeSetWeightedSadINTEL = 5756, - SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL = 5757, - SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL = 5758, - SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL = 5759, - SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL = 5760, - SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL = 5761, - SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL = 5762, - SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL = 5763, - SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL = 5764, - SpvOpSubgroupAvcImeConvertToMceResultINTEL = 5765, - SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL = 5766, - SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL = 5767, - SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL = 5768, - SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL = 5769, - SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL = 5770, - SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL = 5771, - SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL = 5772, - SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL = 5773, - SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL = 5774, - SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL = 5775, - SpvOpSubgroupAvcImeGetBorderReachedINTEL = 5776, - SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL = 5777, - SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL = 5778, - SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL = 5779, - SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL = 5780, - SpvOpSubgroupAvcFmeInitializeINTEL = 5781, - SpvOpSubgroupAvcBmeInitializeINTEL = 5782, - SpvOpSubgroupAvcRefConvertToMcePayloadINTEL = 5783, - SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL = 5784, - SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL = 5785, - SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL = 5786, - SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL = 5787, - SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL = 5788, - SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL = 5789, - SpvOpSubgroupAvcRefConvertToMceResultINTEL = 5790, - SpvOpSubgroupAvcSicInitializeINTEL = 5791, - SpvOpSubgroupAvcSicConfigureSkcINTEL = 5792, - SpvOpSubgroupAvcSicConfigureIpeLumaINTEL = 5793, - SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL = 5794, - SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL = 5795, - SpvOpSubgroupAvcSicConvertToMcePayloadINTEL = 5796, - SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL = 5797, - SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL = 5798, - SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL = 5799, - SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL = 5800, - SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL = 5801, - SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL = 5802, - SpvOpSubgroupAvcSicEvaluateIpeINTEL = 5803, - SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL = 5804, - SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL = 5805, - SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL = 5806, - SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL = 5807, - SpvOpSubgroupAvcSicConvertToMceResultINTEL = 5808, - SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL = 5809, - SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL = 5810, - SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL = 5811, - SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL = 5812, - SpvOpSubgroupAvcSicGetIpeChromaModeINTEL = 5813, - SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, - SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, - SpvOpSubgroupAvcSicGetInterRawSadsINTEL = 5816, - SpvOpLoopControlINTEL = 5887, - SpvOpReadPipeBlockingINTEL = 5946, - SpvOpWritePipeBlockingINTEL = 5947, - SpvOpFPGARegINTEL = 5949, - SpvOpRayQueryGetRayTMinKHR = 6016, - SpvOpRayQueryGetRayFlagsKHR = 6017, - SpvOpRayQueryGetIntersectionTKHR = 6018, - SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR = 6019, - SpvOpRayQueryGetIntersectionInstanceIdKHR = 6020, - SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR = 6021, - SpvOpRayQueryGetIntersectionGeometryIndexKHR = 6022, - SpvOpRayQueryGetIntersectionPrimitiveIndexKHR = 6023, - SpvOpRayQueryGetIntersectionBarycentricsKHR = 6024, - SpvOpRayQueryGetIntersectionFrontFaceKHR = 6025, - SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR = 6026, - SpvOpRayQueryGetIntersectionObjectRayDirectionKHR = 6027, - SpvOpRayQueryGetIntersectionObjectRayOriginKHR = 6028, - SpvOpRayQueryGetWorldRayDirectionKHR = 6029, - SpvOpRayQueryGetWorldRayOriginKHR = 6030, - SpvOpRayQueryGetIntersectionObjectToWorldKHR = 6031, - SpvOpRayQueryGetIntersectionWorldToObjectKHR = 6032, - SpvOpAtomicFAddEXT = 6035, - SpvOpMax = 0x7fffffff, -} SpvOp; - -#ifdef SPV_ENABLE_UTILITY_CODE -inline void SpvHasResultAndType(SpvOp opcode, bool *hasResult, bool *hasResultType) { - *hasResult = *hasResultType = false; - switch (opcode) { - default: /* unknown opcode */ break; - case SpvOpNop: *hasResult = false; *hasResultType = false; break; - case SpvOpUndef: *hasResult = true; *hasResultType = true; break; - case SpvOpSourceContinued: *hasResult = false; *hasResultType = false; break; - case SpvOpSource: *hasResult = false; *hasResultType = false; break; - case SpvOpSourceExtension: *hasResult = false; *hasResultType = false; break; - case SpvOpName: *hasResult = false; *hasResultType = false; break; - case SpvOpMemberName: *hasResult = false; *hasResultType = false; break; - case SpvOpString: *hasResult = true; *hasResultType = false; break; - case SpvOpLine: *hasResult = false; *hasResultType = false; break; - case SpvOpExtension: *hasResult = false; *hasResultType = false; break; - case SpvOpExtInstImport: *hasResult = true; *hasResultType = false; break; - case SpvOpExtInst: *hasResult = true; *hasResultType = true; break; - case SpvOpMemoryModel: *hasResult = false; *hasResultType = false; break; - case SpvOpEntryPoint: *hasResult = false; *hasResultType = false; break; - case SpvOpExecutionMode: *hasResult = false; *hasResultType = false; break; - case SpvOpCapability: *hasResult = false; *hasResultType = false; break; - case SpvOpTypeVoid: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeBool: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeInt: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeFloat: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeVector: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeMatrix: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeImage: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeSampler: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeSampledImage: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeArray: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeRuntimeArray: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeStruct: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeOpaque: *hasResult = true; *hasResultType = false; break; - case SpvOpTypePointer: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeFunction: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeEvent: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeDeviceEvent: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeReserveId: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeQueue: *hasResult = true; *hasResultType = false; break; - case SpvOpTypePipe: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeForwardPointer: *hasResult = false; *hasResultType = false; break; - case SpvOpConstantTrue: *hasResult = true; *hasResultType = true; break; - case SpvOpConstantFalse: *hasResult = true; *hasResultType = true; break; - case SpvOpConstant: *hasResult = true; *hasResultType = true; break; - case SpvOpConstantComposite: *hasResult = true; *hasResultType = true; break; - case SpvOpConstantSampler: *hasResult = true; *hasResultType = true; break; - case SpvOpConstantNull: *hasResult = true; *hasResultType = true; break; - case SpvOpSpecConstantTrue: *hasResult = true; *hasResultType = true; break; - case SpvOpSpecConstantFalse: *hasResult = true; *hasResultType = true; break; - case SpvOpSpecConstant: *hasResult = true; *hasResultType = true; break; - case SpvOpSpecConstantComposite: *hasResult = true; *hasResultType = true; break; - case SpvOpSpecConstantOp: *hasResult = true; *hasResultType = true; break; - case SpvOpFunction: *hasResult = true; *hasResultType = true; break; - case SpvOpFunctionParameter: *hasResult = true; *hasResultType = true; break; - case SpvOpFunctionEnd: *hasResult = false; *hasResultType = false; break; - case SpvOpFunctionCall: *hasResult = true; *hasResultType = true; break; - case SpvOpVariable: *hasResult = true; *hasResultType = true; break; - case SpvOpImageTexelPointer: *hasResult = true; *hasResultType = true; break; - case SpvOpLoad: *hasResult = true; *hasResultType = true; break; - case SpvOpStore: *hasResult = false; *hasResultType = false; break; - case SpvOpCopyMemory: *hasResult = false; *hasResultType = false; break; - case SpvOpCopyMemorySized: *hasResult = false; *hasResultType = false; break; - case SpvOpAccessChain: *hasResult = true; *hasResultType = true; break; - case SpvOpInBoundsAccessChain: *hasResult = true; *hasResultType = true; break; - case SpvOpPtrAccessChain: *hasResult = true; *hasResultType = true; break; - case SpvOpArrayLength: *hasResult = true; *hasResultType = true; break; - case SpvOpGenericPtrMemSemantics: *hasResult = true; *hasResultType = true; break; - case SpvOpInBoundsPtrAccessChain: *hasResult = true; *hasResultType = true; break; - case SpvOpDecorate: *hasResult = false; *hasResultType = false; break; - case SpvOpMemberDecorate: *hasResult = false; *hasResultType = false; break; - case SpvOpDecorationGroup: *hasResult = true; *hasResultType = false; break; - case SpvOpGroupDecorate: *hasResult = false; *hasResultType = false; break; - case SpvOpGroupMemberDecorate: *hasResult = false; *hasResultType = false; break; - case SpvOpVectorExtractDynamic: *hasResult = true; *hasResultType = true; break; - case SpvOpVectorInsertDynamic: *hasResult = true; *hasResultType = true; break; - case SpvOpVectorShuffle: *hasResult = true; *hasResultType = true; break; - case SpvOpCompositeConstruct: *hasResult = true; *hasResultType = true; break; - case SpvOpCompositeExtract: *hasResult = true; *hasResultType = true; break; - case SpvOpCompositeInsert: *hasResult = true; *hasResultType = true; break; - case SpvOpCopyObject: *hasResult = true; *hasResultType = true; break; - case SpvOpTranspose: *hasResult = true; *hasResultType = true; break; - case SpvOpSampledImage: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageFetch: *hasResult = true; *hasResultType = true; break; - case SpvOpImageGather: *hasResult = true; *hasResultType = true; break; - case SpvOpImageDrefGather: *hasResult = true; *hasResultType = true; break; - case SpvOpImageRead: *hasResult = true; *hasResultType = true; break; - case SpvOpImageWrite: *hasResult = false; *hasResultType = false; break; - case SpvOpImage: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQueryFormat: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQueryOrder: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQuerySizeLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQuerySize: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQueryLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQueryLevels: *hasResult = true; *hasResultType = true; break; - case SpvOpImageQuerySamples: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertFToU: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertFToS: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertSToF: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertUToF: *hasResult = true; *hasResultType = true; break; - case SpvOpUConvert: *hasResult = true; *hasResultType = true; break; - case SpvOpSConvert: *hasResult = true; *hasResultType = true; break; - case SpvOpFConvert: *hasResult = true; *hasResultType = true; break; - case SpvOpQuantizeToF16: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertPtrToU: *hasResult = true; *hasResultType = true; break; - case SpvOpSatConvertSToU: *hasResult = true; *hasResultType = true; break; - case SpvOpSatConvertUToS: *hasResult = true; *hasResultType = true; break; - case SpvOpConvertUToPtr: *hasResult = true; *hasResultType = true; break; - case SpvOpPtrCastToGeneric: *hasResult = true; *hasResultType = true; break; - case SpvOpGenericCastToPtr: *hasResult = true; *hasResultType = true; break; - case SpvOpGenericCastToPtrExplicit: *hasResult = true; *hasResultType = true; break; - case SpvOpBitcast: *hasResult = true; *hasResultType = true; break; - case SpvOpSNegate: *hasResult = true; *hasResultType = true; break; - case SpvOpFNegate: *hasResult = true; *hasResultType = true; break; - case SpvOpIAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpFAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpISub: *hasResult = true; *hasResultType = true; break; - case SpvOpFSub: *hasResult = true; *hasResultType = true; break; - case SpvOpIMul: *hasResult = true; *hasResultType = true; break; - case SpvOpFMul: *hasResult = true; *hasResultType = true; break; - case SpvOpUDiv: *hasResult = true; *hasResultType = true; break; - case SpvOpSDiv: *hasResult = true; *hasResultType = true; break; - case SpvOpFDiv: *hasResult = true; *hasResultType = true; break; - case SpvOpUMod: *hasResult = true; *hasResultType = true; break; - case SpvOpSRem: *hasResult = true; *hasResultType = true; break; - case SpvOpSMod: *hasResult = true; *hasResultType = true; break; - case SpvOpFRem: *hasResult = true; *hasResultType = true; break; - case SpvOpFMod: *hasResult = true; *hasResultType = true; break; - case SpvOpVectorTimesScalar: *hasResult = true; *hasResultType = true; break; - case SpvOpMatrixTimesScalar: *hasResult = true; *hasResultType = true; break; - case SpvOpVectorTimesMatrix: *hasResult = true; *hasResultType = true; break; - case SpvOpMatrixTimesVector: *hasResult = true; *hasResultType = true; break; - case SpvOpMatrixTimesMatrix: *hasResult = true; *hasResultType = true; break; - case SpvOpOuterProduct: *hasResult = true; *hasResultType = true; break; - case SpvOpDot: *hasResult = true; *hasResultType = true; break; - case SpvOpIAddCarry: *hasResult = true; *hasResultType = true; break; - case SpvOpISubBorrow: *hasResult = true; *hasResultType = true; break; - case SpvOpUMulExtended: *hasResult = true; *hasResultType = true; break; - case SpvOpSMulExtended: *hasResult = true; *hasResultType = true; break; - case SpvOpAny: *hasResult = true; *hasResultType = true; break; - case SpvOpAll: *hasResult = true; *hasResultType = true; break; - case SpvOpIsNan: *hasResult = true; *hasResultType = true; break; - case SpvOpIsInf: *hasResult = true; *hasResultType = true; break; - case SpvOpIsFinite: *hasResult = true; *hasResultType = true; break; - case SpvOpIsNormal: *hasResult = true; *hasResultType = true; break; - case SpvOpSignBitSet: *hasResult = true; *hasResultType = true; break; - case SpvOpLessOrGreater: *hasResult = true; *hasResultType = true; break; - case SpvOpOrdered: *hasResult = true; *hasResultType = true; break; - case SpvOpUnordered: *hasResult = true; *hasResultType = true; break; - case SpvOpLogicalEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpLogicalNotEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpLogicalOr: *hasResult = true; *hasResultType = true; break; - case SpvOpLogicalAnd: *hasResult = true; *hasResultType = true; break; - case SpvOpLogicalNot: *hasResult = true; *hasResultType = true; break; - case SpvOpSelect: *hasResult = true; *hasResultType = true; break; - case SpvOpIEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpINotEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpUGreaterThan: *hasResult = true; *hasResultType = true; break; - case SpvOpSGreaterThan: *hasResult = true; *hasResultType = true; break; - case SpvOpUGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpSGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpULessThan: *hasResult = true; *hasResultType = true; break; - case SpvOpSLessThan: *hasResult = true; *hasResultType = true; break; - case SpvOpULessThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpSLessThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdNotEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordNotEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdLessThan: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordLessThan: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdGreaterThan: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordGreaterThan: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdLessThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordLessThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFOrdGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpFUnordGreaterThanEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpShiftRightLogical: *hasResult = true; *hasResultType = true; break; - case SpvOpShiftRightArithmetic: *hasResult = true; *hasResultType = true; break; - case SpvOpShiftLeftLogical: *hasResult = true; *hasResultType = true; break; - case SpvOpBitwiseOr: *hasResult = true; *hasResultType = true; break; - case SpvOpBitwiseXor: *hasResult = true; *hasResultType = true; break; - case SpvOpBitwiseAnd: *hasResult = true; *hasResultType = true; break; - case SpvOpNot: *hasResult = true; *hasResultType = true; break; - case SpvOpBitFieldInsert: *hasResult = true; *hasResultType = true; break; - case SpvOpBitFieldSExtract: *hasResult = true; *hasResultType = true; break; - case SpvOpBitFieldUExtract: *hasResult = true; *hasResultType = true; break; - case SpvOpBitReverse: *hasResult = true; *hasResultType = true; break; - case SpvOpBitCount: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdx: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdy: *hasResult = true; *hasResultType = true; break; - case SpvOpFwidth: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdxFine: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdyFine: *hasResult = true; *hasResultType = true; break; - case SpvOpFwidthFine: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdxCoarse: *hasResult = true; *hasResultType = true; break; - case SpvOpDPdyCoarse: *hasResult = true; *hasResultType = true; break; - case SpvOpFwidthCoarse: *hasResult = true; *hasResultType = true; break; - case SpvOpEmitVertex: *hasResult = false; *hasResultType = false; break; - case SpvOpEndPrimitive: *hasResult = false; *hasResultType = false; break; - case SpvOpEmitStreamVertex: *hasResult = false; *hasResultType = false; break; - case SpvOpEndStreamPrimitive: *hasResult = false; *hasResultType = false; break; - case SpvOpControlBarrier: *hasResult = false; *hasResultType = false; break; - case SpvOpMemoryBarrier: *hasResult = false; *hasResultType = false; break; - case SpvOpAtomicLoad: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicStore: *hasResult = false; *hasResultType = false; break; - case SpvOpAtomicExchange: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicCompareExchange: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicCompareExchangeWeak: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicIIncrement: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicIDecrement: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicIAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicISub: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicSMin: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicUMin: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicSMax: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicUMax: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicAnd: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicOr: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicXor: *hasResult = true; *hasResultType = true; break; - case SpvOpPhi: *hasResult = true; *hasResultType = true; break; - case SpvOpLoopMerge: *hasResult = false; *hasResultType = false; break; - case SpvOpSelectionMerge: *hasResult = false; *hasResultType = false; break; - case SpvOpLabel: *hasResult = true; *hasResultType = false; break; - case SpvOpBranch: *hasResult = false; *hasResultType = false; break; - case SpvOpBranchConditional: *hasResult = false; *hasResultType = false; break; - case SpvOpSwitch: *hasResult = false; *hasResultType = false; break; - case SpvOpKill: *hasResult = false; *hasResultType = false; break; - case SpvOpReturn: *hasResult = false; *hasResultType = false; break; - case SpvOpReturnValue: *hasResult = false; *hasResultType = false; break; - case SpvOpUnreachable: *hasResult = false; *hasResultType = false; break; - case SpvOpLifetimeStart: *hasResult = false; *hasResultType = false; break; - case SpvOpLifetimeStop: *hasResult = false; *hasResultType = false; break; - case SpvOpGroupAsyncCopy: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupWaitEvents: *hasResult = false; *hasResultType = false; break; - case SpvOpGroupAll: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupAny: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupBroadcast: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupIAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupUMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupSMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFMax: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupUMax: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupSMax: *hasResult = true; *hasResultType = true; break; - case SpvOpReadPipe: *hasResult = true; *hasResultType = true; break; - case SpvOpWritePipe: *hasResult = true; *hasResultType = true; break; - case SpvOpReservedReadPipe: *hasResult = true; *hasResultType = true; break; - case SpvOpReservedWritePipe: *hasResult = true; *hasResultType = true; break; - case SpvOpReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpCommitReadPipe: *hasResult = false; *hasResultType = false; break; - case SpvOpCommitWritePipe: *hasResult = false; *hasResultType = false; break; - case SpvOpIsValidReserveId: *hasResult = true; *hasResultType = true; break; - case SpvOpGetNumPipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpGetMaxPipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupReserveReadPipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupReserveWritePipePackets: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupCommitReadPipe: *hasResult = false; *hasResultType = false; break; - case SpvOpGroupCommitWritePipe: *hasResult = false; *hasResultType = false; break; - case SpvOpEnqueueMarker: *hasResult = true; *hasResultType = true; break; - case SpvOpEnqueueKernel: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelNDrangeSubGroupCount: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelNDrangeMaxSubGroupSize: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelWorkGroupSize: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelPreferredWorkGroupSizeMultiple: *hasResult = true; *hasResultType = true; break; - case SpvOpRetainEvent: *hasResult = false; *hasResultType = false; break; - case SpvOpReleaseEvent: *hasResult = false; *hasResultType = false; break; - case SpvOpCreateUserEvent: *hasResult = true; *hasResultType = true; break; - case SpvOpIsValidEvent: *hasResult = true; *hasResultType = true; break; - case SpvOpSetUserEventStatus: *hasResult = false; *hasResultType = false; break; - case SpvOpCaptureEventProfilingInfo: *hasResult = false; *hasResultType = false; break; - case SpvOpGetDefaultQueue: *hasResult = true; *hasResultType = true; break; - case SpvOpBuildNDRange: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleProjImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleProjExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleProjDrefImplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseSampleProjDrefExplicitLod: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseFetch: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseGather: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseDrefGather: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSparseTexelsResident: *hasResult = true; *hasResultType = true; break; - case SpvOpNoLine: *hasResult = false; *hasResultType = false; break; - case SpvOpAtomicFlagTestAndSet: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicFlagClear: *hasResult = false; *hasResultType = false; break; - case SpvOpImageSparseRead: *hasResult = true; *hasResultType = true; break; - case SpvOpSizeOf: *hasResult = true; *hasResultType = true; break; - case SpvOpTypePipeStorage: *hasResult = true; *hasResultType = false; break; - case SpvOpConstantPipeStorage: *hasResult = true; *hasResultType = true; break; - case SpvOpCreatePipeFromPipeStorage: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelLocalSizeForSubgroupCount: *hasResult = true; *hasResultType = true; break; - case SpvOpGetKernelMaxNumSubgroups: *hasResult = true; *hasResultType = true; break; - case SpvOpTypeNamedBarrier: *hasResult = true; *hasResultType = false; break; - case SpvOpNamedBarrierInitialize: *hasResult = true; *hasResultType = true; break; - case SpvOpMemoryNamedBarrier: *hasResult = false; *hasResultType = false; break; - case SpvOpModuleProcessed: *hasResult = false; *hasResultType = false; break; - case SpvOpExecutionModeId: *hasResult = false; *hasResultType = false; break; - case SpvOpDecorateId: *hasResult = false; *hasResultType = false; break; - case SpvOpGroupNonUniformElect: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformAll: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformAny: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformAllEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBroadcast: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBroadcastFirst: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBallot: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformInverseBallot: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBallotBitExtract: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBallotBitCount: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBallotFindLSB: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBallotFindMSB: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformShuffle: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformShuffleXor: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformShuffleUp: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformShuffleDown: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformIAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformFAdd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformIMul: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformFMul: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformSMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformUMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformFMin: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformSMax: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformUMax: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformFMax: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBitwiseAnd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBitwiseOr: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformBitwiseXor: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformLogicalAnd: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformLogicalOr: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformLogicalXor: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformQuadBroadcast: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformQuadSwap: *hasResult = true; *hasResultType = true; break; - case SpvOpCopyLogical: *hasResult = true; *hasResultType = true; break; - case SpvOpPtrEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpPtrNotEqual: *hasResult = true; *hasResultType = true; break; - case SpvOpPtrDiff: *hasResult = true; *hasResultType = true; break; - case SpvOpTerminateInvocation: *hasResult = false; *hasResultType = false; break; - case SpvOpSubgroupBallotKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupFirstInvocationKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpTraceRayKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpTerminateRayKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; - case SpvOpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpRayQueryGenerateIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpRayQueryConfirmIntersectionKHR: *hasResult = false; *hasResultType = false; break; - case SpvOpRayQueryProceedKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionTypeKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupIAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFAddNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupUMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupSMinNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupFMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupUMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupSMaxNonUniformAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpFragmentMaskFetchAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; - case SpvOpReadClockKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; - case SpvOpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; - case SpvOpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; - case SpvOpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; - case SpvOpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; - case SpvOpTerminateRayNV: *hasResult = false; *hasResultType = false; break; - case SpvOpTraceNV: *hasResult = false; *hasResultType = false; break; - case SpvOpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; - case SpvOpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; - case SpvOpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; - case SpvOpCooperativeMatrixLoadNV: *hasResult = true; *hasResultType = true; break; - case SpvOpCooperativeMatrixStoreNV: *hasResult = false; *hasResultType = false; break; - case SpvOpCooperativeMatrixMulAddNV: *hasResult = true; *hasResultType = true; break; - case SpvOpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; - case SpvOpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; - case SpvOpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; - case SpvOpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; - case SpvOpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupShuffleXorINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case SpvOpSubgroupImageBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupImageBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case SpvOpSubgroupImageMediaBlockReadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupImageMediaBlockWriteINTEL: *hasResult = false; *hasResultType = false; break; - case SpvOpUCountLeadingZerosINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUCountTrailingZerosINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpAbsISubINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpAbsUSubINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpIAddSatINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUAddSatINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpIAverageINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUAverageINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpIAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUAverageRoundedINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpISubSatINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpDecorateString: *hasResult = false; *hasResultType = false; break; - case SpvOpMemberDecorateString: *hasResult = false; *hasResultType = false; break; - case SpvOpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpTypeVmeImageINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImePayloadINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcRefPayloadINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcSicPayloadINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcMcePayloadINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcMceResultINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImeResultINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImeResultSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImeResultDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImeSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcImeDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcRefResultINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpTypeAvcSicResultINTEL: *hasResult = true; *hasResultType = false; break; - case SpvOpSubgroupAvcMceGetDefaultInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetInterBaseMultiReferencePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetInterShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetInterDirectionPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultInterMotionVectorCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultHighPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultMediumPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultLowPenaltyCostTableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetMotionVectorCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultIntraLumaModePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultNonDcLumaIntraPenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetDefaultIntraChromaModeBasePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetAcOnlyHaarINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetSourceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetSingleReferenceInterlacedFieldPolarityINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceSetDualReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToImePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToImeResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToRefPayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToRefResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToSicPayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceConvertToSicResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetBestInterDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterMajorShapeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterMinorShapeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterDirectionsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcMceGetInterReferenceInterlacedFieldPolaritiesINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeRefWindowSizeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeAdjustRefOffsetINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetMaxMotionVectorCountINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetUnidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetEarlySearchTerminationThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeSetWeightedSadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithSingleReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeEvaluateWithDualReferenceStreaminoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetSingleReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetDualReferenceStreaminINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeStripSingleReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeStripDualReferenceStreamoutINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutSingleReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeMotionVectorsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeDistortionsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetStreamoutDualReferenceMajorShapeReferenceIdsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetBorderReachedINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetTruncatedSearchIndicationINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetUnidirectionalEarlySearchTerminationINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetWeightingPatternMinimumMotionVectorINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcImeGetWeightingPatternMinimumDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcFmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcBmeInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefSetBidirectionalMixDisableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcRefConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicInitializeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicConfigureSkcINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicConfigureIpeLumaINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicConfigureIpeLumaChromaINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetMotionVectorMaskINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicConvertToMcePayloadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetIntraLumaShapePenaltyINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetIntraLumaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetIntraChromaModeCostFunctionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetBilinearFilterEnableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetSkcForwardTransformEnableINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicSetBlockBasedRawSkipSadINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicEvaluateIpeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicEvaluateWithSingleReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicEvaluateWithDualReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicEvaluateWithMultiReferenceInterlacedINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicConvertToMceResultINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetIpeLumaShapeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetBestIpeLumaDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetBestIpeChromaDistortionINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetPackedIpeLumaModesINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetIpeChromaModeINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; - case SpvOpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetRayTMinKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetRayFlagsKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionTKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionInstanceCustomIndexKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionInstanceIdKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionGeometryIndexKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionPrimitiveIndexKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionBarycentricsKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionFrontFaceKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionCandidateAABBOpaqueKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionObjectRayDirectionKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionObjectRayOriginKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetWorldRayDirectionKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetWorldRayOriginKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; - case SpvOpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; - } -} -#endif /* SPV_ENABLE_UTILITY_CODE */ - -#endif - diff --git a/src/libraries/spirv_cross/spirv.hpp b/src/libraries/spirv_cross/spirv.hpp index 43dd2aaee..e25264af2 100644 --- a/src/libraries/spirv_cross/spirv.hpp +++ b/src/libraries/spirv_cross/spirv.hpp @@ -26,7 +26,7 @@ // the Binary Section of the SPIR-V specification. // Enumeration tokens for SPIR-V, in various styles: -// C, C++, C++11, JSON, Lua, Python, C#, D +// C, C++, C++11, JSON, Lua, Python, C#, D, Beef // // - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL // - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL @@ -36,6 +36,8 @@ // - C# will use enum classes in the Specification class located in the "Spv" namespace, // e.g.: Spv.Specification.SourceLanguage.GLSL // - D will have tokens under the "spv" module, e.g: spv.SourceLanguage.GLSL +// - Beef will use enum classes in the Specification class located in the "Spv" namespace, +// e.g.: Spv.Specification.SourceLanguage.GLSL // // Some tokens act like mask values, which can be OR'd together, // while others are mutually exclusive. The mask-like ones have @@ -49,12 +51,12 @@ namespace spv { typedef unsigned int Id; -#define SPV_VERSION 0x10500 -#define SPV_REVISION 4 +#define SPV_VERSION 0x10600 +#define SPV_REVISION 1 static const unsigned int MagicNumber = 0x07230203; -static const unsigned int Version = 0x00010500; -static const unsigned int Revision = 4; +static const unsigned int Version = 0x00010600; +static const unsigned int Revision = 1; static const unsigned int OpCodeMask = 0xffff; static const unsigned int WordCountShift = 16; @@ -65,6 +67,8 @@ enum SourceLanguage { SourceLanguageOpenCL_C = 3, SourceLanguageOpenCL_CPP = 4, SourceLanguageHLSL = 5, + SourceLanguageCPP_for_OpenCL = 6, + SourceLanguageSYCL = 7, SourceLanguageMax = 0x7fffffff, }; @@ -90,6 +94,8 @@ enum ExecutionModel { ExecutionModelMissNV = 5317, ExecutionModelCallableKHR = 5318, ExecutionModelCallableNV = 5318, + ExecutionModelTaskEXT = 5364, + ExecutionModelMeshEXT = 5365, ExecutionModelMax = 0x7fffffff, }; @@ -150,17 +156,28 @@ enum ExecutionMode { ExecutionModeSubgroupsPerWorkgroupId = 37, ExecutionModeLocalSizeId = 38, ExecutionModeLocalSizeHintId = 39, + ExecutionModeSubgroupUniformControlFlowKHR = 4421, ExecutionModePostDepthCoverage = 4446, ExecutionModeDenormPreserve = 4459, ExecutionModeDenormFlushToZero = 4460, ExecutionModeSignedZeroInfNanPreserve = 4461, ExecutionModeRoundingModeRTE = 4462, ExecutionModeRoundingModeRTZ = 4463, + ExecutionModeEarlyAndLateFragmentTestsAMD = 5017, ExecutionModeStencilRefReplacingEXT = 5027, + ExecutionModeStencilRefUnchangedFrontAMD = 5079, + ExecutionModeStencilRefGreaterFrontAMD = 5080, + ExecutionModeStencilRefLessFrontAMD = 5081, + ExecutionModeStencilRefUnchangedBackAMD = 5082, + ExecutionModeStencilRefGreaterBackAMD = 5083, + ExecutionModeStencilRefLessBackAMD = 5084, + ExecutionModeOutputLinesEXT = 5269, ExecutionModeOutputLinesNV = 5269, + ExecutionModeOutputPrimitivesEXT = 5270, ExecutionModeOutputPrimitivesNV = 5270, ExecutionModeDerivativeGroupQuadsNV = 5289, ExecutionModeDerivativeGroupLinearNV = 5290, + ExecutionModeOutputTrianglesEXT = 5298, ExecutionModeOutputTrianglesNV = 5298, ExecutionModePixelInterlockOrderedEXT = 5366, ExecutionModePixelInterlockUnorderedEXT = 5367, @@ -168,10 +185,17 @@ enum ExecutionMode { ExecutionModeSampleInterlockUnorderedEXT = 5369, ExecutionModeShadingRateInterlockOrderedEXT = 5370, ExecutionModeShadingRateInterlockUnorderedEXT = 5371, + ExecutionModeSharedLocalMemorySizeINTEL = 5618, + ExecutionModeRoundingModeRTPINTEL = 5620, + ExecutionModeRoundingModeRTNINTEL = 5621, + ExecutionModeFloatingPointModeALTINTEL = 5622, + ExecutionModeFloatingPointModeIEEEINTEL = 5623, ExecutionModeMaxWorkgroupSizeINTEL = 5893, ExecutionModeMaxWorkDimINTEL = 5894, ExecutionModeNoGlobalOffsetINTEL = 5895, ExecutionModeNumSIMDWorkitemsINTEL = 5896, + ExecutionModeSchedulerTargetFmaxMhzINTEL = 5903, + ExecutionModeNamedBarrierCountINTEL = 6417, ExecutionModeMax = 0x7fffffff, }; @@ -203,7 +227,10 @@ enum StorageClass { StorageClassShaderRecordBufferNV = 5343, StorageClassPhysicalStorageBuffer = 5349, StorageClassPhysicalStorageBufferEXT = 5349, + StorageClassTaskPayloadWorkgroupEXT = 5402, StorageClassCodeSectionINTEL = 5605, + StorageClassDeviceOnlyINTEL = 5936, + StorageClassHostOnlyINTEL = 5937, StorageClassMax = 0x7fffffff, }; @@ -343,6 +370,8 @@ enum ImageOperandsShift { ImageOperandsVolatileTexelKHRShift = 11, ImageOperandsSignExtendShift = 12, ImageOperandsZeroExtendShift = 13, + ImageOperandsNontemporalShift = 14, + ImageOperandsOffsetsShift = 16, ImageOperandsMax = 0x7fffffff, }; @@ -366,6 +395,8 @@ enum ImageOperandsMask { ImageOperandsVolatileTexelKHRMask = 0x00000800, ImageOperandsSignExtendMask = 0x00001000, ImageOperandsZeroExtendMask = 0x00002000, + ImageOperandsNontemporalMask = 0x00004000, + ImageOperandsOffsetsMask = 0x00010000, }; enum FPFastMathModeShift { @@ -374,6 +405,8 @@ enum FPFastMathModeShift { FPFastMathModeNSZShift = 2, FPFastMathModeAllowRecipShift = 3, FPFastMathModeFastShift = 4, + FPFastMathModeAllowContractFastINTELShift = 16, + FPFastMathModeAllowReassocINTELShift = 17, FPFastMathModeMax = 0x7fffffff, }; @@ -384,6 +417,8 @@ enum FPFastMathModeMask { FPFastMathModeNSZMask = 0x00000004, FPFastMathModeAllowRecipMask = 0x00000008, FPFastMathModeFastMask = 0x00000010, + FPFastMathModeAllowContractFastINTELMask = 0x00010000, + FPFastMathModeAllowReassocINTELMask = 0x00020000, }; enum FPRoundingMode { @@ -397,6 +432,7 @@ enum FPRoundingMode { enum LinkageType { LinkageTypeExport = 0, LinkageTypeImport = 1, + LinkageTypeLinkOnceODR = 2, LinkageTypeMax = 0x7fffffff, }; @@ -474,9 +510,11 @@ enum Decoration { DecorationPassthroughNV = 5250, DecorationViewportRelativeNV = 5252, DecorationSecondaryViewportRelativeNV = 5256, + DecorationPerPrimitiveEXT = 5271, DecorationPerPrimitiveNV = 5271, DecorationPerViewNV = 5272, DecorationPerTaskNV = 5273, + DecorationPerVertexKHR = 5285, DecorationPerVertexNV = 5285, DecorationNonUniform = 5300, DecorationNonUniformEXT = 5300, @@ -484,12 +522,26 @@ enum Decoration { DecorationRestrictPointerEXT = 5355, DecorationAliasedPointer = 5356, DecorationAliasedPointerEXT = 5356, + DecorationBindlessSamplerNV = 5398, + DecorationBindlessImageNV = 5399, + DecorationBoundSamplerNV = 5400, + DecorationBoundImageNV = 5401, + DecorationSIMTCallINTEL = 5599, DecorationReferencedIndirectlyINTEL = 5602, + DecorationClobberINTEL = 5607, + DecorationSideEffectsINTEL = 5608, + DecorationVectorComputeVariableINTEL = 5624, + DecorationFuncParamIOKindINTEL = 5625, + DecorationVectorComputeFunctionINTEL = 5626, + DecorationStackCallINTEL = 5627, + DecorationGlobalVariableOffsetINTEL = 5628, DecorationCounterBuffer = 5634, DecorationHlslCounterBufferGOOGLE = 5634, DecorationHlslSemanticGOOGLE = 5635, DecorationUserSemantic = 5635, DecorationUserTypeGOOGLE = 5636, + DecorationFunctionRoundingModeINTEL = 5822, + DecorationFunctionDenormModeINTEL = 5823, DecorationRegisterINTEL = 5825, DecorationMemoryINTEL = 5826, DecorationNumbanksINTEL = 5827, @@ -502,6 +554,20 @@ enum Decoration { DecorationMergeINTEL = 5834, DecorationBankBitsINTEL = 5835, DecorationForcePow2DepthINTEL = 5836, + DecorationBurstCoalesceINTEL = 5899, + DecorationCacheSizeINTEL = 5900, + DecorationDontStaticallyCoalesceINTEL = 5901, + DecorationPrefetchINTEL = 5902, + DecorationStallEnableINTEL = 5905, + DecorationFuseLoopsInFunctionINTEL = 5907, + DecorationAliasScopeINTEL = 5914, + DecorationNoAliasINTEL = 5915, + DecorationBufferLocationINTEL = 5921, + DecorationIOPipeStorageINTEL = 5944, + DecorationFunctionFloatingPointModeINTEL = 6080, + DecorationSingleElementVectorINTEL = 6085, + DecorationVectorComputeCallableFunctionINTEL = 6087, + DecorationMediaBlockIOINTEL = 6140, DecorationMax = 0x7fffffff, }; @@ -586,12 +652,18 @@ enum BuiltIn { BuiltInLayerPerViewNV = 5279, BuiltInMeshViewCountNV = 5280, BuiltInMeshViewIndicesNV = 5281, + BuiltInBaryCoordKHR = 5286, BuiltInBaryCoordNV = 5286, + BuiltInBaryCoordNoPerspKHR = 5287, BuiltInBaryCoordNoPerspNV = 5287, BuiltInFragSizeEXT = 5292, BuiltInFragmentSizeNV = 5292, BuiltInFragInvocationCountEXT = 5293, BuiltInInvocationsPerPixelNV = 5293, + BuiltInPrimitivePointIndicesEXT = 5294, + BuiltInPrimitiveLineIndicesEXT = 5295, + BuiltInPrimitiveTriangleIndicesEXT = 5296, + BuiltInCullPrimitiveEXT = 5299, BuiltInLaunchIdKHR = 5319, BuiltInLaunchIdNV = 5319, BuiltInLaunchSizeKHR = 5320, @@ -617,6 +689,7 @@ enum BuiltIn { BuiltInHitTNV = 5332, BuiltInHitKindKHR = 5333, BuiltInHitKindNV = 5333, + BuiltInCurrentRayTimeNV = 5334, BuiltInIncomingRayFlagsKHR = 5351, BuiltInIncomingRayFlagsNV = 5351, BuiltInRayGeometryIndexKHR = 5352, @@ -624,6 +697,7 @@ enum BuiltIn { BuiltInSMCountNV = 5375, BuiltInWarpIDNV = 5376, BuiltInSMIDNV = 5377, + BuiltInCullMaskKHR = 6021, BuiltInMax = 0x7fffffff, }; @@ -656,6 +730,7 @@ enum LoopControlShift { LoopControlLoopCoalesceINTELShift = 20, LoopControlMaxInterleavingINTELShift = 21, LoopControlSpeculatedIterationsINTELShift = 22, + LoopControlNoFusionINTELShift = 23, LoopControlMax = 0x7fffffff, }; @@ -677,6 +752,7 @@ enum LoopControlMask { LoopControlLoopCoalesceINTELMask = 0x00100000, LoopControlMaxInterleavingINTELMask = 0x00200000, LoopControlSpeculatedIterationsINTELMask = 0x00400000, + LoopControlNoFusionINTELMask = 0x00800000, }; enum FunctionControlShift { @@ -684,6 +760,7 @@ enum FunctionControlShift { FunctionControlDontInlineShift = 1, FunctionControlPureShift = 2, FunctionControlConstShift = 3, + FunctionControlOptNoneINTELShift = 16, FunctionControlMax = 0x7fffffff, }; @@ -693,6 +770,7 @@ enum FunctionControlMask { FunctionControlDontInlineMask = 0x00000002, FunctionControlPureMask = 0x00000004, FunctionControlConstMask = 0x00000008, + FunctionControlOptNoneINTELMask = 0x00010000, }; enum MemorySemanticsShift { @@ -747,6 +825,8 @@ enum MemoryAccessShift { MemoryAccessMakePointerVisibleKHRShift = 4, MemoryAccessNonPrivatePointerShift = 5, MemoryAccessNonPrivatePointerKHRShift = 5, + MemoryAccessAliasScopeINTELMaskShift = 16, + MemoryAccessNoAliasINTELMaskShift = 17, MemoryAccessMax = 0x7fffffff, }; @@ -761,6 +841,8 @@ enum MemoryAccessMask { MemoryAccessMakePointerVisibleKHRMask = 0x00000010, MemoryAccessNonPrivatePointerMask = 0x00000020, MemoryAccessNonPrivatePointerKHRMask = 0x00000020, + MemoryAccessAliasScopeINTELMaskMask = 0x00010000, + MemoryAccessNoAliasINTELMaskMask = 0x00020000, }; enum Scope { @@ -873,9 +955,13 @@ enum Capability { CapabilityGroupNonUniformQuad = 68, CapabilityShaderLayer = 69, CapabilityShaderViewportIndex = 70, + CapabilityUniformDecoration = 71, CapabilityFragmentShadingRateKHR = 4422, CapabilitySubgroupBallotKHR = 4423, CapabilityDrawParameters = 4427, + CapabilityWorkgroupMemoryExplicitLayoutKHR = 4428, + CapabilityWorkgroupMemoryExplicitLayout8BitAccessKHR = 4429, + CapabilityWorkgroupMemoryExplicitLayout16BitAccessKHR = 4430, CapabilitySubgroupVoteKHR = 4431, CapabilityStorageBuffer16BitAccess = 4433, CapabilityStorageUniformBufferBlock16 = 4433, @@ -918,6 +1004,8 @@ enum Capability { CapabilityFragmentFullyCoveredEXT = 5265, CapabilityMeshShadingNV = 5266, CapabilityImageFootprintNV = 5282, + CapabilityMeshShadingEXT = 5283, + CapabilityFragmentBarycentricKHR = 5284, CapabilityFragmentBarycentricNV = 5284, CapabilityComputeDerivativeGroupQuadsNV = 5288, CapabilityFragmentDensityEXT = 5291, @@ -948,6 +1036,7 @@ enum Capability { CapabilityStorageTexelBufferArrayNonUniformIndexing = 5312, CapabilityStorageTexelBufferArrayNonUniformIndexingEXT = 5312, CapabilityRayTracingNV = 5340, + CapabilityRayTracingMotionBlurNV = 5341, CapabilityVulkanMemoryModel = 5345, CapabilityVulkanMemoryModelKHR = 5345, CapabilityVulkanMemoryModelDeviceScope = 5346, @@ -961,26 +1050,67 @@ enum Capability { CapabilityFragmentShaderShadingRateInterlockEXT = 5372, CapabilityShaderSMBuiltinsNV = 5373, CapabilityFragmentShaderPixelInterlockEXT = 5378, + CapabilityDemoteToHelperInvocation = 5379, CapabilityDemoteToHelperInvocationEXT = 5379, + CapabilityBindlessTextureNV = 5390, CapabilitySubgroupShuffleINTEL = 5568, CapabilitySubgroupBufferBlockIOINTEL = 5569, CapabilitySubgroupImageBlockIOINTEL = 5570, CapabilitySubgroupImageMediaBlockIOINTEL = 5579, + CapabilityRoundToInfinityINTEL = 5582, + CapabilityFloatingPointModeINTEL = 5583, CapabilityIntegerFunctions2INTEL = 5584, CapabilityFunctionPointersINTEL = 5603, CapabilityIndirectReferencesINTEL = 5604, + CapabilityAsmINTEL = 5606, + CapabilityAtomicFloat32MinMaxEXT = 5612, + CapabilityAtomicFloat64MinMaxEXT = 5613, + CapabilityAtomicFloat16MinMaxEXT = 5616, + CapabilityVectorComputeINTEL = 5617, + CapabilityVectorAnyINTEL = 5619, + CapabilityExpectAssumeKHR = 5629, CapabilitySubgroupAvcMotionEstimationINTEL = 5696, CapabilitySubgroupAvcMotionEstimationIntraINTEL = 5697, CapabilitySubgroupAvcMotionEstimationChromaINTEL = 5698, + CapabilityVariableLengthArrayINTEL = 5817, + CapabilityFunctionFloatControlINTEL = 5821, CapabilityFPGAMemoryAttributesINTEL = 5824, + CapabilityFPFastMathModeINTEL = 5837, + CapabilityArbitraryPrecisionIntegersINTEL = 5844, + CapabilityArbitraryPrecisionFloatingPointINTEL = 5845, CapabilityUnstructuredLoopControlsINTEL = 5886, CapabilityFPGALoopControlsINTEL = 5888, CapabilityKernelAttributesINTEL = 5892, CapabilityFPGAKernelAttributesINTEL = 5897, + CapabilityFPGAMemoryAccessesINTEL = 5898, + CapabilityFPGAClusterAttributesINTEL = 5904, + CapabilityLoopFuseINTEL = 5906, + CapabilityMemoryAccessAliasingINTEL = 5910, + CapabilityFPGABufferLocationINTEL = 5920, + CapabilityArbitraryPrecisionFixedPointINTEL = 5922, + CapabilityUSMStorageClassesINTEL = 5935, + CapabilityIOPipesINTEL = 5943, CapabilityBlockingPipesINTEL = 5945, CapabilityFPGARegINTEL = 5948, + CapabilityDotProductInputAll = 6016, + CapabilityDotProductInputAllKHR = 6016, + CapabilityDotProductInput4x8Bit = 6017, + CapabilityDotProductInput4x8BitKHR = 6017, + CapabilityDotProductInput4x8BitPacked = 6018, + CapabilityDotProductInput4x8BitPackedKHR = 6018, + CapabilityDotProduct = 6019, + CapabilityDotProductKHR = 6019, + CapabilityRayCullMaskKHR = 6020, + CapabilityBitInstructions = 6025, + CapabilityGroupNonUniformRotateKHR = 6026, CapabilityAtomicFloat32AddEXT = 6033, CapabilityAtomicFloat64AddEXT = 6034, + CapabilityLongConstantCompositeINTEL = 6089, + CapabilityOptNoneINTEL = 6094, + CapabilityAtomicFloat16AddEXT = 6095, + CapabilityDebugInfoModuleINTEL = 6114, + CapabilitySplitBarrierINTEL = 6141, + CapabilityGroupUniformArithmeticKHR = 6400, CapabilityMax = 0x7fffffff, }; @@ -1047,6 +1177,44 @@ enum FragmentShadingRateMask { FragmentShadingRateHorizontal4PixelsMask = 0x00000008, }; +enum FPDenormMode { + FPDenormModePreserve = 0, + FPDenormModeFlushToZero = 1, + FPDenormModeMax = 0x7fffffff, +}; + +enum FPOperationMode { + FPOperationModeIEEE = 0, + FPOperationModeALT = 1, + FPOperationModeMax = 0x7fffffff, +}; + +enum QuantizationModes { + QuantizationModesTRN = 0, + QuantizationModesTRN_ZERO = 1, + QuantizationModesRND = 2, + QuantizationModesRND_ZERO = 3, + QuantizationModesRND_INF = 4, + QuantizationModesRND_MIN_INF = 5, + QuantizationModesRND_CONV = 6, + QuantizationModesRND_CONV_ODD = 7, + QuantizationModesMax = 0x7fffffff, +}; + +enum OverflowModes { + OverflowModesWRAP = 0, + OverflowModesSAT = 1, + OverflowModesSAT_ZERO = 2, + OverflowModesSAT_SYM = 3, + OverflowModesMax = 0x7fffffff, +}; + +enum PackedVectorFormat { + PackedVectorFormatPackedVectorFormat4x8Bit = 0, + PackedVectorFormatPackedVectorFormat4x8BitKHR = 0, + PackedVectorFormatMax = 0x7fffffff, +}; + enum Op { OpNop = 0, OpUndef = 1, @@ -1398,12 +1566,25 @@ enum Op { OpSubgroupAllKHR = 4428, OpSubgroupAnyKHR = 4429, OpSubgroupAllEqualKHR = 4430, + OpGroupNonUniformRotateKHR = 4431, OpSubgroupReadInvocationKHR = 4432, OpTraceRayKHR = 4445, OpExecuteCallableKHR = 4446, OpConvertUToAccelerationStructureKHR = 4447, OpIgnoreIntersectionKHR = 4448, OpTerminateRayKHR = 4449, + OpSDot = 4450, + OpSDotKHR = 4450, + OpUDot = 4451, + OpUDotKHR = 4451, + OpSUDot = 4452, + OpSUDotKHR = 4452, + OpSDotAccSat = 4453, + OpSDotAccSatKHR = 4453, + OpUDotAccSat = 4454, + OpUDotAccSatKHR = 4454, + OpSUDotAccSat = 4455, + OpSUDotAccSatKHR = 4455, OpTypeRayQueryKHR = 4472, OpRayQueryInitializeKHR = 4473, OpRayQueryTerminateKHR = 4474, @@ -1423,6 +1604,8 @@ enum Op { OpFragmentFetchAMD = 5012, OpReadClockKHR = 5056, OpImageSampleFootprintNV = 5283, + OpEmitMeshTasksEXT = 5294, + OpSetMeshOutputsEXT = 5295, OpGroupNonUniformPartitionNV = 5296, OpWritePackedPrimitiveIndices4x8NV = 5299, OpReportIntersectionKHR = 5334, @@ -1430,6 +1613,8 @@ enum Op { OpIgnoreIntersectionNV = 5335, OpTerminateRayNV = 5336, OpTraceNV = 5337, + OpTraceMotionNV = 5338, + OpTraceRayMotionNV = 5339, OpTypeAccelerationStructureKHR = 5341, OpTypeAccelerationStructureNV = 5341, OpExecuteCallableNV = 5344, @@ -1440,8 +1625,16 @@ enum Op { OpCooperativeMatrixLengthNV = 5362, OpBeginInvocationInterlockEXT = 5364, OpEndInvocationInterlockEXT = 5365, + OpDemoteToHelperInvocation = 5380, OpDemoteToHelperInvocationEXT = 5380, OpIsHelperInvocationEXT = 5381, + OpConvertUToImageNV = 5391, + OpConvertUToSamplerNV = 5392, + OpConvertImageToUNV = 5393, + OpConvertSamplerToUNV = 5394, + OpConvertUToSampledImageNV = 5395, + OpConvertSampledImageToUNV = 5396, + OpSamplerImageAddressingModeNV = 5397, OpSubgroupShuffleINTEL = 5571, OpSubgroupShuffleDownINTEL = 5572, OpSubgroupShuffleUpINTEL = 5573, @@ -1466,8 +1659,15 @@ enum Op { OpUSubSatINTEL = 5596, OpIMul32x16INTEL = 5597, OpUMul32x16INTEL = 5598, - OpFunctionPointerINTEL = 5600, + OpConstantFunctionPointerINTEL = 5600, OpFunctionPointerCallINTEL = 5601, + OpAsmTargetINTEL = 5609, + OpAsmINTEL = 5610, + OpAsmCallINTEL = 5611, + OpAtomicFMinEXT = 5614, + OpAtomicFMaxEXT = 5615, + OpAssumeTrueKHR = 5630, + OpExpectKHR = 5631, OpDecorateString = 5632, OpDecorateStringGOOGLE = 5632, OpMemberDecorateString = 5633, @@ -1590,7 +1790,67 @@ enum Op { OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL = 5814, OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL = 5815, OpSubgroupAvcSicGetInterRawSadsINTEL = 5816, + OpVariableLengthArrayINTEL = 5818, + OpSaveMemoryINTEL = 5819, + OpRestoreMemoryINTEL = 5820, + OpArbitraryFloatSinCosPiINTEL = 5840, + OpArbitraryFloatCastINTEL = 5841, + OpArbitraryFloatCastFromIntINTEL = 5842, + OpArbitraryFloatCastToIntINTEL = 5843, + OpArbitraryFloatAddINTEL = 5846, + OpArbitraryFloatSubINTEL = 5847, + OpArbitraryFloatMulINTEL = 5848, + OpArbitraryFloatDivINTEL = 5849, + OpArbitraryFloatGTINTEL = 5850, + OpArbitraryFloatGEINTEL = 5851, + OpArbitraryFloatLTINTEL = 5852, + OpArbitraryFloatLEINTEL = 5853, + OpArbitraryFloatEQINTEL = 5854, + OpArbitraryFloatRecipINTEL = 5855, + OpArbitraryFloatRSqrtINTEL = 5856, + OpArbitraryFloatCbrtINTEL = 5857, + OpArbitraryFloatHypotINTEL = 5858, + OpArbitraryFloatSqrtINTEL = 5859, + OpArbitraryFloatLogINTEL = 5860, + OpArbitraryFloatLog2INTEL = 5861, + OpArbitraryFloatLog10INTEL = 5862, + OpArbitraryFloatLog1pINTEL = 5863, + OpArbitraryFloatExpINTEL = 5864, + OpArbitraryFloatExp2INTEL = 5865, + OpArbitraryFloatExp10INTEL = 5866, + OpArbitraryFloatExpm1INTEL = 5867, + OpArbitraryFloatSinINTEL = 5868, + OpArbitraryFloatCosINTEL = 5869, + OpArbitraryFloatSinCosINTEL = 5870, + OpArbitraryFloatSinPiINTEL = 5871, + OpArbitraryFloatCosPiINTEL = 5872, + OpArbitraryFloatASinINTEL = 5873, + OpArbitraryFloatASinPiINTEL = 5874, + OpArbitraryFloatACosINTEL = 5875, + OpArbitraryFloatACosPiINTEL = 5876, + OpArbitraryFloatATanINTEL = 5877, + OpArbitraryFloatATanPiINTEL = 5878, + OpArbitraryFloatATan2INTEL = 5879, + OpArbitraryFloatPowINTEL = 5880, + OpArbitraryFloatPowRINTEL = 5881, + OpArbitraryFloatPowNINTEL = 5882, OpLoopControlINTEL = 5887, + OpAliasDomainDeclINTEL = 5911, + OpAliasScopeDeclINTEL = 5912, + OpAliasScopeListDeclINTEL = 5913, + OpFixedSqrtINTEL = 5923, + OpFixedRecipINTEL = 5924, + OpFixedRsqrtINTEL = 5925, + OpFixedSinINTEL = 5926, + OpFixedCosINTEL = 5927, + OpFixedSinCosINTEL = 5928, + OpFixedSinPiINTEL = 5929, + OpFixedCosPiINTEL = 5930, + OpFixedSinCosPiINTEL = 5931, + OpFixedLogINTEL = 5932, + OpFixedExpINTEL = 5933, + OpPtrCastToCrossWorkgroupINTEL = 5934, + OpCrossWorkgroupCastToPtrINTEL = 5938, OpReadPipeBlockingINTEL = 5946, OpWritePipeBlockingINTEL = 5947, OpFPGARegINTEL = 5949, @@ -1612,10 +1872,27 @@ enum Op { OpRayQueryGetIntersectionObjectToWorldKHR = 6031, OpRayQueryGetIntersectionWorldToObjectKHR = 6032, OpAtomicFAddEXT = 6035, + OpTypeBufferSurfaceINTEL = 6086, + OpTypeStructContinuedINTEL = 6090, + OpConstantCompositeContinuedINTEL = 6091, + OpSpecConstantCompositeContinuedINTEL = 6092, + OpControlBarrierArriveINTEL = 6142, + OpControlBarrierWaitINTEL = 6143, + OpGroupIMulKHR = 6401, + OpGroupFMulKHR = 6402, + OpGroupBitwiseAndKHR = 6403, + OpGroupBitwiseOrKHR = 6404, + OpGroupBitwiseXorKHR = 6405, + OpGroupLogicalAndKHR = 6406, + OpGroupLogicalOrKHR = 6407, + OpGroupLogicalXorKHR = 6408, OpMax = 0x7fffffff, }; #ifdef SPV_ENABLE_UTILITY_CODE +#ifndef __cplusplus +#include +#endif inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { *hasResult = *hasResultType = false; switch (opcode) { @@ -1970,12 +2247,19 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpSubgroupAllKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupAnyKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupAllEqualKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupNonUniformRotateKHR: *hasResult = true; *hasResultType = true; break; case OpSubgroupReadInvocationKHR: *hasResult = true; *hasResultType = true; break; case OpTraceRayKHR: *hasResult = false; *hasResultType = false; break; case OpExecuteCallableKHR: *hasResult = false; *hasResultType = false; break; case OpConvertUToAccelerationStructureKHR: *hasResult = true; *hasResultType = true; break; case OpIgnoreIntersectionKHR: *hasResult = false; *hasResultType = false; break; case OpTerminateRayKHR: *hasResult = false; *hasResultType = false; break; + case OpSDot: *hasResult = true; *hasResultType = true; break; + case OpUDot: *hasResult = true; *hasResultType = true; break; + case OpSUDot: *hasResult = true; *hasResultType = true; break; + case OpSDotAccSat: *hasResult = true; *hasResultType = true; break; + case OpUDotAccSat: *hasResult = true; *hasResultType = true; break; + case OpSUDotAccSat: *hasResult = true; *hasResultType = true; break; case OpTypeRayQueryKHR: *hasResult = true; *hasResultType = false; break; case OpRayQueryInitializeKHR: *hasResult = false; *hasResultType = false; break; case OpRayQueryTerminateKHR: *hasResult = false; *hasResultType = false; break; @@ -1995,12 +2279,16 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpFragmentFetchAMD: *hasResult = true; *hasResultType = true; break; case OpReadClockKHR: *hasResult = true; *hasResultType = true; break; case OpImageSampleFootprintNV: *hasResult = true; *hasResultType = true; break; + case OpEmitMeshTasksEXT: *hasResult = false; *hasResultType = false; break; + case OpSetMeshOutputsEXT: *hasResult = false; *hasResultType = false; break; case OpGroupNonUniformPartitionNV: *hasResult = true; *hasResultType = true; break; case OpWritePackedPrimitiveIndices4x8NV: *hasResult = false; *hasResultType = false; break; case OpReportIntersectionNV: *hasResult = true; *hasResultType = true; break; case OpIgnoreIntersectionNV: *hasResult = false; *hasResultType = false; break; case OpTerminateRayNV: *hasResult = false; *hasResultType = false; break; case OpTraceNV: *hasResult = false; *hasResultType = false; break; + case OpTraceMotionNV: *hasResult = false; *hasResultType = false; break; + case OpTraceRayMotionNV: *hasResult = false; *hasResultType = false; break; case OpTypeAccelerationStructureNV: *hasResult = true; *hasResultType = false; break; case OpExecuteCallableNV: *hasResult = false; *hasResultType = false; break; case OpTypeCooperativeMatrixNV: *hasResult = true; *hasResultType = false; break; @@ -2010,8 +2298,15 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpCooperativeMatrixLengthNV: *hasResult = true; *hasResultType = true; break; case OpBeginInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; case OpEndInvocationInterlockEXT: *hasResult = false; *hasResultType = false; break; - case OpDemoteToHelperInvocationEXT: *hasResult = false; *hasResultType = false; break; + case OpDemoteToHelperInvocation: *hasResult = false; *hasResultType = false; break; case OpIsHelperInvocationEXT: *hasResult = true; *hasResultType = true; break; + case OpConvertUToImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSamplerNV: *hasResult = true; *hasResultType = true; break; + case OpConvertImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSamplerToUNV: *hasResult = true; *hasResultType = true; break; + case OpConvertUToSampledImageNV: *hasResult = true; *hasResultType = true; break; + case OpConvertSampledImageToUNV: *hasResult = true; *hasResultType = true; break; + case OpSamplerImageAddressingModeNV: *hasResult = false; *hasResultType = false; break; case OpSubgroupShuffleINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupShuffleDownINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupShuffleUpINTEL: *hasResult = true; *hasResultType = true; break; @@ -2036,8 +2331,15 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpUSubSatINTEL: *hasResult = true; *hasResultType = true; break; case OpIMul32x16INTEL: *hasResult = true; *hasResultType = true; break; case OpUMul32x16INTEL: *hasResult = true; *hasResultType = true; break; - case OpFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; + case OpConstantFunctionPointerINTEL: *hasResult = true; *hasResultType = true; break; case OpFunctionPointerCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmTargetINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmINTEL: *hasResult = true; *hasResultType = true; break; + case OpAsmCallINTEL: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMinEXT: *hasResult = true; *hasResultType = true; break; + case OpAtomicFMaxEXT: *hasResult = true; *hasResultType = true; break; + case OpAssumeTrueKHR: *hasResult = false; *hasResultType = false; break; + case OpExpectKHR: *hasResult = true; *hasResultType = true; break; case OpDecorateString: *hasResult = false; *hasResultType = false; break; case OpMemberDecorateString: *hasResult = false; *hasResultType = false; break; case OpVmeImageINTEL: *hasResult = true; *hasResultType = true; break; @@ -2158,7 +2460,67 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpSubgroupAvcSicGetPackedSkcLumaCountThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetPackedSkcLumaSumThresholdINTEL: *hasResult = true; *hasResultType = true; break; case OpSubgroupAvcSicGetInterRawSadsINTEL: *hasResult = true; *hasResultType = true; break; + case OpVariableLengthArrayINTEL: *hasResult = true; *hasResultType = true; break; + case OpSaveMemoryINTEL: *hasResult = true; *hasResultType = true; break; + case OpRestoreMemoryINTEL: *hasResult = false; *hasResultType = false; break; + case OpArbitraryFloatSinCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastFromIntINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCastToIntINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatAddINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSubINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatMulINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatDivINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatGTINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatGEINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLTINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLEINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatEQINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatRecipINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatRSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCbrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatHypotINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLogINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog10INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatLog1pINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExpINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExp2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExp10INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatExpm1INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatSinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatASinINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatASinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatACosINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatACosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATanINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATanPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatATan2INTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowRINTEL: *hasResult = true; *hasResultType = true; break; + case OpArbitraryFloatPowNINTEL: *hasResult = true; *hasResultType = true; break; case OpLoopControlINTEL: *hasResult = false; *hasResultType = false; break; + case OpAliasDomainDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpAliasScopeDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpAliasScopeListDeclINTEL: *hasResult = true; *hasResultType = false; break; + case OpFixedSqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedRecipINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedRsqrtINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinCosINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedSinCosPiINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedLogINTEL: *hasResult = true; *hasResultType = true; break; + case OpFixedExpINTEL: *hasResult = true; *hasResultType = true; break; + case OpPtrCastToCrossWorkgroupINTEL: *hasResult = true; *hasResultType = true; break; + case OpCrossWorkgroupCastToPtrINTEL: *hasResult = true; *hasResultType = true; break; case OpReadPipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; case OpWritePipeBlockingINTEL: *hasResult = true; *hasResultType = true; break; case OpFPGARegINTEL: *hasResult = true; *hasResultType = true; break; @@ -2180,6 +2542,20 @@ inline void HasResultAndType(Op opcode, bool *hasResult, bool *hasResultType) { case OpRayQueryGetIntersectionObjectToWorldKHR: *hasResult = true; *hasResultType = true; break; case OpRayQueryGetIntersectionWorldToObjectKHR: *hasResult = true; *hasResultType = true; break; case OpAtomicFAddEXT: *hasResult = true; *hasResultType = true; break; + case OpTypeBufferSurfaceINTEL: *hasResult = true; *hasResultType = false; break; + case OpTypeStructContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpSpecConstantCompositeContinuedINTEL: *hasResult = false; *hasResultType = false; break; + case OpControlBarrierArriveINTEL: *hasResult = false; *hasResultType = false; break; + case OpControlBarrierWaitINTEL: *hasResult = false; *hasResultType = false; break; + case OpGroupIMulKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupFMulKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseAndKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseOrKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupBitwiseXorKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalAndKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalOrKHR: *hasResult = true; *hasResultType = true; break; + case OpGroupLogicalXorKHR: *hasResult = true; *hasResultType = true; break; } } #endif /* SPV_ENABLE_UTILITY_CODE */ diff --git a/src/libraries/spirv_cross/spirv_cfg.cpp b/src/libraries/spirv_cross/spirv_cfg.cpp index a938634e2..932994798 100644 --- a/src/libraries/spirv_cross/spirv_cfg.cpp +++ b/src/libraries/spirv_cross/spirv_cfg.cpp @@ -306,15 +306,36 @@ bool CFG::node_terminates_control_flow_in_sub_graph(BlockID from, BlockID to) co bool true_path_ignore = false; bool false_path_ignore = false; - if (ignore_block_id && dom.terminator == SPIRBlock::Select) + + bool merges_to_nothing = dom.merge == SPIRBlock::MergeNone || + (dom.merge == SPIRBlock::MergeSelection && dom.next_block && + compiler.get(dom.next_block).terminator == SPIRBlock::Unreachable) || + (dom.merge == SPIRBlock::MergeLoop && dom.merge_block && + compiler.get(dom.merge_block).terminator == SPIRBlock::Unreachable); + + if (dom.self == from || merges_to_nothing) { - auto &true_block = compiler.get(dom.true_block); - auto &false_block = compiler.get(dom.false_block); - auto &ignore_block = compiler.get(ignore_block_id); - true_path_ignore = compiler.execution_is_branchless(true_block, ignore_block); - false_path_ignore = compiler.execution_is_branchless(false_block, ignore_block); + // We can only ignore inner branchy paths if there is no merge, + // i.e. no code is generated afterwards. E.g. this allows us to elide continue: + // for (;;) { if (cond) { continue; } else { break; } }. + // Codegen here in SPIR-V will be something like either no merge if one path directly breaks, or + // we merge to Unreachable. + if (ignore_block_id && dom.terminator == SPIRBlock::Select) + { + auto &true_block = compiler.get(dom.true_block); + auto &false_block = compiler.get(dom.false_block); + auto &ignore_block = compiler.get(ignore_block_id); + true_path_ignore = compiler.execution_is_branchless(true_block, ignore_block); + false_path_ignore = compiler.execution_is_branchless(false_block, ignore_block); + } } + // Cases where we allow traversal. This serves as a proxy for post-dominance in a loop body. + // TODO: Might want to do full post-dominance analysis, but it's a lot of churn for something like this ... + // - We're the merge block of a selection construct. Jump to header. + // - We're the merge block of a loop. Jump to header. + // - Direct branch. Trivial. + // - Allow cases inside a branch if the header cannot merge execution before loop exit. if ((dom.merge == SPIRBlock::MergeSelection && dom.next_block == to) || (dom.merge == SPIRBlock::MergeLoop && dom.merge_block == to) || (dom.terminator == SPIRBlock::Direct && dom.next_block == to) || diff --git a/src/libraries/spirv_cross/spirv_cfg.hpp b/src/libraries/spirv_cross/spirv_cfg.hpp index 90973b567..1d85fe0a9 100644 --- a/src/libraries/spirv_cross/spirv_cfg.hpp +++ b/src/libraries/spirv_cross/spirv_cfg.hpp @@ -59,6 +59,11 @@ public: return 0; } + bool is_reachable(uint32_t block) const + { + return visit_order.count(block) != 0; + } + uint32_t get_visit_order(uint32_t block) const { auto itr = visit_order.find(block); diff --git a/src/libraries/spirv_cross/spirv_common.hpp b/src/libraries/spirv_cross/spirv_common.hpp index bb2260e4d..7fce7ae7e 100644 --- a/src/libraries/spirv_cross/spirv_common.hpp +++ b/src/libraries/spirv_cross/spirv_common.hpp @@ -24,7 +24,11 @@ #ifndef SPIRV_CROSS_COMMON_HPP #define SPIRV_CROSS_COMMON_HPP +#ifndef SPV_ENABLE_UTILITY_CODE +#define SPV_ENABLE_UTILITY_CODE +#endif #include "spirv.hpp" + #include "spirv_cross_containers.hpp" #include "spirv_cross_error_handling.hpp" #include @@ -291,6 +295,20 @@ inline std::string convert_to_string(double t, char locale_radix_point) return buf; } +#if defined(__clang__) || defined(__GNUC__) +#pragma GCC diagnostic pop +#elif defined(_MSC_VER) +#pragma warning(pop) +#endif + +class FloatFormatter +{ +public: + virtual ~FloatFormatter() = default; + virtual std::string format_float(float value) = 0; + virtual std::string format_double(double value) = 0; +}; + template struct ValueSaver { @@ -314,12 +332,6 @@ struct ValueSaver T saved; }; -#if defined(__clang__) || defined(__GNUC__) -#pragma GCC diagnostic pop -#elif defined(_MSC_VER) -#pragma warning(pop) -#endif - struct Instruction { uint16_t op = 0; @@ -536,6 +548,9 @@ struct SPIRType : IVariant type = TypeType }; + spv::Op op = spv::Op::OpNop; + explicit SPIRType(spv::Op op_) : op(op_) {} + enum BaseType { Unknown, @@ -606,7 +621,7 @@ struct SPIRType : IVariant uint32_t sampled; spv::ImageFormat format; spv::AccessQualifier access; - } image; + } image = {}; // Structs can be declared multiple times if they are used as part of interface blocks. // We want to detect this so that we only emit the struct definition once. @@ -638,7 +653,10 @@ struct SPIRExtension : IVariant SPV_AMD_shader_ballot, SPV_AMD_shader_explicit_vertex_parameter, SPV_AMD_shader_trinary_minmax, - SPV_AMD_gcn_shader + SPV_AMD_gcn_shader, + NonSemanticDebugPrintf, + NonSemanticShaderDebugInfo, + NonSemanticGeneric }; explicit SPIRExtension(Extension ext_) @@ -672,10 +690,12 @@ struct SPIREntryPoint struct WorkgroupSize { uint32_t x = 0, y = 0, z = 0; + uint32_t id_x = 0, id_y = 0, id_z = 0; uint32_t constant = 0; // Workgroup size can be expressed as a constant/spec-constant instead. } workgroup_size; uint32_t invocations = 0; uint32_t output_vertices = 0; + uint32_t output_primitives = 0; spv::ExecutionModel model = spv::ExecutionModelMax; bool geometry_passthrough = false; }; @@ -689,7 +709,7 @@ struct SPIRExpression : IVariant // Only created by the backend target to avoid creating tons of temporaries. SPIRExpression(std::string expr, TypeID expression_type_, bool immutable_) - : expression(move(expr)) + : expression(std::move(expr)) , expression_type(expression_type_) , immutable(immutable_) { @@ -720,6 +740,9 @@ struct SPIRExpression : IVariant // Whether or not this is an access chain expression. bool access_chain = false; + // Whether or not gl_MeshVerticesEXT[].gl_Position (as a whole or .y) is referenced + bool access_meshlet_position_y = false; + // A list of expressions which this expression depends on. SmallVector expression_dependencies; @@ -770,7 +793,8 @@ struct SPIRBlock : IVariant Unreachable, // Noop Kill, // Discard IgnoreIntersection, // Ray Tracing - TerminateRay // Ray Tracing + TerminateRay, // Ray Tracing + EmitMeshTasks // Mesh shaders }; enum Merge @@ -832,6 +856,13 @@ struct SPIRBlock : IVariant BlockID false_block = 0; BlockID default_block = 0; + // If terminator is EmitMeshTasksEXT. + struct + { + ID groups[3]; + ID payload; + } mesh = {}; + SmallVector ops; struct Phi @@ -1071,7 +1102,6 @@ struct SPIRVariable : IVariant // Temporaries which can remain forwarded as long as this variable is not modified. SmallVector dependees; - bool forwardable = true; bool deferred_declaration = false; bool phi_variable = false; @@ -1563,6 +1593,8 @@ struct AccessChainMeta bool storage_is_packed = false; bool storage_is_invariant = false; bool flattened_struct = false; + bool relaxed_precision = false; + bool access_meshlet_position_y = false; }; enum ExtendedDecorations @@ -1630,6 +1662,12 @@ enum ExtendedDecorations // results of interpolation can. SPIRVCrossDecorationInterpolantComponentExpr, + // Apply to any struct type that is used in the Workgroup storage class. + // This causes matrices in MSL prior to Metal 3.0 to be emitted using a special + // class that is convertible to the standard matrix type, to work around the + // lack of constructors in the 'threadgroup' address space. + SPIRVCrossDecorationWorkgroupStruct, + SPIRVCrossDecorationCount }; @@ -1640,6 +1678,7 @@ struct Meta std::string alias; std::string qualified_alias; std::string hlsl_semantic; + std::string user_type; Bitset decoration_flags; spv::BuiltIn builtin_type = spv::BuiltInMax; uint32_t location = 0; @@ -1775,6 +1814,33 @@ static inline bool opcode_is_sign_invariant(spv::Op opcode) } } +static inline bool opcode_can_promote_integer_implicitly(spv::Op opcode) +{ + switch (opcode) + { + case spv::OpSNegate: + case spv::OpNot: + case spv::OpBitwiseAnd: + case spv::OpBitwiseOr: + case spv::OpBitwiseXor: + case spv::OpShiftLeftLogical: + case spv::OpShiftRightLogical: + case spv::OpShiftRightArithmetic: + case spv::OpIAdd: + case spv::OpISub: + case spv::OpIMul: + case spv::OpSDiv: + case spv::OpUDiv: + case spv::OpSRem: + case spv::OpUMod: + case spv::OpSMod: + return true; + + default: + return false; + } +} + struct SetBindingPair { uint32_t desc_set; diff --git a/src/libraries/spirv_cross/spirv_cpp.cpp b/src/libraries/spirv_cross/spirv_cpp.cpp index b7946bf33..dd0a84c83 100644 --- a/src/libraries/spirv_cross/spirv_cpp.cpp +++ b/src/libraries/spirv_cross/spirv_cpp.cpp @@ -274,8 +274,6 @@ void CompilerCPP::emit_resources() if (emitted) statement(""); - declare_undefined_values(); - statement("inline void init(spirv_cross_shader& s)"); begin_scope(); statement(resource_type, "::init(s);"); @@ -338,11 +336,8 @@ string CompilerCPP::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - resource_registrations.clear(); - reset(); + reset(pass_count); // Move constructor for this type is broken on GCC 4.9 ... buffer.reset(); diff --git a/src/libraries/spirv_cross/spirv_cross.cpp b/src/libraries/spirv_cross/spirv_cross.cpp index dc8360663..4ab985efd 100644 --- a/src/libraries/spirv_cross/spirv_cross.cpp +++ b/src/libraries/spirv_cross/spirv_cross.cpp @@ -36,16 +36,16 @@ using namespace SPIRV_CROSS_NAMESPACE; Compiler::Compiler(vector ir_) { - Parser parser(move(ir_)); + Parser parser(std::move(ir_)); parser.parse(); - set_ir(move(parser.get_parsed_ir())); + set_ir(std::move(parser.get_parsed_ir())); } Compiler::Compiler(const uint32_t *ir_, size_t word_count) { Parser parser(ir_, word_count); parser.parse(); - set_ir(move(parser.get_parsed_ir())); + set_ir(std::move(parser.get_parsed_ir())); } Compiler::Compiler(const ParsedIR &ir_) @@ -55,12 +55,12 @@ Compiler::Compiler(const ParsedIR &ir_) Compiler::Compiler(ParsedIR &&ir_) { - set_ir(move(ir_)); + set_ir(std::move(ir_)); } void Compiler::set_ir(ParsedIR &&ir_) { - ir = move(ir_); + ir = std::move(ir_); parse_fixup(); } @@ -98,7 +98,8 @@ bool Compiler::block_is_pure(const SPIRBlock &block) // This is a global side effect of the function. if (block.terminator == SPIRBlock::Kill || block.terminator == SPIRBlock::TerminateRay || - block.terminator == SPIRBlock::IgnoreIntersection) + block.terminator == SPIRBlock::IgnoreIntersection || + block.terminator == SPIRBlock::EmitMeshTasks) return false; for (auto &i : block.ops) @@ -154,6 +155,11 @@ bool Compiler::block_is_pure(const SPIRBlock &block) case OpEmitVertex: return false; + // Mesh shader functions modify global state. + // (EmitMeshTasks is a terminator). + case OpSetMeshOutputsEXT: + return false; + // Barriers disallow any reordering, so we should treat blocks with barrier as writing. case OpControlBarrier: case OpMemoryBarrier: @@ -621,7 +627,22 @@ bool Compiler::is_matrix(const SPIRType &type) const bool Compiler::is_array(const SPIRType &type) const { - return !type.array.empty(); + return type.op == OpTypeArray || type.op == OpTypeRuntimeArray; +} + +bool Compiler::is_pointer(const SPIRType &type) const +{ + return type.op == OpTypePointer && type.basetype != SPIRType::Unknown; // Ignore function pointers. +} + +bool Compiler::is_physical_pointer(const SPIRType &type) const +{ + return type.op == OpTypePointer && type.storage == StorageClassPhysicalStorageBuffer; +} + +bool Compiler::is_runtime_size_array(const SPIRType &type) +{ + return type.op == OpTypeRuntimeArray; } ShaderResources Compiler::get_shader_resources() const @@ -719,7 +740,7 @@ bool Compiler::InterfaceVariableAccessHandler::handle(Op opcode, const uint32_t case OpExtInst: { - if (length < 5) + if (length < 3) return false; auto &extension_set = compiler.get(args[2]); switch (extension_set.ext) @@ -852,7 +873,7 @@ unordered_set Compiler::get_active_interface_variables() const void Compiler::set_enabled_interface_variables(std::unordered_set active_variables) { - active_interface_variables = move(active_variables); + active_interface_variables = std::move(active_variables); check_active_interface_variables = true; } @@ -985,57 +1006,74 @@ ShaderResources Compiler::get_shader_resources(const unordered_set * // in the future. res.push_constant_buffers.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); } - // Images - else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::Image && - type.image.sampled == 2) + else if (type.storage == StorageClassShaderRecordBufferKHR) { - res.storage_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); - } - // Separate images - else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::Image && - type.image.sampled == 1) - { - res.separate_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); - } - // Separate samplers - else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::Sampler) - { - res.separate_samplers.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); - } - // Textures - else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::SampledImage) - { - res.sampled_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + res.shader_record_buffers.push_back({ var.self, var.basetype, type.self, get_remapped_declared_block_name(var.self, ssbo_instance_name) }); } // Atomic counters else if (type.storage == StorageClassAtomicCounter) { res.atomic_counters.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); } - // Acceleration structures - else if (type.storage == StorageClassUniformConstant && type.basetype == SPIRType::AccelerationStructure) + else if (type.storage == StorageClassUniformConstant) { - res.acceleration_structures.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + if (type.basetype == SPIRType::Image) + { + // Images + if (type.image.sampled == 2) + { + res.storage_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } + // Separate images + else if (type.image.sampled == 1) + { + res.separate_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } + } + // Separate samplers + else if (type.basetype == SPIRType::Sampler) + { + res.separate_samplers.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } + // Textures + else if (type.basetype == SPIRType::SampledImage) + { + res.sampled_images.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } + // Acceleration structures + else if (type.basetype == SPIRType::AccelerationStructure) + { + res.acceleration_structures.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } + else + { + res.gl_plain_uniforms.push_back({ var.self, var.basetype, type.self, get_name(var.self) }); + } } }); return res; } -bool Compiler::type_is_block_like(const SPIRType &type) const +bool Compiler::type_is_top_level_block(const SPIRType &type) const { if (type.basetype != SPIRType::Struct) return false; + return has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock); +} - if (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock)) - { +bool Compiler::type_is_block_like(const SPIRType &type) const +{ + if (type_is_top_level_block(type)) return true; - } - // Block-like types may have Offset decorations. - for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++) - if (has_member_decoration(type.self, i, DecorationOffset)) - return true; + if (type.basetype == SPIRType::Struct) + { + // Block-like types may have Offset decorations. + for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++) + if (has_member_decoration(type.self, i, DecorationOffset)) + return true; + } return false; } @@ -1050,10 +1088,12 @@ void Compiler::parse_fixup() if (id.get_type() == TypeConstant) { auto &c = id.get(); - if (ir.meta[c.self].decoration.builtin && ir.meta[c.self].decoration.builtin_type == BuiltInWorkgroupSize) + if (has_decoration(c.self, DecorationBuiltIn) && + BuiltIn(get_decoration(c.self, DecorationBuiltIn)) == BuiltInWorkgroupSize) { // In current SPIR-V, there can be just one constant like this. // All entry points will receive the constant value. + // WorkgroupSize take precedence over LocalSizeId. for (auto &entry : ir.entry_points) { entry.second.workgroup_size.constant = c.self; @@ -1067,8 +1107,11 @@ void Compiler::parse_fixup() { auto &var = id.get(); if (var.storage == StorageClassPrivate || var.storage == StorageClassWorkgroup || + var.storage == StorageClassTaskPayloadWorkgroupEXT || var.storage == StorageClassOutput) + { global_variables.push_back(var.self); + } if (variable_storage_is_aliased(var)) aliased_variables.push_back(var.self); } @@ -1453,6 +1496,58 @@ bool Compiler::get_binary_offset_for_decoration(VariableID id, spv::Decoration d return true; } +bool Compiler::block_is_noop(const SPIRBlock &block) const +{ + if (block.terminator != SPIRBlock::Direct) + return false; + + auto &child = get(block.next_block); + + // If this block participates in PHI, the block isn't really noop. + for (auto &phi : block.phi_variables) + if (phi.parent == block.self || phi.parent == child.self) + return false; + + for (auto &phi : child.phi_variables) + if (phi.parent == block.self) + return false; + + // Verify all instructions have no semantic impact. + for (auto &i : block.ops) + { + auto op = static_cast(i.op); + + switch (op) + { + // Non-Semantic instructions. + case OpLine: + case OpNoLine: + break; + + case OpExtInst: + { + auto *ops = stream(i); + auto ext = get(ops[2]).ext; + + bool ext_is_nonsemantic_only = + ext == SPIRExtension::NonSemanticShaderDebugInfo || + ext == SPIRExtension::SPV_debug_info || + ext == SPIRExtension::NonSemanticGeneric; + + if (!ext_is_nonsemantic_only) + return false; + + break; + } + + default: + return false; + } + } + + return true; +} + bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const { // Tried and failed. @@ -1510,7 +1605,7 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method { // Empty loop header that just sets up merge target // and branches to loop body. - bool ret = block.terminator == SPIRBlock::Direct && block.merge == SPIRBlock::MergeLoop && block.ops.empty(); + bool ret = block.terminator == SPIRBlock::Direct && block.merge == SPIRBlock::MergeLoop && block_is_noop(block); if (!ret) return false; @@ -1536,19 +1631,8 @@ bool Compiler::block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method ret = child.terminator == SPIRBlock::Select && child.merge == SPIRBlock::MergeNone && (positive_candidate || negative_candidate); - // If we have OpPhi which depends on branches which came from our own block, - // we need to flush phi variables in else block instead of a trivial break, - // so we cannot assume this is a for loop candidate. if (ret) { - for (auto &phi : block.phi_variables) - if (phi.parent == block.self || phi.parent == child.self) - return false; - - for (auto &phi : child.phi_variables) - if (phi.parent == block.self) - return false; - auto *merge = maybe_get(block.merge_block); if (merge) for (auto &phi : merge->phi_variables) @@ -1573,15 +1657,10 @@ bool Compiler::execution_is_noop(const SPIRBlock &from, const SPIRBlock &to) con if (start->self == to.self) return true; - if (!start->ops.empty()) + if (!block_is_noop(*start)) return false; auto &next = get(start->next_block); - // Flushing phi variables does not count as noop. - for (auto &phi : next.phi_variables) - if (phi.parent == start->self) - return false; - start = &next; } } @@ -1675,6 +1754,11 @@ const SmallVector &Compiler::get_case_list(const SPIRBlock &blo const auto &type = get(var->basetype); width = type.width; } + else if (const auto *undef = maybe_get(block.condition)) + { + const auto &type = get(undef->basetype); + width = type.width; + } else { auto search = ir.load_type_width.find(block.condition); @@ -2156,6 +2240,12 @@ void Compiler::set_execution_mode(ExecutionMode mode, uint32_t arg0, uint32_t ar execution.workgroup_size.z = arg2; break; + case ExecutionModeLocalSizeId: + execution.workgroup_size.id_x = arg0; + execution.workgroup_size.id_y = arg1; + execution.workgroup_size.id_z = arg2; + break; + case ExecutionModeInvocations: execution.invocations = arg0; break; @@ -2164,6 +2254,10 @@ void Compiler::set_execution_mode(ExecutionMode mode, uint32_t arg0, uint32_t ar execution.output_vertices = arg0; break; + case ExecutionModeOutputPrimitivesEXT: + execution.output_primitives = arg0; + break; + default: break; } @@ -2183,6 +2277,7 @@ uint32_t Compiler::get_work_group_size_specialization_constants(SpecializationCo y = { 0, 0 }; z = { 0, 0 }; + // WorkgroupSize builtin takes precedence over LocalSize / LocalSizeId. if (execution.workgroup_size.constant != 0) { auto &c = get(execution.workgroup_size.constant); @@ -2205,6 +2300,29 @@ uint32_t Compiler::get_work_group_size_specialization_constants(SpecializationCo z.constant_id = get_decoration(c.m.c[0].id[2], DecorationSpecId); } } + else if (execution.flags.get(ExecutionModeLocalSizeId)) + { + auto &cx = get(execution.workgroup_size.id_x); + if (cx.specialization) + { + x.id = execution.workgroup_size.id_x; + x.constant_id = get_decoration(execution.workgroup_size.id_x, DecorationSpecId); + } + + auto &cy = get(execution.workgroup_size.id_y); + if (cy.specialization) + { + y.id = execution.workgroup_size.id_y; + y.constant_id = get_decoration(execution.workgroup_size.id_y, DecorationSpecId); + } + + auto &cz = get(execution.workgroup_size.id_z); + if (cz.specialization) + { + z.id = execution.workgroup_size.id_z; + z.constant_id = get_decoration(execution.workgroup_size.id_z, DecorationSpecId); + } + } return execution.workgroup_size.constant; } @@ -2214,15 +2332,42 @@ uint32_t Compiler::get_execution_mode_argument(spv::ExecutionMode mode, uint32_t auto &execution = get_entry_point(); switch (mode) { + case ExecutionModeLocalSizeId: + if (execution.flags.get(ExecutionModeLocalSizeId)) + { + switch (index) + { + case 0: + return execution.workgroup_size.id_x; + case 1: + return execution.workgroup_size.id_y; + case 2: + return execution.workgroup_size.id_z; + default: + return 0; + } + } + else + return 0; + case ExecutionModeLocalSize: switch (index) { case 0: - return execution.workgroup_size.x; + if (execution.flags.get(ExecutionModeLocalSizeId) && execution.workgroup_size.id_x != 0) + return get(execution.workgroup_size.id_x).scalar(); + else + return execution.workgroup_size.x; case 1: - return execution.workgroup_size.y; + if (execution.flags.get(ExecutionModeLocalSizeId) && execution.workgroup_size.id_y != 0) + return get(execution.workgroup_size.id_y).scalar(); + else + return execution.workgroup_size.y; case 2: - return execution.workgroup_size.z; + if (execution.flags.get(ExecutionModeLocalSizeId) && execution.workgroup_size.id_z != 0) + return get(execution.workgroup_size.id_z).scalar(); + else + return execution.workgroup_size.z; default: return 0; } @@ -2233,6 +2378,9 @@ uint32_t Compiler::get_execution_mode_argument(spv::ExecutionMode mode, uint32_t case ExecutionModeOutputVertices: return execution.output_vertices; + case ExecutionModeOutputPrimitivesEXT: + return execution.output_primitives; + default: return 0; } @@ -2261,6 +2409,11 @@ bool Compiler::is_tessellation_shader() const return is_tessellation_shader(get_execution_model()); } +bool Compiler::is_tessellating_triangles() const +{ + return get_execution_mode_bitset().get(ExecutionModeTriangles); +} + void Compiler::set_remapped_variable_state(VariableID id, bool remap_enable) { get(id).remapped_variable = remap_enable; @@ -2295,6 +2448,19 @@ void Compiler::add_implied_read_expression(SPIRAccessChain &e, uint32_t source) e.implied_read_expressions.push_back(source); } +void Compiler::add_active_interface_variable(uint32_t var_id) +{ + active_interface_variables.insert(var_id); + + // In SPIR-V 1.4 and up we must also track the interface variable in the entry point. + if (ir.get_spirv_version() >= 0x10400) + { + auto &vars = get_entry_point().interface_variables; + if (find(begin(vars), end(vars), VariableID(var_id)) == end(vars)) + vars.push_back(var_id); + } +} + void Compiler::inherit_expression_dependencies(uint32_t dst, uint32_t source_expression) { // Don't inherit any expression dependencies if the expression in dst @@ -2449,7 +2615,7 @@ void Compiler::CombinedImageSamplerHandler::push_remap_parameters(const SPIRFunc unordered_map remapping; for (uint32_t i = 0; i < length; i++) remapping[func.arguments[i].id] = remap_parameter(args[i]); - parameter_remapping.push(move(remapping)); + parameter_remapping.push(std::move(remapping)); } void Compiler::CombinedImageSamplerHandler::pop_remap_parameters() @@ -2579,8 +2745,8 @@ void Compiler::CombinedImageSamplerHandler::register_combined_image_sampler(SPIR auto ptr_type_id = id + 1; auto combined_id = id + 2; auto &base = compiler.expression_type(image_id); - auto &type = compiler.set(type_id); - auto &ptr_type = compiler.set(ptr_type_id); + auto &type = compiler.set(type_id, OpTypeSampledImage); + auto &ptr_type = compiler.set(ptr_type_id, OpTypePointer); type = base; type.self = type_id; @@ -2839,7 +3005,7 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar { // Have to invent the sampled image type. sampled_type = compiler.ir.increase_bound_by(1); - auto &type = compiler.set(sampled_type); + auto &type = compiler.set(sampled_type, OpTypeSampledImage); type = compiler.expression_type(args[2]); type.self = sampled_type; type.basetype = SPIRType::SampledImage; @@ -2858,7 +3024,7 @@ bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *ar // Make a new type, pointer to OpTypeSampledImage, so we can make a variable of this type. // We will probably have this type lying around, but it doesn't hurt to make duplicates for internal purposes. - auto &type = compiler.set(type_id); + auto &type = compiler.set(type_id, OpTypePointer); auto &base = compiler.get(sampled_type); type = base; type.pointer = true; @@ -2904,11 +3070,10 @@ VariableID Compiler::build_dummy_sampler_for_combined_images() auto ptr_type_id = offset + 1; auto var_id = offset + 2; - SPIRType sampler_type; - auto &sampler = set(type_id); + auto &sampler = set(type_id, OpTypeSampler); sampler.basetype = SPIRType::Sampler; - auto &ptr_sampler = set(ptr_type_id); + auto &ptr_sampler = set(ptr_type_id, OpTypePointer); ptr_sampler = sampler; ptr_sampler.self = type_id; ptr_sampler.storage = StorageClassUniformConstant; @@ -3111,8 +3276,8 @@ void Compiler::AnalyzeVariableScopeAccessHandler::notify_variable_access(uint32_ return; // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers. - auto itr = access_chain_children.find(id); - if (itr != end(access_chain_children)) + auto itr = rvalue_forward_children.find(id); + if (itr != end(rvalue_forward_children)) for (auto child_id : itr->second) notify_variable_access(child_id, block); @@ -3165,7 +3330,20 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 // Keep track of the types of temporaries, so we can hoist them out as necessary. uint32_t result_type, result_id; if (compiler.instruction_to_result_type(result_type, result_id, op, args, length)) + { + // For some opcodes, we will need to override the result id. + // If we need to hoist the temporary, the temporary type is the input, not the result. + // FIXME: This will likely break with OpCopyObject + hoisting, but we'll have to + // solve it if we ever get there ... + if (op == OpConvertUToAccelerationStructureKHR) + { + auto itr = result_id_to_type.find(args[2]); + if (itr != result_id_to_type.end()) + result_type = itr->second; + } + result_id_to_type[result_id] = result_type; + } switch (op) { @@ -3207,14 +3385,14 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 if (var) { accessed_variables_to_block[var->self].insert(current_block->self); - access_chain_children[args[1]].insert(var->self); + rvalue_forward_children[args[1]].insert(var->self); } // args[2] might be another access chain we have to track use of. for (uint32_t i = 2; i < length; i++) { notify_variable_access(args[i], current_block->self); - access_chain_children[args[1]].insert(args[i]); + rvalue_forward_children[args[1]].insert(args[i]); } // Also keep track of the access chain pointer itself. @@ -3296,6 +3474,12 @@ bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint3 // Might be an access chain we have to track use of. notify_variable_access(args[2], current_block->self); + + // If we're loading an opaque type we cannot lower it to a temporary, + // we must defer access of args[2] until it's used. + auto &type = compiler.get(args[0]); + if (compiler.type_is_opaque_value(type)) + rvalue_forward_children[args[1]].insert(args[2]); break; } @@ -3667,6 +3851,7 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA DominatorBuilder builder(cfg); auto &blocks = var.second; auto &type = expression_type(var.first); + BlockID potential_continue_block = 0; // Figure out which block is dominating all accesses of those variables. for (auto &block : blocks) @@ -3688,14 +3873,13 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA { // The variable is used in multiple continue blocks, this is not a loop // candidate, signal that by setting block to -1u. - auto &potential = potential_loop_variables[var.first]; - - if (potential == 0) - potential = block; + if (potential_continue_block == 0) + potential_continue_block = block; else - potential = ~(0u); + potential_continue_block = ~(0u); } } + builder.add_block(block); } @@ -3704,6 +3888,34 @@ void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeA // Add it to a per-block list of variables. BlockID dominating_block = builder.get_dominator(); + if (dominating_block && potential_continue_block != 0 && potential_continue_block != ~0u) + { + auto &inner_block = get(dominating_block); + + BlockID merge_candidate = 0; + + // Analyze the dominator. If it lives in a different loop scope than the candidate continue + // block, reject the loop variable candidate. + if (inner_block.merge == SPIRBlock::MergeLoop) + merge_candidate = inner_block.merge_block; + else if (inner_block.loop_dominator != SPIRBlock::NoDominator) + merge_candidate = get(inner_block.loop_dominator).merge_block; + + if (merge_candidate != 0 && cfg.is_reachable(merge_candidate)) + { + // If the merge block has a higher post-visit order, we know that continue candidate + // cannot reach the merge block, and we have two separate scopes. + if (!cfg.is_reachable(potential_continue_block) || + cfg.get_visit_order(merge_candidate) > cfg.get_visit_order(potential_continue_block)) + { + potential_continue_block = 0; + } + } + } + + if (potential_continue_block != 0 && potential_continue_block != ~0u) + potential_loop_variables[var.first] = potential_continue_block; + // For variables whose dominating block is inside a loop, there is a risk that these variables // actually need to be preserved across loop iterations. We can express this by adding // a "read" access to the loop header. @@ -4303,8 +4515,9 @@ void Compiler::analyze_image_and_sampler_usage() handler.dependency_hierarchy.clear(); traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); - comparison_ids = move(handler.comparison_ids); + comparison_ids = std::move(handler.comparison_ids); need_subpass_input = handler.need_subpass_input; + need_subpass_input_ms = handler.need_subpass_input_ms; // Forward information from separate images and samplers into combined image samplers. for (auto &combined : combined_image_samplers) @@ -4356,7 +4569,7 @@ void Compiler::build_function_control_flow_graphs_and_analyze() CFGBuilder handler(*this); handler.function_cfgs[ir.default_entry_point].reset(new CFG(*this, get(ir.default_entry_point))); traverse_all_reachable_opcodes(get(ir.default_entry_point), handler); - function_cfgs = move(handler.function_cfgs); + function_cfgs = std::move(handler.function_cfgs); bool single_function = function_cfgs.size() <= 1; for (auto &f : function_cfgs) @@ -4471,7 +4684,11 @@ bool Compiler::CombinedImageSamplerUsageHandler::handle(Op opcode, const uint32_ // If we load an image, we're going to use it and there is little harm in declaring an unused gl_FragCoord. auto &type = compiler.get(args[0]); if (type.image.dim == DimSubpassData) + { need_subpass_input = true; + if (type.image.ms) + need_subpass_input_ms = true; + } // If we load a SampledImage and it will be used with Dref, propagate the state up. if (dref_combined_samplers.count(args[1]) != 0) @@ -4646,46 +4863,22 @@ bool Compiler::reflection_ssbo_instance_name_is_significant() const return aliased_ssbo_types; } -bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op, const uint32_t *args, - uint32_t length) +bool Compiler::instruction_to_result_type(uint32_t &result_type, uint32_t &result_id, spv::Op op, + const uint32_t *args, uint32_t length) { - // Most instructions follow the pattern of . - // There are some exceptions. - switch (op) - { - case OpStore: - case OpCopyMemory: - case OpCopyMemorySized: - case OpImageWrite: - case OpAtomicStore: - case OpAtomicFlagClear: - case OpEmitStreamVertex: - case OpEndStreamPrimitive: - case OpControlBarrier: - case OpMemoryBarrier: - case OpGroupWaitEvents: - case OpRetainEvent: - case OpReleaseEvent: - case OpSetUserEventStatus: - case OpCaptureEventProfilingInfo: - case OpCommitReadPipe: - case OpCommitWritePipe: - case OpGroupCommitReadPipe: - case OpGroupCommitWritePipe: - case OpLine: - case OpNoLine: + if (length < 2) return false; - default: - if (length > 1 && maybe_get(args[0]) != nullptr) - { - result_type = args[0]; - result_id = args[1]; - return true; - } - else - return false; + bool has_result_id = false, has_result_type = false; + HasResultAndType(op, &has_result_id, &has_result_type); + if (has_result_id && has_result_type) + { + result_type = args[0]; + result_id = args[1]; + return true; } + else + return false; } Bitset Compiler::combined_decoration_for_member(const SPIRType &type, uint32_t index) const @@ -4769,6 +4962,12 @@ void Compiler::force_recompile() is_force_recompile = true; } +void Compiler::force_recompile_guarantee_forward_progress() +{ + force_recompile(); + is_force_recompile_forward_progress = true; +} + bool Compiler::is_forcing_recompilation() const { return is_force_recompile; @@ -4777,6 +4976,7 @@ bool Compiler::is_forcing_recompilation() const void Compiler::clear_force_recompile() { is_force_recompile = false; + is_force_recompile_forward_progress = false; } Compiler::PhysicalStorageBufferPointerHandler::PhysicalStorageBufferPointerHandler(Compiler &compiler_) @@ -4958,7 +5158,7 @@ void Compiler::analyze_non_block_pointer_types() for (auto type : handler.non_block_types) physical_storage_non_block_pointer_types.push_back(type); sort(begin(physical_storage_non_block_pointer_types), end(physical_storage_non_block_pointer_types)); - physical_storage_type_to_alignment = move(handler.physical_block_type_meta); + physical_storage_type_to_alignment = std::move(handler.physical_block_type_meta); } bool Compiler::InterlockedResourceAccessPrepassHandler::handle(Op op, const uint32_t *, uint32_t) @@ -5271,19 +5471,51 @@ void Compiler::analyze_interlocked_resource_usage() } } -bool Compiler::type_is_array_of_pointers(const SPIRType &type) const +// Helper function +bool Compiler::check_internal_recursion(const SPIRType &type, std::unordered_set &checked_ids) { - if (!type.pointer) + if (type.basetype != SPIRType::Struct) return false; - // If parent type has same pointer depth, we must have an array of pointers. - return type.pointer_depth == get(type.parent_type).pointer_depth; + if (checked_ids.count(type.self)) + return true; + + // Recurse into struct members + bool is_recursive = false; + checked_ids.insert(type.self); + uint32_t mbr_cnt = uint32_t(type.member_types.size()); + for (uint32_t mbr_idx = 0; !is_recursive && mbr_idx < mbr_cnt; mbr_idx++) + { + uint32_t mbr_type_id = type.member_types[mbr_idx]; + auto &mbr_type = get(mbr_type_id); + is_recursive |= check_internal_recursion(mbr_type, checked_ids); + } + checked_ids.erase(type.self); + return is_recursive; } -bool Compiler::type_is_top_level_physical_pointer(const SPIRType &type) const +// Return whether the struct type contains a structural recursion nested somewhere within its content. +bool Compiler::type_contains_recursion(const SPIRType &type) { - return type.pointer && type.storage == StorageClassPhysicalStorageBuffer && - type.pointer_depth > get(type.parent_type).pointer_depth; + std::unordered_set checked_ids; + return check_internal_recursion(type, checked_ids); +} + +bool Compiler::type_is_array_of_pointers(const SPIRType &type) const +{ + if (!is_array(type)) + return false; + + // BDA types must have parent type hierarchy. + if (!type.parent_type) + return false; + + // Punch through all array layers. + auto *parent = &get(type.parent_type); + while (is_array(*parent)) + parent = &get(parent->parent_type); + + return is_pointer(*parent); } bool Compiler::flush_phi_required(BlockID from, BlockID to) const diff --git a/src/libraries/spirv_cross/spirv_cross.hpp b/src/libraries/spirv_cross/spirv_cross.hpp index c945401d8..9fe6c41c4 100644 --- a/src/libraries/spirv_cross/spirv_cross.hpp +++ b/src/libraries/spirv_cross/spirv_cross.hpp @@ -24,6 +24,9 @@ #ifndef SPIRV_CROSS_HPP #define SPIRV_CROSS_HPP +#ifndef SPV_ENABLE_UTILITY_CODE +#define SPV_ENABLE_UTILITY_CODE +#endif #include "spirv.hpp" #include "spirv_cfg.hpp" #include "spirv_cross_parsed_ir.hpp" @@ -91,11 +94,14 @@ struct ShaderResources SmallVector sampled_images; SmallVector atomic_counters; SmallVector acceleration_structures; + SmallVector gl_plain_uniforms; // There can only be one push constant block, // but keep the vector in case this restriction is lifted in the future. SmallVector push_constant_buffers; + SmallVector shader_record_buffers; + // For Vulkan GLSL and HLSL source, // these correspond to separate texture2D and samplers respectively. SmallVector separate_images; @@ -357,12 +363,16 @@ public: void set_execution_mode(spv::ExecutionMode mode, uint32_t arg0 = 0, uint32_t arg1 = 0, uint32_t arg2 = 0); // Gets argument for an execution mode (LocalSize, Invocations, OutputVertices). - // For LocalSize, the index argument is used to select the dimension (X = 0, Y = 1, Z = 2). + // For LocalSize or LocalSizeId, the index argument is used to select the dimension (X = 0, Y = 1, Z = 2). // For execution modes which do not have arguments, 0 is returned. + // LocalSizeId query returns an ID. If LocalSizeId execution mode is not used, it returns 0. + // LocalSize always returns a literal. If execution mode is LocalSizeId, + // the literal (spec constant or not) is still returned. uint32_t get_execution_mode_argument(spv::ExecutionMode mode, uint32_t index = 0) const; spv::ExecutionModel get_execution_model() const; bool is_tessellation_shader() const; + bool is_tessellating_triangles() const; // In SPIR-V, the compute work group size can be represented by a constant vector, in which case // the LocalSize execution mode is ignored. @@ -380,6 +390,8 @@ public: // If the component is not a specialization constant, a zeroed out struct will be written. // The return value is the constant ID of the builtin WorkGroupSize, but this is not expected to be useful // for most use cases. + // If LocalSizeId is used, there is no uvec3 value representing the workgroup size, so the return value is 0, + // but x, y and z are written as normal if the components are specialization constants. uint32_t get_work_group_size_specialization_constants(SpecializationConstant &x, SpecializationConstant &y, SpecializationConstant &z) const; @@ -551,6 +563,11 @@ protected: } } + uint32_t *stream_mutable(const Instruction &instr) const + { + return const_cast(stream(instr)); + } + ParsedIR ir; // Marks variables which have global scope and variables which can alias with other variables // (SSBO, image load store, etc) @@ -666,6 +683,9 @@ protected: bool is_vector(const SPIRType &type) const; bool is_matrix(const SPIRType &type) const; bool is_array(const SPIRType &type) const; + bool is_pointer(const SPIRType &type) const; + bool is_physical_pointer(const SPIRType &type) const; + static bool is_runtime_size_array(const SPIRType &type); uint32_t expression_type_id(uint32_t id) const; const SPIRType &expression_type(uint32_t id) const; bool expression_is_lvalue(uint32_t id) const; @@ -730,16 +750,20 @@ protected: SPIRBlock::ContinueBlockType continue_block_type(const SPIRBlock &continue_block) const; void force_recompile(); + void force_recompile_guarantee_forward_progress(); void clear_force_recompile(); bool is_forcing_recompilation() const; bool is_force_recompile = false; + bool is_force_recompile_forward_progress = false; + bool block_is_noop(const SPIRBlock &block) const; bool block_is_loop_candidate(const SPIRBlock &block, SPIRBlock::Method method) const; bool types_are_logically_equivalent(const SPIRType &a, const SPIRType &b) const; void inherit_expression_dependencies(uint32_t dst, uint32_t source); void add_implied_read_expression(SPIRExpression &e, uint32_t source); void add_implied_read_expression(SPIRAccessChain &e, uint32_t source); + void add_active_interface_variable(uint32_t var_id); // For proper multiple entry point support, allow querying if an Input or Output // variable is part of that entry points interface. @@ -915,6 +939,7 @@ protected: // Similar is implemented for images, as well as if subpass inputs are needed. std::unordered_set comparison_ids; bool need_subpass_input = false; + bool need_subpass_input_ms = false; // In certain backends, we will need to use a dummy sampler to be able to emit code. // GLSL does not support texelFetch on texture2D objects, but SPIR-V does, @@ -954,6 +979,7 @@ protected: void add_hierarchy_to_comparison_ids(uint32_t ids); bool need_subpass_input = false; + bool need_subpass_input_ms = false; void add_dependency(uint32_t dst, uint32_t src); }; @@ -994,7 +1020,8 @@ protected: std::unordered_map> partial_write_variables_to_block; std::unordered_set access_chain_expressions; // Access chains used in multiple blocks mean hoisting all the variables used to construct the access chain as not all backends can use pointers. - std::unordered_map> access_chain_children; + // This is also relevant when forwarding opaque objects since we cannot lower these to temporaries. + std::unordered_map> rvalue_forward_children; const SPIRBlock *current_block = nullptr; }; @@ -1120,9 +1147,11 @@ protected: bool has_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration) const; void unset_extended_member_decoration(uint32_t type, uint32_t index, ExtendedDecorations decoration); + bool check_internal_recursion(const SPIRType &type, std::unordered_set &checked_ids); + bool type_contains_recursion(const SPIRType &type); bool type_is_array_of_pointers(const SPIRType &type) const; - bool type_is_top_level_physical_pointer(const SPIRType &type) const; bool type_is_block_like(const SPIRType &type) const; + bool type_is_top_level_block(const SPIRType &type) const; bool type_is_opaque_value(const SPIRType &type) const; bool reflection_ssbo_instance_name_is_significant() const; diff --git a/src/libraries/spirv_cross/spirv_cross_c.cpp b/src/libraries/spirv_cross/spirv_cross_c.cpp deleted file mode 100644 index 4d5615404..000000000 --- a/src/libraries/spirv_cross/spirv_cross_c.cpp +++ /dev/null @@ -1,2633 +0,0 @@ -/* - * Copyright 2019-2021 Hans-Kristian Arntzen - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - * 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. - */ - -/* - * At your option, you may choose to accept this material under either: - * 1. The Apache License, Version 2.0, found at , or - * 2. The MIT License, found at . - */ - -#include "spirv_cross_c.h" - -#if SPIRV_CROSS_C_API_CPP -#include "spirv_cpp.hpp" -#endif -#if SPIRV_CROSS_C_API_GLSL -#include "spirv_glsl.hpp" -#else -#include "spirv_cross.hpp" -#endif -#if SPIRV_CROSS_C_API_HLSL -#include "spirv_hlsl.hpp" -#endif -#if SPIRV_CROSS_C_API_MSL -#include "spirv_msl.hpp" -#endif -#if SPIRV_CROSS_C_API_REFLECT -#include "spirv_reflect.hpp" -#endif - -#ifdef HAVE_SPIRV_CROSS_GIT_VERSION -#include "gitversion.h" -#endif - -#include "spirv_parser.hpp" -#include -#include -#include - -// clang-format off - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable : 4996) -#endif - -#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS -#define SPVC_BEGIN_SAFE_SCOPE try -#else -#define SPVC_BEGIN_SAFE_SCOPE -#endif - -#ifndef SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS -#define SPVC_END_SAFE_SCOPE(context, error) \ - catch (const std::exception &e) \ - { \ - (context)->report_error(e.what()); \ - return (error); \ - } -#else -#define SPVC_END_SAFE_SCOPE(context, error) -#endif - -using namespace std; -using namespace SPIRV_CROSS_NAMESPACE; - -struct ScratchMemoryAllocation -{ - virtual ~ScratchMemoryAllocation() = default; -}; - -struct StringAllocation : ScratchMemoryAllocation -{ - explicit StringAllocation(const char *name) - : str(name) - { - } - - explicit StringAllocation(std::string name) - : str(std::move(name)) - { - } - - std::string str; -}; - -template -struct TemporaryBuffer : ScratchMemoryAllocation -{ - SmallVector buffer; -}; - -template -static inline std::unique_ptr spvc_allocate(Ts &&... ts) -{ - return std::unique_ptr(new T(std::forward(ts)...)); -} - -struct spvc_context_s -{ - string last_error; - SmallVector> allocations; - const char *allocate_name(const std::string &name); - - spvc_error_callback callback = nullptr; - void *callback_userdata = nullptr; - void report_error(std::string msg); -}; - -void spvc_context_s::report_error(std::string msg) -{ - last_error = std::move(msg); - if (callback) - callback(callback_userdata, last_error.c_str()); -} - -const char *spvc_context_s::allocate_name(const std::string &name) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto alloc = spvc_allocate(name); - auto *ret = alloc->str.c_str(); - allocations.emplace_back(std::move(alloc)); - return ret; - } - SPVC_END_SAFE_SCOPE(this, nullptr) -} - -struct spvc_parsed_ir_s : ScratchMemoryAllocation -{ - spvc_context context = nullptr; - ParsedIR parsed; -}; - -struct spvc_compiler_s : ScratchMemoryAllocation -{ - spvc_context context = nullptr; - unique_ptr compiler; - spvc_backend backend = SPVC_BACKEND_NONE; -}; - -struct spvc_compiler_options_s : ScratchMemoryAllocation -{ - spvc_context context = nullptr; - uint32_t backend_flags = 0; -#if SPIRV_CROSS_C_API_GLSL - CompilerGLSL::Options glsl; -#endif -#if SPIRV_CROSS_C_API_MSL - CompilerMSL::Options msl; -#endif -#if SPIRV_CROSS_C_API_HLSL - CompilerHLSL::Options hlsl; -#endif -}; - -struct spvc_set_s : ScratchMemoryAllocation -{ - std::unordered_set set; -}; - -// Dummy-inherit to we can keep our opaque type handle type safe in C-land as well, -// and avoid just throwing void * around. -struct spvc_type_s : SPIRType -{ -}; - -struct spvc_constant_s : SPIRConstant -{ -}; - -struct spvc_resources_s : ScratchMemoryAllocation -{ - spvc_context context = nullptr; - SmallVector uniform_buffers; - SmallVector storage_buffers; - SmallVector stage_inputs; - SmallVector stage_outputs; - SmallVector subpass_inputs; - SmallVector storage_images; - SmallVector sampled_images; - SmallVector atomic_counters; - SmallVector push_constant_buffers; - SmallVector separate_images; - SmallVector separate_samplers; - SmallVector acceleration_structures; - SmallVector builtin_inputs; - SmallVector builtin_outputs; - - bool copy_resources(SmallVector &outputs, const SmallVector &inputs); - bool copy_resources(SmallVector &outputs, const SmallVector &inputs); - bool copy_resources(const ShaderResources &resources); -}; - -spvc_result spvc_context_create(spvc_context *context) -{ - auto *ctx = new (std::nothrow) spvc_context_s; - if (!ctx) - return SPVC_ERROR_OUT_OF_MEMORY; - - *context = ctx; - return SPVC_SUCCESS; -} - -void spvc_context_destroy(spvc_context context) -{ - delete context; -} - -void spvc_context_release_allocations(spvc_context context) -{ - context->allocations.clear(); -} - -const char *spvc_context_get_last_error_string(spvc_context context) -{ - return context->last_error.c_str(); -} - -SPVC_PUBLIC_API void spvc_context_set_error_callback(spvc_context context, spvc_error_callback cb, void *userdata) -{ - context->callback = cb; - context->callback_userdata = userdata; -} - -spvc_result spvc_context_parse_spirv(spvc_context context, const SpvId *spirv, size_t word_count, - spvc_parsed_ir *parsed_ir) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr pir(new (std::nothrow) spvc_parsed_ir_s); - if (!pir) - { - context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - pir->context = context; - Parser parser(spirv, word_count); - parser.parse(); - pir->parsed = move(parser.get_parsed_ir()); - *parsed_ir = pir.get(); - context->allocations.push_back(std::move(pir)); - } - SPVC_END_SAFE_SCOPE(context, SPVC_ERROR_INVALID_SPIRV) - return SPVC_SUCCESS; -} - -spvc_result spvc_context_create_compiler(spvc_context context, spvc_backend backend, spvc_parsed_ir parsed_ir, - spvc_capture_mode mode, spvc_compiler *compiler) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr comp(new (std::nothrow) spvc_compiler_s); - if (!comp) - { - context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - comp->backend = backend; - comp->context = context; - - if (mode != SPVC_CAPTURE_MODE_COPY && mode != SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - { - context->report_error("Invalid argument for capture mode."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - switch (backend) - { - case SPVC_BACKEND_NONE: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new Compiler(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new Compiler(parsed_ir->parsed)); - break; - -#if SPIRV_CROSS_C_API_GLSL - case SPVC_BACKEND_GLSL: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new CompilerGLSL(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new CompilerGLSL(parsed_ir->parsed)); - break; -#endif - -#if SPIRV_CROSS_C_API_HLSL - case SPVC_BACKEND_HLSL: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new CompilerHLSL(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new CompilerHLSL(parsed_ir->parsed)); - break; -#endif - -#if SPIRV_CROSS_C_API_MSL - case SPVC_BACKEND_MSL: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new CompilerMSL(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new CompilerMSL(parsed_ir->parsed)); - break; -#endif - -#if SPIRV_CROSS_C_API_CPP - case SPVC_BACKEND_CPP: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new CompilerCPP(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new CompilerCPP(parsed_ir->parsed)); - break; -#endif - -#if SPIRV_CROSS_C_API_REFLECT - case SPVC_BACKEND_JSON: - if (mode == SPVC_CAPTURE_MODE_TAKE_OWNERSHIP) - comp->compiler.reset(new CompilerReflection(move(parsed_ir->parsed))); - else if (mode == SPVC_CAPTURE_MODE_COPY) - comp->compiler.reset(new CompilerReflection(parsed_ir->parsed)); - break; -#endif - - default: - context->report_error("Invalid backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - *compiler = comp.get(); - context->allocations.push_back(std::move(comp)); - } - SPVC_END_SAFE_SCOPE(context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_create_compiler_options(spvc_compiler compiler, spvc_compiler_options *options) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr opt(new (std::nothrow) spvc_compiler_options_s); - if (!opt) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - opt->context = compiler->context; - opt->backend_flags = 0; - switch (compiler->backend) - { -#if SPIRV_CROSS_C_API_MSL - case SPVC_BACKEND_MSL: - opt->backend_flags |= SPVC_COMPILER_OPTION_MSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; - opt->glsl = static_cast(compiler->compiler.get())->get_common_options(); - opt->msl = static_cast(compiler->compiler.get())->get_msl_options(); - break; -#endif - -#if SPIRV_CROSS_C_API_HLSL - case SPVC_BACKEND_HLSL: - opt->backend_flags |= SPVC_COMPILER_OPTION_HLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; - opt->glsl = static_cast(compiler->compiler.get())->get_common_options(); - opt->hlsl = static_cast(compiler->compiler.get())->get_hlsl_options(); - break; -#endif - -#if SPIRV_CROSS_C_API_GLSL - case SPVC_BACKEND_GLSL: - opt->backend_flags |= SPVC_COMPILER_OPTION_GLSL_BIT | SPVC_COMPILER_OPTION_COMMON_BIT; - opt->glsl = static_cast(compiler->compiler.get())->get_common_options(); - break; -#endif - - default: - break; - } - - *options = opt.get(); - compiler->context->allocations.push_back(std::move(opt)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_options_set_bool(spvc_compiler_options options, spvc_compiler_option option, - spvc_bool value) -{ - return spvc_compiler_options_set_uint(options, option, value ? 1 : 0); -} - -spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, spvc_compiler_option option, unsigned value) -{ - (void)value; - (void)option; - uint32_t supported_mask = options->backend_flags; - uint32_t required_mask = option & SPVC_COMPILER_OPTION_LANG_BITS; - if ((required_mask | supported_mask) != supported_mask) - { - options->context->report_error("Option is not supported by current backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - switch (option) - { -#if SPIRV_CROSS_C_API_GLSL - case SPVC_COMPILER_OPTION_FORCE_TEMPORARY: - options->glsl.force_temporary = value != 0; - break; - case SPVC_COMPILER_OPTION_FLATTEN_MULTIDIMENSIONAL_ARRAYS: - options->glsl.flatten_multidimensional_arrays = value != 0; - break; - case SPVC_COMPILER_OPTION_FIXUP_DEPTH_CONVENTION: - options->glsl.vertex.fixup_clipspace = value != 0; - break; - case SPVC_COMPILER_OPTION_FLIP_VERTEX_Y: - options->glsl.vertex.flip_vert_y = value != 0; - break; - case SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES: - options->glsl.emit_line_directives = value != 0; - break; - case SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION: - options->glsl.enable_storage_image_qualifier_deduction = value != 0; - break; - case SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES: - options->glsl.force_zero_initialized_variables = value != 0; - break; - - case SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE: - options->glsl.vertex.support_nonzero_base_instance = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_SEPARATE_SHADER_OBJECTS: - options->glsl.separate_shader_objects = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION: - options->glsl.enable_420pack_extension = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_VERSION: - options->glsl.version = value; - break; - case SPVC_COMPILER_OPTION_GLSL_ES: - options->glsl.es = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS: - options->glsl.vulkan_semantics = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_FLOAT_PRECISION_HIGHP: - options->glsl.fragment.default_float_precision = - value != 0 ? CompilerGLSL::Options::Precision::Highp : CompilerGLSL::Options::Precision::Mediump; - break; - case SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_INT_PRECISION_HIGHP: - options->glsl.fragment.default_int_precision = - value != 0 ? CompilerGLSL::Options::Precision::Highp : CompilerGLSL::Options::Precision::Mediump; - break; - case SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER: - options->glsl.emit_push_constant_as_uniform_buffer = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS: - options->glsl.emit_uniform_buffer_as_plain_uniforms = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS: - options->glsl.force_flattened_io_blocks = value != 0; - break; - case SPVC_COMPILER_OPTION_GLSL_OVR_MULTIVIEW_VIEW_COUNT: - options->glsl.ovr_multiview_view_count = value; - break; -#endif - -#if SPIRV_CROSS_C_API_HLSL - case SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL: - options->hlsl.shader_model = value; - break; - - case SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT: - options->hlsl.point_size_compat = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_POINT_COORD_COMPAT: - options->hlsl.point_coord_compat = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE: - options->hlsl.support_nonzero_base_vertex_base_instance = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV: - options->hlsl.force_storage_buffer_as_uav = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV: - options->hlsl.nonwritable_uav_texture_as_srv = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES: - options->hlsl.enable_16bit_types = value != 0; - break; - - case SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS: - options->hlsl.flatten_matrix_vertex_input_semantics = value != 0; - break; -#endif - -#if SPIRV_CROSS_C_API_MSL - case SPVC_COMPILER_OPTION_MSL_VERSION: - options->msl.msl_version = value; - break; - - case SPVC_COMPILER_OPTION_MSL_TEXEL_BUFFER_TEXTURE_WIDTH: - options->msl.texel_buffer_texture_width = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SWIZZLE_BUFFER_INDEX: - options->msl.swizzle_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_INDIRECT_PARAMS_BUFFER_INDEX: - options->msl.indirect_params_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_OUTPUT_BUFFER_INDEX: - options->msl.shader_output_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_OUTPUT_BUFFER_INDEX: - options->msl.shader_patch_output_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_TESS_FACTOR_OUTPUT_BUFFER_INDEX: - options->msl.shader_tess_factor_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_WORKGROUP_INDEX: - options->msl.shader_input_wg_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_BUILTIN: - options->msl.enable_point_size_builtin = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_DISABLE_RASTERIZATION: - options->msl.disable_rasterization = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_CAPTURE_OUTPUT_TO_BUFFER: - options->msl.capture_output_to_buffer = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_SWIZZLE_TEXTURE_SAMPLES: - options->msl.swizzle_texture_samples = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS: - options->msl.pad_fragment_output_components = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_TESS_DOMAIN_ORIGIN_LOWER_LEFT: - options->msl.tess_domain_origin_lower_left = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_PLATFORM: - options->msl.platform = static_cast(value); - break; - - case SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS: - options->msl.argument_buffers = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_TEXTURE_BUFFER_NATIVE: - options->msl.texture_buffer_native = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_BUFFER_SIZE_BUFFER_INDEX: - options->msl.buffer_size_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_MULTIVIEW: - options->msl.multiview = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX: - options->msl.view_mask_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX: - options->msl.device_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX: - options->msl.view_index_from_device_index = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE: - options->msl.dispatch_base = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX: - options->msl.dynamic_offsets_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D: - options->msl.texture_1D_as_2D = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO: - options->msl.enable_base_index_zero = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS: - options->msl.use_framebuffer_fetch_subpasses = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH: - options->msl.invariant_float_math = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY: - options->msl.emulate_cube_array = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING: - options->msl.enable_decoration_binding = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES: - options->msl.force_active_argument_buffer_resources = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS: - options->msl.force_native_arrays = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK: - options->msl.enable_frag_output_mask = value; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN: - options->msl.enable_frag_depth_builtin = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN: - options->msl.enable_frag_stencil_ref_builtin = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING: - options->msl.enable_clip_distance_user_varying = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP: - options->msl.multi_patch_workgroup = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX: - options->msl.shader_input_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX: - options->msl.shader_index_buffer_index = value; - break; - - case SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION: - options->msl.vertex_for_tessellation = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE: - options->msl.vertex_index_type = static_cast(value); - break; - - case SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING: - options->msl.multiview_layered_rendering = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT: - options->msl.arrayed_subpass_input = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT: - options->msl.r32ui_linear_texture_alignment = value; - break; - - case SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID: - options->msl.r32ui_alignment_constant_id = value; - break; - - case SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS: - options->msl.ios_use_simdgroup_functions = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS: - options->msl.emulate_subgroups = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE: - options->msl.fixed_subgroup_size = value; - break; - - case SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING: - options->msl.force_sample_rate_shading = value != 0; - break; - - case SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE: - options->msl.ios_support_base_vertex_instance = value != 0; - break; -#endif - - default: - options->context->report_error("Unknown option."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_install_compiler_options(spvc_compiler compiler, spvc_compiler_options options) -{ - (void)options; - switch (compiler->backend) - { -#if SPIRV_CROSS_C_API_GLSL - case SPVC_BACKEND_GLSL: - static_cast(*compiler->compiler).set_common_options(options->glsl); - break; -#endif - -#if SPIRV_CROSS_C_API_HLSL - case SPVC_BACKEND_HLSL: - static_cast(*compiler->compiler).set_common_options(options->glsl); - static_cast(*compiler->compiler).set_hlsl_options(options->hlsl); - break; -#endif - -#if SPIRV_CROSS_C_API_MSL - case SPVC_BACKEND_MSL: - static_cast(*compiler->compiler).set_common_options(options->glsl); - static_cast(*compiler->compiler).set_msl_options(options->msl); - break; -#endif - - default: - break; - } - - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_add_header_line(spvc_compiler compiler, const char *line) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - static_cast(compiler->compiler.get())->add_header_line(line); - return SPVC_SUCCESS; -#else - (void)line; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *line) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - static_cast(compiler->compiler.get())->require_extension(line); - return SPVC_SUCCESS; -#else - (void)line; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - static_cast(compiler->compiler.get())->flatten_buffer_block(id); - return SPVC_SUCCESS; -#else - (void)id; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - return static_cast(compiler->compiler.get())->variable_is_depth_or_compare(id) ? SPVC_TRUE : SPVC_FALSE; -#else - (void)id; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_FALSE; -#endif -} - -spvc_result spvc_compiler_mask_stage_output_by_location(spvc_compiler compiler, - unsigned location, unsigned component) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - static_cast(compiler->compiler.get())->mask_stage_output_by_location(location, component); - return SPVC_SUCCESS; -#else - (void)location; - (void)component; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_mask_stage_output_by_builtin(spvc_compiler compiler, SpvBuiltIn builtin) -{ -#if SPIRV_CROSS_C_API_GLSL - if (compiler->backend == SPVC_BACKEND_NONE) - { - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - static_cast(compiler->compiler.get())->mask_stage_output_by_builtin(spv::BuiltIn(builtin)); - return SPVC_SUCCESS; -#else - (void)builtin; - compiler->context->report_error("Cross-compilation related option used on NONE backend which only supports reflection."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler, - const spvc_hlsl_root_constants *constant_info, - size_t count) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &hlsl = *static_cast(compiler->compiler.get()); - vector roots; - roots.reserve(count); - for (size_t i = 0; i < count; i++) - { - RootConstants root; - root.binding = constant_info[i].binding; - root.space = constant_info[i].space; - root.start = constant_info[i].start; - root.end = constant_info[i].end; - roots.push_back(root); - } - - hlsl.set_root_constant_layouts(std::move(roots)); - return SPVC_SUCCESS; -#else - (void)constant_info; - (void)count; - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_hlsl_add_vertex_attribute_remap(spvc_compiler compiler, - const spvc_hlsl_vertex_attribute_remap *remap, - size_t count) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - HLSLVertexAttributeRemap re; - auto &hlsl = *static_cast(compiler->compiler.get()); - for (size_t i = 0; i < count; i++) - { - re.location = remap[i].location; - re.semantic = remap[i].semantic; - hlsl.add_vertex_attribute_remap(re); - } - - return SPVC_SUCCESS; -#else - (void)remap; - (void)count; - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return 0; - } - - auto &hlsl = *static_cast(compiler->compiler.get()); - return hlsl.remap_num_workgroups_builtin(); -#else - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return 0; -#endif -} - -spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler, - spvc_hlsl_binding_flags flags) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &hlsl = *static_cast(compiler->compiler.get()); - hlsl.set_resource_binding_flags(flags); - return SPVC_SUCCESS; -#else - (void)flags; - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler, - const spvc_hlsl_resource_binding *binding) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &hlsl = *static_cast(compiler->compiler.get()); - HLSLResourceBinding bind; - bind.binding = binding->binding; - bind.desc_set = binding->desc_set; - bind.stage = static_cast(binding->stage); - bind.cbv.register_binding = binding->cbv.register_binding; - bind.cbv.register_space = binding->cbv.register_space; - bind.uav.register_binding = binding->uav.register_binding; - bind.uav.register_space = binding->uav.register_space; - bind.srv.register_binding = binding->srv.register_binding; - bind.srv.register_space = binding->srv.register_space; - bind.sampler.register_binding = binding->sampler.register_binding; - bind.sampler.register_space = binding->sampler.register_space; - hlsl.add_hlsl_resource_binding(bind); - return SPVC_SUCCESS; -#else - (void)binding; - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set, - unsigned binding) -{ -#if SPIRV_CROSS_C_API_HLSL - if (compiler->backend != SPVC_BACKEND_HLSL) - { - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_FALSE; - } - - auto &hlsl = *static_cast(compiler->compiler.get()); - return hlsl.is_hlsl_resource_binding_used(static_cast(model), set, binding) ? SPVC_TRUE : - SPVC_FALSE; -#else - (void)model; - (void)set; - (void)binding; - compiler->context->report_error("HLSL function used on a non-HLSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.get_is_rasterization_disabled() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_needs_swizzle_buffer(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.needs_swizzle_buffer() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_needs_buffer_size_buffer(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.needs_buffer_size_buffer() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_needs_aux_buffer(spvc_compiler compiler) -{ - return spvc_compiler_msl_needs_swizzle_buffer(compiler); -} - -spvc_bool spvc_compiler_msl_needs_output_buffer(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.needs_output_buffer() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_needs_patch_output_buffer(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.needs_patch_output_buffer() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_needs_input_threadgroup_mem(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.needs_input_threadgroup_mem() ? SPVC_TRUE : SPVC_FALSE; -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, const spvc_msl_vertex_attribute *va) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLShaderInput attr; - attr.location = va->location; - attr.format = static_cast(va->format); - attr.builtin = static_cast(va->builtin); - msl.add_msl_shader_input(attr); - return SPVC_SUCCESS; -#else - (void)va; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, const spvc_msl_shader_input *si) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLShaderInput input; - input.location = si->location; - input.format = static_cast(si->format); - input.builtin = static_cast(si->builtin); - input.vecsize = si->vecsize; - msl.add_msl_shader_input(input); - return SPVC_SUCCESS; -#else - (void)si; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, - const spvc_msl_resource_binding *binding) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLResourceBinding bind; - bind.binding = binding->binding; - bind.desc_set = binding->desc_set; - bind.stage = static_cast(binding->stage); - bind.msl_buffer = binding->msl_buffer; - bind.msl_texture = binding->msl_texture; - bind.msl_sampler = binding->msl_sampler; - msl.add_msl_resource_binding(bind); - return SPVC_SUCCESS; -#else - (void)binding; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.add_dynamic_buffer(desc_set, binding, index); - return SPVC_SUCCESS; -#else - (void)binding; - (void)desc_set; - (void)index; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.add_inline_uniform_block(desc_set, binding); - return SPVC_SUCCESS; -#else - (void)binding; - (void)desc_set; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.add_discrete_descriptor_set(desc_set); - return SPVC_SUCCESS; -#else - (void)desc_set; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.set_argument_buffer_device_address_space(desc_set, bool(device_address)); - return SPVC_SUCCESS; -#else - (void)desc_set; - (void)device_address; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_bool spvc_compiler_msl_is_shader_input_used(spvc_compiler compiler, unsigned location) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.is_msl_shader_input_used(location) ? SPVC_TRUE : SPVC_FALSE; -#else - (void)location; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location) -{ - return spvc_compiler_msl_is_shader_input_used(compiler, location); -} - -spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, SpvExecutionModel model, unsigned set, - unsigned binding) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.is_msl_resource_binding_used(static_cast(model), set, binding) ? SPVC_TRUE : - SPVC_FALSE; -#else - (void)model; - (void)set; - (void)binding; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_FALSE; -#endif -} - -spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.set_combined_sampler_suffix(suffix); - return SPVC_SUCCESS; -#else - (void)suffix; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return ""; - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.get_combined_sampler_suffix(); -#else - compiler->context->report_error("MSL function used on a non-MSL backend."); - return ""; -#endif -} - -#if SPIRV_CROSS_C_API_MSL -static void spvc_convert_msl_sampler(MSLConstexprSampler &samp, const spvc_msl_constexpr_sampler *sampler) -{ - samp.s_address = static_cast(sampler->s_address); - samp.t_address = static_cast(sampler->t_address); - samp.r_address = static_cast(sampler->r_address); - samp.lod_clamp_min = sampler->lod_clamp_min; - samp.lod_clamp_max = sampler->lod_clamp_max; - samp.lod_clamp_enable = sampler->lod_clamp_enable != 0; - samp.min_filter = static_cast(sampler->min_filter); - samp.mag_filter = static_cast(sampler->mag_filter); - samp.mip_filter = static_cast(sampler->mip_filter); - samp.compare_enable = sampler->compare_enable != 0; - samp.anisotropy_enable = sampler->anisotropy_enable != 0; - samp.max_anisotropy = sampler->max_anisotropy; - samp.compare_func = static_cast(sampler->compare_func); - samp.coord = static_cast(sampler->coord); - samp.border_color = static_cast(sampler->border_color); -} - -static void spvc_convert_msl_sampler_ycbcr_conversion(MSLConstexprSampler &samp, const spvc_msl_sampler_ycbcr_conversion *conv) -{ - samp.ycbcr_conversion_enable = conv != nullptr; - if (conv == nullptr) return; - samp.planes = conv->planes; - samp.resolution = static_cast(conv->resolution); - samp.chroma_filter = static_cast(conv->chroma_filter); - samp.x_chroma_offset = static_cast(conv->x_chroma_offset); - samp.y_chroma_offset = static_cast(conv->y_chroma_offset); - for (int i = 0; i < 4; i++) - samp.swizzle[i] = static_cast(conv->swizzle[i]); - samp.ycbcr_model = static_cast(conv->ycbcr_model); - samp.ycbcr_range = static_cast(conv->ycbcr_range); - samp.bpc = conv->bpc; -} -#endif - -spvc_result spvc_compiler_msl_remap_constexpr_sampler(spvc_compiler compiler, spvc_variable_id id, - const spvc_msl_constexpr_sampler *sampler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLConstexprSampler samp; - spvc_convert_msl_sampler(samp, sampler); - msl.remap_constexpr_sampler(id, samp); - return SPVC_SUCCESS; -#else - (void)id; - (void)sampler; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding(spvc_compiler compiler, - unsigned desc_set, unsigned binding, - const spvc_msl_constexpr_sampler *sampler) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLConstexprSampler samp; - spvc_convert_msl_sampler(samp, sampler); - msl.remap_constexpr_sampler_by_binding(desc_set, binding, samp); - return SPVC_SUCCESS; -#else - (void)desc_set; - (void)binding; - (void)sampler; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_remap_constexpr_sampler_ycbcr(spvc_compiler compiler, spvc_variable_id id, - const spvc_msl_constexpr_sampler *sampler, - const spvc_msl_sampler_ycbcr_conversion *conv) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLConstexprSampler samp; - spvc_convert_msl_sampler(samp, sampler); - spvc_convert_msl_sampler_ycbcr_conversion(samp, conv); - msl.remap_constexpr_sampler(id, samp); - return SPVC_SUCCESS; -#else - (void)id; - (void)sampler; - (void)conv; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(spvc_compiler compiler, - unsigned desc_set, unsigned binding, - const spvc_msl_constexpr_sampler *sampler, - const spvc_msl_sampler_ycbcr_conversion *conv) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - MSLConstexprSampler samp; - spvc_convert_msl_sampler(samp, sampler); - spvc_convert_msl_sampler_ycbcr_conversion(samp, conv); - msl.remap_constexpr_sampler_by_binding(desc_set, binding, samp); - return SPVC_SUCCESS; -#else - (void)desc_set; - (void)binding; - (void)sampler; - (void)conv; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -spvc_result spvc_compiler_msl_set_fragment_output_components(spvc_compiler compiler, unsigned location, - unsigned components) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - auto &msl = *static_cast(compiler->compiler.get()); - msl.set_fragment_output_components(location, components); - return SPVC_SUCCESS; -#else - (void)location; - (void)components; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return SPVC_ERROR_INVALID_ARGUMENT; -#endif -} - -unsigned spvc_compiler_msl_get_automatic_resource_binding(spvc_compiler compiler, spvc_variable_id id) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return uint32_t(-1); - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.get_automatic_msl_resource_binding(id); -#else - (void)id; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return uint32_t(-1); -#endif -} - -unsigned spvc_compiler_msl_get_automatic_resource_binding_secondary(spvc_compiler compiler, spvc_variable_id id) -{ -#if SPIRV_CROSS_C_API_MSL - if (compiler->backend != SPVC_BACKEND_MSL) - { - compiler->context->report_error("MSL function used on a non-MSL backend."); - return uint32_t(-1); - } - - auto &msl = *static_cast(compiler->compiler.get()); - return msl.get_automatic_msl_resource_binding_secondary(id); -#else - (void)id; - compiler->context->report_error("MSL function used on a non-MSL backend."); - return uint32_t(-1); -#endif -} - -spvc_result spvc_compiler_compile(spvc_compiler compiler, const char **source) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto result = compiler->compiler->compile(); - if (result.empty()) - { - compiler->context->report_error("Unsupported SPIR-V."); - return SPVC_ERROR_UNSUPPORTED_SPIRV; - } - - *source = compiler->context->allocate_name(result); - if (!*source) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - return SPVC_SUCCESS; - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_UNSUPPORTED_SPIRV) -} - -bool spvc_resources_s::copy_resources(SmallVector &outputs, - const SmallVector &inputs) -{ - for (auto &i : inputs) - { - spvc_reflected_resource r; - r.base_type_id = i.base_type_id; - r.type_id = i.type_id; - r.id = i.id; - r.name = context->allocate_name(i.name); - if (!r.name) - return false; - - outputs.push_back(r); - } - - return true; -} - -bool spvc_resources_s::copy_resources(SmallVector &outputs, - const SmallVector &inputs) -{ - for (auto &i : inputs) - { - spvc_reflected_builtin_resource br; - - br.value_type_id = i.value_type_id; - br.builtin = SpvBuiltIn(i.builtin); - - auto &r = br.resource; - r.base_type_id = i.resource.base_type_id; - r.type_id = i.resource.type_id; - r.id = i.resource.id; - r.name = context->allocate_name(i.resource.name); - if (!r.name) - return false; - - outputs.push_back(br); - } - - return true; -} - -bool spvc_resources_s::copy_resources(const ShaderResources &resources) -{ - if (!copy_resources(uniform_buffers, resources.uniform_buffers)) - return false; - if (!copy_resources(storage_buffers, resources.storage_buffers)) - return false; - if (!copy_resources(stage_inputs, resources.stage_inputs)) - return false; - if (!copy_resources(stage_outputs, resources.stage_outputs)) - return false; - if (!copy_resources(subpass_inputs, resources.subpass_inputs)) - return false; - if (!copy_resources(storage_images, resources.storage_images)) - return false; - if (!copy_resources(sampled_images, resources.sampled_images)) - return false; - if (!copy_resources(atomic_counters, resources.atomic_counters)) - return false; - if (!copy_resources(push_constant_buffers, resources.push_constant_buffers)) - return false; - if (!copy_resources(separate_images, resources.separate_images)) - return false; - if (!copy_resources(separate_samplers, resources.separate_samplers)) - return false; - if (!copy_resources(acceleration_structures, resources.acceleration_structures)) - return false; - if (!copy_resources(builtin_inputs, resources.builtin_inputs)) - return false; - if (!copy_resources(builtin_outputs, resources.builtin_outputs)) - return false; - - return true; -} - -spvc_result spvc_compiler_get_active_interface_variables(spvc_compiler compiler, spvc_set *set) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr ptr(new (std::nothrow) spvc_set_s); - if (!ptr) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - auto active = compiler->compiler->get_active_interface_variables(); - ptr->set = std::move(active); - *set = ptr.get(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_set_enabled_interface_variables(spvc_compiler compiler, spvc_set set) -{ - SPVC_BEGIN_SAFE_SCOPE - { - compiler->compiler->set_enabled_interface_variables(set->set); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_create_shader_resources_for_active_variables(spvc_compiler compiler, spvc_resources *resources, - spvc_set set) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr res(new (std::nothrow) spvc_resources_s); - if (!res) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - res->context = compiler->context; - auto accessed_resources = compiler->compiler->get_shader_resources(set->set); - - if (!res->copy_resources(accessed_resources)) - { - res->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - *resources = res.get(); - compiler->context->allocations.push_back(std::move(res)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_create_shader_resources(spvc_compiler compiler, spvc_resources *resources) -{ - SPVC_BEGIN_SAFE_SCOPE - { - std::unique_ptr res(new (std::nothrow) spvc_resources_s); - if (!res) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - res->context = compiler->context; - auto accessed_resources = compiler->compiler->get_shader_resources(); - - if (!res->copy_resources(accessed_resources)) - { - res->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - - *resources = res.get(); - compiler->context->allocations.push_back(std::move(res)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_resources_get_resource_list_for_type(spvc_resources resources, spvc_resource_type type, - const spvc_reflected_resource **resource_list, - size_t *resource_size) -{ - const SmallVector *list = nullptr; - switch (type) - { - case SPVC_RESOURCE_TYPE_UNIFORM_BUFFER: - list = &resources->uniform_buffers; - break; - - case SPVC_RESOURCE_TYPE_STORAGE_BUFFER: - list = &resources->storage_buffers; - break; - - case SPVC_RESOURCE_TYPE_STAGE_INPUT: - list = &resources->stage_inputs; - break; - - case SPVC_RESOURCE_TYPE_STAGE_OUTPUT: - list = &resources->stage_outputs; - break; - - case SPVC_RESOURCE_TYPE_SUBPASS_INPUT: - list = &resources->subpass_inputs; - break; - - case SPVC_RESOURCE_TYPE_STORAGE_IMAGE: - list = &resources->storage_images; - break; - - case SPVC_RESOURCE_TYPE_SAMPLED_IMAGE: - list = &resources->sampled_images; - break; - - case SPVC_RESOURCE_TYPE_ATOMIC_COUNTER: - list = &resources->atomic_counters; - break; - - case SPVC_RESOURCE_TYPE_PUSH_CONSTANT: - list = &resources->push_constant_buffers; - break; - - case SPVC_RESOURCE_TYPE_SEPARATE_IMAGE: - list = &resources->separate_images; - break; - - case SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS: - list = &resources->separate_samplers; - break; - - case SPVC_RESOURCE_TYPE_ACCELERATION_STRUCTURE: - list = &resources->acceleration_structures; - break; - - default: - break; - } - - if (!list) - { - resources->context->report_error("Invalid argument."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - *resource_size = list->size(); - *resource_list = list->data(); - return SPVC_SUCCESS; -} - -spvc_result spvc_resources_get_builtin_resource_list_for_type( - spvc_resources resources, spvc_builtin_resource_type type, - const spvc_reflected_builtin_resource **resource_list, - size_t *resource_size) -{ - const SmallVector *list = nullptr; - switch (type) - { - case SPVC_BUILTIN_RESOURCE_TYPE_STAGE_INPUT: - list = &resources->builtin_inputs; - break; - - case SPVC_BUILTIN_RESOURCE_TYPE_STAGE_OUTPUT: - list = &resources->builtin_outputs; - break; - - default: - break; - } - - if (!list) - { - resources->context->report_error("Invalid argument."); - return SPVC_ERROR_INVALID_ARGUMENT; - } - - *resource_size = list->size(); - *resource_list = list->data(); - return SPVC_SUCCESS; -} - -void spvc_compiler_set_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration, unsigned argument) -{ - compiler->compiler->set_decoration(id, static_cast(decoration), argument); -} - -void spvc_compiler_set_decoration_string(spvc_compiler compiler, SpvId id, SpvDecoration decoration, - const char *argument) -{ - compiler->compiler->set_decoration_string(id, static_cast(decoration), argument); -} - -void spvc_compiler_set_name(spvc_compiler compiler, SpvId id, const char *argument) -{ - compiler->compiler->set_name(id, argument); -} - -void spvc_compiler_set_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration, unsigned argument) -{ - compiler->compiler->set_member_decoration(id, member_index, static_cast(decoration), argument); -} - -void spvc_compiler_set_member_decoration_string(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration, const char *argument) -{ - compiler->compiler->set_member_decoration_string(id, member_index, static_cast(decoration), - argument); -} - -void spvc_compiler_set_member_name(spvc_compiler compiler, spvc_type_id id, unsigned member_index, const char *argument) -{ - compiler->compiler->set_member_name(id, member_index, argument); -} - -void spvc_compiler_unset_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration) -{ - compiler->compiler->unset_decoration(id, static_cast(decoration)); -} - -void spvc_compiler_unset_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration) -{ - compiler->compiler->unset_member_decoration(id, member_index, static_cast(decoration)); -} - -spvc_bool spvc_compiler_has_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration) -{ - return compiler->compiler->has_decoration(id, static_cast(decoration)) ? SPVC_TRUE : SPVC_FALSE; -} - -spvc_bool spvc_compiler_has_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration) -{ - return compiler->compiler->has_member_decoration(id, member_index, static_cast(decoration)) ? - SPVC_TRUE : - SPVC_FALSE; -} - -const char *spvc_compiler_get_name(spvc_compiler compiler, SpvId id) -{ - return compiler->compiler->get_name(id).c_str(); -} - -unsigned spvc_compiler_get_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration) -{ - return compiler->compiler->get_decoration(id, static_cast(decoration)); -} - -const char *spvc_compiler_get_decoration_string(spvc_compiler compiler, SpvId id, SpvDecoration decoration) -{ - return compiler->compiler->get_decoration_string(id, static_cast(decoration)).c_str(); -} - -unsigned spvc_compiler_get_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration) -{ - return compiler->compiler->get_member_decoration(id, member_index, static_cast(decoration)); -} - -const char *spvc_compiler_get_member_decoration_string(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration) -{ - return compiler->compiler->get_member_decoration_string(id, member_index, static_cast(decoration)) - .c_str(); -} - -const char *spvc_compiler_get_member_name(spvc_compiler compiler, spvc_type_id id, unsigned member_index) -{ - return compiler->compiler->get_member_name(id, member_index).c_str(); -} - -spvc_result spvc_compiler_get_entry_points(spvc_compiler compiler, const spvc_entry_point **entry_points, - size_t *num_entry_points) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto entries = compiler->compiler->get_entry_points_and_stages(); - SmallVector translated; - translated.reserve(entries.size()); - - for (auto &entry : entries) - { - spvc_entry_point new_entry; - new_entry.execution_model = static_cast(entry.execution_model); - new_entry.name = compiler->context->allocate_name(entry.name); - if (!new_entry.name) - { - compiler->context->report_error("Out of memory."); - return SPVC_ERROR_OUT_OF_MEMORY; - } - translated.push_back(new_entry); - } - - auto ptr = spvc_allocate>(); - ptr->buffer = std::move(translated); - *entry_points = ptr->buffer.data(); - *num_entry_points = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_set_entry_point(spvc_compiler compiler, const char *name, SpvExecutionModel model) -{ - compiler->compiler->set_entry_point(name, static_cast(model)); - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_rename_entry_point(spvc_compiler compiler, const char *old_name, const char *new_name, - SpvExecutionModel model) -{ - SPVC_BEGIN_SAFE_SCOPE - { - compiler->compiler->rename_entry_point(old_name, new_name, static_cast(model)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -const char *spvc_compiler_get_cleansed_entry_point_name(spvc_compiler compiler, const char *name, - SpvExecutionModel model) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto cleansed_name = - compiler->compiler->get_cleansed_entry_point_name(name, static_cast(model)); - return compiler->context->allocate_name(cleansed_name); - } - SPVC_END_SAFE_SCOPE(compiler->context, nullptr) -} - -void spvc_compiler_set_execution_mode(spvc_compiler compiler, SpvExecutionMode mode) -{ - compiler->compiler->set_execution_mode(static_cast(mode)); -} - -void spvc_compiler_set_execution_mode_with_arguments(spvc_compiler compiler, SpvExecutionMode mode, unsigned arg0, - unsigned arg1, - unsigned arg2) -{ - compiler->compiler->set_execution_mode(static_cast(mode), arg0, arg1, arg2); -} - -void spvc_compiler_unset_execution_mode(spvc_compiler compiler, SpvExecutionMode mode) -{ - compiler->compiler->unset_execution_mode(static_cast(mode)); -} - -spvc_result spvc_compiler_get_execution_modes(spvc_compiler compiler, const SpvExecutionMode **modes, size_t *num_modes) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto ptr = spvc_allocate>(); - - compiler->compiler->get_execution_mode_bitset().for_each_bit( - [&](uint32_t bit) { ptr->buffer.push_back(static_cast(bit)); }); - - *modes = ptr->buffer.data(); - *num_modes = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -unsigned spvc_compiler_get_execution_mode_argument(spvc_compiler compiler, SpvExecutionMode mode) -{ - return compiler->compiler->get_execution_mode_argument(static_cast(mode)); -} - -unsigned spvc_compiler_get_execution_mode_argument_by_index(spvc_compiler compiler, SpvExecutionMode mode, - unsigned index) -{ - return compiler->compiler->get_execution_mode_argument(static_cast(mode), index); -} - -SpvExecutionModel spvc_compiler_get_execution_model(spvc_compiler compiler) -{ - return static_cast(compiler->compiler->get_execution_model()); -} - -void spvc_compiler_update_active_builtins(spvc_compiler compiler) -{ - compiler->compiler->update_active_builtins(); -} - -spvc_bool spvc_compiler_has_active_builtin(spvc_compiler compiler, SpvBuiltIn builtin, SpvStorageClass storage) -{ - return compiler->compiler->has_active_builtin(static_cast(builtin), static_cast(storage)) ? - SPVC_TRUE : - SPVC_FALSE; -} - -spvc_type spvc_compiler_get_type_handle(spvc_compiler compiler, spvc_type_id id) -{ - // Should only throw if an intentionally garbage ID is passed, but the IDs are not type-safe. - SPVC_BEGIN_SAFE_SCOPE - { - return static_cast(&compiler->compiler->get_type(id)); - } - SPVC_END_SAFE_SCOPE(compiler->context, nullptr) -} - -spvc_type_id spvc_type_get_base_type_id(spvc_type type) -{ - return type->self; -} - -static spvc_basetype convert_basetype(SPIRType::BaseType type) -{ - // For now the enums match up. - return static_cast(type); -} - -spvc_basetype spvc_type_get_basetype(spvc_type type) -{ - return convert_basetype(type->basetype); -} - -unsigned spvc_type_get_bit_width(spvc_type type) -{ - return type->width; -} - -unsigned spvc_type_get_vector_size(spvc_type type) -{ - return type->vecsize; -} - -unsigned spvc_type_get_columns(spvc_type type) -{ - return type->columns; -} - -unsigned spvc_type_get_num_array_dimensions(spvc_type type) -{ - return unsigned(type->array.size()); -} - -spvc_bool spvc_type_array_dimension_is_literal(spvc_type type, unsigned dimension) -{ - return type->array_size_literal[dimension] ? SPVC_TRUE : SPVC_FALSE; -} - -SpvId spvc_type_get_array_dimension(spvc_type type, unsigned dimension) -{ - return type->array[dimension]; -} - -unsigned spvc_type_get_num_member_types(spvc_type type) -{ - return unsigned(type->member_types.size()); -} - -spvc_type_id spvc_type_get_member_type(spvc_type type, unsigned index) -{ - return type->member_types[index]; -} - -SpvStorageClass spvc_type_get_storage_class(spvc_type type) -{ - return static_cast(type->storage); -} - -// Image type query. -spvc_type_id spvc_type_get_image_sampled_type(spvc_type type) -{ - return type->image.type; -} - -SpvDim spvc_type_get_image_dimension(spvc_type type) -{ - return static_cast(type->image.dim); -} - -spvc_bool spvc_type_get_image_is_depth(spvc_type type) -{ - return type->image.depth ? SPVC_TRUE : SPVC_FALSE; -} - -spvc_bool spvc_type_get_image_arrayed(spvc_type type) -{ - return type->image.arrayed ? SPVC_TRUE : SPVC_FALSE; -} - -spvc_bool spvc_type_get_image_multisampled(spvc_type type) -{ - return type->image.ms ? SPVC_TRUE : SPVC_FALSE; -} - -spvc_bool spvc_type_get_image_is_storage(spvc_type type) -{ - return type->image.sampled == 2 ? SPVC_TRUE : SPVC_FALSE; -} - -SpvImageFormat spvc_type_get_image_storage_format(spvc_type type) -{ - return static_cast(static_cast(type)->image.format); -} - -SpvAccessQualifier spvc_type_get_image_access_qualifier(spvc_type type) -{ - return static_cast(static_cast(type)->image.access); -} - -spvc_result spvc_compiler_get_declared_struct_size(spvc_compiler compiler, spvc_type struct_type, size_t *size) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *size = compiler->compiler->get_declared_struct_size(*static_cast(struct_type)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_get_declared_struct_size_runtime_array(spvc_compiler compiler, spvc_type struct_type, - size_t array_size, size_t *size) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *size = compiler->compiler->get_declared_struct_size_runtime_array(*static_cast(struct_type), - array_size); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_get_declared_struct_member_size(spvc_compiler compiler, spvc_type struct_type, unsigned index, size_t *size) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *size = compiler->compiler->get_declared_struct_member_size(*static_cast(struct_type), index); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_type_struct_member_offset(spvc_compiler compiler, spvc_type type, unsigned index, unsigned *offset) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *offset = compiler->compiler->type_struct_member_offset(*static_cast(type), index); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_type_struct_member_array_stride(spvc_compiler compiler, spvc_type type, unsigned index, unsigned *stride) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *stride = compiler->compiler->type_struct_member_array_stride(*static_cast(type), index); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_type_struct_member_matrix_stride(spvc_compiler compiler, spvc_type type, unsigned index, unsigned *stride) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *stride = compiler->compiler->type_struct_member_matrix_stride(*static_cast(type), index); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_build_dummy_sampler_for_combined_images(spvc_compiler compiler, spvc_variable_id *id) -{ - SPVC_BEGIN_SAFE_SCOPE - { - *id = compiler->compiler->build_dummy_sampler_for_combined_images(); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_build_combined_image_samplers(spvc_compiler compiler) -{ - SPVC_BEGIN_SAFE_SCOPE - { - compiler->compiler->build_combined_image_samplers(); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_UNSUPPORTED_SPIRV) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_get_combined_image_samplers(spvc_compiler compiler, - const spvc_combined_image_sampler **samplers, - size_t *num_samplers) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto combined = compiler->compiler->get_combined_image_samplers(); - SmallVector translated; - translated.reserve(combined.size()); - for (auto &c : combined) - { - spvc_combined_image_sampler trans = { c.combined_id, c.image_id, c.sampler_id }; - translated.push_back(trans); - } - - auto ptr = spvc_allocate>(); - ptr->buffer = std::move(translated); - *samplers = ptr->buffer.data(); - *num_samplers = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_get_specialization_constants(spvc_compiler compiler, - const spvc_specialization_constant **constants, - size_t *num_constants) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto spec_constants = compiler->compiler->get_specialization_constants(); - SmallVector translated; - translated.reserve(spec_constants.size()); - for (auto &c : spec_constants) - { - spvc_specialization_constant trans = { c.id, c.constant_id }; - translated.push_back(trans); - } - - auto ptr = spvc_allocate>(); - ptr->buffer = std::move(translated); - *constants = ptr->buffer.data(); - *num_constants = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -spvc_constant spvc_compiler_get_constant_handle(spvc_compiler compiler, spvc_variable_id id) -{ - SPVC_BEGIN_SAFE_SCOPE - { - return static_cast(&compiler->compiler->get_constant(id)); - } - SPVC_END_SAFE_SCOPE(compiler->context, nullptr) -} - -spvc_constant_id spvc_compiler_get_work_group_size_specialization_constants(spvc_compiler compiler, - spvc_specialization_constant *x, - spvc_specialization_constant *y, - spvc_specialization_constant *z) -{ - SpecializationConstant tmpx; - SpecializationConstant tmpy; - SpecializationConstant tmpz; - spvc_constant_id ret = compiler->compiler->get_work_group_size_specialization_constants(tmpx, tmpy, tmpz); - x->id = tmpx.id; - x->constant_id = tmpx.constant_id; - y->id = tmpy.id; - y->constant_id = tmpy.constant_id; - z->id = tmpz.id; - z->constant_id = tmpz.constant_id; - return ret; -} - -spvc_result spvc_compiler_get_active_buffer_ranges(spvc_compiler compiler, - spvc_variable_id id, - const spvc_buffer_range **ranges, - size_t *num_ranges) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto active_ranges = compiler->compiler->get_active_buffer_ranges(id); - SmallVector translated; - translated.reserve(active_ranges.size()); - for (auto &r : active_ranges) - { - spvc_buffer_range trans = { r.index, r.offset, r.range }; - translated.push_back(trans); - } - - auto ptr = spvc_allocate>(); - ptr->buffer = std::move(translated); - *ranges = ptr->buffer.data(); - *num_ranges = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -float spvc_constant_get_scalar_fp16(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_f16(column, row); -} - -float spvc_constant_get_scalar_fp32(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_f32(column, row); -} - -double spvc_constant_get_scalar_fp64(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_f64(column, row); -} - -unsigned spvc_constant_get_scalar_u32(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar(column, row); -} - -int spvc_constant_get_scalar_i32(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_i32(column, row); -} - -unsigned spvc_constant_get_scalar_u16(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_u16(column, row); -} - -int spvc_constant_get_scalar_i16(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_i16(column, row); -} - -unsigned spvc_constant_get_scalar_u8(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_u8(column, row); -} - -int spvc_constant_get_scalar_i8(spvc_constant constant, unsigned column, unsigned row) -{ - return constant->scalar_i8(column, row); -} - -void spvc_constant_get_subconstants(spvc_constant constant, const spvc_constant_id **constituents, size_t *count) -{ - static_assert(sizeof(spvc_constant_id) == sizeof(constant->subconstants.front()), "ID size is not consistent."); - *constituents = reinterpret_cast(constant->subconstants.data()); - *count = constant->subconstants.size(); -} - -spvc_type_id spvc_constant_get_type(spvc_constant constant) -{ - return constant->constant_type; -} - -spvc_bool spvc_compiler_get_binary_offset_for_decoration(spvc_compiler compiler, spvc_variable_id id, - SpvDecoration decoration, - unsigned *word_offset) -{ - uint32_t off = 0; - bool ret = compiler->compiler->get_binary_offset_for_decoration(id, static_cast(decoration), off); - if (ret) - { - *word_offset = off; - return SPVC_TRUE; - } - else - return SPVC_FALSE; -} - -spvc_bool spvc_compiler_buffer_is_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id) -{ - return compiler->compiler->buffer_is_hlsl_counter_buffer(id) ? SPVC_TRUE : SPVC_FALSE; -} - -spvc_bool spvc_compiler_buffer_get_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id, - spvc_variable_id *counter_id) -{ - uint32_t buffer; - bool ret = compiler->compiler->buffer_get_hlsl_counter_buffer(id, buffer); - if (ret) - { - *counter_id = buffer; - return SPVC_TRUE; - } - else - return SPVC_FALSE; -} - -spvc_result spvc_compiler_get_declared_capabilities(spvc_compiler compiler, const SpvCapability **capabilities, - size_t *num_capabilities) -{ - auto &caps = compiler->compiler->get_declared_capabilities(); - static_assert(sizeof(SpvCapability) == sizeof(spv::Capability), "Enum size mismatch."); - *capabilities = reinterpret_cast(caps.data()); - *num_capabilities = caps.size(); - return SPVC_SUCCESS; -} - -spvc_result spvc_compiler_get_declared_extensions(spvc_compiler compiler, const char ***extensions, - size_t *num_extensions) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto &exts = compiler->compiler->get_declared_extensions(); - SmallVector duped; - duped.reserve(exts.size()); - for (auto &ext : exts) - duped.push_back(compiler->context->allocate_name(ext)); - - auto ptr = spvc_allocate>(); - ptr->buffer = std::move(duped); - *extensions = ptr->buffer.data(); - *num_extensions = ptr->buffer.size(); - compiler->context->allocations.push_back(std::move(ptr)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_OUT_OF_MEMORY) - return SPVC_SUCCESS; -} - -const char *spvc_compiler_get_remapped_declared_block_name(spvc_compiler compiler, spvc_variable_id id) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto name = compiler->compiler->get_remapped_declared_block_name(id); - return compiler->context->allocate_name(name); - } - SPVC_END_SAFE_SCOPE(compiler->context, nullptr) -} - -spvc_result spvc_compiler_get_buffer_block_decorations(spvc_compiler compiler, spvc_variable_id id, - const SpvDecoration **decorations, size_t *num_decorations) -{ - SPVC_BEGIN_SAFE_SCOPE - { - auto flags = compiler->compiler->get_buffer_block_flags(id); - auto bitset = spvc_allocate>(); - - flags.for_each_bit([&](uint32_t bit) { bitset->buffer.push_back(static_cast(bit)); }); - - *decorations = bitset->buffer.data(); - *num_decorations = bitset->buffer.size(); - compiler->context->allocations.push_back(std::move(bitset)); - } - SPVC_END_SAFE_SCOPE(compiler->context, SPVC_ERROR_INVALID_ARGUMENT) - return SPVC_SUCCESS; -} - -unsigned spvc_msl_get_aux_buffer_struct_version(void) -{ - return SPVC_MSL_AUX_BUFFER_STRUCT_VERSION; -} - -void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr) -{ -#if SPIRV_CROSS_C_API_MSL - // Crude, but works. - MSLShaderInput attr_default; - attr->location = attr_default.location; - attr->format = static_cast(attr_default.format); - attr->builtin = static_cast(attr_default.builtin); -#else - memset(attr, 0, sizeof(*attr)); -#endif -} - -void spvc_msl_shader_input_init(spvc_msl_shader_input *input) -{ -#if SPIRV_CROSS_C_API_MSL - MSLShaderInput input_default; - input->location = input_default.location; - input->format = static_cast(input_default.format); - input->builtin = static_cast(input_default.builtin); - input->vecsize = input_default.vecsize; -#else - memset(input, 0, sizeof(*input)); -#endif -} - -void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding) -{ -#if SPIRV_CROSS_C_API_MSL - MSLResourceBinding binding_default; - binding->desc_set = binding_default.desc_set; - binding->binding = binding_default.binding; - binding->msl_buffer = binding_default.msl_buffer; - binding->msl_texture = binding_default.msl_texture; - binding->msl_sampler = binding_default.msl_sampler; - binding->stage = static_cast(binding_default.stage); -#else - memset(binding, 0, sizeof(*binding)); -#endif -} - -void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding) -{ -#if SPIRV_CROSS_C_API_HLSL - HLSLResourceBinding binding_default; - binding->desc_set = binding_default.desc_set; - binding->binding = binding_default.binding; - binding->cbv.register_binding = binding_default.cbv.register_binding; - binding->cbv.register_space = binding_default.cbv.register_space; - binding->srv.register_binding = binding_default.srv.register_binding; - binding->srv.register_space = binding_default.srv.register_space; - binding->uav.register_binding = binding_default.uav.register_binding; - binding->uav.register_space = binding_default.uav.register_space; - binding->sampler.register_binding = binding_default.sampler.register_binding; - binding->sampler.register_space = binding_default.sampler.register_space; - binding->stage = static_cast(binding_default.stage); -#else - memset(binding, 0, sizeof(*binding)); -#endif -} - -void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler) -{ -#if SPIRV_CROSS_C_API_MSL - MSLConstexprSampler defaults; - sampler->anisotropy_enable = defaults.anisotropy_enable ? SPVC_TRUE : SPVC_FALSE; - sampler->border_color = static_cast(defaults.border_color); - sampler->compare_enable = defaults.compare_enable ? SPVC_TRUE : SPVC_FALSE; - sampler->coord = static_cast(defaults.coord); - sampler->compare_func = static_cast(defaults.compare_func); - sampler->lod_clamp_enable = defaults.lod_clamp_enable ? SPVC_TRUE : SPVC_FALSE; - sampler->lod_clamp_max = defaults.lod_clamp_max; - sampler->lod_clamp_min = defaults.lod_clamp_min; - sampler->mag_filter = static_cast(defaults.mag_filter); - sampler->min_filter = static_cast(defaults.min_filter); - sampler->mip_filter = static_cast(defaults.mip_filter); - sampler->max_anisotropy = defaults.max_anisotropy; - sampler->s_address = static_cast(defaults.s_address); - sampler->t_address = static_cast(defaults.t_address); - sampler->r_address = static_cast(defaults.r_address); -#else - memset(sampler, 0, sizeof(*sampler)); -#endif -} - -void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycbcr_conversion *conv) -{ -#if SPIRV_CROSS_C_API_MSL - MSLConstexprSampler defaults; - conv->planes = defaults.planes; - conv->resolution = static_cast(defaults.resolution); - conv->chroma_filter = static_cast(defaults.chroma_filter); - conv->x_chroma_offset = static_cast(defaults.x_chroma_offset); - conv->y_chroma_offset = static_cast(defaults.y_chroma_offset); - for (int i = 0; i < 4; i++) - conv->swizzle[i] = static_cast(defaults.swizzle[i]); - conv->ycbcr_model = static_cast(defaults.ycbcr_model); - conv->ycbcr_range = static_cast(defaults.ycbcr_range); -#else - memset(conv, 0, sizeof(*conv)); -#endif -} - -unsigned spvc_compiler_get_current_id_bound(spvc_compiler compiler) -{ - return compiler->compiler->get_current_id_bound(); -} - -void spvc_get_version(unsigned *major, unsigned *minor, unsigned *patch) -{ - *major = SPVC_C_API_VERSION_MAJOR; - *minor = SPVC_C_API_VERSION_MINOR; - *patch = SPVC_C_API_VERSION_PATCH; -} - -const char *spvc_get_commit_revision_and_timestamp(void) -{ -#ifdef HAVE_SPIRV_CROSS_GIT_VERSION - return SPIRV_CROSS_GIT_REVISION; -#else - return ""; -#endif -} - -#ifdef _MSC_VER -#pragma warning(pop) -#endif diff --git a/src/libraries/spirv_cross/spirv_cross_c.h b/src/libraries/spirv_cross/spirv_cross_c.h deleted file mode 100644 index a590c805a..000000000 --- a/src/libraries/spirv_cross/spirv_cross_c.h +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * Copyright 2019-2021 Hans-Kristian Arntzen - * SPDX-License-Identifier: Apache-2.0 OR MIT - * - * 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. - */ - -/* - * At your option, you may choose to accept this material under either: - * 1. The Apache License, Version 2.0, found at , or - * 2. The MIT License, found at . - */ - -#ifndef SPIRV_CROSS_C_API_H -#define SPIRV_CROSS_C_API_H - -#include -#include "spirv.h" - -/* - * C89-compatible wrapper for SPIRV-Cross' API. - * Documentation here is sparse unless the behavior does not map 1:1 with C++ API. - * It is recommended to look at the canonical C++ API for more detailed information. - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* Bumped if ABI or API breaks backwards compatibility. */ -#define SPVC_C_API_VERSION_MAJOR 0 -/* Bumped if APIs or enumerations are added in a backwards compatible way. */ -#define SPVC_C_API_VERSION_MINOR 48 -/* Bumped if internal implementation details change. */ -#define SPVC_C_API_VERSION_PATCH 0 - -#if !defined(SPVC_PUBLIC_API) -#if defined(SPVC_EXPORT_SYMBOLS) -/* Exports symbols. Standard C calling convention is used. */ -#if defined(__GNUC__) -#define SPVC_PUBLIC_API __attribute__((visibility("default"))) -#elif defined(_MSC_VER) -#define SPVC_PUBLIC_API __declspec(dllexport) -#else -#define SPVC_PUBLIC_API -#endif -#else -#define SPVC_PUBLIC_API -#endif -#endif - -/* - * Gets the SPVC_C_API_VERSION_* used to build this library. - * Can be used to check for ABI mismatch if so-versioning did not catch it. - */ -SPVC_PUBLIC_API void spvc_get_version(unsigned *major, unsigned *minor, unsigned *patch); - -/* Gets a human readable version string to identify which commit a particular binary was created from. */ -SPVC_PUBLIC_API const char *spvc_get_commit_revision_and_timestamp(void); - -/* These types are opaque to the user. */ -typedef struct spvc_context_s *spvc_context; -typedef struct spvc_parsed_ir_s *spvc_parsed_ir; -typedef struct spvc_compiler_s *spvc_compiler; -typedef struct spvc_compiler_options_s *spvc_compiler_options; -typedef struct spvc_resources_s *spvc_resources; -struct spvc_type_s; -typedef const struct spvc_type_s *spvc_type; -typedef struct spvc_constant_s *spvc_constant; -struct spvc_set_s; -typedef const struct spvc_set_s *spvc_set; - -/* - * Shallow typedefs. All SPIR-V IDs are plain 32-bit numbers, but this helps communicate which data is used. - * Maps to a SPIRType. - */ -typedef SpvId spvc_type_id; -/* Maps to a SPIRVariable. */ -typedef SpvId spvc_variable_id; -/* Maps to a SPIRConstant. */ -typedef SpvId spvc_constant_id; - -/* See C++ API. */ -typedef struct spvc_reflected_resource -{ - spvc_variable_id id; - spvc_type_id base_type_id; - spvc_type_id type_id; - const char *name; -} spvc_reflected_resource; - -typedef struct spvc_reflected_builtin_resource -{ - SpvBuiltIn builtin; - spvc_type_id value_type_id; - spvc_reflected_resource resource; -} spvc_reflected_builtin_resource; - -/* See C++ API. */ -typedef struct spvc_entry_point -{ - SpvExecutionModel execution_model; - const char *name; -} spvc_entry_point; - -/* See C++ API. */ -typedef struct spvc_combined_image_sampler -{ - spvc_variable_id combined_id; - spvc_variable_id image_id; - spvc_variable_id sampler_id; -} spvc_combined_image_sampler; - -/* See C++ API. */ -typedef struct spvc_specialization_constant -{ - spvc_constant_id id; - unsigned constant_id; -} spvc_specialization_constant; - -/* See C++ API. */ -typedef struct spvc_buffer_range -{ - unsigned index; - size_t offset; - size_t range; -} spvc_buffer_range; - -/* See C++ API. */ -typedef struct spvc_hlsl_root_constants -{ - unsigned start; - unsigned end; - unsigned binding; - unsigned space; -} spvc_hlsl_root_constants; - -/* See C++ API. */ -typedef struct spvc_hlsl_vertex_attribute_remap -{ - unsigned location; - const char *semantic; -} spvc_hlsl_vertex_attribute_remap; - -/* - * Be compatible with non-C99 compilers, which do not have stdbool. - * Only recent MSVC compilers supports this for example, and ideally SPIRV-Cross should be linkable - * from a wide range of compilers in its C wrapper. - */ -typedef unsigned char spvc_bool; -#define SPVC_TRUE ((spvc_bool)1) -#define SPVC_FALSE ((spvc_bool)0) - -typedef enum spvc_result -{ - /* Success. */ - SPVC_SUCCESS = 0, - - /* The SPIR-V is invalid. Should have been caught by validation ideally. */ - SPVC_ERROR_INVALID_SPIRV = -1, - - /* The SPIR-V might be valid or invalid, but SPIRV-Cross currently cannot correctly translate this to your target language. */ - SPVC_ERROR_UNSUPPORTED_SPIRV = -2, - - /* If for some reason we hit this, new or malloc failed. */ - SPVC_ERROR_OUT_OF_MEMORY = -3, - - /* Invalid API argument. */ - SPVC_ERROR_INVALID_ARGUMENT = -4, - - SPVC_ERROR_INT_MAX = 0x7fffffff -} spvc_result; - -typedef enum spvc_capture_mode -{ - /* The Parsed IR payload will be copied, and the handle can be reused to create other compiler instances. */ - SPVC_CAPTURE_MODE_COPY = 0, - - /* - * The payload will now be owned by the compiler. - * parsed_ir should now be considered a dead blob and must not be used further. - * This is optimal for performance and should be the go-to option. - */ - SPVC_CAPTURE_MODE_TAKE_OWNERSHIP = 1, - - SPVC_CAPTURE_MODE_INT_MAX = 0x7fffffff -} spvc_capture_mode; - -typedef enum spvc_backend -{ - /* This backend can only perform reflection, no compiler options are supported. Maps to spirv_cross::Compiler. */ - SPVC_BACKEND_NONE = 0, - SPVC_BACKEND_GLSL = 1, /* spirv_cross::CompilerGLSL */ - SPVC_BACKEND_HLSL = 2, /* CompilerHLSL */ - SPVC_BACKEND_MSL = 3, /* CompilerMSL */ - SPVC_BACKEND_CPP = 4, /* CompilerCPP */ - SPVC_BACKEND_JSON = 5, /* CompilerReflection w/ JSON backend */ - SPVC_BACKEND_INT_MAX = 0x7fffffff -} spvc_backend; - -/* Maps to C++ API. */ -typedef enum spvc_resource_type -{ - SPVC_RESOURCE_TYPE_UNKNOWN = 0, - SPVC_RESOURCE_TYPE_UNIFORM_BUFFER = 1, - SPVC_RESOURCE_TYPE_STORAGE_BUFFER = 2, - SPVC_RESOURCE_TYPE_STAGE_INPUT = 3, - SPVC_RESOURCE_TYPE_STAGE_OUTPUT = 4, - SPVC_RESOURCE_TYPE_SUBPASS_INPUT = 5, - SPVC_RESOURCE_TYPE_STORAGE_IMAGE = 6, - SPVC_RESOURCE_TYPE_SAMPLED_IMAGE = 7, - SPVC_RESOURCE_TYPE_ATOMIC_COUNTER = 8, - SPVC_RESOURCE_TYPE_PUSH_CONSTANT = 9, - SPVC_RESOURCE_TYPE_SEPARATE_IMAGE = 10, - SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS = 11, - SPVC_RESOURCE_TYPE_ACCELERATION_STRUCTURE = 12, - SPVC_RESOURCE_TYPE_RAY_QUERY = 13, - SPVC_RESOURCE_TYPE_INT_MAX = 0x7fffffff -} spvc_resource_type; - -typedef enum spvc_builtin_resource_type -{ - SPVC_BUILTIN_RESOURCE_TYPE_UNKNOWN = 0, - SPVC_BUILTIN_RESOURCE_TYPE_STAGE_INPUT = 1, - SPVC_BUILTIN_RESOURCE_TYPE_STAGE_OUTPUT = 2, - SPVC_BUILTIN_RESOURCE_TYPE_INT_MAX = 0x7fffffff -} spvc_builtin_resource_type; - -/* Maps to spirv_cross::SPIRType::BaseType. */ -typedef enum spvc_basetype -{ - SPVC_BASETYPE_UNKNOWN = 0, - SPVC_BASETYPE_VOID = 1, - SPVC_BASETYPE_BOOLEAN = 2, - SPVC_BASETYPE_INT8 = 3, - SPVC_BASETYPE_UINT8 = 4, - SPVC_BASETYPE_INT16 = 5, - SPVC_BASETYPE_UINT16 = 6, - SPVC_BASETYPE_INT32 = 7, - SPVC_BASETYPE_UINT32 = 8, - SPVC_BASETYPE_INT64 = 9, - SPVC_BASETYPE_UINT64 = 10, - SPVC_BASETYPE_ATOMIC_COUNTER = 11, - SPVC_BASETYPE_FP16 = 12, - SPVC_BASETYPE_FP32 = 13, - SPVC_BASETYPE_FP64 = 14, - SPVC_BASETYPE_STRUCT = 15, - SPVC_BASETYPE_IMAGE = 16, - SPVC_BASETYPE_SAMPLED_IMAGE = 17, - SPVC_BASETYPE_SAMPLER = 18, - SPVC_BASETYPE_ACCELERATION_STRUCTURE = 19, - - SPVC_BASETYPE_INT_MAX = 0x7fffffff -} spvc_basetype; - -#define SPVC_COMPILER_OPTION_COMMON_BIT 0x1000000 -#define SPVC_COMPILER_OPTION_GLSL_BIT 0x2000000 -#define SPVC_COMPILER_OPTION_HLSL_BIT 0x4000000 -#define SPVC_COMPILER_OPTION_MSL_BIT 0x8000000 -#define SPVC_COMPILER_OPTION_LANG_BITS 0x0f000000 -#define SPVC_COMPILER_OPTION_ENUM_BITS 0xffffff - -#define SPVC_MAKE_MSL_VERSION(major, minor, patch) ((major) * 10000 + (minor) * 100 + (patch)) - -/* Maps to C++ API. */ -typedef enum spvc_msl_platform -{ - SPVC_MSL_PLATFORM_IOS = 0, - SPVC_MSL_PLATFORM_MACOS = 1, - SPVC_MSL_PLATFORM_MAX_INT = 0x7fffffff -} spvc_msl_platform; - -/* Maps to C++ API. */ -typedef enum spvc_msl_index_type -{ - SPVC_MSL_INDEX_TYPE_NONE = 0, - SPVC_MSL_INDEX_TYPE_UINT16 = 1, - SPVC_MSL_INDEX_TYPE_UINT32 = 2, - SPVC_MSL_INDEX_TYPE_MAX_INT = 0x7fffffff -} spvc_msl_index_type; - -/* Maps to C++ API. */ -typedef enum spvc_msl_shader_input_format -{ - SPVC_MSL_SHADER_INPUT_FORMAT_OTHER = 0, - SPVC_MSL_SHADER_INPUT_FORMAT_UINT8 = 1, - SPVC_MSL_SHADER_INPUT_FORMAT_UINT16 = 2, - SPVC_MSL_SHADER_INPUT_FORMAT_ANY16 = 3, - SPVC_MSL_SHADER_INPUT_FORMAT_ANY32 = 4, - - /* Deprecated names. */ - SPVC_MSL_VERTEX_FORMAT_OTHER = SPVC_MSL_SHADER_INPUT_FORMAT_OTHER, - SPVC_MSL_VERTEX_FORMAT_UINT8 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT8, - SPVC_MSL_VERTEX_FORMAT_UINT16 = SPVC_MSL_SHADER_INPUT_FORMAT_UINT16, - - SPVC_MSL_SHADER_INPUT_FORMAT_INT_MAX = 0x7fffffff -} spvc_msl_shader_input_format, spvc_msl_vertex_format; - -/* Maps to C++ API. Deprecated; use spvc_msl_shader_input. */ -typedef struct spvc_msl_vertex_attribute -{ - unsigned location; - - /* Obsolete, do not use. Only lingers on for ABI compatibility. */ - unsigned msl_buffer; - /* Obsolete, do not use. Only lingers on for ABI compatibility. */ - unsigned msl_offset; - /* Obsolete, do not use. Only lingers on for ABI compatibility. */ - unsigned msl_stride; - /* Obsolete, do not use. Only lingers on for ABI compatibility. */ - spvc_bool per_instance; - - spvc_msl_vertex_format format; - SpvBuiltIn builtin; -} spvc_msl_vertex_attribute; - -/* - * Initializes the vertex attribute struct. - */ -SPVC_PUBLIC_API void spvc_msl_vertex_attribute_init(spvc_msl_vertex_attribute *attr); - -/* Maps to C++ API. */ -typedef struct spvc_msl_shader_input -{ - unsigned location; - spvc_msl_vertex_format format; - SpvBuiltIn builtin; - unsigned vecsize; -} spvc_msl_shader_input; - -/* - * Initializes the shader input struct. - */ -SPVC_PUBLIC_API void spvc_msl_shader_input_init(spvc_msl_shader_input *input); - -/* Maps to C++ API. */ -typedef struct spvc_msl_resource_binding -{ - SpvExecutionModel stage; - unsigned desc_set; - unsigned binding; - unsigned msl_buffer; - unsigned msl_texture; - unsigned msl_sampler; -} spvc_msl_resource_binding; - -/* - * Initializes the resource binding struct. - * The defaults are non-zero. - */ -SPVC_PUBLIC_API void spvc_msl_resource_binding_init(spvc_msl_resource_binding *binding); - -#define SPVC_MSL_PUSH_CONSTANT_DESC_SET (~(0u)) -#define SPVC_MSL_PUSH_CONSTANT_BINDING (0) -#define SPVC_MSL_SWIZZLE_BUFFER_BINDING (~(1u)) -#define SPVC_MSL_BUFFER_SIZE_BUFFER_BINDING (~(2u)) -#define SPVC_MSL_ARGUMENT_BUFFER_BINDING (~(3u)) - -/* Obsolete. Sticks around for backwards compatibility. */ -#define SPVC_MSL_AUX_BUFFER_STRUCT_VERSION 1 - -/* Runtime check for incompatibility. Obsolete. */ -SPVC_PUBLIC_API unsigned spvc_msl_get_aux_buffer_struct_version(void); - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_coord -{ - SPVC_MSL_SAMPLER_COORD_NORMALIZED = 0, - SPVC_MSL_SAMPLER_COORD_PIXEL = 1, - SPVC_MSL_SAMPLER_INT_MAX = 0x7fffffff -} spvc_msl_sampler_coord; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_filter -{ - SPVC_MSL_SAMPLER_FILTER_NEAREST = 0, - SPVC_MSL_SAMPLER_FILTER_LINEAR = 1, - SPVC_MSL_SAMPLER_FILTER_INT_MAX = 0x7fffffff -} spvc_msl_sampler_filter; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_mip_filter -{ - SPVC_MSL_SAMPLER_MIP_FILTER_NONE = 0, - SPVC_MSL_SAMPLER_MIP_FILTER_NEAREST = 1, - SPVC_MSL_SAMPLER_MIP_FILTER_LINEAR = 2, - SPVC_MSL_SAMPLER_MIP_FILTER_INT_MAX = 0x7fffffff -} spvc_msl_sampler_mip_filter; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_address -{ - SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_ZERO = 0, - SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_EDGE = 1, - SPVC_MSL_SAMPLER_ADDRESS_CLAMP_TO_BORDER = 2, - SPVC_MSL_SAMPLER_ADDRESS_REPEAT = 3, - SPVC_MSL_SAMPLER_ADDRESS_MIRRORED_REPEAT = 4, - SPVC_MSL_SAMPLER_ADDRESS_INT_MAX = 0x7fffffff -} spvc_msl_sampler_address; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_compare_func -{ - SPVC_MSL_SAMPLER_COMPARE_FUNC_NEVER = 0, - SPVC_MSL_SAMPLER_COMPARE_FUNC_LESS = 1, - SPVC_MSL_SAMPLER_COMPARE_FUNC_LESS_EQUAL = 2, - SPVC_MSL_SAMPLER_COMPARE_FUNC_GREATER = 3, - SPVC_MSL_SAMPLER_COMPARE_FUNC_GREATER_EQUAL = 4, - SPVC_MSL_SAMPLER_COMPARE_FUNC_EQUAL = 5, - SPVC_MSL_SAMPLER_COMPARE_FUNC_NOT_EQUAL = 6, - SPVC_MSL_SAMPLER_COMPARE_FUNC_ALWAYS = 7, - SPVC_MSL_SAMPLER_COMPARE_FUNC_INT_MAX = 0x7fffffff -} spvc_msl_sampler_compare_func; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_border_color -{ - SPVC_MSL_SAMPLER_BORDER_COLOR_TRANSPARENT_BLACK = 0, - SPVC_MSL_SAMPLER_BORDER_COLOR_OPAQUE_BLACK = 1, - SPVC_MSL_SAMPLER_BORDER_COLOR_OPAQUE_WHITE = 2, - SPVC_MSL_SAMPLER_BORDER_COLOR_INT_MAX = 0x7fffffff -} spvc_msl_sampler_border_color; - -/* Maps to C++ API. */ -typedef enum spvc_msl_format_resolution -{ - SPVC_MSL_FORMAT_RESOLUTION_444 = 0, - SPVC_MSL_FORMAT_RESOLUTION_422, - SPVC_MSL_FORMAT_RESOLUTION_420, - SPVC_MSL_FORMAT_RESOLUTION_INT_MAX = 0x7fffffff -} spvc_msl_format_resolution; - -/* Maps to C++ API. */ -typedef enum spvc_msl_chroma_location -{ - SPVC_MSL_CHROMA_LOCATION_COSITED_EVEN = 0, - SPVC_MSL_CHROMA_LOCATION_MIDPOINT, - SPVC_MSL_CHROMA_LOCATION_INT_MAX = 0x7fffffff -} spvc_msl_chroma_location; - -/* Maps to C++ API. */ -typedef enum spvc_msl_component_swizzle -{ - SPVC_MSL_COMPONENT_SWIZZLE_IDENTITY = 0, - SPVC_MSL_COMPONENT_SWIZZLE_ZERO, - SPVC_MSL_COMPONENT_SWIZZLE_ONE, - SPVC_MSL_COMPONENT_SWIZZLE_R, - SPVC_MSL_COMPONENT_SWIZZLE_G, - SPVC_MSL_COMPONENT_SWIZZLE_B, - SPVC_MSL_COMPONENT_SWIZZLE_A, - SPVC_MSL_COMPONENT_SWIZZLE_INT_MAX = 0x7fffffff -} spvc_msl_component_swizzle; - -/* Maps to C++ API. */ -typedef enum spvc_msl_sampler_ycbcr_model_conversion -{ - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_RGB_IDENTITY = 0, - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_IDENTITY, - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_709, - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_601, - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_BT_2020, - SPVC_MSL_SAMPLER_YCBCR_MODEL_CONVERSION_INT_MAX = 0x7fffffff -} spvc_msl_sampler_ycbcr_model_conversion; - -/* Maps to C+ API. */ -typedef enum spvc_msl_sampler_ycbcr_range -{ - SPVC_MSL_SAMPLER_YCBCR_RANGE_ITU_FULL = 0, - SPVC_MSL_SAMPLER_YCBCR_RANGE_ITU_NARROW, - SPVC_MSL_SAMPLER_YCBCR_RANGE_INT_MAX = 0x7fffffff -} spvc_msl_sampler_ycbcr_range; - -/* Maps to C++ API. */ -typedef struct spvc_msl_constexpr_sampler -{ - spvc_msl_sampler_coord coord; - spvc_msl_sampler_filter min_filter; - spvc_msl_sampler_filter mag_filter; - spvc_msl_sampler_mip_filter mip_filter; - spvc_msl_sampler_address s_address; - spvc_msl_sampler_address t_address; - spvc_msl_sampler_address r_address; - spvc_msl_sampler_compare_func compare_func; - spvc_msl_sampler_border_color border_color; - float lod_clamp_min; - float lod_clamp_max; - int max_anisotropy; - - spvc_bool compare_enable; - spvc_bool lod_clamp_enable; - spvc_bool anisotropy_enable; -} spvc_msl_constexpr_sampler; - -/* - * Initializes the constexpr sampler struct. - * The defaults are non-zero. - */ -SPVC_PUBLIC_API void spvc_msl_constexpr_sampler_init(spvc_msl_constexpr_sampler *sampler); - -/* Maps to the sampler Y'CbCr conversion-related portions of MSLConstexprSampler. See C++ API for defaults and details. */ -typedef struct spvc_msl_sampler_ycbcr_conversion -{ - unsigned planes; - spvc_msl_format_resolution resolution; - spvc_msl_sampler_filter chroma_filter; - spvc_msl_chroma_location x_chroma_offset; - spvc_msl_chroma_location y_chroma_offset; - spvc_msl_component_swizzle swizzle[4]; - spvc_msl_sampler_ycbcr_model_conversion ycbcr_model; - spvc_msl_sampler_ycbcr_range ycbcr_range; - unsigned bpc; -} spvc_msl_sampler_ycbcr_conversion; - -/* - * Initializes the constexpr sampler struct. - * The defaults are non-zero. - */ -SPVC_PUBLIC_API void spvc_msl_sampler_ycbcr_conversion_init(spvc_msl_sampler_ycbcr_conversion *conv); - -/* Maps to C++ API. */ -typedef enum spvc_hlsl_binding_flag_bits -{ - SPVC_HLSL_BINDING_AUTO_NONE_BIT = 0, - SPVC_HLSL_BINDING_AUTO_PUSH_CONSTANT_BIT = 1 << 0, - SPVC_HLSL_BINDING_AUTO_CBV_BIT = 1 << 1, - SPVC_HLSL_BINDING_AUTO_SRV_BIT = 1 << 2, - SPVC_HLSL_BINDING_AUTO_UAV_BIT = 1 << 3, - SPVC_HLSL_BINDING_AUTO_SAMPLER_BIT = 1 << 4, - SPVC_HLSL_BINDING_AUTO_ALL = 0x7fffffff -} spvc_hlsl_binding_flag_bits; -typedef unsigned spvc_hlsl_binding_flags; - -#define SPVC_HLSL_PUSH_CONSTANT_DESC_SET (~(0u)) -#define SPVC_HLSL_PUSH_CONSTANT_BINDING (0) - -/* Maps to C++ API. */ -typedef struct spvc_hlsl_resource_binding_mapping -{ - unsigned register_space; - unsigned register_binding; -} spvc_hlsl_resource_binding_mapping; - -typedef struct spvc_hlsl_resource_binding -{ - SpvExecutionModel stage; - unsigned desc_set; - unsigned binding; - - spvc_hlsl_resource_binding_mapping cbv, uav, srv, sampler; -} spvc_hlsl_resource_binding; - -/* - * Initializes the resource binding struct. - * The defaults are non-zero. - */ -SPVC_PUBLIC_API void spvc_hlsl_resource_binding_init(spvc_hlsl_resource_binding *binding); - -/* Maps to the various spirv_cross::Compiler*::Option structures. See C++ API for defaults and details. */ -typedef enum spvc_compiler_option -{ - SPVC_COMPILER_OPTION_UNKNOWN = 0, - - SPVC_COMPILER_OPTION_FORCE_TEMPORARY = 1 | SPVC_COMPILER_OPTION_COMMON_BIT, - SPVC_COMPILER_OPTION_FLATTEN_MULTIDIMENSIONAL_ARRAYS = 2 | SPVC_COMPILER_OPTION_COMMON_BIT, - SPVC_COMPILER_OPTION_FIXUP_DEPTH_CONVENTION = 3 | SPVC_COMPILER_OPTION_COMMON_BIT, - SPVC_COMPILER_OPTION_FLIP_VERTEX_Y = 4 | SPVC_COMPILER_OPTION_COMMON_BIT, - - SPVC_COMPILER_OPTION_GLSL_SUPPORT_NONZERO_BASE_INSTANCE = 5 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_SEPARATE_SHADER_OBJECTS = 6 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_ENABLE_420PACK_EXTENSION = 7 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_VERSION = 8 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_ES = 9 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_VULKAN_SEMANTICS = 10 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_FLOAT_PRECISION_HIGHP = 11 | SPVC_COMPILER_OPTION_GLSL_BIT, - SPVC_COMPILER_OPTION_GLSL_ES_DEFAULT_INT_PRECISION_HIGHP = 12 | SPVC_COMPILER_OPTION_GLSL_BIT, - - SPVC_COMPILER_OPTION_HLSL_SHADER_MODEL = 13 | SPVC_COMPILER_OPTION_HLSL_BIT, - SPVC_COMPILER_OPTION_HLSL_POINT_SIZE_COMPAT = 14 | SPVC_COMPILER_OPTION_HLSL_BIT, - SPVC_COMPILER_OPTION_HLSL_POINT_COORD_COMPAT = 15 | SPVC_COMPILER_OPTION_HLSL_BIT, - SPVC_COMPILER_OPTION_HLSL_SUPPORT_NONZERO_BASE_VERTEX_BASE_INSTANCE = 16 | SPVC_COMPILER_OPTION_HLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_VERSION = 17 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_TEXEL_BUFFER_TEXTURE_WIDTH = 18 | SPVC_COMPILER_OPTION_MSL_BIT, - - /* Obsolete, use SWIZZLE_BUFFER_INDEX instead. */ - SPVC_COMPILER_OPTION_MSL_AUX_BUFFER_INDEX = 19 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SWIZZLE_BUFFER_INDEX = 19 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_MSL_INDIRECT_PARAMS_BUFFER_INDEX = 20 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_OUTPUT_BUFFER_INDEX = 21 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_PATCH_OUTPUT_BUFFER_INDEX = 22 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_TESS_FACTOR_OUTPUT_BUFFER_INDEX = 23 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_WORKGROUP_INDEX = 24 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_POINT_SIZE_BUILTIN = 25 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_DISABLE_RASTERIZATION = 26 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_CAPTURE_OUTPUT_TO_BUFFER = 27 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SWIZZLE_TEXTURE_SAMPLES = 28 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_PAD_FRAGMENT_OUTPUT_COMPONENTS = 29 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_TESS_DOMAIN_ORIGIN_LOWER_LEFT = 30 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_PLATFORM = 31 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ARGUMENT_BUFFERS = 32 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_GLSL_EMIT_PUSH_CONSTANT_AS_UNIFORM_BUFFER = 33 | SPVC_COMPILER_OPTION_GLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_TEXTURE_BUFFER_NATIVE = 34 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_GLSL_EMIT_UNIFORM_BUFFER_AS_PLAIN_UNIFORMS = 35 | SPVC_COMPILER_OPTION_GLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_BUFFER_SIZE_BUFFER_INDEX = 36 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_EMIT_LINE_DIRECTIVES = 37 | SPVC_COMPILER_OPTION_COMMON_BIT, - - SPVC_COMPILER_OPTION_MSL_MULTIVIEW = 38 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_VIEW_MASK_BUFFER_INDEX = 39 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_DEVICE_INDEX = 40 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_VIEW_INDEX_FROM_DEVICE_INDEX = 41 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_DISPATCH_BASE = 42 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_DYNAMIC_OFFSETS_BUFFER_INDEX = 43 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_TEXTURE_1D_AS_2D = 44 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_BASE_INDEX_ZERO = 45 | SPVC_COMPILER_OPTION_MSL_BIT, - - /* Obsolete. Use MSL_FRAMEBUFFER_FETCH_SUBPASS instead. */ - SPVC_COMPILER_OPTION_MSL_IOS_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_FRAMEBUFFER_FETCH_SUBPASS = 46 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_MSL_INVARIANT_FP_MATH = 47 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_EMULATE_CUBEMAP_ARRAY = 48 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_DECORATION_BINDING = 49 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_FORCE_ACTIVE_ARGUMENT_BUFFER_RESOURCES = 50 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_FORCE_NATIVE_ARRAYS = 51 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_ENABLE_STORAGE_IMAGE_QUALIFIER_DEDUCTION = 52 | SPVC_COMPILER_OPTION_COMMON_BIT, - - SPVC_COMPILER_OPTION_HLSL_FORCE_STORAGE_BUFFER_AS_UAV = 53 | SPVC_COMPILER_OPTION_HLSL_BIT, - - SPVC_COMPILER_OPTION_FORCE_ZERO_INITIALIZED_VARIABLES = 54 | SPVC_COMPILER_OPTION_COMMON_BIT, - - SPVC_COMPILER_OPTION_HLSL_NONWRITABLE_UAV_TEXTURE_AS_SRV = 55 | SPVC_COMPILER_OPTION_HLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_OUTPUT_MASK = 56 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_DEPTH_BUILTIN = 57 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_FRAG_STENCIL_REF_BUILTIN = 58 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ENABLE_CLIP_DISTANCE_USER_VARYING = 59 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_HLSL_ENABLE_16BIT_TYPES = 60 | SPVC_COMPILER_OPTION_HLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_MULTI_PATCH_WORKGROUP = 61 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_INPUT_BUFFER_INDEX = 62 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_SHADER_INDEX_BUFFER_INDEX = 63 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_VERTEX_FOR_TESSELLATION = 64 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_VERTEX_INDEX_TYPE = 65 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_GLSL_FORCE_FLATTENED_IO_BLOCKS = 66 | SPVC_COMPILER_OPTION_GLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_MULTIVIEW_LAYERED_RENDERING = 67 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_ARRAYED_SUBPASS_INPUT = 68 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_R32UI_LINEAR_TEXTURE_ALIGNMENT = 69 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_R32UI_ALIGNMENT_CONSTANT_ID = 70 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_HLSL_FLATTEN_MATRIX_VERTEX_INPUT_SEMANTICS = 71 | SPVC_COMPILER_OPTION_HLSL_BIT, - - SPVC_COMPILER_OPTION_MSL_IOS_USE_SIMDGROUP_FUNCTIONS = 72 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_EMULATE_SUBGROUPS = 73 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_FIXED_SUBGROUP_SIZE = 74 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_FORCE_SAMPLE_RATE_SHADING = 75 | SPVC_COMPILER_OPTION_MSL_BIT, - SPVC_COMPILER_OPTION_MSL_IOS_SUPPORT_BASE_VERTEX_INSTANCE = 76 | SPVC_COMPILER_OPTION_MSL_BIT, - - SPVC_COMPILER_OPTION_GLSL_OVR_MULTIVIEW_VIEW_COUNT = 77 | SPVC_COMPILER_OPTION_GLSL_BIT, - - SPVC_COMPILER_OPTION_INT_MAX = 0x7fffffff -} spvc_compiler_option; - -/* - * Context is the highest-level API construct. - * The context owns all memory allocations made by its child object hierarchy, including various non-opaque structs and strings. - * This means that the API user only has to care about one "destroy" call ever when using the C API. - * All pointers handed out by the APIs are only valid as long as the context - * is alive and spvc_context_release_allocations has not been called. - */ -SPVC_PUBLIC_API spvc_result spvc_context_create(spvc_context *context); - -/* Frees all memory allocations and objects associated with the context and its child objects. */ -SPVC_PUBLIC_API void spvc_context_destroy(spvc_context context); - -/* Frees all memory allocations and objects associated with the context and its child objects, but keeps the context alive. */ -SPVC_PUBLIC_API void spvc_context_release_allocations(spvc_context context); - -/* Get the string for the last error which was logged. */ -SPVC_PUBLIC_API const char *spvc_context_get_last_error_string(spvc_context context); - -/* Get notified in a callback when an error triggers. Useful for debugging. */ -typedef void (*spvc_error_callback)(void *userdata, const char *error); -SPVC_PUBLIC_API void spvc_context_set_error_callback(spvc_context context, spvc_error_callback cb, void *userdata); - -/* SPIR-V parsing interface. Maps to Parser which then creates a ParsedIR, and that IR is extracted into the handle. */ -SPVC_PUBLIC_API spvc_result spvc_context_parse_spirv(spvc_context context, const SpvId *spirv, size_t word_count, - spvc_parsed_ir *parsed_ir); - -/* - * Create a compiler backend. Capture mode controls if we construct by copy or move semantics. - * It is always recommended to use SPVC_CAPTURE_MODE_TAKE_OWNERSHIP if you only intend to cross-compile the IR once. - */ -SPVC_PUBLIC_API spvc_result spvc_context_create_compiler(spvc_context context, spvc_backend backend, - spvc_parsed_ir parsed_ir, spvc_capture_mode mode, - spvc_compiler *compiler); - -/* Maps directly to C++ API. */ -SPVC_PUBLIC_API unsigned spvc_compiler_get_current_id_bound(spvc_compiler compiler); - -/* Create compiler options, which will initialize defaults. */ -SPVC_PUBLIC_API spvc_result spvc_compiler_create_compiler_options(spvc_compiler compiler, - spvc_compiler_options *options); -/* Override options. Will return error if e.g. MSL options are used for the HLSL backend, etc. */ -SPVC_PUBLIC_API spvc_result spvc_compiler_options_set_bool(spvc_compiler_options options, - spvc_compiler_option option, spvc_bool value); -SPVC_PUBLIC_API spvc_result spvc_compiler_options_set_uint(spvc_compiler_options options, - spvc_compiler_option option, unsigned value); -/* Set compiler options. */ -SPVC_PUBLIC_API spvc_result spvc_compiler_install_compiler_options(spvc_compiler compiler, - spvc_compiler_options options); - -/* Compile IR into a string. *source is owned by the context, and caller must not free it themselves. */ -SPVC_PUBLIC_API spvc_result spvc_compiler_compile(spvc_compiler compiler, const char **source); - -/* Maps to C++ API. */ -SPVC_PUBLIC_API spvc_result spvc_compiler_add_header_line(spvc_compiler compiler, const char *line); -SPVC_PUBLIC_API spvc_result spvc_compiler_require_extension(spvc_compiler compiler, const char *ext); -SPVC_PUBLIC_API spvc_result spvc_compiler_flatten_buffer_block(spvc_compiler compiler, spvc_variable_id id); - -SPVC_PUBLIC_API spvc_bool spvc_compiler_variable_is_depth_or_compare(spvc_compiler compiler, spvc_variable_id id); - -SPVC_PUBLIC_API spvc_result spvc_compiler_mask_stage_output_by_location(spvc_compiler compiler, - unsigned location, unsigned component); -SPVC_PUBLIC_API spvc_result spvc_compiler_mask_stage_output_by_builtin(spvc_compiler compiler, SpvBuiltIn builtin); - -/* - * HLSL specifics. - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_root_constants_layout(spvc_compiler compiler, - const spvc_hlsl_root_constants *constant_info, - size_t count); -SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_vertex_attribute_remap(spvc_compiler compiler, - const spvc_hlsl_vertex_attribute_remap *remap, - size_t remaps); -SPVC_PUBLIC_API spvc_variable_id spvc_compiler_hlsl_remap_num_workgroups_builtin(spvc_compiler compiler); - -SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_set_resource_binding_flags(spvc_compiler compiler, - spvc_hlsl_binding_flags flags); - -SPVC_PUBLIC_API spvc_result spvc_compiler_hlsl_add_resource_binding(spvc_compiler compiler, - const spvc_hlsl_resource_binding *binding); -SPVC_PUBLIC_API spvc_bool spvc_compiler_hlsl_is_resource_used(spvc_compiler compiler, - SpvExecutionModel model, - unsigned set, - unsigned binding); - -/* - * MSL specifics. - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_rasterization_disabled(spvc_compiler compiler); - -/* Obsolete. Renamed to needs_swizzle_buffer. */ -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_aux_buffer(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_swizzle_buffer(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_buffer_size_buffer(spvc_compiler compiler); - -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_output_buffer(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_patch_output_buffer(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_needs_input_threadgroup_mem(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_vertex_attribute(spvc_compiler compiler, - const spvc_msl_vertex_attribute *attrs); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_resource_binding(spvc_compiler compiler, - const spvc_msl_resource_binding *binding); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_shader_input(spvc_compiler compiler, - const spvc_msl_shader_input *input); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_discrete_descriptor_set(spvc_compiler compiler, unsigned desc_set); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_argument_buffer_device_address_space(spvc_compiler compiler, unsigned desc_set, spvc_bool device_address); - -/* Obsolete, use is_shader_input_used. */ -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_vertex_attribute_used(spvc_compiler compiler, unsigned location); -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_shader_input_used(spvc_compiler compiler, unsigned location); - -SPVC_PUBLIC_API spvc_bool spvc_compiler_msl_is_resource_used(spvc_compiler compiler, - SpvExecutionModel model, - unsigned set, - unsigned binding); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler(spvc_compiler compiler, spvc_variable_id id, const spvc_msl_constexpr_sampler *sampler); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding(spvc_compiler compiler, unsigned desc_set, unsigned binding, const spvc_msl_constexpr_sampler *sampler); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_ycbcr(spvc_compiler compiler, spvc_variable_id id, const spvc_msl_constexpr_sampler *sampler, const spvc_msl_sampler_ycbcr_conversion *conv); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_remap_constexpr_sampler_by_binding_ycbcr(spvc_compiler compiler, unsigned desc_set, unsigned binding, const spvc_msl_constexpr_sampler *sampler, const spvc_msl_sampler_ycbcr_conversion *conv); -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_fragment_output_components(spvc_compiler compiler, unsigned location, unsigned components); - -SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding(spvc_compiler compiler, spvc_variable_id id); -SPVC_PUBLIC_API unsigned spvc_compiler_msl_get_automatic_resource_binding_secondary(spvc_compiler compiler, spvc_variable_id id); - -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_dynamic_buffer(spvc_compiler compiler, unsigned desc_set, unsigned binding, unsigned index); - -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_add_inline_uniform_block(spvc_compiler compiler, unsigned desc_set, unsigned binding); - -SPVC_PUBLIC_API spvc_result spvc_compiler_msl_set_combined_sampler_suffix(spvc_compiler compiler, const char *suffix); -SPVC_PUBLIC_API const char *spvc_compiler_msl_get_combined_sampler_suffix(spvc_compiler compiler); - -/* - * Reflect resources. - * Maps almost 1:1 to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_get_active_interface_variables(spvc_compiler compiler, spvc_set *set); -SPVC_PUBLIC_API spvc_result spvc_compiler_set_enabled_interface_variables(spvc_compiler compiler, spvc_set set); -SPVC_PUBLIC_API spvc_result spvc_compiler_create_shader_resources(spvc_compiler compiler, spvc_resources *resources); -SPVC_PUBLIC_API spvc_result spvc_compiler_create_shader_resources_for_active_variables(spvc_compiler compiler, - spvc_resources *resources, - spvc_set active); -SPVC_PUBLIC_API spvc_result spvc_resources_get_resource_list_for_type(spvc_resources resources, spvc_resource_type type, - const spvc_reflected_resource **resource_list, - size_t *resource_size); - -SPVC_PUBLIC_API spvc_result spvc_resources_get_builtin_resource_list_for_type( - spvc_resources resources, spvc_builtin_resource_type type, - const spvc_reflected_builtin_resource **resource_list, - size_t *resource_size); - -/* - * Decorations. - * Maps to C++ API. - */ -SPVC_PUBLIC_API void spvc_compiler_set_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration, - unsigned argument); -SPVC_PUBLIC_API void spvc_compiler_set_decoration_string(spvc_compiler compiler, SpvId id, SpvDecoration decoration, - const char *argument); -SPVC_PUBLIC_API void spvc_compiler_set_name(spvc_compiler compiler, SpvId id, const char *argument); -SPVC_PUBLIC_API void spvc_compiler_set_member_decoration(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - SpvDecoration decoration, unsigned argument); -SPVC_PUBLIC_API void spvc_compiler_set_member_decoration_string(spvc_compiler compiler, spvc_type_id id, - unsigned member_index, SpvDecoration decoration, - const char *argument); -SPVC_PUBLIC_API void spvc_compiler_set_member_name(spvc_compiler compiler, spvc_type_id id, unsigned member_index, - const char *argument); -SPVC_PUBLIC_API void spvc_compiler_unset_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration); -SPVC_PUBLIC_API void spvc_compiler_unset_member_decoration(spvc_compiler compiler, spvc_type_id id, - unsigned member_index, SpvDecoration decoration); - -SPVC_PUBLIC_API spvc_bool spvc_compiler_has_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration); -SPVC_PUBLIC_API spvc_bool spvc_compiler_has_member_decoration(spvc_compiler compiler, spvc_type_id id, - unsigned member_index, SpvDecoration decoration); -SPVC_PUBLIC_API const char *spvc_compiler_get_name(spvc_compiler compiler, SpvId id); -SPVC_PUBLIC_API unsigned spvc_compiler_get_decoration(spvc_compiler compiler, SpvId id, SpvDecoration decoration); -SPVC_PUBLIC_API const char *spvc_compiler_get_decoration_string(spvc_compiler compiler, SpvId id, - SpvDecoration decoration); -SPVC_PUBLIC_API unsigned spvc_compiler_get_member_decoration(spvc_compiler compiler, spvc_type_id id, - unsigned member_index, SpvDecoration decoration); -SPVC_PUBLIC_API const char *spvc_compiler_get_member_decoration_string(spvc_compiler compiler, spvc_type_id id, - unsigned member_index, SpvDecoration decoration); -SPVC_PUBLIC_API const char *spvc_compiler_get_member_name(spvc_compiler compiler, spvc_type_id id, unsigned member_index); - -/* - * Entry points. - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_get_entry_points(spvc_compiler compiler, - const spvc_entry_point **entry_points, - size_t *num_entry_points); -SPVC_PUBLIC_API spvc_result spvc_compiler_set_entry_point(spvc_compiler compiler, const char *name, - SpvExecutionModel model); -SPVC_PUBLIC_API spvc_result spvc_compiler_rename_entry_point(spvc_compiler compiler, const char *old_name, - const char *new_name, SpvExecutionModel model); -SPVC_PUBLIC_API const char *spvc_compiler_get_cleansed_entry_point_name(spvc_compiler compiler, const char *name, - SpvExecutionModel model); -SPVC_PUBLIC_API void spvc_compiler_set_execution_mode(spvc_compiler compiler, SpvExecutionMode mode); -SPVC_PUBLIC_API void spvc_compiler_unset_execution_mode(spvc_compiler compiler, SpvExecutionMode mode); -SPVC_PUBLIC_API void spvc_compiler_set_execution_mode_with_arguments(spvc_compiler compiler, SpvExecutionMode mode, - unsigned arg0, unsigned arg1, unsigned arg2); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_execution_modes(spvc_compiler compiler, const SpvExecutionMode **modes, - size_t *num_modes); -SPVC_PUBLIC_API unsigned spvc_compiler_get_execution_mode_argument(spvc_compiler compiler, SpvExecutionMode mode); -SPVC_PUBLIC_API unsigned spvc_compiler_get_execution_mode_argument_by_index(spvc_compiler compiler, - SpvExecutionMode mode, unsigned index); -SPVC_PUBLIC_API SpvExecutionModel spvc_compiler_get_execution_model(spvc_compiler compiler); -SPVC_PUBLIC_API void spvc_compiler_update_active_builtins(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_bool spvc_compiler_has_active_builtin(spvc_compiler compiler, SpvBuiltIn builtin, SpvStorageClass storage); - -/* - * Type query interface. - * Maps to C++ API, except it's read-only. - */ -SPVC_PUBLIC_API spvc_type spvc_compiler_get_type_handle(spvc_compiler compiler, spvc_type_id id); - -/* Pulls out SPIRType::self. This effectively gives the type ID without array or pointer qualifiers. - * This is necessary when reflecting decoration/name information on members of a struct, - * which are placed in the base type, not the qualified type. - * This is similar to spvc_reflected_resource::base_type_id. */ -SPVC_PUBLIC_API spvc_type_id spvc_type_get_base_type_id(spvc_type type); - -SPVC_PUBLIC_API spvc_basetype spvc_type_get_basetype(spvc_type type); -SPVC_PUBLIC_API unsigned spvc_type_get_bit_width(spvc_type type); -SPVC_PUBLIC_API unsigned spvc_type_get_vector_size(spvc_type type); -SPVC_PUBLIC_API unsigned spvc_type_get_columns(spvc_type type); -SPVC_PUBLIC_API unsigned spvc_type_get_num_array_dimensions(spvc_type type); -SPVC_PUBLIC_API spvc_bool spvc_type_array_dimension_is_literal(spvc_type type, unsigned dimension); -SPVC_PUBLIC_API SpvId spvc_type_get_array_dimension(spvc_type type, unsigned dimension); -SPVC_PUBLIC_API unsigned spvc_type_get_num_member_types(spvc_type type); -SPVC_PUBLIC_API spvc_type_id spvc_type_get_member_type(spvc_type type, unsigned index); -SPVC_PUBLIC_API SpvStorageClass spvc_type_get_storage_class(spvc_type type); - -/* Image type query. */ -SPVC_PUBLIC_API spvc_type_id spvc_type_get_image_sampled_type(spvc_type type); -SPVC_PUBLIC_API SpvDim spvc_type_get_image_dimension(spvc_type type); -SPVC_PUBLIC_API spvc_bool spvc_type_get_image_is_depth(spvc_type type); -SPVC_PUBLIC_API spvc_bool spvc_type_get_image_arrayed(spvc_type type); -SPVC_PUBLIC_API spvc_bool spvc_type_get_image_multisampled(spvc_type type); -SPVC_PUBLIC_API spvc_bool spvc_type_get_image_is_storage(spvc_type type); -SPVC_PUBLIC_API SpvImageFormat spvc_type_get_image_storage_format(spvc_type type); -SPVC_PUBLIC_API SpvAccessQualifier spvc_type_get_image_access_qualifier(spvc_type type); - -/* - * Buffer layout query. - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_struct_size(spvc_compiler compiler, spvc_type struct_type, size_t *size); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_struct_size_runtime_array(spvc_compiler compiler, - spvc_type struct_type, size_t array_size, size_t *size); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_struct_member_size(spvc_compiler compiler, spvc_type type, unsigned index, size_t *size); - -SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_offset(spvc_compiler compiler, - spvc_type type, unsigned index, unsigned *offset); -SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_array_stride(spvc_compiler compiler, - spvc_type type, unsigned index, unsigned *stride); -SPVC_PUBLIC_API spvc_result spvc_compiler_type_struct_member_matrix_stride(spvc_compiler compiler, - spvc_type type, unsigned index, unsigned *stride); - -/* - * Workaround helper functions. - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_build_dummy_sampler_for_combined_images(spvc_compiler compiler, spvc_variable_id *id); -SPVC_PUBLIC_API spvc_result spvc_compiler_build_combined_image_samplers(spvc_compiler compiler); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_combined_image_samplers(spvc_compiler compiler, - const spvc_combined_image_sampler **samplers, - size_t *num_samplers); - -/* - * Constants - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_get_specialization_constants(spvc_compiler compiler, - const spvc_specialization_constant **constants, - size_t *num_constants); -SPVC_PUBLIC_API spvc_constant spvc_compiler_get_constant_handle(spvc_compiler compiler, - spvc_constant_id id); - -SPVC_PUBLIC_API spvc_constant_id spvc_compiler_get_work_group_size_specialization_constants(spvc_compiler compiler, - spvc_specialization_constant *x, - spvc_specialization_constant *y, - spvc_specialization_constant *z); - -/* - * Buffer ranges - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_result spvc_compiler_get_active_buffer_ranges(spvc_compiler compiler, - spvc_variable_id id, - const spvc_buffer_range **ranges, - size_t *num_ranges); - -/* - * No stdint.h until C99, sigh :( - * For smaller types, the result is sign or zero-extended as appropriate. - * Maps to C++ API. - * TODO: The SPIRConstant query interface and modification interface is not quite complete. - */ -SPVC_PUBLIC_API float spvc_constant_get_scalar_fp16(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API float spvc_constant_get_scalar_fp32(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API double spvc_constant_get_scalar_fp64(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u32(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API int spvc_constant_get_scalar_i32(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u16(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API int spvc_constant_get_scalar_i16(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API unsigned spvc_constant_get_scalar_u8(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API int spvc_constant_get_scalar_i8(spvc_constant constant, unsigned column, unsigned row); -SPVC_PUBLIC_API void spvc_constant_get_subconstants(spvc_constant constant, const spvc_constant_id **constituents, size_t *count); -SPVC_PUBLIC_API spvc_type_id spvc_constant_get_type(spvc_constant constant); - -/* - * Misc reflection - * Maps to C++ API. - */ -SPVC_PUBLIC_API spvc_bool spvc_compiler_get_binary_offset_for_decoration(spvc_compiler compiler, - spvc_variable_id id, - SpvDecoration decoration, - unsigned *word_offset); - -SPVC_PUBLIC_API spvc_bool spvc_compiler_buffer_is_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id); -SPVC_PUBLIC_API spvc_bool spvc_compiler_buffer_get_hlsl_counter_buffer(spvc_compiler compiler, spvc_variable_id id, - spvc_variable_id *counter_id); - -SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_capabilities(spvc_compiler compiler, - const SpvCapability **capabilities, - size_t *num_capabilities); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_declared_extensions(spvc_compiler compiler, const char ***extensions, - size_t *num_extensions); - -SPVC_PUBLIC_API const char *spvc_compiler_get_remapped_declared_block_name(spvc_compiler compiler, spvc_variable_id id); -SPVC_PUBLIC_API spvc_result spvc_compiler_get_buffer_block_decorations(spvc_compiler compiler, spvc_variable_id id, - const SpvDecoration **decorations, - size_t *num_decorations); - -#ifdef __cplusplus -} -#endif -#endif diff --git a/src/libraries/spirv_cross/spirv_cross_containers.hpp b/src/libraries/spirv_cross/spirv_cross_containers.hpp index 506b069c7..e79b32093 100644 --- a/src/libraries/spirv_cross/spirv_cross_containers.hpp +++ b/src/libraries/spirv_cross/spirv_cross_containers.hpp @@ -26,6 +26,7 @@ #include "spirv_cross_error_handling.hpp" #include +#include #include #include #include @@ -210,7 +211,8 @@ public: buffer_capacity = N; } - SmallVector(const T *arg_list_begin, const T *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector() + template + SmallVector(const U *arg_list_begin, const U *arg_list_end) SPIRV_CROSS_NOEXCEPT : SmallVector() { auto count = size_t(arg_list_end - arg_list_begin); reserve(count); @@ -219,7 +221,13 @@ public: this->buffer_size = count; } - SmallVector(std::initializer_list init) SPIRV_CROSS_NOEXCEPT : SmallVector(init.begin(), init.end()) + template + SmallVector(std::initializer_list init) SPIRV_CROSS_NOEXCEPT : SmallVector(init.begin(), init.end()) + { + } + + template + explicit SmallVector(const U (&init)[M]) SPIRV_CROSS_NOEXCEPT : SmallVector(init, init + M) { } diff --git a/src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp b/src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp index e7fcdff04..c6ddb6a45 100644 --- a/src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp +++ b/src/libraries/spirv_cross/spirv_cross_parsed_ir.cpp @@ -54,26 +54,26 @@ ParsedIR::ParsedIR() // Should have been default-implemented, but need this on MSVC 2013. ParsedIR::ParsedIR(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT { - *this = move(other); + *this = std::move(other); } ParsedIR &ParsedIR::operator=(ParsedIR &&other) SPIRV_CROSS_NOEXCEPT { if (this != &other) { - pool_group = move(other.pool_group); - spirv = move(other.spirv); - meta = move(other.meta); + pool_group = std::move(other.pool_group); + spirv = std::move(other.spirv); + meta = std::move(other.meta); for (int i = 0; i < TypeCount; i++) - ids_for_type[i] = move(other.ids_for_type[i]); - ids_for_constant_or_type = move(other.ids_for_constant_or_type); - ids_for_constant_or_variable = move(other.ids_for_constant_or_variable); - declared_capabilities = move(other.declared_capabilities); - declared_extensions = move(other.declared_extensions); - block_meta = move(other.block_meta); - continue_block_to_loop_header = move(other.continue_block_to_loop_header); - entry_points = move(other.entry_points); - ids = move(other.ids); + ids_for_type[i] = std::move(other.ids_for_type[i]); + ids_for_constant_undef_or_type = std::move(other.ids_for_constant_undef_or_type); + ids_for_constant_or_variable = std::move(other.ids_for_constant_or_variable); + declared_capabilities = std::move(other.declared_capabilities); + declared_extensions = std::move(other.declared_extensions); + block_meta = std::move(other.block_meta); + continue_block_to_loop_header = std::move(other.continue_block_to_loop_header); + entry_points = std::move(other.entry_points); + ids = std::move(other.ids); addressing_model = other.addressing_model; memory_model = other.memory_model; @@ -102,7 +102,7 @@ ParsedIR &ParsedIR::operator=(const ParsedIR &other) meta = other.meta; for (int i = 0; i < TypeCount; i++) ids_for_type[i] = other.ids_for_type[i]; - ids_for_constant_or_type = other.ids_for_constant_or_type; + ids_for_constant_undef_or_type = other.ids_for_constant_undef_or_type; ids_for_constant_or_variable = other.ids_for_constant_or_variable; declared_capabilities = other.declared_capabilities; declared_extensions = other.declared_extensions; @@ -330,6 +330,10 @@ void ParsedIR::fixup_reserved_names() { for (uint32_t id : meta_needing_name_fixup) { + // Don't rename remapped variables like 'gl_LastFragDepthARM'. + if (ids[id].get_type() == TypeVariable && get(id).remapped_variable) + continue; + auto &m = meta[id]; sanitize_identifier(m.decoration.alias, false, false); for (auto &memb : m.members) @@ -349,7 +353,7 @@ void ParsedIR::set_name(ID id, const string &name) void ParsedIR::set_member_name(TypeID id, uint32_t index, const string &name) { auto &m = meta[id]; - m.members.resize(max(meta[id].members.size(), size_t(index) + 1)); + m.members.resize(max(m.members.size(), size_t(index) + 1)); m.members[index].alias = name; if (!is_valid_identifier(name) || is_reserved_identifier(name, true, false)) meta_needing_name_fixup.insert(id); @@ -366,6 +370,10 @@ void ParsedIR::set_decoration_string(ID id, Decoration decoration, const string dec.hlsl_semantic = argument; break; + case DecorationUserTypeGOOGLE: + dec.user_type = argument; + break; + default: break; } @@ -451,8 +459,9 @@ void ParsedIR::set_decoration(ID id, Decoration decoration, uint32_t argument) void ParsedIR::set_member_decoration(TypeID id, uint32_t index, Decoration decoration, uint32_t argument) { - meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); - auto &dec = meta[id].members[index]; + auto &m = meta[id]; + m.members.resize(max(m.members.size(), size_t(index) + 1)); + auto &dec = m.members[index]; dec.decoration_flags.set(decoration); switch (decoration) @@ -654,6 +663,9 @@ const string &ParsedIR::get_decoration_string(ID id, Decoration decoration) cons case DecorationHlslSemanticGOOGLE: return dec.hlsl_semantic; + case DecorationUserTypeGOOGLE: + return dec.user_type; + default: return empty_string; } @@ -792,7 +804,8 @@ const Bitset &ParsedIR::get_decoration_bitset(ID id) const void ParsedIR::set_member_decoration_string(TypeID id, uint32_t index, Decoration decoration, const string &argument) { - meta[id].members.resize(max(meta[id].members.size(), size_t(index) + 1)); + auto &m = meta[id]; + m.members.resize(max(m.members.size(), size_t(index) + 1)); auto &dec = meta[id].members[index]; dec.decoration_flags.set(decoration); @@ -928,7 +941,7 @@ void ParsedIR::add_typed_id(Types type, ID id) { case TypeConstant: ids_for_constant_or_variable.push_back(id); - ids_for_constant_or_type.push_back(id); + ids_for_constant_undef_or_type.push_back(id); break; case TypeVariable: @@ -937,7 +950,8 @@ void ParsedIR::add_typed_id(Types type, ID id) case TypeType: case TypeConstantOp: - ids_for_constant_or_type.push_back(id); + case TypeUndef: + ids_for_constant_undef_or_type.push_back(id); break; default: @@ -999,7 +1013,7 @@ ParsedIR::LoopLock::LoopLock(uint32_t *lock_) ParsedIR::LoopLock::LoopLock(LoopLock &&other) SPIRV_CROSS_NOEXCEPT { - *this = move(other); + *this = std::move(other); } ParsedIR::LoopLock &ParsedIR::LoopLock::operator=(LoopLock &&other) SPIRV_CROSS_NOEXCEPT diff --git a/src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp b/src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp index 138d9dd43..7f35c3815 100644 --- a/src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp +++ b/src/libraries/spirv_cross/spirv_cross_parsed_ir.hpp @@ -74,8 +74,8 @@ public: // Special purpose lists which contain a union of types. // This is needed so we can declare specialization constants and structs in an interleaved fashion, // among other things. - // Constants can be of struct type, and struct array sizes can use specialization constants. - SmallVector ids_for_constant_or_type; + // Constants can be undef or of struct type, and struct array sizes can use specialization constants. + SmallVector ids_for_constant_undef_or_type; SmallVector ids_for_constant_or_variable; // We need to keep track of the width the Ops that contains a type for the diff --git a/src/libraries/spirv_cross/spirv_glsl.cpp b/src/libraries/spirv_cross/spirv_glsl.cpp index cdc1c6b6e..f200b424d 100644 --- a/src/libraries/spirv_cross/spirv_glsl.cpp +++ b/src/libraries/spirv_cross/spirv_glsl.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #ifndef _WIN32 #include @@ -222,7 +223,7 @@ static const char *to_pls_layout(PlsFormat format) } } -static SPIRType::BaseType pls_format_to_basetype(PlsFormat format) +static std::pair pls_format_to_basetype(PlsFormat format) { switch (format) { @@ -233,17 +234,17 @@ static SPIRType::BaseType pls_format_to_basetype(PlsFormat format) case PlsRGB10A2: case PlsRGBA8: case PlsRG16: - return SPIRType::Float; + return std::make_pair(spv::OpTypeFloat, SPIRType::Float); case PlsRGBA8I: case PlsRG16I: - return SPIRType::Int; + return std::make_pair(spv::OpTypeInt, SPIRType::Int); case PlsRGB10A2UI: case PlsRGBA8UI: case PlsRG16UI: case PlsR32UI: - return SPIRType::UInt; + return std::make_pair(spv::OpTypeInt, SPIRType::UInt); } } @@ -296,8 +297,19 @@ const char *CompilerGLSL::vector_swizzle(int vecsize, int index) return swizzle[vecsize - 1][index]; } -void CompilerGLSL::reset() +void CompilerGLSL::reset(uint32_t iteration_count) { + // Sanity check the iteration count to be robust against a certain class of bugs where + // we keep forcing recompilations without making clear forward progress. + // In buggy situations we will loop forever, or loop for an unbounded number of iterations. + // Certain types of recompilations are considered to make forward progress, + // but in almost all situations, we'll never see more than 3 iterations. + // It is highly context-sensitive when we need to force recompilation, + // and it is not practical with the current architecture + // to resolve everything up front. + if (iteration_count >= options.force_recompile_max_debug_iterations && !is_force_recompile_forward_progress) + SPIRV_CROSS_THROW("Maximum compilation loops detected and no forward progress was made. Must be a SPIRV-Cross bug!"); + // We do some speculative optimizations which should pretty much always work out, // but just in case the SPIR-V is rather weird, recompile until it's happy. // This typically only means one extra pass. @@ -305,6 +317,7 @@ void CompilerGLSL::reset() // Clear invalid expression tracking. invalid_expressions.clear(); + composite_insert_overwritten.clear(); current_function = nullptr; // Clear temporary usage tracking. @@ -315,6 +328,8 @@ void CompilerGLSL::reset() // Ensure that we declare phi-variable copies even if the original declaration isn't deferred flushed_phi_variables.clear(); + current_emitting_switch_stack.clear(); + reset_name_caches(); ir.for_each_typed_id([&](uint32_t, SPIRFunction &func) { @@ -393,10 +408,9 @@ void CompilerGLSL::find_static_extensions() } else if (type.basetype == SPIRType::Int64 || type.basetype == SPIRType::UInt64) { - if (options.es) - SPIRV_CROSS_THROW("64-bit integers not supported in ES profile."); - if (!options.es) - require_extension_internal("GL_ARB_gpu_shader_int64"); + if (options.es && options.version < 310) // GL_NV_gpu_shader5 fallback requires 310. + SPIRV_CROSS_THROW("64-bit integers not supported in ES profile before version 310."); + require_extension_internal("GL_ARB_gpu_shader_int64"); } else if (type.basetype == SPIRType::Half) { @@ -484,6 +498,15 @@ void CompilerGLSL::find_static_extensions() require_extension_internal("GL_NV_ray_tracing"); break; + case ExecutionModelMeshEXT: + case ExecutionModelTaskEXT: + if (options.es || options.version < 450) + SPIRV_CROSS_THROW("Mesh shaders require GLSL 450 or above."); + if (!options.vulkan_semantics) + SPIRV_CROSS_THROW("Mesh shaders require Vulkan semantics."); + require_extension_internal("GL_EXT_mesh_shader"); + break; + default: break; } @@ -530,7 +553,7 @@ void CompilerGLSL::find_static_extensions() SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires ESSL 320."); else if (!options.es && options.version < 450) SPIRV_CROSS_THROW("GL_EXT_buffer_reference requires GLSL 450."); - require_extension_internal("GL_EXT_buffer_reference"); + require_extension_internal("GL_EXT_buffer_reference2"); } else if (ir.addressing_model != AddressingModelLogical) { @@ -607,6 +630,22 @@ void CompilerGLSL::find_static_extensions() SPIRV_CROSS_THROW("OVR_multiview2 can only be used with Vertex shaders."); require_extension_internal("GL_OVR_multiview2"); } + + // KHR one is likely to get promoted at some point, so if we don't see an explicit SPIR-V extension, assume KHR. + for (auto &ext : ir.declared_extensions) + if (ext == "SPV_NV_fragment_shader_barycentric") + barycentric_is_nv = true; +} + +void CompilerGLSL::require_polyfill(Polyfill polyfill, bool relaxed) +{ + uint32_t &polyfills = (relaxed && options.es) ? required_polyfills_relaxed : required_polyfills; + + if ((polyfills & polyfill) == 0) + { + polyfills |= polyfill; + force_recompile(); + } } void CompilerGLSL::ray_tracing_khr_fixup_locations() @@ -631,19 +670,22 @@ string CompilerGLSL::compile() { // only NV_gpu_shader5 supports divergent indexing on OpenGL, and it does so without extra qualifiers backend.nonuniform_qualifier = ""; - backend.needs_row_major_load_workaround = true; + backend.needs_row_major_load_workaround = options.enable_row_major_load_workaround; } backend.allow_precision_qualifiers = options.vulkan_semantics || options.es; backend.force_gl_in_out_block = true; backend.supports_extensions = true; backend.use_array_constructor = true; - - backend.support_precise_qualifier = (!options.es && options.version >= 400) || (options.es && options.version >= 320); + backend.workgroup_size_is_hidden = true; + backend.requires_relaxed_precision_analysis = options.es || options.vulkan_semantics; + backend.support_precise_qualifier = + (!options.es && options.version >= 400) || (options.es && options.version >= 320); if (is_legacy_es()) backend.support_case_fallthrough = false; // Scan the SPIR-V to find trivial uses of extensions. + fixup_anonymous_struct_names(); fixup_type_alias(); reorder_type_alias(); build_function_control_flow_graphs_and_analyze(); @@ -663,10 +705,7 @@ string CompilerGLSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); buffer.reset(); @@ -674,6 +713,11 @@ string CompilerGLSL::compile() emit_resources(); emit_extension_workarounds(get_execution_model()); + if (required_polyfills != 0) + emit_polyfills(required_polyfills, false); + if (options.es && required_polyfills_relaxed != 0) + emit_polyfills(required_polyfills_relaxed, true); + emit_function(get(ir.default_entry_point), Bitset()); pass_count++; @@ -707,6 +751,8 @@ void CompilerGLSL::build_workgroup_size(SmallVector &arguments, const Sp const SpecializationConstant &wg_y, const SpecializationConstant &wg_z) { auto &execution = get_entry_point(); + bool builtin_workgroup = execution.workgroup_size.constant != 0; + bool use_local_size_id = !builtin_workgroup && execution.flags.get(ExecutionModeLocalSizeId); if (wg_x.id) { @@ -715,6 +761,8 @@ void CompilerGLSL::build_workgroup_size(SmallVector &arguments, const Sp else arguments.push_back(join("local_size_x = ", get(wg_x.id).specialization_constant_macro_name)); } + else if (use_local_size_id && execution.workgroup_size.id_x) + arguments.push_back(join("local_size_x = ", get(execution.workgroup_size.id_x).scalar())); else arguments.push_back(join("local_size_x = ", execution.workgroup_size.x)); @@ -725,6 +773,8 @@ void CompilerGLSL::build_workgroup_size(SmallVector &arguments, const Sp else arguments.push_back(join("local_size_y = ", get(wg_y.id).specialization_constant_macro_name)); } + else if (use_local_size_id && execution.workgroup_size.id_y) + arguments.push_back(join("local_size_y = ", get(execution.workgroup_size.id_y).scalar())); else arguments.push_back(join("local_size_y = ", execution.workgroup_size.y)); @@ -735,6 +785,8 @@ void CompilerGLSL::build_workgroup_size(SmallVector &arguments, const Sp else arguments.push_back(join("local_size_z = ", get(wg_z.id).specialization_constant_macro_name)); } + else if (use_local_size_id && execution.workgroup_size.id_z) + arguments.push_back(join("local_size_z = ", get(execution.workgroup_size.id_z).scalar())); else arguments.push_back(join("local_size_z = ", execution.workgroup_size.z)); } @@ -801,7 +853,20 @@ void CompilerGLSL::emit_header() for (auto &ext : forced_extensions) { - if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16") + if (ext == "GL_ARB_gpu_shader_int64") + { + statement("#if defined(GL_ARB_gpu_shader_int64)"); + statement("#extension GL_ARB_gpu_shader_int64 : require"); + if (!options.vulkan_semantics || options.es) + { + statement("#elif defined(GL_NV_gpu_shader5)"); + statement("#extension GL_NV_gpu_shader5 : require"); + } + statement("#else"); + statement("#error No extension available for 64-bit integers."); + statement("#endif"); + } + else if (ext == "GL_EXT_shader_explicit_arithmetic_types_float16") { // Special case, this extension has a potential fallback to another vendor extension in normal GLSL. // GL_AMD_gpu_shader_half_float is a superset, so try that first. @@ -821,13 +886,30 @@ void CompilerGLSL::emit_header() statement("#error No extension available for FP16."); statement("#endif"); } + else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int8") + { + if (options.vulkan_semantics) + statement("#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require"); + else + { + statement("#if defined(GL_EXT_shader_explicit_arithmetic_types_int8)"); + statement("#extension GL_EXT_shader_explicit_arithmetic_types_int8 : require"); + statement("#elif defined(GL_NV_gpu_shader5)"); + statement("#extension GL_NV_gpu_shader5 : require"); + statement("#else"); + statement("#error No extension available for Int8."); + statement("#endif"); + } + } else if (ext == "GL_EXT_shader_explicit_arithmetic_types_int16") { if (options.vulkan_semantics) statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require"); else { - statement("#if defined(GL_AMD_gpu_shader_int16)"); + statement("#if defined(GL_EXT_shader_explicit_arithmetic_types_int16)"); + statement("#extension GL_EXT_shader_explicit_arithmetic_types_int16 : require"); + statement("#elif defined(GL_AMD_gpu_shader_int16)"); statement("#extension GL_AMD_gpu_shader_int16 : require"); statement("#elif defined(GL_NV_gpu_shader5)"); statement("#extension GL_NV_gpu_shader5 : require"); @@ -1004,8 +1086,10 @@ void CompilerGLSL::emit_header() break; case ExecutionModelGLCompute: + case ExecutionModelTaskEXT: + case ExecutionModelMeshEXT: { - if (execution.workgroup_size.constant != 0) + if (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId)) { SpecializationConstant wg_x, wg_y, wg_z; get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); @@ -1022,6 +1106,18 @@ void CompilerGLSL::emit_header() inputs.push_back(join("local_size_y = ", execution.workgroup_size.y)); inputs.push_back(join("local_size_z = ", execution.workgroup_size.z)); } + + if (execution.model == ExecutionModelMeshEXT) + { + outputs.push_back(join("max_vertices = ", execution.output_vertices)); + outputs.push_back(join("max_primitives = ", execution.output_primitives)); + if (execution.flags.get(ExecutionModeOutputTrianglesEXT)) + outputs.push_back("triangles"); + else if (execution.flags.get(ExecutionModeOutputLinesEXT)) + outputs.push_back("lines"); + else if (execution.flags.get(ExecutionModeOutputPoints)) + outputs.push_back("points"); + } break; } @@ -1170,15 +1266,39 @@ string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags) if (flags.get(DecorationFlat)) res += "flat "; if (flags.get(DecorationNoPerspective)) + { + if (options.es) + { + if (options.version < 300) + SPIRV_CROSS_THROW("noperspective requires ESSL 300."); + require_extension_internal("GL_NV_shader_noperspective_interpolation"); + } + else if (is_legacy_desktop()) + require_extension_internal("GL_EXT_gpu_shader4"); res += "noperspective "; + } if (flags.get(DecorationCentroid)) res += "centroid "; if (flags.get(DecorationPatch)) res += "patch "; if (flags.get(DecorationSample)) + { + if (options.es) + { + if (options.version < 300) + SPIRV_CROSS_THROW("sample requires ESSL 300."); + else if (options.version < 320) + require_extension_internal("GL_OES_shader_multisample_interpolation"); + } res += "sample "; - if (flags.get(DecorationInvariant)) + } + if (flags.get(DecorationInvariant) && (options.es || options.version >= 120)) res += "invariant "; + if (flags.get(DecorationPerPrimitiveEXT)) + { + res += "perprimitiveEXT "; + require_extension_internal("GL_EXT_mesh_shader"); + } if (flags.get(DecorationExplicitInterpAMD)) { @@ -1186,14 +1306,23 @@ string CompilerGLSL::to_interpolation_qualifiers(const Bitset &flags) res += "__explicitInterpAMD "; } - if (flags.get(DecorationPerVertexNV)) + if (flags.get(DecorationPerVertexKHR)) { if (options.es && options.version < 320) - SPIRV_CROSS_THROW("pervertexNV requires ESSL 320."); + SPIRV_CROSS_THROW("pervertexEXT requires ESSL 320."); else if (!options.es && options.version < 450) - SPIRV_CROSS_THROW("pervertexNV requires GLSL 450."); - require_extension_internal("GL_NV_fragment_shader_barycentric"); - res += "pervertexNV "; + SPIRV_CROSS_THROW("pervertexEXT requires GLSL 450."); + + if (barycentric_is_nv) + { + require_extension_internal("GL_NV_fragment_shader_barycentric"); + res += "pervertexNV "; + } + else + { + require_extension_internal("GL_EXT_fragment_shader_barycentric"); + res += "pervertexEXT "; + } } return res; @@ -1360,6 +1489,10 @@ const char *CompilerGLSL::format_to_glsl(spv::ImageFormat format) return "rg8i"; case ImageFormatR16i: return "r16i"; + case ImageFormatR64i: + return "r64i"; + case ImageFormatR64ui: + return "r64ui"; default: case ImageFormatUnknown: return nullptr; @@ -1396,7 +1529,7 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bits { // If using PhysicalStorageBufferEXT storage class, this is a pointer, // and is 64-bit. - if (type.storage == StorageClassPhysicalStorageBufferEXT) + if (is_physical_pointer(type)) { if (!type.pointer) SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers."); @@ -1411,8 +1544,7 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bits else SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT."); } - - if (!type.array.empty()) + else if (is_array(type)) { uint32_t minimum_alignment = 1; if (packing_is_vec4_padded(packing)) @@ -1439,7 +1571,7 @@ uint32_t CompilerGLSL::type_to_packed_alignment(const SPIRType &type, const Bits // In std140, struct alignment is rounded up to 16. if (packing_is_vec4_padded(packing)) - alignment = max(alignment, 16u); + alignment = max(alignment, 16u); return alignment; } @@ -1518,7 +1650,19 @@ uint32_t CompilerGLSL::type_to_packed_array_stride(const SPIRType &type, const B uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &flags, BufferPackingStandard packing) { - if (!type.array.empty()) + // If using PhysicalStorageBufferEXT storage class, this is a pointer, + // and is 64-bit. + if (is_physical_pointer(type)) + { + if (!type.pointer) + SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers."); + + if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT) + return 8; + else + SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT."); + } + else if (is_array(type)) { uint32_t packed_size = to_array_size_literal(type) * type_to_packed_array_stride(type, flags, packing); @@ -1530,19 +1674,6 @@ uint32_t CompilerGLSL::type_to_packed_size(const SPIRType &type, const Bitset &f return packed_size; } - // If using PhysicalStorageBufferEXT storage class, this is a pointer, - // and is 64-bit. - if (type.storage == StorageClassPhysicalStorageBufferEXT) - { - if (!type.pointer) - SPIRV_CROSS_THROW("Types in PhysicalStorageBufferEXT must be pointers."); - - if (ir.addressing_model == AddressingModelPhysicalStorageBuffer64EXT) - return 8; - else - SPIRV_CROSS_THROW("AddressingModelPhysicalStorageBuffer64EXT must be used for PhysicalStorageBufferEXT."); - } - uint32_t size = 0; if (type.basetype == SPIRType::Struct) @@ -1661,16 +1792,29 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin packed_size = type_to_packed_size(memb_type, member_flags, packing); // We only need to care about this if we have non-array types which can straddle the vec4 boundary. + uint32_t actual_offset = type_struct_member_offset(type, i); + if (packing_is_hlsl(packing)) { // If a member straddles across a vec4 boundary, alignment is actually vec4. - uint32_t begin_word = offset / 16; - uint32_t end_word = (offset + packed_size - 1) / 16; + uint32_t target_offset; + + // If we intend to use explicit packing, we must check for improper straddle with that offset. + // In implicit packing, we must check with implicit offset, since the explicit offset + // might have already accounted for the straddle, and we'd miss the alignment promotion to vec4. + // This is important when packing sub-structs that don't support packoffset(). + if (packing_has_flexible_offset(packing)) + target_offset = actual_offset; + else + target_offset = offset; + + uint32_t begin_word = target_offset / 16; + uint32_t end_word = (target_offset + packed_size - 1) / 16; + if (begin_word != end_word) - packed_alignment = max(packed_alignment, 16u); + packed_alignment = max(packed_alignment, 16u); } - uint32_t actual_offset = type_struct_member_offset(type, i); // Field is not in the specified range anymore and we can ignore any further fields. if (actual_offset >= end_offset) break; @@ -1708,8 +1852,9 @@ bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackin } // Verify array stride rules. - if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) != - type_struct_member_array_stride(type, i)) + if (is_array(memb_type) && + type_to_packed_array_stride(memb_type, member_flags, packing) != + type_struct_member_array_stride(type, i)) { if (failed_validation_index) *failed_validation_index = i; @@ -2112,9 +2257,8 @@ void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var) // OpenGL has no concept of push constant blocks, implement it as a uniform struct. auto &type = get(var.basetype); - auto &flags = ir.meta[var.self].decoration.decoration_flags; - flags.clear(DecorationBinding); - flags.clear(DecorationDescriptorSet); + unset_decoration(var.self, DecorationBinding); + unset_decoration(var.self, DecorationDescriptorSet); #if 0 if (flags & ((1ull << DecorationBinding) | (1ull << DecorationDescriptorSet))) @@ -2124,14 +2268,13 @@ void CompilerGLSL::emit_push_constant_block_glsl(const SPIRVariable &var) // We're emitting the push constant block as a regular struct, so disable the block qualifier temporarily. // Otherwise, we will end up emitting layout() qualifiers on naked structs which is not allowed. - auto &block_flags = ir.meta[type.self].decoration.decoration_flags; - bool block_flag = block_flags.get(DecorationBlock); - block_flags.clear(DecorationBlock); + bool block_flag = has_decoration(type.self, DecorationBlock); + unset_decoration(type.self, DecorationBlock); emit_struct(type); if (block_flag) - block_flags.set(DecorationBlock); + set_decoration(type.self, DecorationBlock); emit_uniform(var); statement(""); @@ -2334,6 +2477,10 @@ void CompilerGLSL::emit_buffer_block_native(const SPIRVariable &var) i++; } + // Don't declare empty blocks in GLSL, this is not allowed. + if (type_is_empty(type) && !backend.supports_empty_struct) + statement("int empty_struct_member;"); + // var.self can be used as a backup name for the block name, // so we need to make sure we don't disturb the name here on a recompile. // It will need to be reset if we have to recompile. @@ -2354,7 +2501,7 @@ void CompilerGLSL::emit_buffer_block_flattened(const SPIRVariable &var) SPIRType::BaseType basic_type; if (get_common_basic_type(type, basic_type)) { - SPIRType tmp; + SPIRType tmp { OpTypeVector }; tmp.basetype = basic_type; tmp.vecsize = 4; if (basic_type != SPIRType::Float && basic_type != SPIRType::Int && basic_type != SPIRType::UInt) @@ -2561,7 +2708,7 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) } // Workaround to make sure we can emit "patch in/out" correctly. - fixup_io_block_patch_qualifiers(var); + fixup_io_block_patch_primitive_qualifiers(var); // Block names should never alias. auto block_name = to_name(type.self, false); @@ -2584,8 +2731,15 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) // Instance names cannot alias block names. resource_names.insert(block_name); - bool is_patch = has_decoration(var.self, DecorationPatch); - statement(layout_for_variable(var), (is_patch ? "patch " : ""), qual, block_name); + const char *block_qualifier; + if (has_decoration(var.self, DecorationPatch)) + block_qualifier = "patch "; + else if (has_decoration(var.self, DecorationPerPrimitiveEXT)) + block_qualifier = "perprimitiveEXT "; + else + block_qualifier = ""; + + statement(layout_for_variable(var), block_qualifier, qual, block_name); begin_scope(); type.member_name_cache.clear(); @@ -2618,30 +2772,26 @@ void CompilerGLSL::emit_interface_block(const SPIRVariable &var) { add_resource_name(var.self); - // Tessellation control and evaluation shaders must have either gl_MaxPatchVertices or unsized arrays for input arrays. + // Legacy GLSL did not support int attributes, we automatically + // declare them as float and cast them on load/store + SPIRType newtype = type; + if (is_legacy() && var.storage == StorageClassInput && type.basetype == SPIRType::Int) + newtype.basetype = SPIRType::Float; + + // Tessellation control and evaluation shaders must have either + // gl_MaxPatchVertices or unsized arrays for input arrays. // Opt for unsized as it's the more "correct" variant to use. - bool control_point_input_array = type.storage == StorageClassInput && !type.array.empty() && - !has_decoration(var.self, DecorationPatch) && - (get_entry_point().model == ExecutionModelTessellationControl || - get_entry_point().model == ExecutionModelTessellationEvaluation); - - uint32_t old_array_size = 0; - bool old_array_size_literal = true; - - if (control_point_input_array) + if (type.storage == StorageClassInput && !type.array.empty() && + !has_decoration(var.self, DecorationPatch) && + (get_entry_point().model == ExecutionModelTessellationControl || + get_entry_point().model == ExecutionModelTessellationEvaluation)) { - swap(type.array.back(), old_array_size); - swap(type.array_size_literal.back(), old_array_size_literal); + newtype.array.back() = 0; + newtype.array_size_literal.back() = true; } statement(layout_for_variable(var), to_qualifiers_glsl(var.self), - variable_decl(type, to_name(var.self), var.self), ";"); - - if (control_point_input_array) - { - swap(type.array.back(), old_array_size); - swap(type.array_size_literal.back(), old_array_size_literal); - } + variable_decl(newtype, to_name(var.self), var.self), ";"); } } } @@ -2669,14 +2819,41 @@ string CompilerGLSL::constant_value_macro_name(uint32_t id) void CompilerGLSL::emit_specialization_constant_op(const SPIRConstantOp &constant) { auto &type = get(constant.basetype); + // This will break. It is bogus and should not be legal. + if (type_is_top_level_block(type)) + return; + add_resource_name(constant.self); auto name = to_name(constant.self); statement("const ", variable_decl(type, name), " = ", constant_op_expression(constant), ";"); } +int CompilerGLSL::get_constant_mapping_to_workgroup_component(const SPIRConstant &c) const +{ + auto &entry_point = get_entry_point(); + int index = -1; + + // Need to redirect specialization constants which are used as WorkGroupSize to the builtin, + // since the spec constant declarations are never explicitly declared. + if (entry_point.workgroup_size.constant == 0 && entry_point.flags.get(ExecutionModeLocalSizeId)) + { + if (c.self == entry_point.workgroup_size.id_x) + index = 0; + else if (c.self == entry_point.workgroup_size.id_y) + index = 1; + else if (c.self == entry_point.workgroup_size.id_z) + index = 2; + } + + return index; +} + void CompilerGLSL::emit_constant(const SPIRConstant &constant) { auto &type = get(constant.constant_type); - auto name = to_name(constant.self); + + // This will break. It is bogus and should not be legal. + if (type_is_top_level_block(type)) + return; SpecializationConstant wg_x, wg_y, wg_z; ID workgroup_size_id = get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); @@ -2703,6 +2880,9 @@ void CompilerGLSL::emit_constant(const SPIRConstant &constant) return; } + add_resource_name(constant.self); + auto name = to_name(constant.self); + // Only scalars have constant IDs. if (has_decoration(constant.self, DecorationSpecId)) { @@ -2945,11 +3125,10 @@ void CompilerGLSL::fixup_image_load_store_access() // Solve this by making the image access as restricted as possible and loosen up if we need to. // If any no-read/no-write flags are actually set, assume that the compiler knows what it's doing. - auto &flags = ir.meta[var].decoration.decoration_flags; - if (!flags.get(DecorationNonWritable) && !flags.get(DecorationNonReadable)) + if (!has_decoration(var, DecorationNonWritable) && !has_decoration(var, DecorationNonReadable)) { - flags.set(DecorationNonWritable); - flags.set(DecorationNonReadable); + set_decoration(var, DecorationNonWritable); + set_decoration(var, DecorationNonReadable); } } }); @@ -2999,16 +3178,21 @@ bool CompilerGLSL::should_force_emit_builtin_block(StorageClass storage) }); // If we're declaring clip/cull planes with control points we need to force block declaration. - if (get_execution_model() == ExecutionModelTessellationControl && + if ((get_execution_model() == ExecutionModelTessellationControl || + get_execution_model() == ExecutionModelMeshEXT) && (clip_distance_count || cull_distance_count)) { should_force = true; } + // Either glslang bug or oversight, but global invariant position does not work in mesh shaders. + if (get_execution_model() == ExecutionModelMeshEXT && position_invariant) + should_force = true; + return should_force; } -void CompilerGLSL::fixup_implicit_builtin_block_names() +void CompilerGLSL::fixup_implicit_builtin_block_names(ExecutionModel model) { ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { auto &type = this->get(var.basetype); @@ -3016,11 +3200,43 @@ void CompilerGLSL::fixup_implicit_builtin_block_names() if ((var.storage == StorageClassOutput || var.storage == StorageClassInput) && block && is_builtin_variable(var)) { - // Make sure the array has a supported name in the code. - if (var.storage == StorageClassOutput) - set_name(var.self, "gl_out"); - else if (var.storage == StorageClassInput) - set_name(var.self, "gl_in"); + if (model != ExecutionModelMeshEXT) + { + // Make sure the array has a supported name in the code. + if (var.storage == StorageClassOutput) + set_name(var.self, "gl_out"); + else if (var.storage == StorageClassInput) + set_name(var.self, "gl_in"); + } + else + { + auto flags = get_buffer_block_flags(var.self); + if (flags.get(DecorationPerPrimitiveEXT)) + { + set_name(var.self, "gl_MeshPrimitivesEXT"); + set_name(type.self, "gl_MeshPerPrimitiveEXT"); + } + else + { + set_name(var.self, "gl_MeshVerticesEXT"); + set_name(type.self, "gl_MeshPerVertexEXT"); + } + } + } + + if (model == ExecutionModelMeshEXT && var.storage == StorageClassOutput && !block) + { + auto *m = ir.find_meta(var.self); + if (m && m->decoration.builtin) + { + auto builtin_type = m->decoration.builtin_type; + if (builtin_type == BuiltInPrimitivePointIndicesEXT) + set_name(var.self, "gl_PrimitivePointIndicesEXT"); + else if (builtin_type == BuiltInPrimitiveLineIndicesEXT) + set_name(var.self, "gl_PrimitiveLineIndicesEXT"); + else if (builtin_type == BuiltInPrimitiveTriangleIndicesEXT) + set_name(var.self, "gl_PrimitiveTriangleIndicesEXT"); + } } }); } @@ -3031,7 +3247,6 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo Bitset global_builtins; const SPIRVariable *block_var = nullptr; bool emitted_block = false; - bool builtin_array = false; // Need to use declared size in the type. // These variables might have been declared, but not statically used, so we haven't deduced their size yet. @@ -3044,6 +3259,11 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo uint32_t xfb_stride = 0, xfb_buffer = 0, geom_stream = 0; std::unordered_map builtin_xfb_offsets; + const auto builtin_is_per_vertex_set = [](BuiltIn builtin) -> bool { + return builtin == BuiltInPosition || builtin == BuiltInPointSize || + builtin == BuiltInClipDistance || builtin == BuiltInCullDistance; + }; + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { auto &type = this->get(var.basetype); bool block = has_decoration(type.self, DecorationBlock); @@ -3054,7 +3274,7 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo uint32_t index = 0; for (auto &m : ir.meta[type.self].members) { - if (m.builtin) + if (m.builtin && builtin_is_per_vertex_set(m.builtin_type)) { builtins.set(m.builtin_type); if (m.builtin_type == BuiltInCullDistance) @@ -3107,13 +3327,15 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo { // While we're at it, collect all declared global builtins (HLSL mostly ...). auto &m = ir.meta[var.self].decoration; - if (m.builtin) + if (m.builtin && builtin_is_per_vertex_set(m.builtin_type)) { + // For mesh/tesc output, Clip/Cull is an array-of-array. Look at innermost array type + // for correct result. global_builtins.set(m.builtin_type); if (m.builtin_type == BuiltInCullDistance) - cull_distance_size = to_array_size_literal(type); + cull_distance_size = to_array_size_literal(type, 0); else if (m.builtin_type == BuiltInClipDistance) - clip_distance_size = to_array_size_literal(type); + clip_distance_size = to_array_size_literal(type, 0); if (is_block_builtin(m.builtin_type) && m.decoration_flags.get(DecorationXfbStride) && m.decoration_flags.get(DecorationXfbBuffer) && m.decoration_flags.get(DecorationOffset)) @@ -3150,7 +3372,6 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo emitted_builtins = builtins; emitted_block = true; - builtin_array = !type.array.empty(); block_var = &var; }); @@ -3196,7 +3417,9 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo attr.push_back(join("stream = ", geom_stream)); } - if (!attr.empty()) + if (model == ExecutionModelMeshEXT) + statement("out gl_MeshPerVertexEXT"); + else if (!attr.empty()) statement("layout(", merge(attr), ") out gl_PerVertex"); else statement("out gl_PerVertex"); @@ -3216,6 +3439,8 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo auto itr = builtin_xfb_offsets.find(BuiltInPosition); if (itr != end(builtin_xfb_offsets)) statement("layout(xfb_offset = ", itr->second, ") vec4 gl_Position;"); + else if (position_invariant) + statement("invariant vec4 gl_Position;"); else statement("vec4 gl_Position;"); } @@ -3247,39 +3472,29 @@ void CompilerGLSL::emit_declared_builtin_block(StorageClass storage, ExecutionMo statement("float gl_CullDistance[", cull_distance_size, "];"); } + bool builtin_array = model == ExecutionModelTessellationControl || + (model == ExecutionModelMeshEXT && storage == StorageClassOutput) || + (model == ExecutionModelGeometry && storage == StorageClassInput) || + (model == ExecutionModelTessellationEvaluation && storage == StorageClassInput); + if (builtin_array) { - if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) - end_scope_decl(join(to_name(block_var->self), "[", get_entry_point().output_vertices, "]")); + const char *instance_name; + if (model == ExecutionModelMeshEXT) + instance_name = "gl_MeshVerticesEXT"; // Per primitive is never synthesized. else - end_scope_decl(join(to_name(block_var->self), "[]")); + instance_name = storage == StorageClassInput ? "gl_in" : "gl_out"; + + if (model == ExecutionModelTessellationControl && storage == StorageClassOutput) + end_scope_decl(join(instance_name, "[", get_entry_point().output_vertices, "]")); + else + end_scope_decl(join(instance_name, "[]")); } else end_scope_decl(); statement(""); } -void CompilerGLSL::declare_undefined_values() -{ - bool emitted = false; - ir.for_each_typed_id([&](uint32_t, const SPIRUndef &undef) { - auto &type = this->get(undef.basetype); - // OpUndef can be void for some reason ... - if (type.basetype == SPIRType::Void) - return; - - string initializer; - if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) - initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); - - statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";"); - emitted = true; - }); - - if (emitted) - statement(""); -} - bool CompilerGLSL::variable_is_lut(const SPIRVariable &var) const { bool statically_assigned = var.statically_assigned && var.static_expression != ID(0) && var.remapped_variable; @@ -3314,13 +3529,16 @@ void CompilerGLSL::emit_resources() case ExecutionModelGeometry: case ExecutionModelTessellationControl: case ExecutionModelTessellationEvaluation: - fixup_implicit_builtin_block_names(); + case ExecutionModelMeshEXT: + fixup_implicit_builtin_block_names(execution.model); break; default: break; } + bool global_invariant_position = position_invariant && (options.es || options.version >= 120); + // Emit custom gl_PerVertex for SSO compatibility. if (options.separate_shader_objects && !options.es && execution.model != ExecutionModelFragment) { @@ -3331,10 +3549,13 @@ void CompilerGLSL::emit_resources() case ExecutionModelTessellationEvaluation: emit_declared_builtin_block(StorageClassInput, execution.model); emit_declared_builtin_block(StorageClassOutput, execution.model); + global_invariant_position = false; break; case ExecutionModelVertex: + case ExecutionModelMeshEXT: emit_declared_builtin_block(StorageClassOutput, execution.model); + global_invariant_position = false; break; default: @@ -3344,6 +3565,7 @@ void CompilerGLSL::emit_resources() else if (should_force_emit_builtin_block(StorageClassOutput)) { emit_declared_builtin_block(StorageClassOutput, execution.model); + global_invariant_position = false; } else if (execution.geometry_passthrough) { @@ -3364,7 +3586,7 @@ void CompilerGLSL::emit_resources() statement(""); } - if (position_invariant) + if (global_invariant_position) { statement("invariant gl_Position;"); statement(""); @@ -3378,10 +3600,14 @@ void CompilerGLSL::emit_resources() // { auto loop_lock = ir.create_loop_hard_lock(); - for (auto &id_ : ir.ids_for_constant_or_type) + for (auto &id_ : ir.ids_for_constant_undef_or_type) { auto &id = ir.ids[id_]; + // Skip declaring any bogus constants or undefs which use block types. + // We don't declare block types directly, so this will never work. + // Should not be legal SPIR-V, so this is considered a workaround. + if (id.get_type() == TypeConstant) { auto &c = id.get(); @@ -3431,6 +3657,26 @@ void CompilerGLSL::emit_resources() emit_struct(*type); } } + else if (id.get_type() == TypeUndef) + { + auto &undef = id.get(); + auto &type = this->get(undef.basetype); + // OpUndef can be void for some reason ... + if (type.basetype == SPIRType::Void) + return; + + // This will break. It is bogus and should not be legal. + if (type_is_top_level_block(type)) + return; + + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); + + // FIXME: If used in a constant, we must declare it as one. + statement(variable_decl(type, to_name(undef.self), undef.self), initializer, ";"); + emitted = true; + } } } @@ -3441,7 +3687,7 @@ void CompilerGLSL::emit_resources() // If the work group size depends on a specialization constant, we need to declare the layout() block // after constants (and their macros) have been declared. if (execution.model == ExecutionModelGLCompute && !options.vulkan_semantics && - execution.workgroup_size.constant != 0) + (execution.workgroup_size.constant != 0 || execution.flags.get(ExecutionModeLocalSizeId))) { SpecializationConstant wg_x, wg_y, wg_z; get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); @@ -3647,8 +3893,6 @@ void CompilerGLSL::emit_resources() if (emitted) statement(""); - - declare_undefined_values(); } void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var) @@ -3694,6 +3938,7 @@ void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var) auto &member_type = get(member_type_id); auto array_type = member_type; array_type.parent_type = member_type_id; + array_type.op = OpTypeArray; array_type.array.push_back(array_size); array_type.array_size_literal.push_back(true); @@ -3717,10 +3962,9 @@ void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var) if (is_control_point) { uint32_t ids = ir.increase_bound_by(3); - SPIRType uint_type; + auto &uint_type = set(ids, OpTypeInt); uint_type.basetype = SPIRType::UInt; uint_type.width = 32; - set(ids, uint_type); set(ids + 1, builtin_to_glsl(BuiltInInvocationId, StorageClassInput), ids, true); set(ids + 2, ids, i, false); invocation_id = ids + 1; @@ -3800,6 +4044,169 @@ void CompilerGLSL::emit_output_variable_initializer(const SPIRVariable &var) } } +void CompilerGLSL::emit_subgroup_arithmetic_workaround(const std::string &func, Op op, GroupOperation group_op) +{ + std::string result; + switch (group_op) + { + case GroupOperationReduce: + result = "reduction"; + break; + + case GroupOperationExclusiveScan: + result = "excl_scan"; + break; + + case GroupOperationInclusiveScan: + result = "incl_scan"; + break; + + default: + SPIRV_CROSS_THROW("Unsupported workaround for arithmetic group operation"); + } + + struct TypeInfo + { + std::string type; + std::string identity; + }; + + std::vector type_infos; + switch (op) + { + case OpGroupNonUniformIAdd: + { + type_infos.emplace_back(TypeInfo{ "uint", "0u" }); + type_infos.emplace_back(TypeInfo{ "uvec2", "uvec2(0u)" }); + type_infos.emplace_back(TypeInfo{ "uvec3", "uvec3(0u)" }); + type_infos.emplace_back(TypeInfo{ "uvec4", "uvec4(0u)" }); + type_infos.emplace_back(TypeInfo{ "int", "0" }); + type_infos.emplace_back(TypeInfo{ "ivec2", "ivec2(0)" }); + type_infos.emplace_back(TypeInfo{ "ivec3", "ivec3(0)" }); + type_infos.emplace_back(TypeInfo{ "ivec4", "ivec4(0)" }); + break; + } + + case OpGroupNonUniformFAdd: + { + type_infos.emplace_back(TypeInfo{ "float", "0.0f" }); + type_infos.emplace_back(TypeInfo{ "vec2", "vec2(0.0f)" }); + type_infos.emplace_back(TypeInfo{ "vec3", "vec3(0.0f)" }); + type_infos.emplace_back(TypeInfo{ "vec4", "vec4(0.0f)" }); + // ARB_gpu_shader_fp64 is required in GL4.0 which in turn is required by NV_thread_shuffle + type_infos.emplace_back(TypeInfo{ "double", "0.0LF" }); + type_infos.emplace_back(TypeInfo{ "dvec2", "dvec2(0.0LF)" }); + type_infos.emplace_back(TypeInfo{ "dvec3", "dvec3(0.0LF)" }); + type_infos.emplace_back(TypeInfo{ "dvec4", "dvec4(0.0LF)" }); + break; + } + + case OpGroupNonUniformIMul: + { + type_infos.emplace_back(TypeInfo{ "uint", "1u" }); + type_infos.emplace_back(TypeInfo{ "uvec2", "uvec2(1u)" }); + type_infos.emplace_back(TypeInfo{ "uvec3", "uvec3(1u)" }); + type_infos.emplace_back(TypeInfo{ "uvec4", "uvec4(1u)" }); + type_infos.emplace_back(TypeInfo{ "int", "1" }); + type_infos.emplace_back(TypeInfo{ "ivec2", "ivec2(1)" }); + type_infos.emplace_back(TypeInfo{ "ivec3", "ivec3(1)" }); + type_infos.emplace_back(TypeInfo{ "ivec4", "ivec4(1)" }); + break; + } + + case OpGroupNonUniformFMul: + { + type_infos.emplace_back(TypeInfo{ "float", "1.0f" }); + type_infos.emplace_back(TypeInfo{ "vec2", "vec2(1.0f)" }); + type_infos.emplace_back(TypeInfo{ "vec3", "vec3(1.0f)" }); + type_infos.emplace_back(TypeInfo{ "vec4", "vec4(1.0f)" }); + type_infos.emplace_back(TypeInfo{ "double", "0.0LF" }); + type_infos.emplace_back(TypeInfo{ "dvec2", "dvec2(1.0LF)" }); + type_infos.emplace_back(TypeInfo{ "dvec3", "dvec3(1.0LF)" }); + type_infos.emplace_back(TypeInfo{ "dvec4", "dvec4(1.0LF)" }); + break; + } + + default: + SPIRV_CROSS_THROW("Unsupported workaround for arithmetic group operation"); + } + + const bool op_is_addition = op == OpGroupNonUniformIAdd || op == OpGroupNonUniformFAdd; + const bool op_is_multiplication = op == OpGroupNonUniformIMul || op == OpGroupNonUniformFMul; + std::string op_symbol; + if (op_is_addition) + { + op_symbol = "+="; + } + else if (op_is_multiplication) + { + op_symbol = "*="; + } + + for (const TypeInfo &t : type_infos) + { + statement(t.type, " ", func, "(", t.type, " v)"); + begin_scope(); + statement(t.type, " ", result, " = ", t.identity, ";"); + statement("uvec4 active_threads = subgroupBallot(true);"); + statement("if (subgroupBallotBitCount(active_threads) == gl_SubgroupSize)"); + begin_scope(); + statement("uint total = gl_SubgroupSize / 2u;"); + statement(result, " = v;"); + statement("for (uint i = 1u; i <= total; i <<= 1u)"); + begin_scope(); + statement("bool valid;"); + if (group_op == GroupOperationReduce) + { + statement(t.type, " s = shuffleXorNV(", result, ", i, gl_SubgroupSize, valid);"); + } + else if (group_op == GroupOperationExclusiveScan || group_op == GroupOperationInclusiveScan) + { + statement(t.type, " s = shuffleUpNV(", result, ", i, gl_SubgroupSize, valid);"); + } + if (op_is_addition || op_is_multiplication) + { + statement(result, " ", op_symbol, " valid ? s : ", t.identity, ";"); + } + end_scope(); + if (group_op == GroupOperationExclusiveScan) + { + statement(result, " = shuffleUpNV(", result, ", 1u, gl_SubgroupSize);"); + statement("if (subgroupElect())"); + begin_scope(); + statement(result, " = ", t.identity, ";"); + end_scope(); + } + end_scope(); + statement("else"); + begin_scope(); + if (group_op == GroupOperationExclusiveScan) + { + statement("uint total = subgroupBallotBitCount(gl_SubgroupLtMask);"); + } + else if (group_op == GroupOperationInclusiveScan) + { + statement("uint total = subgroupBallotBitCount(gl_SubgroupLeMask);"); + } + statement("for (uint i = 0u; i < gl_SubgroupSize; ++i)"); + begin_scope(); + statement("bool valid = subgroupBallotBitExtract(active_threads, i);"); + statement(t.type, " s = shuffleNV(v, i, gl_SubgroupSize);"); + if (group_op == GroupOperationExclusiveScan || group_op == GroupOperationInclusiveScan) + { + statement("valid = valid && (i < total);"); + } + if (op_is_addition || op_is_multiplication) + { + statement(result, " ", op_symbol, " valid ? s : ", t.identity, ";"); + } + end_scope(); + end_scope(); + statement("return ", result, ";"); + end_scope(); + } +} + void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model) { static const char *workaround_types[] = { "int", "ivec2", "ivec3", "ivec4", "uint", "uvec2", "uvec3", "uvec4", @@ -4203,6 +4610,57 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model) statement("#endif"); statement(""); } + + auto arithmetic_feature_helper = + [&](Supp::Feature feat, std::string func_name, spv::Op op, spv::GroupOperation group_op) + { + if (shader_subgroup_supporter.is_feature_requested(feat)) + { + auto exts = Supp::get_candidates_for_feature(feat, result); + for (auto &e : exts) + { + const char *name = Supp::get_extension_name(e); + statement(&e == &exts.front() ? "#if" : "#elif", " defined(", name, ")"); + + switch (e) + { + case Supp::NV_shader_thread_shuffle: + emit_subgroup_arithmetic_workaround(func_name, op, group_op); + break; + default: + break; + } + } + statement("#endif"); + statement(""); + } + }; + + arithmetic_feature_helper(Supp::SubgroupArithmeticIAddReduce, "subgroupAdd", OpGroupNonUniformIAdd, + GroupOperationReduce); + arithmetic_feature_helper(Supp::SubgroupArithmeticIAddExclusiveScan, "subgroupExclusiveAdd", + OpGroupNonUniformIAdd, GroupOperationExclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticIAddInclusiveScan, "subgroupInclusiveAdd", + OpGroupNonUniformIAdd, GroupOperationInclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticFAddReduce, "subgroupAdd", OpGroupNonUniformFAdd, + GroupOperationReduce); + arithmetic_feature_helper(Supp::SubgroupArithmeticFAddExclusiveScan, "subgroupExclusiveAdd", + OpGroupNonUniformFAdd, GroupOperationExclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticFAddInclusiveScan, "subgroupInclusiveAdd", + OpGroupNonUniformFAdd, GroupOperationInclusiveScan); + + arithmetic_feature_helper(Supp::SubgroupArithmeticIMulReduce, "subgroupMul", OpGroupNonUniformIMul, + GroupOperationReduce); + arithmetic_feature_helper(Supp::SubgroupArithmeticIMulExclusiveScan, "subgroupExclusiveMul", + OpGroupNonUniformIMul, GroupOperationExclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticIMulInclusiveScan, "subgroupInclusiveMul", + OpGroupNonUniformIMul, GroupOperationInclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticFMulReduce, "subgroupMul", OpGroupNonUniformFMul, + GroupOperationReduce); + arithmetic_feature_helper(Supp::SubgroupArithmeticFMulExclusiveScan, "subgroupExclusiveMul", + OpGroupNonUniformFMul, GroupOperationExclusiveScan); + arithmetic_feature_helper(Supp::SubgroupArithmeticFMulInclusiveScan, "subgroupInclusiveMul", + OpGroupNonUniformFMul, GroupOperationInclusiveScan); } if (!workaround_ubo_load_overload_types.empty()) @@ -4210,39 +4668,150 @@ void CompilerGLSL::emit_extension_workarounds(spv::ExecutionModel model) for (auto &type_id : workaround_ubo_load_overload_types) { auto &type = get(type_id); - statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type), - " wrap) { return wrap; }"); + + if (options.es && is_matrix(type)) + { + // Need both variants. + // GLSL cannot overload on precision, so need to dispatch appropriately. + statement("highp ", type_to_glsl(type), " spvWorkaroundRowMajor(highp ", type_to_glsl(type), " wrap) { return wrap; }"); + statement("mediump ", type_to_glsl(type), " spvWorkaroundRowMajorMP(mediump ", type_to_glsl(type), " wrap) { return wrap; }"); + } + else + { + statement(type_to_glsl(type), " spvWorkaroundRowMajor(", type_to_glsl(type), " wrap) { return wrap; }"); + } } statement(""); } +} - if (requires_transpose_2x2) +void CompilerGLSL::emit_polyfills(uint32_t polyfills, bool relaxed) +{ + const char *qual = ""; + const char *suffix = (options.es && relaxed) ? "MP" : ""; + if (options.es) + qual = relaxed ? "mediump " : "highp "; + + if (polyfills & PolyfillTranspose2x2) { - statement("mat2 spvTranspose(mat2 m)"); + statement(qual, "mat2 spvTranspose", suffix, "(", qual, "mat2 m)"); begin_scope(); statement("return mat2(m[0][0], m[1][0], m[0][1], m[1][1]);"); end_scope(); statement(""); } - if (requires_transpose_3x3) + if (polyfills & PolyfillTranspose3x3) { - statement("mat3 spvTranspose(mat3 m)"); + statement(qual, "mat3 spvTranspose", suffix, "(", qual, "mat3 m)"); begin_scope(); statement("return mat3(m[0][0], m[1][0], m[2][0], m[0][1], m[1][1], m[2][1], m[0][2], m[1][2], m[2][2]);"); end_scope(); statement(""); } - if (requires_transpose_4x4) + if (polyfills & PolyfillTranspose4x4) { - statement("mat4 spvTranspose(mat4 m)"); + statement(qual, "mat4 spvTranspose", suffix, "(", qual, "mat4 m)"); begin_scope(); statement("return mat4(m[0][0], m[1][0], m[2][0], m[3][0], m[0][1], m[1][1], m[2][1], m[3][1], m[0][2], " "m[1][2], m[2][2], m[3][2], m[0][3], m[1][3], m[2][3], m[3][3]);"); end_scope(); statement(""); } + + if (polyfills & PolyfillDeterminant2x2) + { + statement(qual, "float spvDeterminant", suffix, "(", qual, "mat2 m)"); + begin_scope(); + statement("return m[0][0] * m[1][1] - m[0][1] * m[1][0];"); + end_scope(); + statement(""); + } + + if (polyfills & PolyfillDeterminant3x3) + { + statement(qual, "float spvDeterminant", suffix, "(", qual, "mat3 m)"); + begin_scope(); + statement("return dot(m[0], vec3(m[1][1] * m[2][2] - m[1][2] * m[2][1], " + "m[1][2] * m[2][0] - m[1][0] * m[2][2], " + "m[1][0] * m[2][1] - m[1][1] * m[2][0]));"); + end_scope(); + statement(""); + } + + if (polyfills & PolyfillDeterminant4x4) + { + statement(qual, "float spvDeterminant", suffix, "(", qual, "mat4 m)"); + begin_scope(); + statement("return dot(m[0], vec4(" + "m[2][1] * m[3][2] * m[1][3] - m[3][1] * m[2][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3] - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] + m[1][1] * m[2][2] * m[3][3], " + "m[3][0] * m[2][2] * m[1][3] - m[2][0] * m[3][2] * m[1][3] - m[3][0] * m[1][2] * m[2][3] + m[1][0] * m[3][2] * m[2][3] + m[2][0] * m[1][2] * m[3][3] - m[1][0] * m[2][2] * m[3][3], " + "m[2][0] * m[3][1] * m[1][3] - m[3][0] * m[2][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3] - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] + m[1][0] * m[2][1] * m[3][3], " + "m[3][0] * m[2][1] * m[1][2] - m[2][0] * m[3][1] * m[1][2] - m[3][0] * m[1][1] * m[2][2] + m[1][0] * m[3][1] * m[2][2] + m[2][0] * m[1][1] * m[3][2] - m[1][0] * m[2][1] * m[3][2]));"); + end_scope(); + statement(""); + } + + if (polyfills & PolyfillMatrixInverse2x2) + { + statement(qual, "mat2 spvInverse", suffix, "(", qual, "mat2 m)"); + begin_scope(); + statement("return mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) " + "* (1.0 / (m[0][0] * m[1][1] - m[1][0] * m[0][1]));"); + end_scope(); + statement(""); + } + + if (polyfills & PolyfillMatrixInverse3x3) + { + statement(qual, "mat3 spvInverse", suffix, "(", qual, "mat3 m)"); + begin_scope(); + statement(qual, "vec3 t = vec3(m[1][1] * m[2][2] - m[1][2] * m[2][1], m[1][2] * m[2][0] - m[1][0] * m[2][2], m[1][0] * m[2][1] - m[1][1] * m[2][0]);"); + statement("return mat3(t[0], " + "m[0][2] * m[2][1] - m[0][1] * m[2][2], " + "m[0][1] * m[1][2] - m[0][2] * m[1][1], " + "t[1], " + "m[0][0] * m[2][2] - m[0][2] * m[2][0], " + "m[0][2] * m[1][0] - m[0][0] * m[1][2], " + "t[2], " + "m[0][1] * m[2][0] - m[0][0] * m[2][1], " + "m[0][0] * m[1][1] - m[0][1] * m[1][0]) " + "* (1.0 / dot(m[0], t));"); + end_scope(); + statement(""); + } + + if (polyfills & PolyfillMatrixInverse4x4) + { + statement(qual, "mat4 spvInverse", suffix, "(", qual, "mat4 m)"); + begin_scope(); + statement(qual, "vec4 t = vec4(" + "m[2][1] * m[3][2] * m[1][3] - m[3][1] * m[2][2] * m[1][3] + m[3][1] * m[1][2] * m[2][3] - m[1][1] * m[3][2] * m[2][3] - m[2][1] * m[1][2] * m[3][3] + m[1][1] * m[2][2] * m[3][3], " + "m[3][0] * m[2][2] * m[1][3] - m[2][0] * m[3][2] * m[1][3] - m[3][0] * m[1][2] * m[2][3] + m[1][0] * m[3][2] * m[2][3] + m[2][0] * m[1][2] * m[3][3] - m[1][0] * m[2][2] * m[3][3], " + "m[2][0] * m[3][1] * m[1][3] - m[3][0] * m[2][1] * m[1][3] + m[3][0] * m[1][1] * m[2][3] - m[1][0] * m[3][1] * m[2][3] - m[2][0] * m[1][1] * m[3][3] + m[1][0] * m[2][1] * m[3][3], " + "m[3][0] * m[2][1] * m[1][2] - m[2][0] * m[3][1] * m[1][2] - m[3][0] * m[1][1] * m[2][2] + m[1][0] * m[3][1] * m[2][2] + m[2][0] * m[1][1] * m[3][2] - m[1][0] * m[2][1] * m[3][2]);"); + statement("return mat4(" + "t[0], " + "m[3][1] * m[2][2] * m[0][3] - m[2][1] * m[3][2] * m[0][3] - m[3][1] * m[0][2] * m[2][3] + m[0][1] * m[3][2] * m[2][3] + m[2][1] * m[0][2] * m[3][3] - m[0][1] * m[2][2] * m[3][3], " + "m[1][1] * m[3][2] * m[0][3] - m[3][1] * m[1][2] * m[0][3] + m[3][1] * m[0][2] * m[1][3] - m[0][1] * m[3][2] * m[1][3] - m[1][1] * m[0][2] * m[3][3] + m[0][1] * m[1][2] * m[3][3], " + "m[2][1] * m[1][2] * m[0][3] - m[1][1] * m[2][2] * m[0][3] - m[2][1] * m[0][2] * m[1][3] + m[0][1] * m[2][2] * m[1][3] + m[1][1] * m[0][2] * m[2][3] - m[0][1] * m[1][2] * m[2][3], " + "t[1], " + "m[2][0] * m[3][2] * m[0][3] - m[3][0] * m[2][2] * m[0][3] + m[3][0] * m[0][2] * m[2][3] - m[0][0] * m[3][2] * m[2][3] - m[2][0] * m[0][2] * m[3][3] + m[0][0] * m[2][2] * m[3][3], " + "m[3][0] * m[1][2] * m[0][3] - m[1][0] * m[3][2] * m[0][3] - m[3][0] * m[0][2] * m[1][3] + m[0][0] * m[3][2] * m[1][3] + m[1][0] * m[0][2] * m[3][3] - m[0][0] * m[1][2] * m[3][3], " + "m[1][0] * m[2][2] * m[0][3] - m[2][0] * m[1][2] * m[0][3] + m[2][0] * m[0][2] * m[1][3] - m[0][0] * m[2][2] * m[1][3] - m[1][0] * m[0][2] * m[2][3] + m[0][0] * m[1][2] * m[2][3], " + "t[2], " + "m[3][0] * m[2][1] * m[0][3] - m[2][0] * m[3][1] * m[0][3] - m[3][0] * m[0][1] * m[2][3] + m[0][0] * m[3][1] * m[2][3] + m[2][0] * m[0][1] * m[3][3] - m[0][0] * m[2][1] * m[3][3], " + "m[1][0] * m[3][1] * m[0][3] - m[3][0] * m[1][1] * m[0][3] + m[3][0] * m[0][1] * m[1][3] - m[0][0] * m[3][1] * m[1][3] - m[1][0] * m[0][1] * m[3][3] + m[0][0] * m[1][1] * m[3][3], " + "m[2][0] * m[1][1] * m[0][3] - m[1][0] * m[2][1] * m[0][3] - m[2][0] * m[0][1] * m[1][3] + m[0][0] * m[2][1] * m[1][3] + m[1][0] * m[0][1] * m[2][3] - m[0][0] * m[1][1] * m[2][3], " + "t[3], " + "m[2][0] * m[3][1] * m[0][2] - m[3][0] * m[2][1] * m[0][2] + m[3][0] * m[0][1] * m[2][2] - m[0][0] * m[3][1] * m[2][2] - m[2][0] * m[0][1] * m[3][2] + m[0][0] * m[2][1] * m[3][2], " + "m[3][0] * m[1][1] * m[0][2] - m[1][0] * m[3][1] * m[0][2] - m[3][0] * m[0][1] * m[1][2] + m[0][0] * m[3][1] * m[1][2] + m[1][0] * m[0][1] * m[3][2] - m[0][0] * m[1][1] * m[3][2], " + "m[1][0] * m[2][1] * m[0][2] - m[2][0] * m[1][1] * m[0][2] + m[2][0] * m[0][1] * m[1][2] - m[0][0] * m[2][1] * m[1][2] - m[1][0] * m[0][1] * m[2][2] + m[0][0] * m[1][1] * m[2][2]) " + "* (1.0 / dot(m[0], t));"); + end_scope(); + statement(""); + } } // Returns a string representation of the ID, usable as a function arg. @@ -4258,12 +4827,96 @@ string CompilerGLSL::to_func_call_arg(const SPIRFunction::Parameter &, uint32_t return to_expression(name_id); } +void CompilerGLSL::force_temporary_and_recompile(uint32_t id) +{ + auto res = forced_temporaries.insert(id); + + // Forcing new temporaries guarantees forward progress. + if (res.second) + force_recompile_guarantee_forward_progress(); + else + force_recompile(); +} + +uint32_t CompilerGLSL::consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision) +{ + // Constants do not have innate precision. + auto handle_type = ir.ids[id].get_type(); + if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef) + return id; + + // Ignore anything that isn't 32-bit values. + auto &type = get(type_id); + if (type.pointer) + return id; + if (type.basetype != SPIRType::Float && type.basetype != SPIRType::UInt && type.basetype != SPIRType::Int) + return id; + + if (precision == Options::DontCare) + { + // If precision is consumed as don't care (operations only consisting of constants), + // we need to bind the expression to a temporary, + // otherwise we have no way of controlling the precision later. + auto itr = forced_temporaries.insert(id); + if (itr.second) + force_recompile_guarantee_forward_progress(); + return id; + } + + auto current_precision = has_decoration(id, DecorationRelaxedPrecision) ? Options::Mediump : Options::Highp; + if (current_precision == precision) + return id; + + auto itr = temporary_to_mirror_precision_alias.find(id); + if (itr == temporary_to_mirror_precision_alias.end()) + { + uint32_t alias_id = ir.increase_bound_by(1); + auto &m = ir.meta[alias_id]; + if (auto *input_m = ir.find_meta(id)) + m = *input_m; + + const char *prefix; + if (precision == Options::Mediump) + { + set_decoration(alias_id, DecorationRelaxedPrecision); + prefix = "mp_copy_"; + } + else + { + unset_decoration(alias_id, DecorationRelaxedPrecision); + prefix = "hp_copy_"; + } + + auto alias_name = join(prefix, to_name(id)); + ParsedIR::sanitize_underscores(alias_name); + set_name(alias_id, alias_name); + + emit_op(type_id, alias_id, to_expression(id), true); + temporary_to_mirror_precision_alias[id] = alias_id; + forced_temporaries.insert(id); + forced_temporaries.insert(alias_id); + force_recompile_guarantee_forward_progress(); + id = alias_id; + } + else + { + id = itr->second; + } + + return id; +} + void CompilerGLSL::handle_invalid_expression(uint32_t id) { // We tried to read an invalidated expression. - // This means we need another pass at compilation, but next time, force temporary variables so that they cannot be invalidated. - forced_temporaries.insert(id); - force_recompile(); + // This means we need another pass at compilation, but next time, + // force temporary variables so that they cannot be invalidated. + force_temporary_and_recompile(id); + + // If the invalid expression happened as a result of a CompositeInsert + // overwrite, we must block this from happening next iteration. + if (composite_insert_overwritten.count(id)) + block_composite_insert_overwrite.insert(id); } // Converts the format of the current expression from packed to unpacked, @@ -4301,7 +4954,7 @@ void CompilerGLSL::strip_enclosed_expression(string &expr) expr.erase(begin(expr)); } -string CompilerGLSL::enclose_expression(const string &expr) +bool CompilerGLSL::needs_enclose_expression(const std::string &expr) { bool need_parens = false; @@ -4335,10 +4988,15 @@ string CompilerGLSL::enclose_expression(const string &expr) assert(paren_count == 0); } + return need_parens; +} + +string CompilerGLSL::enclose_expression(const string &expr) +{ // If this expression contains any spaces which are not enclosed by parentheses, // we need to enclose it so we can treat the whole string as an expression. // This happens when two expressions have been part of a binary op earlier. - if (need_parens) + if (needs_enclose_expression(expr)) return join('(', expr, ')'); else return expr; @@ -4495,8 +5153,27 @@ string CompilerGLSL::to_extract_constant_composite_expression(uint32_t result_ty return constant_expression(tmp); } -string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const SPIRType &type) +string CompilerGLSL::to_rerolled_array_expression(const SPIRType &parent_type, + const string &base_expr, const SPIRType &type) { + bool remapped_boolean = parent_type.basetype == SPIRType::Struct && + type.basetype == SPIRType::Boolean && + backend.boolean_in_struct_remapped_type != SPIRType::Boolean; + + SPIRType tmp_type { OpNop }; + if (remapped_boolean) + { + tmp_type = get(type.parent_type); + tmp_type.basetype = backend.boolean_in_struct_remapped_type; + } + else if (type.basetype == SPIRType::Boolean && backend.boolean_in_struct_remapped_type != SPIRType::Boolean) + { + // It's possible that we have an r-value expression that was OpLoaded from a struct. + // We have to reroll this and explicitly cast the input to bool, because the r-value is short. + tmp_type = get(type.parent_type); + remapped_boolean = true; + } + uint32_t size = to_array_size_literal(type); auto &parent = get(type.parent_type); string expr = "{ "; @@ -4504,10 +5181,14 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const for (uint32_t i = 0; i < size; i++) { auto subexpr = join(base_expr, "[", convert_to_string(i), "]"); - if (parent.array.empty()) + if (!is_array(parent)) + { + if (remapped_boolean) + subexpr = join(type_to_glsl(tmp_type), "(", subexpr, ")"); expr += subexpr; + } else - expr += to_rerolled_array_expression(subexpr, parent); + expr += to_rerolled_array_expression(parent_type, subexpr, parent); if (i + 1 < size) expr += ", "; @@ -4517,12 +5198,26 @@ string CompilerGLSL::to_rerolled_array_expression(const string &base_expr, const return expr; } -string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset) +string CompilerGLSL::to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type) { auto &type = expression_type(id); - bool reroll_array = !type.array.empty() && (!backend.array_is_value_type || - (uses_buffer_offset && !backend.buffer_offset_array_is_value_type)); + bool reroll_array = false; + bool remapped_boolean = parent_type.basetype == SPIRType::Struct && + type.basetype == SPIRType::Boolean && + backend.boolean_in_struct_remapped_type != SPIRType::Boolean; + + if (is_array(type)) + { + reroll_array = !backend.array_is_value_type || + (block_like_type && !backend.array_is_value_type_in_buffer_blocks); + + if (remapped_boolean) + { + // Forced to reroll if we have to change bool[] to short[]. + reroll_array = true; + } + } if (reroll_array) { @@ -4536,10 +5231,20 @@ string CompilerGLSL::to_composite_constructor_expression(uint32_t id, bool uses_ // We're only triggering one read of the array expression, but this is fine since arrays have to be declared // as temporaries anyways. - return to_rerolled_array_expression(to_enclosed_expression(id), type); + return to_rerolled_array_expression(parent_type, to_enclosed_expression(id), type); } else - return to_unpacked_expression(id); + { + auto expr = to_unpacked_expression(id); + if (remapped_boolean) + { + auto tmp_type = type; + tmp_type.basetype = backend.boolean_in_struct_remapped_type; + expr = join(type_to_glsl(tmp_type), "(", expr, ")"); + } + + return expr; + } } string CompilerGLSL::to_non_uniform_aware_expression(uint32_t id) @@ -4593,8 +5298,9 @@ string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) // when consuming an access chain expression. uint32_t physical_type_id = get_extended_decoration(id, SPIRVCrossDecorationPhysicalTypeID); bool is_packed = has_extended_decoration(id, SPIRVCrossDecorationPhysicalTypePacked); + bool relaxed = has_decoration(id, DecorationRelaxedPrecision); return convert_row_major_matrix(e.expression, get(e.expression_type), physical_type_id, - is_packed); + is_packed, relaxed); } else if (flattened_structs.count(id)) { @@ -4620,11 +5326,27 @@ string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) auto &type = get(c.constant_type); // WorkGroupSize may be a constant. - auto &dec = ir.meta[c.self].decoration; - if (dec.builtin) - return builtin_to_glsl(dec.builtin_type, StorageClassGeneric); + if (has_decoration(c.self, DecorationBuiltIn)) + return builtin_to_glsl(BuiltIn(get_decoration(c.self, DecorationBuiltIn)), StorageClassGeneric); else if (c.specialization) + { + if (backend.workgroup_size_is_hidden) + { + int wg_index = get_constant_mapping_to_workgroup_component(c); + if (wg_index >= 0) + { + auto wg_size = join(builtin_to_glsl(BuiltInWorkgroupSize, StorageClassInput), vector_swizzle(1, wg_index)); + if (type.basetype != SPIRType::UInt) + wg_size = bitcast_expression(type, SPIRType::UInt, wg_size); + return wg_size; + } + } + + if (expression_is_forwarded(id)) + return constant_expression(c); + return to_name(id); + } else if (c.is_used_as_lut) return to_name(id); else if (type.basetype == SPIRType::Struct && !backend.can_declare_struct_inline) @@ -4644,7 +5366,20 @@ string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) // If we try to use a loop variable before the loop header, we have to redirect it to the static expression, // the variable has not been declared yet. if (var.statically_assigned || (var.loop_variable && !var.loop_variable_enable)) - return to_expression(var.static_expression); + { + // We might try to load from a loop variable before it has been initialized. + // Prefer static expression and fallback to initializer. + if (var.static_expression) + return to_expression(var.static_expression); + else if (var.initializer) + return to_expression(var.initializer); + else + { + // We cannot declare the variable yet, so have to fake it. + uint32_t undef_id = ir.increase_bound_by(1); + return emit_uninitialized_temporary_expression(get_variable_data_type_id(var), undef_id).expression; + } + } else if (var.deferred_declaration) { var.deferred_declaration = false; @@ -4681,6 +5416,80 @@ string CompilerGLSL::to_expression(uint32_t id, bool register_expression_read) } } +SmallVector CompilerGLSL::get_composite_constant_ids(ConstantID const_id) +{ + if (auto *constant = maybe_get(const_id)) + { + const auto &type = get(constant->constant_type); + if (is_array(type) || type.basetype == SPIRType::Struct) + return constant->subconstants; + if (is_matrix(type)) + return SmallVector(constant->m.id); + if (is_vector(type)) + return SmallVector(constant->m.c[0].id); + SPIRV_CROSS_THROW("Unexpected scalar constant!"); + } + if (!const_composite_insert_ids.count(const_id)) + SPIRV_CROSS_THROW("Unimplemented for this OpSpecConstantOp!"); + return const_composite_insert_ids[const_id]; +} + +void CompilerGLSL::fill_composite_constant(SPIRConstant &constant, TypeID type_id, + const SmallVector &initializers) +{ + auto &type = get(type_id); + constant.specialization = true; + if (is_array(type) || type.basetype == SPIRType::Struct) + { + constant.subconstants = initializers; + } + else if (is_matrix(type)) + { + constant.m.columns = type.columns; + for (uint32_t i = 0; i < type.columns; ++i) + { + constant.m.id[i] = initializers[i]; + constant.m.c[i].vecsize = type.vecsize; + } + } + else if (is_vector(type)) + { + constant.m.c[0].vecsize = type.vecsize; + for (uint32_t i = 0; i < type.vecsize; ++i) + constant.m.c[0].id[i] = initializers[i]; + } + else + SPIRV_CROSS_THROW("Unexpected scalar in SpecConstantOp CompositeInsert!"); +} + +void CompilerGLSL::set_composite_constant(ConstantID const_id, TypeID type_id, + const SmallVector &initializers) +{ + if (maybe_get(const_id)) + { + const_composite_insert_ids[const_id] = initializers; + return; + } + + auto &constant = set(const_id, type_id); + fill_composite_constant(constant, type_id, initializers); + forwarded_temporaries.insert(const_id); +} + +TypeID CompilerGLSL::get_composite_member_type(TypeID type_id, uint32_t member_idx) +{ + auto &type = get(type_id); + if (is_array(type)) + return type.parent_type; + if (type.basetype == SPIRType::Struct) + return type.member_types[member_idx]; + if (is_matrix(type)) + return type.parent_type; + if (is_vector(type)) + return type.parent_type; + SPIRV_CROSS_THROW("Shouldn't reach lower than vector handling OpSpecConstantOp CompositeInsert!"); +} + string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) { auto &type = get(cop.basetype); @@ -4785,10 +5594,21 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) for (uint32_t i = 2; i < uint32_t(cop.arguments.size()); i++) { uint32_t index = cop.arguments[i]; - if (index >= left_components) + if (index == 0xFFFFFFFF) + { + SPIRConstant c; + c.constant_type = type.parent_type; + assert(type.parent_type != ID(0)); + expr += constant_expression(c); + } + else if (index >= left_components) + { expr += right_arg + "." + "xyzw"[index - left_components]; + } else + { expr += left_arg + "." + "xyzw"[index]; + } if (i + 1 < uint32_t(cop.arguments.size())) expr += ", "; @@ -4806,7 +5626,30 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) } case OpCompositeInsert: - SPIRV_CROSS_THROW("OpCompositeInsert spec constant op is not supported."); + { + SmallVector new_init = get_composite_constant_ids(cop.arguments[1]); + uint32_t idx; + uint32_t target_id = cop.self; + uint32_t target_type_id = cop.basetype; + // We have to drill down to the part we want to modify, and create new + // constants for each containing part. + for (idx = 2; idx < cop.arguments.size() - 1; ++idx) + { + uint32_t new_const = ir.increase_bound_by(1); + uint32_t old_const = new_init[cop.arguments[idx]]; + new_init[cop.arguments[idx]] = new_const; + set_composite_constant(target_id, target_type_id, new_init); + new_init = get_composite_constant_ids(old_const); + target_id = new_const; + target_type_id = get_composite_member_type(target_type_id, cop.arguments[idx]); + } + // Now replace the initializer with the one from this instruction. + new_init[cop.arguments[idx]] = cop.arguments[0]; + set_composite_constant(target_id, target_type_id, new_init); + SPIRConstant tmp_const(cop.basetype); + fill_composite_constant(tmp_const, cop.basetype, const_composite_insert_ids[cop.self]); + return constant_expression(tmp_const); + } default: // Some opcodes are unimplemented here, these are currently not possible to test from glslang. @@ -4911,11 +5754,13 @@ string CompilerGLSL::constant_op_expression(const SPIRConstantOp &cop) } } -string CompilerGLSL::constant_expression(const SPIRConstant &c) +string CompilerGLSL::constant_expression(const SPIRConstant &c, + bool inside_block_like_struct_scope, + bool inside_struct_scope) { auto &type = get(c.constant_type); - if (type.pointer) + if (is_pointer(type)) { return backend.null_pointer_literal; } @@ -4924,17 +5769,38 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) // Handles Arrays and structures. string res; + // Only consider the decay if we are inside a struct scope where we are emitting a member with Offset decoration. + // Outside a block-like struct declaration, we can always bind to a constant array with templated type. + // Should look at ArrayStride here as well, but it's possible to declare a constant struct + // with Offset = 0, using no ArrayStride on the enclosed array type. + // A particular CTS test hits this scenario. + bool array_type_decays = inside_block_like_struct_scope && + is_array(type) && + !backend.array_is_value_type_in_buffer_blocks; + // Allow Metal to use the array template to make arrays a value type bool needs_trailing_tracket = false; if (backend.use_initializer_list && backend.use_typed_initializer_list && type.basetype == SPIRType::Struct && - type.array.empty()) + !is_array(type)) { res = type_to_glsl_constructor(type) + "{ "; } else if (backend.use_initializer_list && backend.use_typed_initializer_list && backend.array_is_value_type && - !type.array.empty()) + is_array(type) && !array_type_decays) { - res = type_to_glsl_constructor(type) + "({ "; + const auto *p_type = &type; + SPIRType tmp_type { OpNop }; + + if (inside_struct_scope && + backend.boolean_in_struct_remapped_type != SPIRType::Boolean && + type.basetype == SPIRType::Boolean) + { + tmp_type = type; + tmp_type.basetype = backend.boolean_in_struct_remapped_type; + p_type = &tmp_type; + } + + res = type_to_glsl_constructor(*p_type) + "({ "; needs_trailing_tracket = true; } else if (backend.use_initializer_list) @@ -4946,16 +5812,43 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) res = type_to_glsl_constructor(type) + "("; } + uint32_t subconstant_index = 0; for (auto &elem : c.subconstants) { - auto &subc = get(elem); - if (subc.specialization) + if (auto *op = maybe_get(elem)) + { + res += constant_op_expression(*op); + } + else if (maybe_get(elem) != nullptr) + { res += to_name(elem); + } else - res += constant_expression(subc); + { + auto &subc = get(elem); + if (subc.specialization && !expression_is_forwarded(elem)) + res += to_name(elem); + else + { + if (!is_array(type) && type.basetype == SPIRType::Struct) + { + // When we get down to emitting struct members, override the block-like information. + // For constants, we can freely mix and match block-like state. + inside_block_like_struct_scope = + has_member_decoration(type.self, subconstant_index, DecorationOffset); + } + + if (type.basetype == SPIRType::Struct) + inside_struct_scope = true; + + res += constant_expression(subc, inside_block_like_struct_scope, inside_struct_scope); + } + } if (&elem != &c.subconstants.back()) res += ", "; + + subconstant_index++; } res += backend.use_initializer_list ? " }" : ")"; @@ -4970,19 +5863,30 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) if (backend.supports_empty_struct) return "{ }"; else if (backend.use_typed_initializer_list) - return join(type_to_glsl(get(c.constant_type)), "{ 0 }"); + return join(type_to_glsl(type), "{ 0 }"); else if (backend.use_initializer_list) return "{ 0 }"; else - return join(type_to_glsl(get(c.constant_type)), "(0)"); + return join(type_to_glsl(type), "(0)"); } else if (c.columns() == 1) { - return constant_expression_vector(c, 0); + auto res = constant_expression_vector(c, 0); + + if (inside_struct_scope && + backend.boolean_in_struct_remapped_type != SPIRType::Boolean && + type.basetype == SPIRType::Boolean) + { + SPIRType tmp_type = type; + tmp_type.basetype = backend.boolean_in_struct_remapped_type; + res = join(type_to_glsl(tmp_type), "(", res, ")"); + } + + return res; } else { - string res = type_to_glsl(get(c.constant_type)) + "("; + string res = type_to_glsl(type) + "("; for (uint32_t col = 0; col < c.columns(); col++) { if (c.specialization_constant_id(col) != 0) @@ -4994,13 +5898,23 @@ string CompilerGLSL::constant_expression(const SPIRConstant &c) res += ", "; } res += ")"; + + if (inside_struct_scope && + backend.boolean_in_struct_remapped_type != SPIRType::Boolean && + type.basetype == SPIRType::Boolean) + { + SPIRType tmp_type = type; + tmp_type.basetype = backend.boolean_in_struct_remapped_type; + res = join(type_to_glsl(tmp_type), "(", res, ")"); + } + return res; } } #ifdef _MSC_VER -// sprintf warning. -// We cannot rely on snprintf existing because, ..., MSVC. +// snprintf does not exist or is buggy on older MSVC versions, some of them +// being used by MinGW. Use sprintf instead and disable corresponding warning. #pragma warning(push) #pragma warning(disable : 4996) #endif @@ -5014,7 +5928,7 @@ string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, // of complicated workarounds, just value-cast to the half type always. if (std::isnan(float_value) || std::isinf(float_value)) { - SPIRType type; + SPIRType type { OpTypeFloat }; type.basetype = SPIRType::Half; type.vecsize = 1; type.columns = 1; @@ -5030,11 +5944,11 @@ string CompilerGLSL::convert_half_to_string(const SPIRConstant &c, uint32_t col, } else { - SPIRType type; + SPIRType type { OpTypeFloat }; type.basetype = SPIRType::Half; type.vecsize = 1; type.columns = 1; - res = join(type_to_glsl(type), "(", convert_to_string(float_value, current_locale_radix_character), ")"); + res = join(type_to_glsl(type), "(", format_float(float_value), ")"); } return res; @@ -5050,8 +5964,8 @@ string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col // Use special representation. if (!is_legacy()) { - SPIRType out_type; - SPIRType in_type; + SPIRType out_type { OpTypeFloat }; + SPIRType in_type { OpTypeInt }; out_type.basetype = SPIRType::Float; in_type.basetype = SPIRType::UInt; out_type.vecsize = 1; @@ -5060,7 +5974,11 @@ string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col in_type.width = 32; char print_buffer[32]; +#ifdef _WIN32 sprintf(print_buffer, "0x%xu", c.scalar(col, row)); +#else + snprintf(print_buffer, sizeof(print_buffer), "0x%xu", c.scalar(col, row)); +#endif const char *comment = "inf"; if (float_value == -numeric_limits::infinity()) @@ -5098,7 +6016,7 @@ string CompilerGLSL::convert_float_to_string(const SPIRConstant &c, uint32_t col } else { - res = convert_to_string(float_value, current_locale_radix_character); + res = format_float(float_value); if (backend.float_literal_suffix) res += "f"; } @@ -5116,8 +6034,8 @@ std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32 // Use special representation. if (!is_legacy()) { - SPIRType out_type; - SPIRType in_type; + SPIRType out_type { OpTypeFloat }; + SPIRType in_type { OpTypeInt }; out_type.basetype = SPIRType::Double; in_type.basetype = SPIRType::UInt64; out_type.vecsize = 1; @@ -5127,13 +6045,18 @@ std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32 uint64_t u64_value = c.scalar_u64(col, row); - if (options.es) - SPIRV_CROSS_THROW("64-bit integers/float not supported in ES profile."); + if (options.es && options.version < 310) // GL_NV_gpu_shader5 fallback requires 310. + SPIRV_CROSS_THROW("64-bit integers not supported in ES profile before version 310."); require_extension_internal("GL_ARB_gpu_shader_int64"); char print_buffer[64]; +#ifdef _WIN32 sprintf(print_buffer, "0x%llx%s", static_cast(u64_value), backend.long_long_literal_suffix ? "ull" : "ul"); +#else + snprintf(print_buffer, sizeof(print_buffer), "0x%llx%s", static_cast(u64_value), + backend.long_long_literal_suffix ? "ull" : "ul"); +#endif const char *comment = "inf"; if (double_value == -numeric_limits::infinity()) @@ -5176,7 +6099,7 @@ std::string CompilerGLSL::convert_double_to_string(const SPIRConstant &c, uint32 } else { - res = convert_to_string(double_value, current_locale_radix_character); + res = format_double(double_value); if (backend.double_literal_suffix) res += "lf"; } @@ -5266,7 +6189,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += convert_half_to_string(c, vector, i); @@ -5288,7 +6211,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += convert_float_to_string(c, vector, i); @@ -5310,7 +6233,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += convert_double_to_string(c, vector, i); @@ -5336,7 +6259,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += convert_to_string(c.scalar_i64(vector, i), int64_type, backend.long_long_literal_suffix); @@ -5361,7 +6284,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { res += convert_to_string(c.scalar_u64(vector, i)); @@ -5396,7 +6319,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { res += convert_to_string(c.scalar(vector, i)); @@ -5426,7 +6349,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += convert_to_string(c.scalar_i32(vector, i)); if (i + 1 < c.vector_size()) @@ -5445,7 +6368,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { if (*backend.uint16_t_literal_suffix) @@ -5479,7 +6402,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { if (*backend.int16_t_literal_suffix) @@ -5513,7 +6436,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { res += type_to_glsl(scalar_type); @@ -5538,7 +6461,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else { res += type_to_glsl(scalar_type); @@ -5561,7 +6484,7 @@ string CompilerGLSL::constant_expression_vector(const SPIRConstant &c, uint32_t for (uint32_t i = 0; i < c.vector_size(); i++) { if (c.vector_size() > 1 && c.specialization_constant_id(vector, i) != 0) - res += to_name(c.specialization_constant_id(vector, i)); + res += to_expression(c.specialization_constant_id(vector, i)); else res += c.scalar(vector, i) ? "true" : "false"; @@ -5592,7 +6515,7 @@ void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t r { // If we're declaring temporaries inside continue blocks, // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables. - if (current_continue_block && !hoisted_temporaries.count(result_id)) + if (!block_temporary_hoisting && current_continue_block && !hoisted_temporaries.count(result_id)) { auto &header = get(current_continue_block->loop_dominator); if (find_if(begin(header.declare_temporary), end(header.declare_temporary), @@ -5608,7 +6531,7 @@ void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t r else if (hoisted_temporaries.count(result_id) == 0) { auto &type = get(result_type); - auto &flags = ir.meta[result_id].decoration.decoration_flags; + auto &flags = get_decoration_bitset(result_id); // The result_id has not been made into an expression yet, so use flags interface. add_local_variable_name(result_id); @@ -5624,11 +6547,10 @@ void CompilerGLSL::emit_uninitialized_temporary(uint32_t result_type, uint32_t r string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id) { auto &type = get(result_type); - auto &flags = ir.meta[result_id].decoration.decoration_flags; // If we're declaring temporaries inside continue blocks, // we must declare the temporary in the loop header so that the continue block can avoid declaring new variables. - if (current_continue_block && !hoisted_temporaries.count(result_id)) + if (!block_temporary_hoisting && current_continue_block && !hoisted_temporaries.count(result_id)) { auto &header = get(current_continue_block->loop_dominator); if (find_if(begin(header.declare_temporary), end(header.declare_temporary), @@ -5638,7 +6560,7 @@ string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id) { header.declare_temporary.emplace_back(result_type, result_id); hoisted_temporaries.insert(result_id); - force_recompile(); + force_recompile_guarantee_forward_progress(); } return join(to_name(result_id), " = "); @@ -5652,6 +6574,7 @@ string CompilerGLSL::declare_temporary(uint32_t result_type, uint32_t result_id) { // The result_id has not been made into an expression yet, so use flags interface. add_local_variable_name(result_id); + auto &flags = get_decoration_bitset(result_id); return join(flags_to_qualifiers_glsl(type, flags), variable_decl(type, to_name(result_id)), " = "); } } @@ -5705,6 +6628,22 @@ void CompilerGLSL::emit_unary_op(uint32_t result_type, uint32_t result_id, uint3 inherit_expression_dependencies(result_id, op0); } +void CompilerGLSL::emit_unary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op) +{ + auto &type = get(result_type); + bool forward = should_forward(op0); + emit_op(result_type, result_id, join(type_to_glsl(type), "(", op, to_enclosed_unpacked_expression(op0), ")"), forward); + inherit_expression_dependencies(result_id, op0); +} + +void CompilerGLSL::emit_mesh_tasks(SPIRBlock &block) +{ + statement("EmitMeshTasksEXT(", + to_unpacked_expression(block.mesh.groups[0]), ", ", + to_unpacked_expression(block.mesh.groups[1]), ", ", + to_unpacked_expression(block.mesh.groups[2]), ");"); +} + void CompilerGLSL::emit_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) { // Various FP arithmetic opcodes such as add, sub, mul will hit this. @@ -5804,7 +6743,7 @@ SPIRType CompilerGLSL::binary_op_bitcast_helper(string &cast_op0, string &cast_o // Create a fake type so we can bitcast to it. // We only deal with regular arithmetic types here like int, uints and so on. - SPIRType expected_type; + SPIRType expected_type{type0.op}; expected_type.basetype = input_type; expected_type.vecsize = type0.vecsize; expected_type.columns = type0.columns; @@ -5848,7 +6787,9 @@ bool CompilerGLSL::emit_complex_bitcast(uint32_t result_type, uint32_t id, uint3 } void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, - const char *op, SPIRType::BaseType input_type, bool skip_cast_if_equal_type) + const char *op, SPIRType::BaseType input_type, + bool skip_cast_if_equal_type, + bool implicit_integer_promotion) { string cast_op0, cast_op1; auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, skip_cast_if_equal_type); @@ -5857,17 +6798,23 @@ void CompilerGLSL::emit_binary_op_cast(uint32_t result_type, uint32_t result_id, // We might have casted away from the result type, so bitcast again. // For example, arithmetic right shift with uint inputs. // Special case boolean outputs since relational opcodes output booleans instead of int/uint. + auto bitop = join(cast_op0, " ", op, " ", cast_op1); string expr; - if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean) + + if (implicit_integer_promotion) + { + // Simple value cast. + expr = join(type_to_glsl(out_type), '(', bitop, ')'); + } + else if (out_type.basetype != input_type && out_type.basetype != SPIRType::Boolean) { expected_type.basetype = input_type; - expr = bitcast_glsl_op(out_type, expected_type); - expr += '('; - expr += join(cast_op0, " ", op, " ", cast_op1); - expr += ')'; + expr = join(bitcast_glsl_op(out_type, expected_type), '(', bitop, ')'); } else - expr += join(cast_op0, " ", op, " ", cast_op1); + { + expr = std::move(bitop); + } emit_op(result_type, result_id, expr, should_forward(op0) && should_forward(op1)); inherit_expression_dependencies(result_id, op0); @@ -5884,7 +6831,10 @@ void CompilerGLSL::emit_unary_func_op(uint32_t result_type, uint32_t result_id, void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) { - bool forward = should_forward(op0) && should_forward(op1); + // Opaque types (e.g. OpTypeSampledImage) must always be forwarded in GLSL + const auto &type = get_type(result_type); + bool must_forward = type_is_opaque_value(type); + bool forward = must_forward || (should_forward(op0) && should_forward(op1)); emit_op(result_type, result_id, join(op, "(", to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ")"), forward); inherit_expression_dependencies(result_id, op0); @@ -5894,6 +6844,16 @@ void CompilerGLSL::emit_binary_func_op(uint32_t result_type, uint32_t result_id, void CompilerGLSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) { + auto &type = get(result_type); + if (type_is_floating_point(type)) + { + if (!options.vulkan_semantics) + SPIRV_CROSS_THROW("Floating point atomics requires Vulkan semantics."); + if (options.es) + SPIRV_CROSS_THROW("Floating point atomics requires desktop GLSL."); + require_extension_internal("GL_EXT_shader_atomic_float"); + } + forced_temporaries.insert(result_id); emit_op(result_type, result_id, join(op, "(", to_non_uniform_aware_expression(op0), ", ", @@ -6137,7 +7097,9 @@ void CompilerGLSL::emit_bitfield_insert_op(uint32_t result_type, uint32_t result auto op2_expr = to_unpacked_expression(op2); auto op3_expr = to_unpacked_expression(op3); - SPIRType target_type; + assert(offset_count_type == SPIRType::UInt || offset_count_type == SPIRType::Int); + SPIRType target_type { OpTypeInt }; + target_type.width = 32; target_type.vecsize = 1; target_type.basetype = offset_count_type; @@ -6168,7 +7130,11 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp switch (imgtype.image.dim) { case spv::Dim1D: - type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D"; + // Force 2D path for ES. + if (options.es) + type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D"; + else + type = (imgtype.image.arrayed && !options.es) ? "1DArray" : "1D"; break; case spv::Dim2D: type = (imgtype.image.arrayed && !options.es) ? "2DArray" : "2D"; @@ -6227,6 +7193,9 @@ string CompilerGLSL::legacy_tex_op(const std::string &op, const SPIRType &imgtyp require_extension_internal("GL_EXT_shadow_samplers"); else SPIRV_CROSS_THROW(join(op, " not allowed on depth samplers in legacy ES")); + + if (imgtype.image.dim == spv::DimCube) + return "shadowCubeNV"; } if (op == "textureSize") @@ -6492,7 +7461,7 @@ string CompilerGLSL::to_combined_image_sampler(VariableID image_id, VariableID s } } -bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op) +bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op, const uint32_t *ops) { switch (op) { @@ -6511,6 +7480,22 @@ bool CompilerGLSL::is_supported_subgroup_op_in_opengl(spv::Op op) case OpGroupNonUniformBallotBitExtract: case OpGroupNonUniformInverseBallot: return true; + case OpGroupNonUniformIAdd: + case OpGroupNonUniformFAdd: + case OpGroupNonUniformIMul: + case OpGroupNonUniformFMul: + { + const GroupOperation operation = static_cast(ops[3]); + if (operation == GroupOperationReduce || operation == GroupOperationInclusiveScan || + operation == GroupOperationExclusiveScan) + { + return true; + } + else + { + return false; + } + } default: return false; } @@ -6835,8 +7820,14 @@ std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool args.grad_x = grad_x; args.grad_y = grad_y; args.lod = lod; - args.coffset = coffset; - args.offset = offset; + + if (coffsets) + args.offset = coffsets; + else if (coffset) + args.offset = coffset; + else + args.offset = offset; + args.bias = bias; args.component = comp; args.sample = sample; @@ -6846,8 +7837,8 @@ std::string CompilerGLSL::to_texture_op(const Instruction &i, bool sparse, bool expr += to_function_args(args, forward); expr += ")"; - // texture(samplerXShadow) returns float. shadowX() returns vec4. Swizzle here. - if (is_legacy() && is_depth_image(imgtype, img)) + // texture(samplerXShadow) returns float. shadowX() returns vec4, but only in desktop GLSL. Swizzle here. + if (is_legacy() && !options.es && is_depth_image(imgtype, img)) expr += ".r"; // Sampling from a texture which was deduced to be a depth image, might actually return 1 component here. @@ -6899,7 +7890,7 @@ bool CompilerGLSL::expression_is_constant_null(uint32_t id) const bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr) { auto &type = expression_type(ptr); - if (type.array.empty()) + if (!is_array(get_pointee_type(type))) return false; if (!backend.array_is_value_type) @@ -6910,7 +7901,7 @@ bool CompilerGLSL::expression_is_non_value_type_array(uint32_t ptr) return false; auto &backed_type = get(var->basetype); - return !backend.buffer_offset_array_is_value_type && backed_type.basetype == SPIRType::Struct && + return !backend.array_is_value_type_in_buffer_blocks && backed_type.basetype == SPIRType::Struct && has_member_decoration(backed_type.self, 0, DecorationOffset); } @@ -6935,7 +7926,7 @@ string CompilerGLSL::to_function_name(const TextureFunctionNameArguments &args) // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = false; if (((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - is_depth_image(imgtype, tex) && args.lod) + is_depth_image(imgtype, tex) && args.lod && !args.base.is_fetch) { if (!expression_is_constant_null(args.lod)) { @@ -7079,7 +8070,7 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool // This happens for HLSL SampleCmpLevelZero on Texture2DArray and TextureCube. bool workaround_lod_array_shadow_as_grad = ((imgtype.image.arrayed && imgtype.image.dim == Dim2D) || imgtype.image.dim == DimCube) && - is_depth_image(imgtype, img) && args.lod != 0; + is_depth_image(imgtype, img) && args.lod != 0 && !args.base.is_fetch; if (args.dref) { @@ -7128,10 +8119,29 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool // Create a composite which merges coord/dref into a single vector. auto type = expression_type(args.coord); type.vecsize = args.coord_components + 1; + if (imgtype.image.dim == Dim1D && options.es) + type.vecsize++; farg_str += ", "; farg_str += type_to_glsl_constructor(type); farg_str += "("; - farg_str += coord_expr; + + if (imgtype.image.dim == Dim1D && options.es) + { + if (imgtype.image.arrayed) + { + farg_str += enclose_expression(coord_expr) + ".x"; + farg_str += ", 0.0, "; + farg_str += enclose_expression(coord_expr) + ".y"; + } + else + { + farg_str += coord_expr; + farg_str += ", 0.0"; + } + } + else + farg_str += coord_expr; + farg_str += ", "; farg_str += to_expression(args.dref); farg_str += ")"; @@ -7139,6 +8149,33 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool } else { + if (imgtype.image.dim == Dim1D && options.es) + { + // Have to fake a second coordinate. + if (type_is_floating_point(coord_type)) + { + // Cannot mix proj and array. + if (imgtype.image.arrayed || args.base.is_proj) + { + coord_expr = join("vec3(", enclose_expression(coord_expr), ".x, 0.0, ", + enclose_expression(coord_expr), ".y)"); + } + else + coord_expr = join("vec2(", coord_expr, ", 0.0)"); + } + else + { + if (imgtype.image.arrayed) + { + coord_expr = join("ivec3(", enclose_expression(coord_expr), + ".x, 0, ", + enclose_expression(coord_expr), ".y)"); + } + else + coord_expr = join("ivec2(", coord_expr, ", 0)"); + } + } + farg_str += ", "; farg_str += coord_expr; } @@ -7169,18 +8206,11 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool forward = forward && should_forward(args.lod); farg_str += ", "; - auto &lod_expr_type = expression_type(args.lod); - // Lod expression for TexelFetch in GLSL must be int, and only int. - if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms && - lod_expr_type.basetype != SPIRType::Int) - { - farg_str += join("int(", to_expression(args.lod), ")"); - } + if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms) + farg_str += bitcast_expression(SPIRType::Int, args.lod); else - { farg_str += to_expression(args.lod); - } } } else if (args.base.is_fetch && imgtype.image.dim != DimBuffer && !imgtype.image.ms) @@ -7189,23 +8219,17 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool farg_str += ", 0"; } - if (args.coffset) - { - forward = forward && should_forward(args.coffset); - farg_str += ", "; - farg_str += to_expression(args.coffset); - } - else if (args.offset) + if (args.offset) { forward = forward && should_forward(args.offset); farg_str += ", "; - farg_str += to_expression(args.offset); + farg_str += bitcast_expression(SPIRType::Int, args.offset); } if (args.sample) { farg_str += ", "; - farg_str += to_expression(args.sample); + farg_str += bitcast_expression(SPIRType::Int, args.sample); } if (args.min_lod) @@ -7232,11 +8256,7 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool { forward = forward && should_forward(args.component); farg_str += ", "; - auto &component_type = expression_type(args.component); - if (component_type.basetype == SPIRType::Int) - farg_str += to_expression(args.component); - else - farg_str += join("int(", to_expression(args.component), ")"); + farg_str += bitcast_expression(SPIRType::Int, args.component); } *p_forward = forward; @@ -7244,6 +8264,63 @@ string CompilerGLSL::to_function_args(const TextureFunctionArguments &args, bool return farg_str; } +Op CompilerGLSL::get_remapped_spirv_op(Op op) const +{ + if (options.relax_nan_checks) + { + switch (op) + { + case OpFUnordLessThan: + op = OpFOrdLessThan; + break; + case OpFUnordLessThanEqual: + op = OpFOrdLessThanEqual; + break; + case OpFUnordGreaterThan: + op = OpFOrdGreaterThan; + break; + case OpFUnordGreaterThanEqual: + op = OpFOrdGreaterThanEqual; + break; + case OpFUnordEqual: + op = OpFOrdEqual; + break; + case OpFOrdNotEqual: + op = OpFUnordNotEqual; + break; + + default: + break; + } + } + + return op; +} + +GLSLstd450 CompilerGLSL::get_remapped_glsl_op(GLSLstd450 std450_op) const +{ + // Relax to non-NaN aware opcodes. + if (options.relax_nan_checks) + { + switch (std450_op) + { + case GLSLstd450NClamp: + std450_op = GLSLstd450FClamp; + break; + case GLSLstd450NMin: + std450_op = GLSLstd450FMin; + break; + case GLSLstd450NMax: + std450_op = GLSLstd450FMax; + break; + default: + break; + } + } + + return std450_op; +} + void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t length) { auto op = static_cast(eop); @@ -7256,6 +8333,8 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, auto int_type = to_signed_basetype(integer_width); auto uint_type = to_unsigned_basetype(integer_width); + op = get_remapped_glsl_op(op); + switch (op) { // FP fiddling @@ -7287,8 +8366,22 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, break; case GLSLstd450Trunc: - emit_unary_func_op(result_type, id, args[0], "trunc"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "trunc"); + else + { + // Implement by value-casting to int and back. + bool forward = should_forward(args[0]); + auto op0 = to_unpacked_expression(args[0]); + auto &op0_type = expression_type(args[0]); + auto via_type = op0_type; + via_type.basetype = SPIRType::Int; + auto expr = join(type_to_glsl(op0_type), "(", type_to_glsl(via_type), "(", op0, "))"); + emit_op(result_type, id, expr, forward); + inherit_expression_dependencies(id, args[0]); + } break; + case GLSLstd450SAbs: emit_unary_func_op_cast(result_type, id, args[0], "abs", int_type, int_type); break; @@ -7330,18 +8423,47 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, else emit_trinary_func_op(result_type, id, args[0], args[1], args[2], "fma"); break; + case GLSLstd450Modf: register_call_out_argument(args[1]); - forced_temporaries.insert(id); - emit_binary_func_op(result_type, id, args[0], args[1], "modf"); + if (!is_legacy()) + { + forced_temporaries.insert(id); + emit_binary_func_op(result_type, id, args[0], args[1], "modf"); + } + else + { + //NB. legacy GLSL doesn't have trunc() either, so we do a value cast + auto &op1_type = expression_type(args[1]); + auto via_type = op1_type; + via_type.basetype = SPIRType::Int; + statement(to_expression(args[1]), " = ", + type_to_glsl(op1_type), "(", type_to_glsl(via_type), + "(", to_expression(args[0]), "));"); + emit_binary_op(result_type, id, args[0], args[1], "-"); + } break; case GLSLstd450ModfStruct: { auto &type = get(result_type); emit_uninitialized_temporary_expression(result_type, id); - statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ", - to_expression(id), ".", to_member_name(type, 1), ");"); + if (!is_legacy()) + { + statement(to_expression(id), ".", to_member_name(type, 0), " = ", "modf(", to_expression(args[0]), ", ", + to_expression(id), ".", to_member_name(type, 1), ");"); + } + else + { + //NB. legacy GLSL doesn't have trunc() either, so we do a value cast + auto &op0_type = expression_type(args[0]); + auto via_type = op0_type; + via_type.basetype = SPIRType::Int; + statement(to_expression(id), ".", to_member_name(type, 1), " = ", type_to_glsl(op0_type), + "(", type_to_glsl(via_type), "(", to_expression(args[0]), "));"); + statement(to_expression(id), ".", to_member_name(type, 0), " = ", to_enclosed_expression(args[0]), " - ", + to_expression(id), ".", to_member_name(type, 1), ";"); + } break; } @@ -7402,22 +8524,77 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, emit_unary_func_op(result_type, id, args[0], "atan"); break; case GLSLstd450Sinh: - emit_unary_func_op(result_type, id, args[0], "sinh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "sinh"); + else + { + bool forward = should_forward(args[0]); + auto expr = join("(exp(", to_expression(args[0]), ") - exp(-", to_enclosed_expression(args[0]), ")) * 0.5"); + emit_op(result_type, id, expr, forward); + inherit_expression_dependencies(id, args[0]); + } break; case GLSLstd450Cosh: - emit_unary_func_op(result_type, id, args[0], "cosh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "cosh"); + else + { + bool forward = should_forward(args[0]); + auto expr = join("(exp(", to_expression(args[0]), ") + exp(-", to_enclosed_expression(args[0]), ")) * 0.5"); + emit_op(result_type, id, expr, forward); + inherit_expression_dependencies(id, args[0]); + } break; case GLSLstd450Tanh: - emit_unary_func_op(result_type, id, args[0], "tanh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "tanh"); + else + { + // Create temporaries to store the result of exp(arg) and exp(-arg). + uint32_t &ids = extra_sub_expressions[id]; + if (!ids) + { + ids = ir.increase_bound_by(2); + + // Inherit precision qualifier (legacy has no NoContraction). + if (has_decoration(id, DecorationRelaxedPrecision)) + { + set_decoration(ids, DecorationRelaxedPrecision); + set_decoration(ids + 1, DecorationRelaxedPrecision); + } + } + uint32_t epos_id = ids; + uint32_t eneg_id = ids + 1; + + emit_op(result_type, epos_id, join("exp(", to_expression(args[0]), ")"), false); + emit_op(result_type, eneg_id, join("exp(-", to_enclosed_expression(args[0]), ")"), false); + inherit_expression_dependencies(epos_id, args[0]); + inherit_expression_dependencies(eneg_id, args[0]); + + auto expr = join("(", to_enclosed_expression(epos_id), " - ", to_enclosed_expression(eneg_id), ") / " + "(", to_enclosed_expression(epos_id), " + ", to_enclosed_expression(eneg_id), ")"); + emit_op(result_type, id, expr, true); + inherit_expression_dependencies(id, epos_id); + inherit_expression_dependencies(id, eneg_id); + } break; case GLSLstd450Asinh: - emit_unary_func_op(result_type, id, args[0], "asinh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "asinh"); + else + emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Asinh); break; case GLSLstd450Acosh: - emit_unary_func_op(result_type, id, args[0], "acosh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "acosh"); + else + emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Acosh); break; case GLSLstd450Atanh: - emit_unary_func_op(result_type, id, args[0], "atanh"); + if (!is_legacy()) + emit_unary_func_op(result_type, id, args[0], "atanh"); + else + emit_emulated_ahyper_op(result_type, id, args[0], GLSLstd450Atanh); break; case GLSLstd450Atan2: emit_binary_func_op(result_type, id, args[0], args[1], "atan"); @@ -7448,11 +8625,74 @@ void CompilerGLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, // Matrix math case GLSLstd450Determinant: - emit_unary_func_op(result_type, id, args[0], "determinant"); + { + // No need to transpose - it doesn't affect the determinant + auto *e = maybe_get(args[0]); + bool old_transpose = e && e->need_transpose; + if (old_transpose) + e->need_transpose = false; + + if (options.version < 150) // also matches ES 100 + { + auto &type = expression_type(args[0]); + assert(type.vecsize >= 2 && type.vecsize <= 4); + assert(type.vecsize == type.columns); + + // ARB_gpu_shader_fp64 needs GLSL 150, other types are not valid + if (type.basetype != SPIRType::Float) + SPIRV_CROSS_THROW("Unsupported type for matrix determinant"); + + bool relaxed = has_decoration(id, DecorationRelaxedPrecision); + require_polyfill(static_cast(PolyfillDeterminant2x2 << (type.vecsize - 2)), + relaxed); + emit_unary_func_op(result_type, id, args[0], + (options.es && relaxed) ? "spvDeterminantMP" : "spvDeterminant"); + } + else + emit_unary_func_op(result_type, id, args[0], "determinant"); + + if (old_transpose) + e->need_transpose = true; break; + } + case GLSLstd450MatrixInverse: - emit_unary_func_op(result_type, id, args[0], "inverse"); + { + // The inverse of the transpose is the same as the transpose of + // the inverse, so we can just flip need_transpose of the result. + auto *a = maybe_get(args[0]); + bool old_transpose = a && a->need_transpose; + if (old_transpose) + a->need_transpose = false; + + const char *func = "inverse"; + if (options.version < 140) // also matches ES 100 + { + auto &type = get(result_type); + assert(type.vecsize >= 2 && type.vecsize <= 4); + assert(type.vecsize == type.columns); + + // ARB_gpu_shader_fp64 needs GLSL 150, other types are invalid + if (type.basetype != SPIRType::Float) + SPIRV_CROSS_THROW("Unsupported type for matrix inverse"); + + bool relaxed = has_decoration(id, DecorationRelaxedPrecision); + require_polyfill(static_cast(PolyfillMatrixInverse2x2 << (type.vecsize - 2)), + relaxed); + func = (options.es && relaxed) ? "spvInverseMP" : "spvInverse"; + } + + bool forward = should_forward(args[0]); + auto &e = emit_op(result_type, id, join(func, "(", to_unpacked_expression(args[0]), ")"), forward); + inherit_expression_dependencies(id, args[0]); + + if (old_transpose) + { + e.need_transpose = true; + a->need_transpose = true; + } break; + } // Lerping case GLSLstd450FMix: @@ -7645,13 +8885,60 @@ void CompilerGLSL::emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t o ir.meta[tmp_id] = ir.meta[id]; ir.meta[mixed_first_id] = ir.meta[id]; - emit_unary_func_op(btype_id, left_nan_id, op0, "isnan"); - emit_unary_func_op(btype_id, right_nan_id, op1, "isnan"); + if (!is_legacy()) + { + emit_unary_func_op(btype_id, left_nan_id, op0, "isnan"); + emit_unary_func_op(btype_id, right_nan_id, op1, "isnan"); + } + else if (expression_type(op0).vecsize > 1) + { + // If the number doesn't equal itself, it must be NaN + emit_binary_func_op(btype_id, left_nan_id, op0, op0, "notEqual"); + emit_binary_func_op(btype_id, right_nan_id, op1, op1, "notEqual"); + } + else + { + emit_binary_op(btype_id, left_nan_id, op0, op0, "!="); + emit_binary_op(btype_id, right_nan_id, op1, op1, "!="); + } emit_binary_func_op(result_type, tmp_id, op0, op1, op == GLSLstd450NMin ? "min" : "max"); emit_mix_op(result_type, mixed_first_id, tmp_id, op1, left_nan_id); emit_mix_op(result_type, id, mixed_first_id, op0, right_nan_id); } +void CompilerGLSL::emit_emulated_ahyper_op(uint32_t result_type, uint32_t id, uint32_t op0, GLSLstd450 op) +{ + const char *one = backend.float_literal_suffix ? "1.0f" : "1.0"; + std::string expr; + bool forward = should_forward(op0); + + switch (op) + { + case GLSLstd450Asinh: + expr = join("log(", to_enclosed_expression(op0), " + sqrt(", + to_enclosed_expression(op0), " * ", to_enclosed_expression(op0), " + ", one, "))"); + emit_op(result_type, id, expr, forward); + break; + + case GLSLstd450Acosh: + expr = join("log(", to_enclosed_expression(op0), " + sqrt(", + to_enclosed_expression(op0), " * ", to_enclosed_expression(op0), " - ", one, "))"); + break; + + case GLSLstd450Atanh: + expr = join("log((", one, " + ", to_enclosed_expression(op0), ") / " + "(", one, " - ", to_enclosed_expression(op0), ")) * 0.5", + backend.float_literal_suffix ? "f" : ""); + break; + + default: + SPIRV_CROSS_THROW("Invalid op."); + } + + emit_op(result_type, id, expr, forward); + inherit_expression_dependencies(id, op0); +} + void CompilerGLSL::emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t id, uint32_t eop, const uint32_t *args, uint32_t) { @@ -7806,7 +9093,7 @@ void CompilerGLSL::emit_subgroup_op(const Instruction &i) const uint32_t *ops = stream(i); auto op = static_cast(i.op); - if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op)) + if (!options.vulkan_semantics && !is_supported_subgroup_op_in_opengl(op, ops)) SPIRV_CROSS_THROW("This subgroup operation is only supported in Vulkan semantics."); // If we need to do implicit bitcasts, make sure we do it with the correct type. @@ -7874,12 +9161,34 @@ void CompilerGLSL::emit_subgroup_op(const Instruction &i) } break; - case OpGroupNonUniformFAdd: - case OpGroupNonUniformFMul: + // clang-format off +#define GLSL_GROUP_OP(OP)\ + case OpGroupNonUniform##OP:\ + {\ + auto operation = static_cast(ops[3]);\ + if (operation == GroupOperationClusteredReduce)\ + require_extension_internal("GL_KHR_shader_subgroup_clustered");\ + else if (operation == GroupOperationReduce)\ + request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupArithmetic##OP##Reduce);\ + else if (operation == GroupOperationExclusiveScan)\ + request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupArithmetic##OP##ExclusiveScan);\ + else if (operation == GroupOperationInclusiveScan)\ + request_subgroup_feature(ShaderSubgroupSupportHelper::SubgroupArithmetic##OP##InclusiveScan);\ + else\ + SPIRV_CROSS_THROW("Invalid group operation.");\ + break;\ + } + + GLSL_GROUP_OP(IAdd) + GLSL_GROUP_OP(FAdd) + GLSL_GROUP_OP(IMul) + GLSL_GROUP_OP(FMul) + +#undef GLSL_GROUP_OP + // clang-format on + case OpGroupNonUniformFMin: case OpGroupNonUniformFMax: - case OpGroupNonUniformIAdd: - case OpGroupNonUniformIMul: case OpGroupNonUniformSMin: case OpGroupNonUniformSMax: case OpGroupNonUniformUMin: @@ -8235,9 +9544,17 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) case BuiltInPointSize: return "gl_PointSize"; case BuiltInClipDistance: + { + if (options.es) + require_extension_internal("GL_EXT_clip_cull_distance"); return "gl_ClipDistance"; + } case BuiltInCullDistance: + { + if (options.es) + require_extension_internal("GL_EXT_clip_cull_distance"); return "gl_CullDistance"; + } case BuiltInVertexId: if (options.vulkan_semantics) SPIRV_CROSS_THROW("Cannot implement gl_VertexID in Vulkan GLSL. This shader was created " @@ -8307,6 +9624,8 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) return "gl_TessLevelInner"; case BuiltInTessCoord: return "gl_TessCoord"; + case BuiltInPatchVertices: + return "gl_PatchVerticesIn"; case BuiltInFragCoord: return "gl_FragCoord"; case BuiltInPointCoord: @@ -8382,17 +9701,21 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) return "gl_DrawIDARB"; case BuiltInSampleId: - if (options.es && options.version < 320) + if (is_legacy()) + SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL."); + else if (options.es && options.version < 320) require_extension_internal("GL_OES_sample_variables"); - if (!options.es && options.version < 400) - SPIRV_CROSS_THROW("gl_SampleID not supported before GLSL 400."); + else if (!options.es && options.version < 400) + require_extension_internal("GL_ARB_sample_shading"); return "gl_SampleID"; case BuiltInSampleMask: - if (options.es && options.version < 320) + if (is_legacy()) + SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL."); + else if (options.es && options.version < 320) require_extension_internal("GL_OES_sample_variables"); - if (!options.es && options.version < 400) - SPIRV_CROSS_THROW("gl_SampleMask/gl_SampleMaskIn not supported before GLSL 400."); + else if (!options.es && options.version < 400) + require_extension_internal("GL_ARB_sample_shading"); if (storage == StorageClassInput) return "gl_SampleMaskIn"; @@ -8400,10 +9723,12 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) return "gl_SampleMask"; case BuiltInSamplePosition: - if (options.es && options.version < 320) + if (is_legacy()) + SPIRV_CROSS_THROW("Sample variables not supported in legacy GLSL."); + else if (options.es && options.version < 320) require_extension_internal("GL_OES_sample_variables"); - if (!options.es && options.version < 400) - SPIRV_CROSS_THROW("gl_SamplePosition not supported before GLSL 400."); + else if (!options.es && options.version < 400) + require_extension_internal("GL_ARB_sample_shading"); return "gl_SamplePosition"; case BuiltInViewIndex: @@ -8478,24 +9803,42 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) case BuiltInIncomingRayFlagsKHR: return ray_tracing_is_khr ? "gl_IncomingRayFlagsEXT" : "gl_IncomingRayFlagsNV"; - case BuiltInBaryCoordNV: + case BuiltInBaryCoordKHR: { if (options.es && options.version < 320) - SPIRV_CROSS_THROW("gl_BaryCoordNV requires ESSL 320."); + SPIRV_CROSS_THROW("gl_BaryCoordEXT requires ESSL 320."); else if (!options.es && options.version < 450) - SPIRV_CROSS_THROW("gl_BaryCoordNV requires GLSL 450."); - require_extension_internal("GL_NV_fragment_shader_barycentric"); - return "gl_BaryCoordNV"; + SPIRV_CROSS_THROW("gl_BaryCoordEXT requires GLSL 450."); + + if (barycentric_is_nv) + { + require_extension_internal("GL_NV_fragment_shader_barycentric"); + return "gl_BaryCoordNV"; + } + else + { + require_extension_internal("GL_EXT_fragment_shader_barycentric"); + return "gl_BaryCoordEXT"; + } } case BuiltInBaryCoordNoPerspNV: { if (options.es && options.version < 320) - SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires ESSL 320."); + SPIRV_CROSS_THROW("gl_BaryCoordNoPerspEXT requires ESSL 320."); else if (!options.es && options.version < 450) - SPIRV_CROSS_THROW("gl_BaryCoordNoPerspNV requires GLSL 450."); - require_extension_internal("GL_NV_fragment_shader_barycentric"); - return "gl_BaryCoordNoPerspNV"; + SPIRV_CROSS_THROW("gl_BaryCoordNoPerspEXT requires GLSL 450."); + + if (barycentric_is_nv) + { + require_extension_internal("GL_NV_fragment_shader_barycentric"); + return "gl_BaryCoordNoPerspNV"; + } + else + { + require_extension_internal("GL_EXT_fragment_shader_barycentric"); + return "gl_BaryCoordNoPerspEXT"; + } } case BuiltInFragStencilRefEXT: @@ -8538,6 +9881,15 @@ string CompilerGLSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) SPIRV_CROSS_THROW("Need desktop GL to use GL_NV_conservative_raster_underestimation."); return "gl_FragFullyCoveredNV"; + case BuiltInPrimitiveTriangleIndicesEXT: + return "gl_PrimitiveTriangleIndicesEXT"; + case BuiltInPrimitiveLineIndicesEXT: + return "gl_PrimitiveLineIndicesEXT"; + case BuiltInPrimitivePointIndicesEXT: + return "gl_PrimitivePointIndicesEXT"; + case BuiltInCullPrimitiveEXT: + return "gl_CullPrimitiveEXT"; + default: return join("gl_BuiltIn_", convert_to_string(builtin)); } @@ -8561,19 +9913,35 @@ const char *CompilerGLSL::index_to_swizzle(uint32_t index) } void CompilerGLSL::access_chain_internal_append_index(std::string &expr, uint32_t /*base*/, const SPIRType * /*type*/, - AccessChainFlags flags, bool & /*access_chain_is_arrayed*/, + AccessChainFlags flags, bool &access_chain_is_arrayed, uint32_t index) { bool index_is_literal = (flags & ACCESS_CHAIN_INDEX_IS_LITERAL_BIT) != 0; + bool ptr_chain = (flags & ACCESS_CHAIN_PTR_CHAIN_BIT) != 0; bool register_expression_read = (flags & ACCESS_CHAIN_SKIP_REGISTER_EXPRESSION_READ_BIT) == 0; + string idx_expr = index_is_literal ? convert_to_string(index) : to_unpacked_expression(index, register_expression_read); + + // For the case where the base of an OpPtrAccessChain already ends in [n], + // we need to use the index as an offset to the existing index, otherwise, + // we can just use the index directly. + if (ptr_chain && access_chain_is_arrayed) + { + size_t split_pos = expr.find_last_of(']'); + size_t enclose_split = expr.find_last_of(')'); + + // If we have already enclosed the expression, don't try to be clever, it will break. + if (split_pos > enclose_split || enclose_split == string::npos) + { + string expr_front = expr.substr(0, split_pos); + string expr_back = expr.substr(split_pos); + expr = expr_front + " + " + enclose_expression(idx_expr) + expr_back; + return; + } + } + expr += "["; - - if (index_is_literal) - expr += convert_to_string(index); - else - expr += to_unpacked_expression(index, register_expression_read); - + expr += idx_expr; expr += "]"; } @@ -8609,6 +9977,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // Start traversing type hierarchy at the proper non-pointer types, // but keep type_id referencing the original pointer for use below. uint32_t type_id = expression_type_id(base); + const auto *type = &get_pointee_type(type_id); if (!backend.native_pointers) { @@ -8618,27 +9987,37 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // Wrapped buffer reference pointer types will need to poke into the internal "value" member before // continuing the access chain. if (should_dereference(base)) - { - auto &type = get(type_id); - expr = dereference_expression(type, expr); - } + expr = dereference_expression(get(type_id), expr); } - - const auto *type = &get_pointee_type(type_id); + else if (should_dereference(base) && type->basetype != SPIRType::Struct && !ptr_chain) + expr = join("(", dereference_expression(*type, expr), ")"); bool access_chain_is_arrayed = expr.find_first_of('[') != string::npos; bool row_major_matrix_needs_conversion = is_non_native_row_major_matrix(base); bool is_packed = has_extended_decoration(base, SPIRVCrossDecorationPhysicalTypePacked); uint32_t physical_type = get_extended_decoration(base, SPIRVCrossDecorationPhysicalTypeID); bool is_invariant = has_decoration(base, DecorationInvariant); + bool relaxed_precision = has_decoration(base, DecorationRelaxedPrecision); bool pending_array_enclose = false; bool dimension_flatten = false; + bool access_meshlet_position_y = false; - const auto append_index = [&](uint32_t index, bool is_literal) { + if (auto *base_expr = maybe_get(base)) + { + access_meshlet_position_y = base_expr->access_meshlet_position_y; + } + + // If we are translating access to a structured buffer, the first subscript '._m0' must be hidden + bool hide_first_subscript = count > 1 && is_user_type_structured(base); + + const auto append_index = [&](uint32_t index, bool is_literal, bool is_ptr_chain = false) { AccessChainFlags mod_flags = flags; if (!is_literal) mod_flags &= ~ACCESS_CHAIN_INDEX_IS_LITERAL_BIT; + if (!is_ptr_chain) + mod_flags &= ~ACCESS_CHAIN_PTR_CHAIN_BIT; access_chain_internal_append_index(expr, base, type, mod_flags, access_chain_is_arrayed, index); + check_physical_type_cast(expr, type, physical_type); }; for (uint32_t i = 0; i < count; i++) @@ -8652,9 +10031,21 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice index &= 0x7fffffffu; } - // Pointer chains + bool ptr_chain_array_entry = ptr_chain && i == 0 && is_array(*type); + + if (ptr_chain_array_entry) + { + // This is highly unusual code, since normally we'd use plain AccessChain, but it's still allowed. + // We are considered to have a pointer to array and one element shifts by one array at a time. + // If we use normal array indexing, we'll first decay to pointer, and lose the array-ness, + // so we have to take pointer to array explicitly. + if (!should_dereference(base)) + expr = enclose_expression(address_of_expression(expr)); + } + if (ptr_chain && i == 0) { + // Pointer chains // If we are flattening multidimensional arrays, only create opening bracket on first // array index. if (options.flatten_multidimensional_arrays) @@ -8689,7 +10080,7 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice } else { - append_index(index, is_literal); + append_index(index, is_literal, true); } if (type->basetype == SPIRType::ControlPointArray) @@ -8699,6 +10090,12 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice } access_chain_is_arrayed = true; + + // Explicitly enclose the expression if this is one of the weird pointer-to-array cases. + // We don't want any future indexing to add to this array dereference. + // Enclosing the expression blocks that and avoids any shenanigans with operand priority. + if (ptr_chain_array_entry) + expr = join("(", expr, ")"); } // Arrays else if (!type->array.empty()) @@ -8724,14 +10121,25 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice // but HLSL seems to just emit straight arrays here. // We must pretend this access goes through gl_in/gl_out arrays // to be able to access certain builtins as arrays. + // Similar concerns apply for mesh shaders where we have to redirect to gl_MeshVerticesEXT or MeshPrimitivesEXT. auto builtin = ir.meta[base].decoration.builtin_type; + bool mesh_shader = get_execution_model() == ExecutionModelMeshEXT; + switch (builtin) { - // case BuiltInCullDistance: // These are already arrays, need to figure out rules for these in tess/geom. - // case BuiltInClipDistance: + case BuiltInCullDistance: + case BuiltInClipDistance: + if (type->array.size() == 1) // Red herring. Only consider block IO for two-dimensional arrays here. + { + append_index(index, is_literal); + break; + } + // fallthrough case BuiltInPosition: case BuiltInPointSize: - if (var->storage == StorageClassInput) + if (mesh_shader) + expr = join("gl_MeshVerticesEXT[", to_expression(index, register_expression_read), "].", expr); + else if (var->storage == StorageClassInput) expr = join("gl_in[", to_expression(index, register_expression_read), "].", expr); else if (var->storage == StorageClassOutput) expr = join("gl_out[", to_expression(index, register_expression_read), "].", expr); @@ -8739,11 +10147,30 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice append_index(index, is_literal); break; + case BuiltInPrimitiveId: + case BuiltInLayer: + case BuiltInViewportIndex: + case BuiltInCullPrimitiveEXT: + case BuiltInPrimitiveShadingRateKHR: + if (mesh_shader) + expr = join("gl_MeshPrimitivesEXT[", to_expression(index, register_expression_read), "].", expr); + else + append_index(index, is_literal); + break; + default: append_index(index, is_literal); break; } } + else if (backend.force_merged_mesh_block && i == 0 && var && + !is_builtin_variable(*var) && var->storage == StorageClassOutput) + { + if (is_per_primitive_variable(*var)) + expr = join("gl_MeshPrimitivesEXT[", to_expression(index, register_expression_read), "].", expr); + else + expr = join("gl_MeshVerticesEXT[", to_expression(index, register_expression_read), "].", expr); + } else if (options.flatten_multidimensional_arrays && dimension_flatten) { // If we are flattening multidimensional arrays, do manual stride computation. @@ -8768,16 +10195,34 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (!pending_array_enclose) expr += "]"; } - // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal. - // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask. - else if (!builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn)))) + else if (index_is_literal || !builtin_translates_to_nonarray(BuiltIn(get_decoration(base, DecorationBuiltIn)))) { + // Some builtins are arrays in SPIR-V but not in other languages, e.g. gl_SampleMask[] is an array in SPIR-V but not in Metal. + // By throwing away the index, we imply the index was 0, which it must be for gl_SampleMask. + // For literal indices we are working on composites, so we ignore this since we have already converted to proper array. append_index(index, is_literal); } + if (var && has_decoration(var->self, DecorationBuiltIn) && + get_decoration(var->self, DecorationBuiltIn) == BuiltInPosition && + get_execution_model() == ExecutionModelMeshEXT) + { + access_meshlet_position_y = true; + } + type_id = type->parent_type; type = &get(type_id); + // If the physical type has an unnatural vecsize, + // we must assume it's a faked struct where the .data member + // is used for the real payload. + if (physical_type && (is_vector(*type) || is_scalar(*type))) + { + auto &phys = get(physical_type); + if (phys.vecsize > 4) + expr += ".data"; + } + access_chain_is_arrayed = true; } // For structs, the index refers to a constant, which indexes into the members, possibly through a redirection mapping. @@ -8793,31 +10238,52 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (index >= type->member_types.size()) SPIRV_CROSS_THROW("Member index is out of bounds!"); - BuiltIn builtin; - if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base)) + if (hide_first_subscript) { - if (access_chain_is_arrayed) - { - expr += "."; - expr += builtin_to_glsl(builtin, type->storage); - } - else - expr = builtin_to_glsl(builtin, type->storage); + // First "._m0" subscript has been hidden, subsequent fields must be emitted even for structured buffers + hide_first_subscript = false; } else { - // If the member has a qualified name, use it as the entire chain - string qual_mbr_name = get_member_qualified_name(type_id, index); - if (!qual_mbr_name.empty()) - expr = qual_mbr_name; - else if (flatten_member_reference) - expr += join("_", to_member_name(*type, index)); + BuiltIn builtin = BuiltInMax; + if (is_member_builtin(*type, index, &builtin) && access_chain_needs_stage_io_builtin_translation(base)) + { + if (access_chain_is_arrayed) + { + expr += "."; + expr += builtin_to_glsl(builtin, type->storage); + } + else + expr = builtin_to_glsl(builtin, type->storage); + + if (builtin == BuiltInPosition && get_execution_model() == ExecutionModelMeshEXT) + { + access_meshlet_position_y = true; + } + } else - expr += to_member_reference(base, *type, index, ptr_chain); + { + // If the member has a qualified name, use it as the entire chain + string qual_mbr_name = get_member_qualified_name(type_id, index); + if (!qual_mbr_name.empty()) + expr = qual_mbr_name; + else if (flatten_member_reference) + expr += join("_", to_member_name(*type, index)); + else + { + // Any pointer de-refences for values are handled in the first access chain. + // For pointer chains, the pointer-ness is resolved through an array access. + // The only time this is not true is when accessing array of SSBO/UBO. + // This case is explicitly handled. + expr += to_member_reference(base, *type, index, ptr_chain || i != 0); + } + } } if (has_member_decoration(type->self, index, DecorationInvariant)) is_invariant = true; + if (has_member_decoration(type->self, index, DecorationRelaxedPrecision)) + relaxed_precision = true; is_packed = member_is_packed_physical_type(*type, index); if (member_is_remapped_physical_type(*type, index)) @@ -8842,6 +10308,16 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice expr += to_unpacked_expression(index, register_expression_read); expr += "]"; + // If the physical type has an unnatural vecsize, + // we must assume it's a faked struct where the .data member + // is used for the real payload. + if (physical_type) + { + auto &phys = get(physical_type); + if (phys.vecsize > 4 || phys.columns > 4) + expr += ".data"; + } + type_id = type->parent_type; type = &get(type_id); } @@ -8856,6 +10332,18 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (column_index != string::npos) { deferred_index = expr.substr(column_index); + + auto end_deferred_index = deferred_index.find_last_of(']'); + if (end_deferred_index != string::npos && end_deferred_index + 1 != deferred_index.size()) + { + // If we have any data member fixups, it must be transposed so that it refers to this index. + // E.g. [0].data followed by [1] would be shuffled to [1][0].data which is wrong, + // and needs to be [1].data[0] instead. + end_deferred_index++; + deferred_index = deferred_index.substr(end_deferred_index) + + deferred_index.substr(0, end_deferred_index); + } + expr.resize(column_index); } } @@ -8894,30 +10382,37 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice is_packed); } - if (is_literal && !is_packed && !row_major_matrix_needs_conversion) + if (is_literal) { - expr += "."; - expr += index_to_swizzle(index); + bool out_of_bounds = (index >= type->vecsize); + + if (!is_packed && !row_major_matrix_needs_conversion) + { + expr += "."; + expr += index_to_swizzle(out_of_bounds ? 0 : index); + } + else + { + // For packed vectors, we can only access them as an array, not by swizzle. + expr += join("[", out_of_bounds ? 0 : index, "]"); + } } else if (ir.ids[index].get_type() == TypeConstant && !is_packed && !row_major_matrix_needs_conversion) { auto &c = get(index); + bool out_of_bounds = (c.scalar() >= type->vecsize); + if (c.specialization) { // If the index is a spec constant, we cannot turn extract into a swizzle. - expr += join("[", to_expression(index), "]"); + expr += join("[", out_of_bounds ? "0" : to_expression(index), "]"); } else { expr += "."; - expr += index_to_swizzle(c.scalar()); + expr += index_to_swizzle(out_of_bounds ? 0 : c.scalar()); } } - else if (is_literal) - { - // For packed vectors, we can only access them as an array, not by swizzle. - expr += join("[", index, "]"); - } else { expr += "["; @@ -8927,8 +10422,34 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice if (row_major_matrix_needs_conversion && !ignore_potential_sliced_writes) { - prepare_access_chain_for_scalar_access(expr, get(type->parent_type), effective_storage, - is_packed); + if (prepare_access_chain_for_scalar_access(expr, get(type->parent_type), effective_storage, + is_packed)) + { + // We're in a pointer context now, so just remove any member dereference. + auto first_index = deferred_index.find_first_of('['); + if (first_index != string::npos && first_index != 0) + deferred_index = deferred_index.substr(first_index); + } + } + + if (access_meshlet_position_y) + { + if (is_literal) + { + access_meshlet_position_y = index == 1; + } + else + { + const auto *c = maybe_get(index); + if (c) + access_meshlet_position_y = c->scalar() == 1; + else + { + // We don't know, but we have to assume no. + // Flip Y in mesh shaders is an opt-in horrible hack, so we'll have to assume shaders try to behave. + access_meshlet_position_y = false; + } + } } expr += deferred_index; @@ -8956,15 +10477,22 @@ string CompilerGLSL::access_chain_internal(uint32_t base, const uint32_t *indice meta->storage_is_packed = is_packed; meta->storage_is_invariant = is_invariant; meta->storage_physical_type = physical_type; + meta->relaxed_precision = relaxed_precision; + meta->access_meshlet_position_y = access_meshlet_position_y; } return expr; } -void CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &) +void CompilerGLSL::check_physical_type_cast(std::string &, const SPIRType *, uint32_t) { } +bool CompilerGLSL::prepare_access_chain_for_scalar_access(std::string &, const SPIRType &, spv::StorageClass, bool &) +{ + return false; +} + string CompilerGLSL::to_flattened_struct_member(const string &basename, const SPIRType &type, uint32_t index) { auto ret = join(basename, "_", to_member_name(type, index)); @@ -9114,8 +10642,13 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin { std::string expr; - expr += type_to_glsl_constructor(target_type); - expr += "("; + if (backend.can_declare_struct_inline) + { + expr += type_to_glsl_constructor(target_type); + expr += "("; + } + else + expr += "{"; for (uint32_t i = 0; i < uint32_t(target_type.member_types.size()); ++i) { @@ -9128,10 +10661,13 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin // The access chain terminates at the struct, so we need to find matrix strides and row-major information // ahead of time. bool need_transpose = false; + bool relaxed = false; uint32_t matrix_stride = 0; if (member_type.columns > 1) { - need_transpose = combined_decoration_for_member(target_type, i).get(DecorationRowMajor); + auto decorations = combined_decoration_for_member(target_type, i); + need_transpose = decorations.get(DecorationRowMajor); + relaxed = decorations.get(DecorationRelaxedPrecision); matrix_stride = type_struct_member_matrix_stride(target_type, i); } @@ -9140,12 +10676,12 @@ std::string CompilerGLSL::flattened_access_chain_struct(uint32_t base, const uin // Cannot forward transpositions, so resolve them here. if (need_transpose) - expr += convert_row_major_matrix(tmp, member_type, 0, false); + expr += convert_row_major_matrix(tmp, member_type, 0, false, relaxed); else expr += tmp; } - expr += ")"; + expr += backend.can_declare_struct_inline ? ")" : "}"; return expr; } @@ -9437,9 +10973,32 @@ bool CompilerGLSL::should_dereference(uint32_t id) if (auto *var = maybe_get(id)) return var->phi_variable; - // If id is an access chain, we should not dereference it. if (auto *expr = maybe_get(id)) - return !expr->access_chain; + { + // If id is an access chain, we should not dereference it. + if (expr->access_chain) + return false; + + // If id is a forwarded copy of a variable pointer, we should not dereference it. + SPIRVariable *var = nullptr; + while (expr->loaded_from && expression_is_forwarded(expr->self)) + { + auto &src_type = expression_type(expr->loaded_from); + // To be a copy, the pointer and its source expression must be the + // same type. Can't check type.self, because for some reason that's + // usually the base type with pointers stripped off. This check is + // complex enough that I've hoisted it out of the while condition. + if (src_type.pointer != type.pointer || src_type.pointer_depth != type.pointer_depth || + src_type.parent_type != type.parent_type) + break; + if ((var = maybe_get(expr->loaded_from))) + break; + if (!(expr = maybe_get(expr->loaded_from))) + break; + } + + return !var || var->phi_variable; + } // Otherwise, we should dereference this pointer expression. return true; @@ -9449,14 +11008,33 @@ bool CompilerGLSL::should_forward(uint32_t id) const { // If id is a variable we will try to forward it regardless of force_temporary check below // This is important because otherwise we'll get local sampler copies (highp sampler2D foo = bar) that are invalid in OpenGL GLSL + auto *var = maybe_get(id); - if (var && var->forwardable) - return true; + if (var) + { + // Never forward volatile builtin variables, e.g. SPIR-V 1.6 HelperInvocation. + return !(has_decoration(id, DecorationBuiltIn) && has_decoration(id, DecorationVolatile)); + } // For debugging emit temporary variables for all expressions if (options.force_temporary) return false; + // If an expression carries enough dependencies we need to stop forwarding at some point, + // or we explode compilers. There are usually limits to how much we can nest expressions. + auto *expr = maybe_get(id); + const uint32_t max_expression_dependencies = 64; + if (expr && expr->expression_dependencies.size() >= max_expression_dependencies) + return false; + + if (expr && expr->loaded_from + && has_decoration(expr->loaded_from, DecorationBuiltIn) + && has_decoration(expr->loaded_from, DecorationVolatile)) + { + // Never forward volatile builtin variables, e.g. SPIR-V 1.6 HelperInvocation. + return false; + } + // Immutable expression can always be forwarded. if (is_immutable(id)) return true; @@ -9513,9 +11091,8 @@ void CompilerGLSL::track_expression_read(uint32_t id) //if (v == 2) // fprintf(stderr, "ID %u was forced to temporary due to more than 1 expression use!\n", id); - forced_temporaries.insert(id); // Force a recompile after this pass to avoid forwarding this variable. - force_recompile(); + force_temporary_and_recompile(id); } } } @@ -9776,7 +11353,7 @@ string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32 bool uses_buffer_offset = type.basetype == SPIRType::Struct && has_member_decoration(type.self, i, DecorationOffset); - subop = to_composite_constructor_expression(elems[i], uses_buffer_offset); + subop = to_composite_constructor_expression(type, elems[i], uses_buffer_offset); } base = e ? e->base_expression : ID(0); @@ -9835,6 +11412,12 @@ bool CompilerGLSL::optimize_read_modify_write(const SPIRType &type, const string char bop = rhs[op]; auto expr = rhs.substr(lhs.size() + 3); + + // Avoids false positives where we get a = a * b + c. + // Normally, these expressions are always enclosed, but unexpected code paths may end up hitting this. + if (needs_enclose_expression(expr)) + return false; + // Try to find increments and decrements. Makes it look neater as += 1, -= 1 is fairly rare to see in real code. // Find some common patterns which are equivalent. if ((bop == '+' || bop == '-') && (expr == "1" || expr == "uint(1)" || expr == "1u" || expr == "int(1u)")) @@ -9856,8 +11439,58 @@ void CompilerGLSL::register_control_dependent_expression(uint32_t expr) void CompilerGLSL::emit_block_instructions(SPIRBlock &block) { current_emitting_block = █ + + if (backend.requires_relaxed_precision_analysis) + { + // If PHI variables are consumed in unexpected precision contexts, copy them here. + for (size_t i = 0, n = block.phi_variables.size(); i < n; i++) + { + auto &phi = block.phi_variables[i]; + + // Ensure we only copy once. We know a-priori that this array will lay out + // the same function variables together. + if (i && block.phi_variables[i - 1].function_variable == phi.function_variable) + continue; + + auto itr = temporary_to_mirror_precision_alias.find(phi.function_variable); + if (itr != temporary_to_mirror_precision_alias.end()) + { + // Explicitly, we don't want to inherit RelaxedPrecision state in this CopyObject, + // so it helps to have handle_instruction_precision() on the outside of emit_instruction(). + EmbeddedInstruction inst; + inst.op = OpCopyObject; + inst.length = 3; + inst.ops.push_back(expression_type_id(itr->first)); + inst.ops.push_back(itr->second); + inst.ops.push_back(itr->first); + emit_instruction(inst); + } + } + } + for (auto &op : block.ops) + { + auto temporary_copy = handle_instruction_precision(op); emit_instruction(op); + if (temporary_copy.dst_id) + { + // Explicitly, we don't want to inherit RelaxedPrecision state in this CopyObject, + // so it helps to have handle_instruction_precision() on the outside of emit_instruction(). + EmbeddedInstruction inst; + inst.op = OpCopyObject; + inst.length = 3; + inst.ops.push_back(expression_type_id(temporary_copy.src_id)); + inst.ops.push_back(temporary_copy.dst_id); + inst.ops.push_back(temporary_copy.src_id); + + // Never attempt to hoist mirrored temporaries. + // They are hoisted in lock-step with their parents. + block_temporary_hoisting = true; + emit_instruction(inst); + block_temporary_hoisting = false; + } + } + current_emitting_block = nullptr; } @@ -9869,9 +11502,8 @@ void CompilerGLSL::disallow_forwarding_in_expression_chain(const SPIRExpression if (expression_is_forwarded(expr.self) && !expression_suppresses_usage_tracking(expr.self) && forced_invariant_temporaries.count(expr.self) == 0) { - forced_temporaries.insert(expr.self); + force_temporary_and_recompile(expr.self); forced_invariant_temporaries.insert(expr.self); - force_recompile(); for (auto &dependent : expr.expression_dependencies) disallow_forwarding_in_expression_chain(get(dependent)); @@ -9990,6 +11622,235 @@ uint32_t CompilerGLSL::get_integer_width_for_glsl_instruction(GLSLstd450 op, con } } +void CompilerGLSL::forward_relaxed_precision(uint32_t dst_id, const uint32_t *args, uint32_t length) +{ + // Only GLSL supports RelaxedPrecision directly. + // We cannot implement this in HLSL or MSL because it is tied to the type system. + // In SPIR-V, everything must masquerade as 32-bit. + if (!backend.requires_relaxed_precision_analysis) + return; + + auto input_precision = analyze_expression_precision(args, length); + + // For expressions which are loaded or directly forwarded, we inherit mediump implicitly. + // For dst_id to be analyzed properly, it must inherit any relaxed precision decoration from src_id. + if (input_precision == Options::Mediump) + set_decoration(dst_id, DecorationRelaxedPrecision); +} + +CompilerGLSL::Options::Precision CompilerGLSL::analyze_expression_precision(const uint32_t *args, uint32_t length) const +{ + // Now, analyze the precision at which the arguments would run. + // GLSL rules are such that the precision used to evaluate an expression is equal to the highest precision + // for the inputs. Constants do not have inherent precision and do not contribute to this decision. + // If all inputs are constants, they inherit precision from outer expressions, including an l-value. + // In this case, we'll have to force a temporary for dst_id so that we can bind the constant expression with + // correct precision. + bool expression_has_highp = false; + bool expression_has_mediump = false; + + for (uint32_t i = 0; i < length; i++) + { + uint32_t arg = args[i]; + + auto handle_type = ir.ids[arg].get_type(); + if (handle_type == TypeConstant || handle_type == TypeConstantOp || handle_type == TypeUndef) + continue; + + if (has_decoration(arg, DecorationRelaxedPrecision)) + expression_has_mediump = true; + else + expression_has_highp = true; + } + + if (expression_has_highp) + return Options::Highp; + else if (expression_has_mediump) + return Options::Mediump; + else + return Options::DontCare; +} + +void CompilerGLSL::analyze_precision_requirements(uint32_t type_id, uint32_t dst_id, uint32_t *args, uint32_t length) +{ + if (!backend.requires_relaxed_precision_analysis) + return; + + auto &type = get(type_id); + + // RelaxedPrecision only applies to 32-bit values. + if (type.basetype != SPIRType::Float && type.basetype != SPIRType::Int && type.basetype != SPIRType::UInt) + return; + + bool operation_is_highp = !has_decoration(dst_id, DecorationRelaxedPrecision); + + auto input_precision = analyze_expression_precision(args, length); + if (input_precision == Options::DontCare) + { + consume_temporary_in_precision_context(type_id, dst_id, input_precision); + return; + } + + // In SPIR-V and GLSL, the semantics are flipped for how relaxed precision is determined. + // In SPIR-V, the operation itself marks RelaxedPrecision, meaning that inputs can be truncated to 16-bit. + // However, if the expression is not, inputs must be expanded to 32-bit first, + // since the operation must run at high precision. + // This is the awkward part, because if we have mediump inputs, or expressions which derived from mediump, + // we might have to forcefully bind the source IDs to highp temporaries. This is done by clearing decorations + // and forcing temporaries. Similarly for mediump operations. We bind highp expressions to mediump variables. + if ((operation_is_highp && input_precision == Options::Mediump) || + (!operation_is_highp && input_precision == Options::Highp)) + { + auto precision = operation_is_highp ? Options::Highp : Options::Mediump; + for (uint32_t i = 0; i < length; i++) + { + // Rewrites the opcode so that we consume an ID in correct precision context. + // This is pretty hacky, but it's the most straight forward way of implementing this without adding + // lots of extra passes to rewrite all code blocks. + args[i] = consume_temporary_in_precision_context(expression_type_id(args[i]), args[i], precision); + } + } +} + +// This is probably not exhaustive ... +static bool opcode_is_precision_sensitive_operation(Op op) +{ + switch (op) + { + case OpFAdd: + case OpFSub: + case OpFMul: + case OpFNegate: + case OpIAdd: + case OpISub: + case OpIMul: + case OpSNegate: + case OpFMod: + case OpFDiv: + case OpFRem: + case OpSMod: + case OpSDiv: + case OpSRem: + case OpUMod: + case OpUDiv: + case OpVectorTimesMatrix: + case OpMatrixTimesVector: + case OpMatrixTimesMatrix: + case OpDPdx: + case OpDPdy: + case OpDPdxCoarse: + case OpDPdyCoarse: + case OpDPdxFine: + case OpDPdyFine: + case OpFwidth: + case OpFwidthCoarse: + case OpFwidthFine: + case OpVectorTimesScalar: + case OpMatrixTimesScalar: + case OpOuterProduct: + case OpFConvert: + case OpSConvert: + case OpUConvert: + case OpConvertSToF: + case OpConvertUToF: + case OpConvertFToU: + case OpConvertFToS: + return true; + + default: + return false; + } +} + +// Instructions which just load data but don't do any arithmetic operation should just inherit the decoration. +// SPIR-V doesn't require this, but it's somewhat implied it has to work this way, relaxed precision is only +// relevant when operating on the IDs, not when shuffling things around. +static bool opcode_is_precision_forwarding_instruction(Op op, uint32_t &arg_count) +{ + switch (op) + { + case OpLoad: + case OpAccessChain: + case OpInBoundsAccessChain: + case OpCompositeExtract: + case OpVectorExtractDynamic: + case OpSampledImage: + case OpImage: + case OpCopyObject: + + case OpImageRead: + case OpImageFetch: + case OpImageSampleImplicitLod: + case OpImageSampleProjImplicitLod: + case OpImageSampleDrefImplicitLod: + case OpImageSampleProjDrefImplicitLod: + case OpImageSampleExplicitLod: + case OpImageSampleProjExplicitLod: + case OpImageSampleDrefExplicitLod: + case OpImageSampleProjDrefExplicitLod: + case OpImageGather: + case OpImageDrefGather: + case OpImageSparseRead: + case OpImageSparseFetch: + case OpImageSparseSampleImplicitLod: + case OpImageSparseSampleProjImplicitLod: + case OpImageSparseSampleDrefImplicitLod: + case OpImageSparseSampleProjDrefImplicitLod: + case OpImageSparseSampleExplicitLod: + case OpImageSparseSampleProjExplicitLod: + case OpImageSparseSampleDrefExplicitLod: + case OpImageSparseSampleProjDrefExplicitLod: + case OpImageSparseGather: + case OpImageSparseDrefGather: + arg_count = 1; + return true; + + case OpVectorShuffle: + arg_count = 2; + return true; + + case OpCompositeConstruct: + return true; + + default: + break; + } + + return false; +} + +CompilerGLSL::TemporaryCopy CompilerGLSL::handle_instruction_precision(const Instruction &instruction) +{ + auto ops = stream_mutable(instruction); + auto opcode = static_cast(instruction.op); + uint32_t length = instruction.length; + + if (backend.requires_relaxed_precision_analysis) + { + if (length > 2) + { + uint32_t forwarding_length = length - 2; + + if (opcode_is_precision_sensitive_operation(opcode)) + analyze_precision_requirements(ops[0], ops[1], &ops[2], forwarding_length); + else if (opcode == OpExtInst && length >= 5 && get(ops[2]).ext == SPIRExtension::GLSL) + analyze_precision_requirements(ops[0], ops[1], &ops[4], forwarding_length - 2); + else if (opcode_is_precision_forwarding_instruction(opcode, forwarding_length)) + forward_relaxed_precision(ops[1], &ops[2], forwarding_length); + } + + uint32_t result_type = 0, result_id = 0; + if (instruction_to_result_type(result_type, result_id, opcode, ops, length)) + { + auto itr = temporary_to_mirror_precision_alias.find(ops[1]); + if (itr != temporary_to_mirror_precision_alias.end()) + return { itr->second, itr->first }; + } + } + + return {}; +} + void CompilerGLSL::emit_instruction(const Instruction &instruction) { auto ops = stream(instruction); @@ -9998,8 +11859,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) #define GLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op) #define GLSL_BOP_CAST(op, type) \ - emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode)) + emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, \ + opcode_is_sign_invariant(opcode), implicit_integer_promotion) #define GLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op) +#define GLSL_UOP_CAST(op) emit_unary_op_cast(ops[0], ops[1], ops[2], #op) #define GLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op) #define GLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op) #define GLSL_BFOP(op) emit_binary_func_op(ops[0], ops[1], ops[2], ops[3], #op) @@ -10013,6 +11876,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto int_type = to_signed_basetype(integer_width); auto uint_type = to_unsigned_basetype(integer_width); + // Handle C implicit integer promotion rules. + // If we get implicit promotion to int, need to make sure we cast by value to intended return type, + // otherwise, future sign-dependent operations and bitcasts will break. + bool implicit_integer_promotion = integer_width < 32 && backend.implicit_c_integer_promotion_rules && + opcode_can_promote_integer_implicitly(opcode) && + get(ops[0]).vecsize == 1; + + opcode = get_remapped_spirv_op(opcode); + switch (opcode) { // Dealing with memory @@ -10077,9 +11949,15 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (expr_type.vecsize > type.vecsize) expr = enclose_expression(expr + vector_swizzle(type.vecsize, 0)); + if (forward && ptr_expression) + ptr_expression->need_transpose = old_need_transpose; + // We might need to cast in order to load from a builtin. cast_from_variable_load(ptr, expr, type); + if (forward && ptr_expression) + ptr_expression->need_transpose = false; + // We might be trying to load a gl_Position[N], where we should be // doing float4[](gl_in[i].gl_Position, ...) instead. // Similar workarounds are required for input arrays in tessellation. @@ -10112,7 +11990,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // it is an array, and our backend does not support arrays as value types. // Emit the temporary, and copy it explicitly. e = &emit_uninitialized_temporary_expression(result_type, id); - emit_array_copy(to_expression(id), id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr)); + emit_array_copy(nullptr, id, ptr, StorageClassFunction, get_expression_effective_storage_class(ptr)); } else e = &emit_op(result_type, id, expr, forward, !usage_tracking); @@ -10156,14 +12034,25 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // If an expression is mutable and forwardable, we speculate that it is immutable. AccessChainMeta meta; bool ptr_chain = opcode == OpPtrAccessChain; - auto e = access_chain(ops[2], &ops[3], length - 3, get(ops[0]), &meta, ptr_chain); + auto &target_type = get(ops[0]); + auto e = access_chain(ops[2], &ops[3], length - 3, target_type, &meta, ptr_chain); - auto &expr = set(ops[1], move(e), ops[0], should_forward(ops[2])); + // If the base is flattened UBO of struct type, the expression has to be a composite. + // In that case, backends which do not support inline syntax need it to be bound to a temporary. + // Otherwise, invalid expressions like ({UBO[0].xyz, UBO[0].w, UBO[1]}).member are emitted. + bool requires_temporary = false; + if (flattened_buffer_blocks.count(ops[2]) && target_type.basetype == SPIRType::Struct) + requires_temporary = !backend.can_declare_struct_inline; + + auto &expr = requires_temporary ? + emit_op(ops[0], ops[1], std::move(e), false) : + set(ops[1], std::move(e), ops[0], should_forward(ops[2])); auto *backing_variable = maybe_get_backing_variable(ops[2]); expr.loaded_from = backing_variable ? backing_variable->self : ID(ops[2]); expr.need_transpose = meta.need_transpose; expr.access_chain = true; + expr.access_meshlet_position_y = meta.access_meshlet_position_y; // Mark the result as being packed. Some platforms handled packed vectors differently than non-packed. if (meta.storage_is_packed) @@ -10174,6 +12063,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) set_decoration(ops[1], DecorationInvariant); if (meta.flattened_struct) flattened_structs[ops[1]] = true; + if (meta.relaxed_precision && backend.requires_relaxed_precision_analysis) + set_decoration(ops[1], DecorationRelaxedPrecision); // If we have some expression dependencies in our access chain, this access chain is technically a forwarded // temporary which could be subject to invalidation. @@ -10538,6 +12429,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) e = &emit_op(result_type, id, expr, true, should_suppress_usage_tracking(ops[2])); inherit_expression_dependencies(id, ops[2]); e->base_expression = ops[2]; + + if (meta.relaxed_precision && backend.requires_relaxed_precision_analysis) + set_decoration(ops[1], DecorationRelaxedPrecision); } else { @@ -10572,11 +12466,66 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) flush_variable_declaration(composite); - // Make a copy, then use access chain to store the variable. - statement(declare_temporary(result_type, id), to_expression(composite), ";"); - set(id, to_name(id), result_type, true); - auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); - statement(chain, " = ", to_unpacked_expression(obj), ";"); + // CompositeInsert requires a copy + modification, but this is very awkward code in HLL. + // Speculate that the input composite is no longer used, and we can modify it in-place. + // There are various scenarios where this is not possible to satisfy. + bool can_modify_in_place = true; + forced_temporaries.insert(id); + + // Cannot safely RMW PHI variables since they have no way to be invalidated, + // forcing temporaries is not going to help. + // This is similar for Constant and Undef inputs. + // The only safe thing to RMW is SPIRExpression. + // If the expression has already been used (i.e. used in a continue block), we have to keep using + // that loop variable, since we won't be able to override the expression after the fact. + // If the composite is hoisted, we might never be able to properly invalidate any usage + // of that composite in a subsequent loop iteration. + if (invalid_expressions.count(composite) || + block_composite_insert_overwrite.count(composite) || + hoisted_temporaries.count(id) || hoisted_temporaries.count(composite) || + maybe_get(composite) == nullptr) + { + can_modify_in_place = false; + } + else if (backend.requires_relaxed_precision_analysis && + has_decoration(composite, DecorationRelaxedPrecision) != + has_decoration(id, DecorationRelaxedPrecision) && + get(result_type).basetype != SPIRType::Struct) + { + // Similarly, if precision does not match for input and output, + // we cannot alias them. If we write a composite into a relaxed precision + // ID, we might get a false truncation. + can_modify_in_place = false; + } + + if (can_modify_in_place) + { + // Have to make sure the modified SSA value is bound to a temporary so we can modify it in-place. + if (!forced_temporaries.count(composite)) + force_temporary_and_recompile(composite); + + auto chain = access_chain_internal(composite, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); + statement(chain, " = ", to_unpacked_expression(obj), ";"); + set(id, to_expression(composite), result_type, true); + invalid_expressions.insert(composite); + composite_insert_overwritten.insert(composite); + } + else + { + if (maybe_get(composite) != nullptr) + { + emit_uninitialized_temporary_expression(result_type, id); + } + else + { + // Make a copy, then use access chain to store the variable. + statement(declare_temporary(result_type, id), to_expression(composite), ";"); + set(id, to_name(id), result_type, true); + } + + auto chain = access_chain_internal(id, elems, length, ACCESS_CHAIN_INDEX_IS_LITERAL_BIT, nullptr); + statement(chain, " = ", to_unpacked_expression(obj), ";"); + } break; } @@ -10653,15 +12602,14 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) { // Need a copy. // For pointer types, we copy the pointer itself. - statement(declare_temporary(result_type, id), to_unpacked_expression(rhs), ";"); - set(id, to_name(id), result_type, true); + emit_op(result_type, id, to_unpacked_expression(rhs), false); } else { // RHS expression is immutable, so just forward it. // Copying these things really make no sense, but // seems to be allowed anyways. - auto &e = set(id, to_expression(rhs), result_type, true); + auto &e = emit_op(result_type, id, to_expression(rhs), true, true); if (pointer) { auto *var = maybe_get_backing_variable(rhs); @@ -10762,14 +12710,66 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // ALU case OpIsNan: - GLSL_UFOP(isnan); + if (!is_legacy()) + GLSL_UFOP(isnan); + else + { + // Check if the number doesn't equal itself + auto &type = get(ops[0]); + if (type.vecsize > 1) + emit_binary_func_op(ops[0], ops[1], ops[2], ops[2], "notEqual"); + else + emit_binary_op(ops[0], ops[1], ops[2], ops[2], "!="); + } break; case OpIsInf: - GLSL_UFOP(isinf); + if (!is_legacy()) + GLSL_UFOP(isinf); + else + { + // inf * 2 == inf by IEEE 754 rules, note this also applies to 0.0 + // This is more reliable than checking if product with zero is NaN + uint32_t result_type = ops[0]; + uint32_t result_id = ops[1]; + uint32_t operand = ops[2]; + + auto &type = get(result_type); + std::string expr; + if (type.vecsize > 1) + { + expr = type_to_glsl_constructor(type); + expr += '('; + for (uint32_t i = 0; i < type.vecsize; i++) + { + auto comp = to_extract_component_expression(operand, i); + expr += join(comp, " != 0.0 && 2.0 * ", comp, " == ", comp); + + if (i + 1 < type.vecsize) + expr += ", "; + } + expr += ')'; + } + else + { + // Register an extra read to force writing out a temporary + auto oper = to_enclosed_expression(operand); + track_expression_read(operand); + expr += join(oper, " != 0.0 && 2.0 * ", oper, " == ", oper); + } + emit_op(result_type, result_id, expr, should_forward(operand)); + + inherit_expression_dependencies(result_id, operand); + } break; case OpSNegate: + if (implicit_integer_promotion || expression_type_id(ops[2]) != ops[0]) + GLSL_UOP_CAST(-); + else + GLSL_UOP(-); + break; + case OpFNegate: GLSL_UOP(-); break; @@ -10859,14 +12859,59 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) break; } - case OpFMul: case OpMatrixTimesScalar: + { + auto *a = maybe_get(ops[2]); + + // If the matrix need transpose, just mark the result as needing so. + if (a && a->need_transpose) + { + a->need_transpose = false; + auto expr = join(enclose_expression(to_unpacked_row_major_matrix_expression(ops[2])), " * ", + to_enclosed_unpacked_expression(ops[3])); + bool forward = should_forward(ops[2]) && should_forward(ops[3]); + auto &e = emit_op(ops[0], ops[1], expr, forward); + e.need_transpose = true; + a->need_transpose = true; + inherit_expression_dependencies(ops[1], ops[2]); + inherit_expression_dependencies(ops[1], ops[3]); + } + else + GLSL_BOP(*); + break; + } + + case OpFMul: case OpVectorTimesScalar: GLSL_BOP(*); break; case OpOuterProduct: - GLSL_BFOP(outerProduct); + if (options.version < 120) // Matches GLSL 1.10 / ESSL 1.00 + { + uint32_t result_type = ops[0]; + uint32_t id = ops[1]; + uint32_t a = ops[2]; + uint32_t b = ops[3]; + + auto &type = get(result_type); + string expr = type_to_glsl_constructor(type); + expr += "("; + for (uint32_t col = 0; col < type.columns; col++) + { + expr += to_enclosed_expression(a); + expr += " * "; + expr += to_extract_component_expression(b, col); + if (col + 1 < type.columns) + expr += ", "; + } + expr += ")"; + emit_op(result_type, id, expr, should_forward(a) && should_forward(b)); + inherit_expression_dependencies(id, a); + inherit_expression_dependencies(id, b); + } + else + GLSL_BFOP(outerProduct); break; case OpDot: @@ -10914,6 +12959,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "(", to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")"); + if (implicit_integer_promotion) + expr = join(type_to_glsl(get(result_type)), '(', expr, ')'); + emit_op(result_type, result_id, expr, forward); inherit_expression_dependencies(result_id, op0); inherit_expression_dependencies(result_id, op1); @@ -11011,7 +13059,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } case OpNot: - GLSL_UOP(~); + if (implicit_integer_promotion || expression_type_id(ops[2]) != ops[0]) + GLSL_UOP_CAST(~); + else + GLSL_UOP(~); break; case OpUMod: @@ -11028,10 +13079,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpFRem: { - if (is_legacy()) - SPIRV_CROSS_THROW("OpFRem requires trunc() and is only supported on non-legacy targets. A workaround is " - "needed for legacy."); - uint32_t result_type = ops[0]; uint32_t result_id = ops[1]; uint32_t op0 = ops[2]; @@ -11039,8 +13086,22 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) // Needs special handling. bool forward = should_forward(op0) && should_forward(op1); - auto expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(", - to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")"); + std::string expr; + if (!is_legacy()) + { + expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", "trunc(", + to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), ")"); + } + else + { + // Legacy GLSL has no trunc, emulate by casting to int and back + auto &op0_type = expression_type(op0); + auto via_type = op0_type; + via_type.basetype = SPIRType::Int; + expr = join(to_enclosed_expression(op0), " - ", to_enclosed_expression(op1), " * ", + type_to_glsl(op0_type), "(", type_to_glsl(via_type), "(", + to_enclosed_expression(op0), " / ", to_enclosed_expression(op1), "))"); + } emit_op(result_type, result_id, expr, forward); inherit_expression_dependencies(result_id, op0); @@ -11129,7 +13190,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpLogicalNotEqual: case OpFOrdNotEqual: + case OpFUnordNotEqual: { + // GLSL is fuzzy on what to do with ordered vs unordered not equal. + // glslang started emitting UnorderedNotEqual some time ago to harmonize with IEEE, + // but this means we have no easy way of implementing ordered not equal. if (expression_type(ops[2]).vecsize > 1) GLSL_BFOP(notEqual); else @@ -11537,6 +13602,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } case OpAtomicIAdd: + case OpAtomicFAddEXT: { const char *op = check_atomic_image(ops[2]) ? "imageAtomicAdd" : "atomicAdd"; emit_atomic_func_op(ops[0], ops[1], ops[2], ops[5], op); @@ -11689,7 +13755,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) op = "textureQueryLOD"; } else if (options.es) - SPIRV_CROSS_THROW("textureQueryLod not supported in ES profile."); + { + if (options.version < 300) + SPIRV_CROSS_THROW("textureQueryLod not supported in legacy ES"); + require_extension_internal("GL_EXT_texture_query_lod"); + op = "textureQueryLOD"; + } else op = "textureQueryLod"; @@ -11735,6 +13806,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; + if (options.es) + SPIRV_CROSS_THROW("textureSamples and imageSamples not supported in ES profile."); + else if (options.version < 450) + require_extension_internal("GL_ARB_texture_query_samples"); + string expr; if (type.image.sampled == 2) expr = join("imageSamples(", to_non_uniform_aware_expression(ops[2]), ")"); @@ -11762,12 +13838,12 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) uint32_t result_type = ops[0]; uint32_t id = ops[1]; uint32_t img = ops[2]; + auto &type = expression_type(img); + auto &imgtype = get(type.self); std::string fname = "textureSize"; if (is_legacy_desktop()) { - auto &type = expression_type(img); - auto &imgtype = get(type.self); fname = legacy_tex_op(fname, imgtype, img); } else if (is_legacy_es()) @@ -11775,6 +13851,11 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto expr = join(fname, "(", convert_separate_image_to_expression(img), ", ", bitcast_expression(SPIRType::Int, ops[3]), ")"); + + // ES needs to emulate 1D images as 2D. + if (type.image.dim == Dim1D && options.es) + expr = join(expr, ".x"); + auto &restype = get(ops[0]); expr = bitcast_expression(restype, SPIRType::Int, expr); emit_op(result_type, id, expr, true); @@ -11791,10 +13872,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto *var = maybe_get_backing_variable(ops[2]); if (var) { - auto &flags = ir.meta[var->self].decoration.decoration_flags; + auto &flags = get_decoration_bitset(var->self); if (flags.get(DecorationNonReadable)) { - flags.clear(DecorationNonReadable); + unset_decoration(var->self, DecorationNonReadable); force_recompile(); } } @@ -11889,6 +13970,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) target_coord_type.basetype = SPIRType::Int; coord_expr = bitcast_expression(target_coord_type, expression_type(ops[3]).basetype, coord_expr); + // ES needs to emulate 1D images as 2D. + if (type.image.dim == Dim1D && options.es) + coord_expr = join("ivec2(", coord_expr, ", 0)"); + // Plain image load/store. if (sparse) { @@ -11933,7 +14018,7 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) pure = false; } - if (var && var->forwardable) + if (var) { bool forward = forced_temporaries.find(id) == end(forced_temporaries); auto &e = emit_op(result_type, id, imgexpr, forward); @@ -11983,10 +14068,9 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) auto *var = maybe_get_backing_variable(ops[0]); if (var) { - auto &flags = ir.meta[var->self].decoration.decoration_flags; - if (flags.get(DecorationNonWritable)) + if (has_decoration(var->self, DecorationNonWritable)) { - flags.clear(DecorationNonWritable); + unset_decoration(var->self, DecorationNonWritable); force_recompile(); } } @@ -12002,6 +14086,10 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) target_coord_type.basetype = SPIRType::Int; coord_expr = bitcast_expression(target_coord_type, expression_type(ops[1]).basetype, coord_expr); + // ES needs to emulate 1D images as 2D. + if (type.image.dim == Dim1D && options.es) + coord_expr = join("ivec2(", coord_expr, ", 0)"); + if (type.image.ms) { uint32_t operands = ops[3]; @@ -12230,31 +14318,52 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) case OpExtInst: { uint32_t extension_set = ops[2]; + auto ext = get(extension_set).ext; - if (get(extension_set).ext == SPIRExtension::GLSL) + if (ext == SPIRExtension::GLSL) { emit_glsl_op(ops[0], ops[1], ops[3], &ops[4], length - 4); } - else if (get(extension_set).ext == SPIRExtension::SPV_AMD_shader_ballot) + else if (ext == SPIRExtension::SPV_AMD_shader_ballot) { emit_spv_amd_shader_ballot_op(ops[0], ops[1], ops[3], &ops[4], length - 4); } - else if (get(extension_set).ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter) + else if (ext == SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter) { emit_spv_amd_shader_explicit_vertex_parameter_op(ops[0], ops[1], ops[3], &ops[4], length - 4); } - else if (get(extension_set).ext == SPIRExtension::SPV_AMD_shader_trinary_minmax) + else if (ext == SPIRExtension::SPV_AMD_shader_trinary_minmax) { emit_spv_amd_shader_trinary_minmax_op(ops[0], ops[1], ops[3], &ops[4], length - 4); } - else if (get(extension_set).ext == SPIRExtension::SPV_AMD_gcn_shader) + else if (ext == SPIRExtension::SPV_AMD_gcn_shader) { emit_spv_amd_gcn_shader_op(ops[0], ops[1], ops[3], &ops[4], length - 4); } - else if (get(extension_set).ext == SPIRExtension::SPV_debug_info) + else if (ext == SPIRExtension::SPV_debug_info || + ext == SPIRExtension::NonSemanticShaderDebugInfo || + ext == SPIRExtension::NonSemanticGeneric) { break; // Ignore SPIR-V debug information extended instructions. } + else if (ext == SPIRExtension::NonSemanticDebugPrintf) + { + // Operation 1 is printf. + if (ops[3] == 1) + { + if (!options.vulkan_semantics) + SPIRV_CROSS_THROW("Debug printf is only supported in Vulkan GLSL.\n"); + require_extension_internal("GL_EXT_debug_printf"); + auto &format_string = get(ops[4]).str; + string expr = join("debugPrintfEXT(\"", format_string, "\""); + for (uint32_t i = 5; i < length; i++) + { + expr += ", "; + expr += to_expression(ops[i]); + } + statement(expr, ");"); + } + } else { statement("// unimplemented ext op ", instruction.op); @@ -12449,7 +14558,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) break; case OpFUnordEqual: - case OpFUnordNotEqual: case OpFUnordLessThan: case OpFUnordGreaterThan: case OpFUnordLessThanEqual: @@ -12472,10 +14580,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) comp_op = "notEqual"; break; - case OpFUnordNotEqual: - comp_op = "equal"; - break; - case OpFUnordLessThan: comp_op = "greaterThanEqual"; break; @@ -12508,10 +14612,6 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) comp_op = " != "; break; - case OpFUnordNotEqual: - comp_op = " == "; - break; - case OpFUnordLessThan: comp_op = " >= "; break; @@ -12645,9 +14745,30 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) #undef GLSL_RAY_QUERY_GET_OP2 case OpConvertUToAccelerationStructureKHR: + { require_extension_internal("GL_EXT_ray_tracing"); - GLSL_UFOP(accelerationStructureEXT); + + bool elide_temporary = should_forward(ops[2]) && forced_temporaries.count(ops[1]) == 0 && + !hoisted_temporaries.count(ops[1]); + + if (elide_temporary) + { + GLSL_UFOP(accelerationStructureEXT); + } + else + { + // Force this path in subsequent iterations. + forced_temporaries.insert(ops[1]); + + // We cannot declare a temporary acceleration structure in GLSL. + // If we get to this point, we'll have to emit a temporary uvec2, + // and cast to RTAS on demand. + statement(declare_temporary(expression_type_id(ops[2]), ops[1]), to_unpacked_expression(ops[2]), ";"); + // Use raw SPIRExpression interface to block all usage tracking. + set(ops[1], join("accelerationStructureEXT(", to_name(ops[1]), ")"), ops[0], true); + } break; + } case OpConvertUToPtr: { @@ -12703,6 +14824,8 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) if (!options.vulkan_semantics) SPIRV_CROSS_THROW("GL_EXT_demote_to_helper_invocation is only supported in Vulkan GLSL."); require_extension_internal("GL_EXT_demote_to_helper_invocation"); + // Helper lane state with demote is volatile by nature. + // Do not forward this. emit_op(ops[0], ops[1], "helperInvocationEXT()", false); break; @@ -12726,6 +14849,46 @@ void CompilerGLSL::emit_instruction(const Instruction &instruction) } break; + case OpSetMeshOutputsEXT: + statement("SetMeshOutputsEXT(", to_unpacked_expression(ops[0]), ", ", to_unpacked_expression(ops[1]), ");"); + break; + + case OpReadClockKHR: + { + auto &type = get(ops[0]); + auto scope = static_cast(evaluate_constant_u32(ops[2])); + const char *op = nullptr; + // Forwarding clock statements leads to a scenario where an SSA value can take on different + // values every time it's evaluated. Block any forwarding attempt. + // We also might want to invalidate all expressions to function as a sort of optimization + // barrier, but might be overkill for now. + if (scope == ScopeDevice) + { + require_extension_internal("GL_EXT_shader_realtime_clock"); + if (type.basetype == SPIRType::BaseType::UInt64) + op = "clockRealtimeEXT()"; + else if (type.basetype == SPIRType::BaseType::UInt && type.vecsize == 2) + op = "clockRealtime2x32EXT()"; + else + SPIRV_CROSS_THROW("Unsupported result type for OpReadClockKHR opcode."); + } + else if (scope == ScopeSubgroup) + { + require_extension_internal("GL_ARB_shader_clock"); + if (type.basetype == SPIRType::BaseType::UInt64) + op = "clockARB()"; + else if (type.basetype == SPIRType::BaseType::UInt && type.vecsize == 2) + op = "clock2x32ARB()"; + else + SPIRV_CROSS_THROW("Unsupported result type for OpReadClockKHR opcode."); + } + else + SPIRV_CROSS_THROW("Unsupported scope for OpReadClockKHR opcode."); + + emit_op(ops[0], ops[1], op, false); + break; + } + default: statement("// unimplemented op ", instruction.op); break; @@ -12858,7 +15021,7 @@ bool CompilerGLSL::member_is_packed_physical_type(const SPIRType &type, uint32_t // Base implementation uses the standard library transpose() function. // Subclasses may override to use a different function. string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t /* physical_type_id */, - bool /*is_packed*/) + bool /*is_packed*/, bool relaxed) { strip_enclosed_expression(exp_str); if (!is_matrix(exp_type)) @@ -12870,6 +15033,17 @@ string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &ex auto column_expr = exp_str.substr(column_index); exp_str.resize(column_index); + auto end_deferred_index = column_expr.find_last_of(']'); + if (end_deferred_index != string::npos && end_deferred_index + 1 != column_expr.size()) + { + // If we have any data member fixups, it must be transposed so that it refers to this index. + // E.g. [0].data followed by [1] would be shuffled to [1][0].data which is wrong, + // and needs to be [1].data[0] instead. + end_deferred_index++; + column_expr = column_expr.substr(end_deferred_index) + + column_expr.substr(0, end_deferred_index); + } + auto transposed_expr = type_to_glsl_constructor(exp_type) + "("; // Loading a column from a row-major matrix. Unroll the load. @@ -12888,32 +15062,14 @@ string CompilerGLSL::convert_row_major_matrix(string exp_str, const SPIRType &ex // GLSL 110, ES 100 do not have transpose(), so emulate it. Note that // these GLSL versions do not support non-square matrices. if (exp_type.vecsize == 2 && exp_type.columns == 2) - { - if (!requires_transpose_2x2) - { - requires_transpose_2x2 = true; - force_recompile(); - } - } + require_polyfill(PolyfillTranspose2x2, relaxed); else if (exp_type.vecsize == 3 && exp_type.columns == 3) - { - if (!requires_transpose_3x3) - { - requires_transpose_3x3 = true; - force_recompile(); - } - } + require_polyfill(PolyfillTranspose3x3, relaxed); else if (exp_type.vecsize == 4 && exp_type.columns == 4) - { - if (!requires_transpose_4x4) - { - requires_transpose_4x4 = true; - force_recompile(); - } - } + require_polyfill(PolyfillTranspose4x4, relaxed); else SPIRV_CROSS_THROW("Non-square matrices are not supported in legacy GLSL, cannot transpose."); - return join("spvTranspose(", exp_str, ")"); + return join("spvTranspose", (options.es && relaxed) ? "MP" : "", "(", exp_str, ")"); } else return join("transpose(", exp_str, ")"); @@ -12982,7 +15138,12 @@ string CompilerGLSL::flags_to_qualifiers_glsl(const SPIRType &type, const Bitset { auto &execution = get_entry_point(); - if (flags.get(DecorationRelaxedPrecision)) + if (type.basetype == SPIRType::UInt && is_legacy_es()) + { + // HACK: This is a bool. See comment in type_to_glsl(). + qual += "lowp "; + } + else if (flags.get(DecorationRelaxedPrecision)) { bool implied_fmediump = type.basetype == SPIRType::Float && options.fragment.default_float_precision == Options::Mediump && @@ -13034,40 +15195,55 @@ string CompilerGLSL::to_precision_qualifiers_glsl(uint32_t id) return flags_to_qualifiers_glsl(type, ir.meta[id].decoration.decoration_flags); } -void CompilerGLSL::fixup_io_block_patch_qualifiers(const SPIRVariable &var) +void CompilerGLSL::fixup_io_block_patch_primitive_qualifiers(const SPIRVariable &var) { // Works around weird behavior in glslangValidator where // a patch out block is translated to just block members getting the decoration. // To make glslang not complain when we compile again, we have to transform this back to a case where // the variable itself has Patch decoration, and not members. + // Same for perprimitiveEXT. auto &type = get(var.basetype); if (has_decoration(type.self, DecorationBlock)) { uint32_t member_count = uint32_t(type.member_types.size()); + Decoration promoted_decoration = {}; + bool do_promote_decoration = false; for (uint32_t i = 0; i < member_count; i++) { if (has_member_decoration(type.self, i, DecorationPatch)) { - set_decoration(var.self, DecorationPatch); + promoted_decoration = DecorationPatch; + do_promote_decoration = true; + break; + } + else if (has_member_decoration(type.self, i, DecorationPerPrimitiveEXT)) + { + promoted_decoration = DecorationPerPrimitiveEXT; + do_promote_decoration = true; break; } } - if (has_decoration(var.self, DecorationPatch)) + if (do_promote_decoration) + { + set_decoration(var.self, promoted_decoration); for (uint32_t i = 0; i < member_count; i++) - unset_member_decoration(type.self, i, DecorationPatch); + unset_member_decoration(type.self, i, promoted_decoration); + } } } string CompilerGLSL::to_qualifiers_glsl(uint32_t id) { - auto &flags = ir.meta[id].decoration.decoration_flags; + auto &flags = get_decoration_bitset(id); string res; auto *var = maybe_get(id); if (var && var->storage == StorageClassWorkgroup && !backend.shared_is_implied) res += "shared "; + else if (var && var->storage == StorageClassTaskPayloadWorkgroupEXT && !backend.shared_is_implied) + res += "taskPayloadSharedEXT "; res += to_interpolation_qualifiers(flags); if (var) @@ -13190,7 +15366,7 @@ string CompilerGLSL::variable_decl(const SPIRVariable &variable) const char *CompilerGLSL::to_pls_qualifiers_glsl(const SPIRVariable &variable) { - auto &flags = ir.meta[variable.self].decoration.decoration_flags; + auto &flags = get_decoration_bitset(variable.self); if (flags.get(DecorationRelaxedPrecision)) return "mediump "; else @@ -13201,9 +15377,16 @@ string CompilerGLSL::pls_decl(const PlsRemap &var) { auto &variable = get(var.id); - SPIRType type; - type.vecsize = pls_format_to_components(var.format); - type.basetype = pls_format_to_basetype(var.format); + auto op_and_basetype = pls_format_to_basetype(var.format); + + SPIRType type { op_and_basetype.first }; + type.basetype = op_and_basetype.second; + auto vecsize = pls_format_to_components(var.format); + if (vecsize > 1) + { + type.op = OpTypeVector; + type.vecsize = vecsize; + } return join(to_pls_layout(var.format), to_pls_qualifiers_glsl(variable), type_to_glsl(type), " ", to_name(variable.self)); @@ -13307,6 +15490,14 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) switch (imagetype.basetype) { + case SPIRType::Int64: + res = "i64"; + require_extension_internal("GL_EXT_shader_image_int64"); + break; + case SPIRType::UInt64: + res = "u64"; + require_extension_internal("GL_EXT_shader_image_int64"); + break; case SPIRType::Int: case SPIRType::Short: case SPIRType::SByte: @@ -13350,7 +15541,8 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) switch (type.image.dim) { case Dim1D: - res += "1D"; + // ES doesn't support 1D. Fake it with 2D. + res += options.es ? "2D" : "1D"; break; case Dim2D: res += "2D"; @@ -13373,7 +15565,7 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) case DimBuffer: if (options.es && options.version < 320) - require_extension_internal("GL_OES_texture_buffer"); + require_extension_internal("GL_EXT_texture_buffer"); else if (!options.es && options.version < 300) require_extension_internal("GL_EXT_texture_buffer_object"); res += "Buffer"; @@ -13400,6 +15592,17 @@ string CompilerGLSL::image_type_glsl(const SPIRType &type, uint32_t id) is_depth_image(type, id)) { res += "Shadow"; + + if (type.image.dim == DimCube && is_legacy()) + { + if (!options.es) + require_extension_internal("GL_EXT_gpu_shader4"); + else + { + require_extension_internal("GL_NV_shadow_samplers_cube"); + res += "NV"; + } + } } return res; @@ -13479,7 +15682,24 @@ string CompilerGLSL::type_to_glsl(const SPIRType &type, uint32_t id) } if (type.basetype == SPIRType::UInt && is_legacy()) - SPIRV_CROSS_THROW("Unsigned integers are not supported on legacy targets."); + { + if (options.es) + // HACK: spirv-cross changes bools into uints and generates code which compares them to + // zero. Input code will have already been validated as not to have contained any uints, + // so any remaining uints must in fact be bools. However, simply returning "bool" here + // will result in invalid code. Instead, return an int. + return backend.basic_int_type; + else + require_extension_internal("GL_EXT_gpu_shader4"); + } + + if (type.basetype == SPIRType::AtomicCounter) + { + if (options.es && options.version < 310) + SPIRV_CROSS_THROW("At least ESSL 3.10 required for atomic counters."); + else if (!options.es && options.version < 420) + require_extension_internal("GL_ARB_shader_atomic_counters"); + } if (type.vecsize == 1 && type.columns == 1) // Scalar builtin { @@ -13634,6 +15854,11 @@ void CompilerGLSL::require_extension(const std::string &ext) forced_extensions.push_back(ext); } +const SmallVector &CompilerGLSL::get_required_extensions() const +{ + return forced_extensions; +} + void CompilerGLSL::require_extension_internal(const string &ext) { if (backend.supports_extensions && !has_extension(ext)) @@ -13648,7 +15873,7 @@ void CompilerGLSL::flatten_buffer_block(VariableID id) auto &var = get(id); auto &type = get(var.basetype); auto name = to_name(type.self, false); - auto &flags = ir.meta[type.self].decoration.decoration_flags; + auto &flags = get_decoration_bitset(type.self); if (!type.array.empty()) SPIRV_CROSS_THROW(name + " is an array of UBOs."); @@ -13667,6 +15892,11 @@ bool CompilerGLSL::builtin_translates_to_nonarray(spv::BuiltIn /*builtin*/) cons return false; // GLSL itself does not need to translate array builtin types to non-array builtin types } +bool CompilerGLSL::is_user_type_structured(uint32_t /*id*/) const +{ + return false; // GLSL itself does not have structured user type, but HLSL does with StructuredBuffer and RWStructuredBuffer resources. +} + bool CompilerGLSL::check_atomic_image(uint32_t id) { auto &type = expression_type(id); @@ -13678,11 +15908,10 @@ bool CompilerGLSL::check_atomic_image(uint32_t id) auto *var = maybe_get_backing_variable(id); if (var) { - auto &flags = ir.meta[var->self].decoration.decoration_flags; - if (flags.get(DecorationNonWritable) || flags.get(DecorationNonReadable)) + if (has_decoration(var->self, DecorationNonWritable) || has_decoration(var->self, DecorationNonReadable)) { - flags.clear(DecorationNonWritable); - flags.clear(DecorationNonReadable); + unset_decoration(var->self, DecorationNonWritable); + unset_decoration(var->self, DecorationNonReadable); force_recompile(); } } @@ -13935,7 +16164,11 @@ void CompilerGLSL::emit_function(SPIRFunction &func, const Bitset &return_flags) // Loop variables are never declared outside their for-loop, so block any implicit declaration. if (var.loop_variable) + { var.deferred_declaration = false; + // Need to reset the static expression so we can fallback to initializer if need be. + var.static_expression = 0; + } } // Enforce declaration order for regression testing purposes. @@ -14120,21 +16353,32 @@ void CompilerGLSL::branch(BlockID from, BlockID to) // - Break merge target all at once ... // Very dirty workaround. - // Switch constructs are able to break, but they cannot break out of a loop at the same time. + // Switch constructs are able to break, but they cannot break out of a loop at the same time, + // yet SPIR-V allows it. // Only sensible solution is to make a ladder variable, which we declare at the top of the switch block, // write to the ladder here, and defer the break. // The loop we're breaking out of must dominate the switch block, or there is no ladder breaking case. - if (current_emitting_switch && is_loop_break(to) && - current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) && - get(current_emitting_switch->loop_dominator).merge_block == to) + if (is_loop_break(to)) { - if (!current_emitting_switch->need_ladder_break) + for (size_t n = current_emitting_switch_stack.size(); n; n--) { - force_recompile(); - current_emitting_switch->need_ladder_break = true; - } + auto *current_emitting_switch = current_emitting_switch_stack[n - 1]; - statement("_", current_emitting_switch->self, "_ladder_break = true;"); + if (current_emitting_switch && + current_emitting_switch->loop_dominator != BlockID(SPIRBlock::NoDominator) && + get(current_emitting_switch->loop_dominator).merge_block == to) + { + if (!current_emitting_switch->need_ladder_break) + { + force_recompile(); + current_emitting_switch->need_ladder_break = true; + } + + statement("_", current_emitting_switch->self, "_ladder_break = true;"); + } + else + break; + } } statement("break;"); } @@ -14379,6 +16623,17 @@ bool CompilerGLSL::for_loop_initializers_are_same_type(const SPIRBlock &block) return true; } +void CompilerGLSL::emit_block_instructions_with_masked_debug(SPIRBlock &block) +{ + // Have to block debug instructions such as OpLine here, since it will be treated as a statement otherwise, + // which breaks loop optimizations. + // Any line directive would be declared outside the loop body, which would just be confusing either way. + bool old_block_debug_directives = block_debug_directives; + block_debug_directives = true; + emit_block_instructions(block); + block_debug_directives = old_block_debug_directives; +} + bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method method) { SPIRBlock::ContinueBlockType continue_type = continue_block_type(get(block.continue_block)); @@ -14389,7 +16644,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method // If we're trying to create a true for loop, // we need to make sure that all opcodes before branch statement do not actually emit any code. // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead. - emit_block_instructions(block); + emit_block_instructions_with_masked_debug(block); bool condition_is_temporary = forced_temporaries.find(block.condition) == end(forced_temporaries); @@ -14469,7 +16724,7 @@ bool CompilerGLSL::attempt_emit_loop_header(SPIRBlock &block, SPIRBlock::Method // If we're trying to create a true for loop, // we need to make sure that all opcodes before branch statement do not actually emit any code. // We can then take the condition expression and create a for (; cond ; ) { body; } structure instead. - emit_block_instructions(child); + emit_block_instructions_with_masked_debug(child); bool condition_is_temporary = forced_temporaries.find(child.condition) == end(forced_temporaries); @@ -14554,10 +16809,17 @@ void CompilerGLSL::emit_hoisted_temporaries(SmallVector> &tempo for (auto &tmp : temporaries) { - add_local_variable_name(tmp.second); - auto &flags = ir.meta[tmp.second].decoration.decoration_flags; auto &type = get(tmp.first); + // There are some rare scenarios where we are asked to declare pointer types as hoisted temporaries. + // This should be ignored unless we're doing actual variable pointers and backend supports it. + // Access chains cannot normally be lowered to temporaries in GLSL and HLSL. + if (type.pointer && !backend.native_pointers) + continue; + + add_local_variable_name(tmp.second); + auto &flags = get_decoration_bitset(tmp.second); + // Not all targets support pointer literals, so don't bother with that case. string initializer; if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) @@ -14570,6 +16832,21 @@ void CompilerGLSL::emit_hoisted_temporaries(SmallVector> &tempo // The temporary might be read from before it's assigned, set up the expression now. set(tmp.second, to_name(tmp.second), tmp.first, true); + + // If we have hoisted temporaries in multi-precision contexts, emit that here too ... + // We will not be able to analyze hoisted-ness for dependent temporaries that we hallucinate here. + auto mirrored_precision_itr = temporary_to_mirror_precision_alias.find(tmp.second); + if (mirrored_precision_itr != temporary_to_mirror_precision_alias.end()) + { + uint32_t mirror_id = mirrored_precision_itr->second; + auto &mirror_flags = get_decoration_bitset(mirror_id); + statement(flags_to_qualifiers_glsl(type, mirror_flags), + variable_decl(type, to_name(mirror_id)), + initializer, ";"); + // The temporary might be read from before it's assigned, set up the expression now. + set(mirror_id, to_name(mirror_id), tmp.first, true); + hoisted_temporaries.insert(mirror_id); + } } } @@ -14585,6 +16862,24 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) if (block.merge == SPIRBlock::MergeLoop) add_loop_level(); + // If we're emitting PHI variables with precision aliases, we have to emit them as hoisted temporaries. + for (auto var_id : block.dominated_variables) + { + auto &var = get(var_id); + if (var.phi_variable) + { + auto mirrored_precision_itr = temporary_to_mirror_precision_alias.find(var_id); + if (mirrored_precision_itr != temporary_to_mirror_precision_alias.end() && + find_if(block.declare_temporary.begin(), block.declare_temporary.end(), + [mirrored_precision_itr](const std::pair &p) { + return p.second == mirrored_precision_itr->second; + }) == block.declare_temporary.end()) + { + block.declare_temporary.push_back({ var.basetype, mirrored_precision_itr->second }); + } + } + } + emit_hoisted_temporaries(block.declare_temporary); SPIRBlock::ContinueBlockType continue_type = SPIRBlock::ContinueNone; @@ -14703,7 +16998,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) // as writes to said loop variables might have been masked out, we need a recompile. if (!emitted_loop_header_variables && !block.loop_variables.empty()) { - force_recompile(); + force_recompile_guarantee_forward_progress(); for (auto var : block.loop_variables) get(var).loop_variable = false; block.loop_variables.clear(); @@ -14797,8 +17092,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) else if (type.basetype == SPIRType::Short) label_suffix = backend.int16_t_literal_suffix; - SPIRBlock *old_emitting_switch = current_emitting_switch; - current_emitting_switch = █ + current_emitting_switch_stack.push_back(&block); if (block.need_ladder_break) statement("bool _", block.self, "_ladder_break = false;"); @@ -14956,26 +17250,32 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) // If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate // non-structured exits with the help of a switch block. // This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic. - bool degenerate_switch = block.default_block != block.merge_block && cases.empty(); + bool block_like_switch = cases.empty(); - if (degenerate_switch || is_legacy_es()) + // If this is true, the switch is completely meaningless, and we should just avoid it. + bool collapsed_switch = block_like_switch && block.default_block == block.next_block; + + if (!collapsed_switch) { - // ESSL 1.0 is not guaranteed to support do/while. - if (is_legacy_es()) + if (block_like_switch || is_legacy_es()) { - uint32_t counter = statement_count; - statement("for (int spvDummy", counter, " = 0; spvDummy", counter, - " < 1; spvDummy", counter, "++)"); + // ESSL 1.0 is not guaranteed to support do/while. + if (is_legacy_es()) + { + uint32_t counter = statement_count; + statement("for (int spvDummy", counter, " = 0; spvDummy", counter, " < 1; spvDummy", counter, + "++)"); + } + else + statement("do"); } else - statement("do"); + { + emit_block_hints(block); + statement("switch (", to_unpacked_expression(block.condition), ")"); + } + begin_scope(); } - else - { - emit_block_hints(block); - statement("switch (", to_unpacked_expression(block.condition), ")"); - } - begin_scope(); for (size_t i = 0; i < num_blocks; i++) { @@ -14985,7 +17285,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) if (literals.empty()) { // Default case. - if (!degenerate_switch) + if (!block_like_switch) { if (is_legacy_es()) statement("else"); @@ -15023,10 +17323,10 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) else current_emitting_switch_fallthrough = false; - if (!degenerate_switch) + if (!block_like_switch) begin_scope(); branch(block.self, target_block); - if (!degenerate_switch) + if (!block_like_switch) end_scope(); current_emitting_switch_fallthrough = false; @@ -15040,7 +17340,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) // - Header -> Merge requires flushing PHI. In this case, we need to collect all cases and flush PHI there. bool header_merge_requires_phi = flush_phi_required(block.self, block.next_block); bool need_fallthrough_block = block.default_block == block.next_block || !literals_to_merge.empty(); - if ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty()) + if (!collapsed_switch && ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty())) { for (auto &case_literal : literals_to_merge) statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":"); @@ -15059,10 +17359,15 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) end_scope(); } - if (degenerate_switch && !is_legacy_es()) - end_scope_decl("while(false)"); + if (!collapsed_switch) + { + if (block_like_switch && !is_legacy_es()) + end_scope_decl("while(false)"); + else + end_scope(); + } else - end_scope(); + flush_phi(block.self, block.next_block); if (block.need_ladder_break) { @@ -15072,7 +17377,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) end_scope(); } - current_emitting_switch = old_emitting_switch; + current_emitting_switch_stack.pop_back(); break; } @@ -15132,8 +17437,43 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) break; case SPIRBlock::Unreachable: + { + // Avoid emitting false fallthrough, which can happen for + // if (cond) break; else discard; inside a case label. + // Discard is not always implementable as a terminator. + + auto &cfg = get_cfg_for_current_function(); + bool inner_dominator_is_switch = false; + ID id = block.self; + + while (id) + { + auto &iter_block = get(id); + if (iter_block.terminator == SPIRBlock::MultiSelect || + iter_block.merge == SPIRBlock::MergeLoop) + { + ID next_block = iter_block.merge == SPIRBlock::MergeLoop ? + iter_block.merge_block : iter_block.next_block; + bool outside_construct = next_block && cfg.find_common_dominator(next_block, block.self) == next_block; + if (!outside_construct) + { + inner_dominator_is_switch = iter_block.terminator == SPIRBlock::MultiSelect; + break; + } + } + + if (cfg.get_preceding_edges(id).empty()) + break; + + id = cfg.get_immediate_dominator(id); + } + + if (inner_dominator_is_switch) + statement("break; // unreachable workaround"); + emit_next_block = false; break; + } case SPIRBlock::IgnoreIntersection: statement("ignoreIntersectionEXT;"); @@ -15143,6 +17483,10 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block) statement("terminateRayEXT;"); break; + case SPIRBlock::EmitMeshTasks: + emit_mesh_tasks(block); + break; + default: SPIRV_CROSS_THROW("Unimplemented block terminator."); } @@ -15317,9 +17661,16 @@ uint32_t CompilerGLSL::mask_relevant_memory_semantics(uint32_t semantics) MemorySemanticsCrossWorkgroupMemoryMask | MemorySemanticsSubgroupMemoryMask); } -void CompilerGLSL::emit_array_copy(const string &lhs, uint32_t, uint32_t rhs_id, StorageClass, StorageClass) +bool CompilerGLSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, StorageClass, StorageClass) { + string lhs; + if (expr) + lhs = expr; + else + lhs = to_expression(lhs_id); + statement(lhs, " = ", to_expression(rhs_id), ";"); + return true; } bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t source_id) @@ -15346,7 +17697,7 @@ bool CompilerGLSL::unroll_array_to_complex_store(uint32_t target_id, uint32_t so else array_expr = to_expression(type.array.back()); - SPIRType target_type; + SPIRType target_type { OpTypeInt }; target_type.basetype = SPIRType::Int; statement("for (int i = 0; i < int(", array_expr, "); i++)"); @@ -15411,7 +17762,7 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s statement(new_expr, "[i] = gl_in[i].", expr, ";"); else if (is_sample_mask) { - SPIRType target_type; + SPIRType target_type { OpTypeInt }; target_type.basetype = SPIRType::Int; statement(new_expr, "[i] = ", bitcast_expression(target_type, type.basetype, join(expr, "[i]")), ";"); } @@ -15419,7 +17770,7 @@ void CompilerGLSL::unroll_array_from_complex_load(uint32_t target_id, uint32_t s statement(new_expr, "[i] = ", expr, "[i];"); end_scope(); - expr = move(new_expr); + expr = std::move(new_expr); } } @@ -15435,7 +17786,12 @@ void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr // Only interested in standalone builtin variables. if (!has_decoration(source_id, DecorationBuiltIn)) + { + // Except for int attributes in legacy GLSL, which are cast from float. + if (is_legacy() && expr_type.basetype == SPIRType::Int && var && var->storage == StorageClassInput) + expr = join(type_to_glsl(expr_type), "(", expr, ")"); return; + } auto builtin = static_cast(get_decoration(source_id, DecorationBuiltIn)); auto expected_type = expr_type.basetype; @@ -15471,6 +17827,9 @@ void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr case BuiltInIncomingRayFlagsNV: case BuiltInLaunchIdNV: case BuiltInLaunchSizeNV: + case BuiltInPrimitiveTriangleIndicesEXT: + case BuiltInPrimitiveLineIndicesEXT: + case BuiltInPrimitivePointIndicesEXT: expected_type = SPIRType::UInt; break; @@ -15482,6 +17841,25 @@ void CompilerGLSL::cast_from_variable_load(uint32_t source_id, std::string &expr expr = bitcast_expression(expr_type, expected_type, expr); } +SPIRType::BaseType CompilerGLSL::get_builtin_basetype(BuiltIn builtin, SPIRType::BaseType default_type) +{ + // TODO: Fill in for more builtins. + switch (builtin) + { + case BuiltInLayer: + case BuiltInPrimitiveId: + case BuiltInViewportIndex: + case BuiltInFragStencilRefEXT: + case BuiltInSampleMask: + case BuiltInPrimitiveShadingRateKHR: + case BuiltInShadingRateKHR: + return SPIRType::Int; + + default: + return default_type; + } +} + void CompilerGLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) { auto *var = maybe_get_backing_variable(target_id); @@ -15493,24 +17871,7 @@ void CompilerGLSL::cast_to_variable_store(uint32_t target_id, std::string &expr, return; auto builtin = static_cast(get_decoration(target_id, DecorationBuiltIn)); - auto expected_type = expr_type.basetype; - - // TODO: Fill in for more builtins. - switch (builtin) - { - case BuiltInLayer: - case BuiltInPrimitiveId: - case BuiltInViewportIndex: - case BuiltInFragStencilRefEXT: - case BuiltInSampleMask: - case BuiltInPrimitiveShadingRateKHR: - case BuiltInShadingRateKHR: - expected_type = SPIRType::Int; - break; - - default: - break; - } + auto expected_type = get_builtin_basetype(builtin, expr_type.basetype); if (expected_type != expr_type.basetype) { @@ -15626,6 +17987,52 @@ void CompilerGLSL::reset_name_caches() function_overloads.clear(); } +void CompilerGLSL::fixup_anonymous_struct_names(std::unordered_set &visited, const SPIRType &type) +{ + if (visited.count(type.self)) + return; + visited.insert(type.self); + + for (uint32_t i = 0; i < uint32_t(type.member_types.size()); i++) + { + auto &mbr_type = get(type.member_types[i]); + + if (mbr_type.basetype == SPIRType::Struct) + { + // If there are multiple aliases, the output might be somewhat unpredictable, + // but the only real alternative in that case is to do nothing, which isn't any better. + // This check should be fine in practice. + if (get_name(mbr_type.self).empty() && !get_member_name(type.self, i).empty()) + { + auto anon_name = join("anon_", get_member_name(type.self, i)); + ParsedIR::sanitize_underscores(anon_name); + set_name(mbr_type.self, anon_name); + } + + fixup_anonymous_struct_names(visited, mbr_type); + } + } +} + +void CompilerGLSL::fixup_anonymous_struct_names() +{ + // HLSL codegen can often end up emitting anonymous structs inside blocks, which + // breaks GL linking since all names must match ... + // Try to emit sensible code, so attempt to find such structs and emit anon_$member. + + // Breaks exponential explosion with weird type trees. + std::unordered_set visited; + + ir.for_each_typed_id([&](uint32_t, SPIRType &type) { + if (type.basetype == SPIRType::Struct && + (has_decoration(type.self, DecorationBlock) || + has_decoration(type.self, DecorationBufferBlock))) + { + fixup_anonymous_struct_names(visited, type); + } + }); +} + void CompilerGLSL::fixup_type_alias() { // Due to how some backends work, the "master" type of type_alias must be a block-like type if it exists. @@ -15678,7 +18085,7 @@ void CompilerGLSL::reorder_type_alias() if (alias_itr < master_itr) { // Must also swap the type order for the constant-type joined array. - auto &joined_types = ir.ids_for_constant_or_type; + auto &joined_types = ir.ids_for_constant_undef_or_type; auto alt_alias_itr = find(begin(joined_types), end(joined_types), *alias_itr); auto alt_master_itr = find(begin(joined_types), end(joined_types), *master_itr); assert(alt_alias_itr != end(joined_types)); @@ -15698,6 +18105,11 @@ void CompilerGLSL::emit_line_directive(uint32_t file_id, uint32_t line_literal) if (redirect_statement) return; + // If we're emitting code in a sensitive context such as condition blocks in for loops, don't emit + // any line directives, because it's not possible. + if (block_debug_directives) + return; + if (options.emit_line_directives) { require_extension_internal("GL_GOOGLE_cpp_style_line_directive"); @@ -15754,7 +18166,7 @@ void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, rhs_id = id + 1; { - auto &lhs_expr = set(lhs_id, move(lhs), lhs_type_id, true); + auto &lhs_expr = set(lhs_id, std::move(lhs), lhs_type_id, true); lhs_expr.need_transpose = lhs_meta.need_transpose; if (lhs_meta.storage_is_packed) @@ -15767,7 +18179,7 @@ void CompilerGLSL::emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, } { - auto &rhs_expr = set(rhs_id, move(rhs), rhs_type_id, true); + auto &rhs_expr = set(rhs_id, std::move(rhs), rhs_type_id, true); rhs_expr.need_transpose = rhs_meta.need_transpose; if (rhs_meta.storage_is_packed) @@ -15860,6 +18272,7 @@ const char *CompilerGLSL::ShaderSubgroupSupportHelper::get_extension_name(Candid static const char *const retval[CandidateCount] = { "GL_KHR_shader_subgroup_ballot", "GL_KHR_shader_subgroup_basic", "GL_KHR_shader_subgroup_vote", + "GL_KHR_shader_subgroup_arithmetic", "GL_NV_gpu_shader_5", "GL_NV_shader_thread_group", "GL_NV_shader_thread_shuffle", @@ -15908,6 +18321,21 @@ CompilerGLSL::ShaderSubgroupSupportHelper::FeatureVector CompilerGLSL::ShaderSub return { SubgroupMask }; case SubgroupBallotBitCount: return { SubgroupBallot }; + case SubgroupArithmeticIAddReduce: + case SubgroupArithmeticIAddInclusiveScan: + case SubgroupArithmeticFAddReduce: + case SubgroupArithmeticFAddInclusiveScan: + case SubgroupArithmeticIMulReduce: + case SubgroupArithmeticIMulInclusiveScan: + case SubgroupArithmeticFMulReduce: + case SubgroupArithmeticFMulInclusiveScan: + return { SubgroupSize, SubgroupBallot, SubgroupBallotBitCount, SubgroupMask, SubgroupBallotBitExtract }; + case SubgroupArithmeticIAddExclusiveScan: + case SubgroupArithmeticFAddExclusiveScan: + case SubgroupArithmeticIMulExclusiveScan: + case SubgroupArithmeticFMulExclusiveScan: + return { SubgroupSize, SubgroupBallot, SubgroupBallotBitCount, + SubgroupMask, SubgroupElect, SubgroupBallotBitExtract }; default: return {}; } @@ -15921,11 +18349,15 @@ CompilerGLSL::ShaderSubgroupSupportHelper::FeatureMask CompilerGLSL::ShaderSubgr bool CompilerGLSL::ShaderSubgroupSupportHelper::can_feature_be_implemented_without_extensions(Feature feature) { - static const bool retval[FeatureCount] = { false, false, false, false, false, false, - true, // SubgroupBalloFindLSB_MSB - false, false, false, false, - true, // SubgroupMemBarrier - replaced with workgroup memory barriers - false, false, true, false }; + static const bool retval[FeatureCount] = { + false, false, false, false, false, false, + true, // SubgroupBalloFindLSB_MSB + false, false, false, false, + true, // SubgroupMemBarrier - replaced with workgroup memory barriers + false, false, true, false, + false, false, false, false, false, false, // iadd, fadd + false, false, false, false, false, false, // imul , fmul + }; return retval[feature]; } @@ -15937,7 +18369,11 @@ CompilerGLSL::ShaderSubgroupSupportHelper::Candidate CompilerGLSL::ShaderSubgrou KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_vote, KHR_shader_subgroup_vote, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, KHR_shader_subgroup_basic, - KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot + KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, KHR_shader_subgroup_ballot, + KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, + KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, + KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, + KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, KHR_shader_subgroup_arithmetic, }; return extensions[feature]; @@ -16033,6 +18469,19 @@ CompilerGLSL::ShaderSubgroupSupportHelper::CandidateVector CompilerGLSL::ShaderS return { NV_shader_thread_group }; case SubgroupBallotBitCount: return {}; + case SubgroupArithmeticIAddReduce: + case SubgroupArithmeticIAddExclusiveScan: + case SubgroupArithmeticIAddInclusiveScan: + case SubgroupArithmeticFAddReduce: + case SubgroupArithmeticFAddExclusiveScan: + case SubgroupArithmeticFAddInclusiveScan: + case SubgroupArithmeticIMulReduce: + case SubgroupArithmeticIMulExclusiveScan: + case SubgroupArithmeticIMulInclusiveScan: + case SubgroupArithmeticFMulReduce: + case SubgroupArithmeticFMulExclusiveScan: + case SubgroupArithmeticFMulInclusiveScan: + return { KHR_shader_subgroup_arithmetic, NV_shader_thread_shuffle }; default: return {}; } @@ -16057,6 +18506,7 @@ CompilerGLSL::ShaderSubgroupSupportHelper::Result::Result() weights[KHR_shader_subgroup_ballot] = big_num; weights[KHR_shader_subgroup_basic] = big_num; weights[KHR_shader_subgroup_vote] = big_num; + weights[KHR_shader_subgroup_arithmetic] = big_num; } void CompilerGLSL::request_workaround_wrapper_overload(TypeID id) @@ -16087,6 +18537,7 @@ void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID auto *type = &get(loaded_type); bool rewrite = false; + bool relaxed = options.es; if (is_matrix(*type)) { @@ -16097,24 +18548,31 @@ void CompilerGLSL::rewrite_load_for_wrapped_row_major(std::string &expr, TypeID // If an access chain occurred, the workaround is not required, so loading vectors or scalars don't need workaround. type = &backing_type; } + else + { + // If we're loading a composite, we don't have overloads like these. + relaxed = false; + } if (type->basetype == SPIRType::Struct) { // If we're loading a struct where any member is a row-major matrix, apply the workaround. for (uint32_t i = 0; i < uint32_t(type->member_types.size()); i++) { - if (combined_decoration_for_member(*type, i).get(DecorationRowMajor)) - { + auto decorations = combined_decoration_for_member(*type, i); + if (decorations.get(DecorationRowMajor)) rewrite = true; - break; - } + + // Since we decide on a per-struct basis, only use mediump wrapper if all candidates are mediump. + if (!decorations.get(DecorationRelaxedPrecision)) + relaxed = false; } } if (rewrite) { request_workaround_wrapper_overload(loaded_type); - expr = join("spvWorkaroundRowMajor(", expr, ")"); + expr = join("spvWorkaroundRowMajor", (relaxed ? "MP" : ""), "(", expr, ")"); } } @@ -16173,6 +18631,22 @@ bool CompilerGLSL::is_stage_output_block_member_masked(const SPIRVariable &var, } } +bool CompilerGLSL::is_per_primitive_variable(const SPIRVariable &var) const +{ + if (has_decoration(var.self, DecorationPerPrimitiveEXT)) + return true; + + auto &type = get(var.basetype); + if (!has_decoration(type.self, DecorationBlock)) + return false; + + for (uint32_t i = 0, n = uint32_t(type.member_types.size()); i < n; i++) + if (!has_member_decoration(type.self, i, DecorationPerPrimitiveEXT)) + return false; + + return true; +} + bool CompilerGLSL::is_stage_output_location_masked(uint32_t location, uint32_t component) const { return masked_output_locations.count({ location, component }) != 0; @@ -16263,3 +18737,22 @@ uint32_t CompilerGLSL::type_to_location_count(const SPIRType &type) const return count; } + +std::string CompilerGLSL::format_float(float value) const +{ + if (float_formatter) + return float_formatter->format_float(value); + + // default behavior + return convert_to_string(value, current_locale_radix_character); +} + +std::string CompilerGLSL::format_double(double value) const +{ + if (float_formatter) + return float_formatter->format_double(value); + + // default behavior + return convert_to_string(value, current_locale_radix_character); +} + diff --git a/src/libraries/spirv_cross/spirv_glsl.hpp b/src/libraries/spirv_cross/spirv_glsl.hpp index b34ed9930..c04ef88bf 100644 --- a/src/libraries/spirv_cross/spirv_glsl.hpp +++ b/src/libraries/spirv_cross/spirv_glsl.hpp @@ -83,6 +83,11 @@ public: // Debug option to always emit temporary variables for all expressions. bool force_temporary = false; + // Debug option, can be increased in an attempt to workaround SPIRV-Cross bugs temporarily. + // If this limit has to be increased, it points to an implementation bug. + // In certain scenarios, the maximum number of debug iterations may increase beyond this limit + // as long as we can prove we're making certain kinds of forward progress. + uint32_t force_recompile_max_debug_iterations = 3; // If true, Vulkan GLSL features are used instead of GL-compatible features. // Mostly useful for debugging SPIR-V files. @@ -133,6 +138,19 @@ public: // what happens on legacy GLSL targets for blocks and structs. bool force_flattened_io_blocks = false; + // For opcodes where we have to perform explicit additional nan checks, very ugly code is generated. + // If we opt-in, ignore these requirements. + // In opcodes like NClamp/NMin/NMax and FP compare, ignore NaN behavior. + // Use FClamp/FMin/FMax semantics for clamps and lets implementation choose ordered or unordered + // compares. + bool relax_nan_checks = false; + + // Loading row-major matrices from UBOs on older AMD Windows OpenGL drivers is problematic. + // To load these types correctly, we must generate a wrapper. them in a dummy function which only purpose is to + // ensure row_major decoration is actually respected. + // This workaround may cause significant performance degeneration on some Android devices. + bool enable_row_major_load_workaround = true; + // If non-zero, controls layout(num_views = N) in; in GL_OVR_multiview2. uint32_t ovr_multiview_view_count = 0; @@ -240,6 +258,10 @@ public: // require_extension("GL_KHR_my_extension"); void require_extension(const std::string &ext); + // Returns the list of required extensions. After compilation this will contains any other + // extensions that the compiler used automatically, in addition to the user specified ones. + const SmallVector &get_required_extensions() const; + // Legacy GLSL compatibility method. // Takes a uniform or push constant variable and flattens it into a (i|u)vec4 array[N]; array instead. // For this to work, all types in the block must be the same basic type, e.g. mixing vec2 and vec4 is fine, but @@ -265,6 +287,14 @@ public: void mask_stage_output_by_location(uint32_t location, uint32_t component); void mask_stage_output_by_builtin(spv::BuiltIn builtin); + // Allow to control how to format float literals in the output. + // Set to "nullptr" to use the default "convert_to_string" function. + // This handle is not owned by SPIRV-Cross and must remain valid until compile() has been called. + void set_float_formatter(FloatFormatter *formatter) + { + float_formatter = formatter; + } + protected: struct ShaderSubgroupSupportHelper { @@ -274,6 +304,7 @@ protected: KHR_shader_subgroup_ballot, KHR_shader_subgroup_basic, KHR_shader_subgroup_vote, + KHR_shader_subgroup_arithmetic, NV_gpu_shader_5, NV_shader_thread_group, NV_shader_thread_shuffle, @@ -306,7 +337,18 @@ protected: SubgroupInverseBallot_InclBitCount_ExclBitCout = 13, SubgroupBallotBitExtract = 14, SubgroupBallotBitCount = 15, - + SubgroupArithmeticIAddReduce = 16, + SubgroupArithmeticIAddExclusiveScan = 17, + SubgroupArithmeticIAddInclusiveScan = 18, + SubgroupArithmeticFAddReduce = 19, + SubgroupArithmeticFAddExclusiveScan = 20, + SubgroupArithmeticFAddInclusiveScan = 21, + SubgroupArithmeticIMulReduce = 22, + SubgroupArithmeticIMulExclusiveScan = 23, + SubgroupArithmeticIMulInclusiveScan = 24, + SubgroupArithmeticFMulReduce = 25, + SubgroupArithmeticFMulExclusiveScan = 26, + SubgroupArithmeticFMulInclusiveScan = 27, FeatureCount }; @@ -340,9 +382,9 @@ protected: }; // TODO remove this function when all subgroup ops are supported (or make it always return true) - static bool is_supported_subgroup_op_in_opengl(spv::Op op); + static bool is_supported_subgroup_op_in_opengl(spv::Op op, const uint32_t *ops); - void reset(); + void reset(uint32_t iteration_count); void emit_function(SPIRFunction &func, const Bitset &return_flags); bool has_extension(const std::string &ext) const; @@ -352,11 +394,23 @@ protected: virtual void emit_function_prototype(SPIRFunction &func, const Bitset &return_flags); SPIRBlock *current_emitting_block = nullptr; - SPIRBlock *current_emitting_switch = nullptr; + SmallVector current_emitting_switch_stack; bool current_emitting_switch_fallthrough = false; virtual void emit_instruction(const Instruction &instr); + struct TemporaryCopy + { + uint32_t dst_id; + uint32_t src_id; + }; + TemporaryCopy handle_instruction_precision(const Instruction &instr); void emit_block_instructions(SPIRBlock &block); + void emit_block_instructions_with_masked_debug(SPIRBlock &block); + + // For relax_nan_checks. + GLSLstd450 get_remapped_glsl_op(GLSLstd450 std450_op) const; + spv::Op get_remapped_spirv_op(spv::Op op) const; + virtual void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, uint32_t count); virtual void emit_spv_amd_shader_ballot_op(uint32_t result_type, uint32_t result_id, uint32_t op, @@ -385,7 +439,9 @@ protected: const std::string &qualifier = "", uint32_t base_offset = 0); virtual void emit_struct_padding_target(const SPIRType &type); virtual std::string image_type_glsl(const SPIRType &type, uint32_t id = 0); - std::string constant_expression(const SPIRConstant &c); + std::string constant_expression(const SPIRConstant &c, + bool inside_block_like_struct_scope = false, + bool inside_struct_scope = false); virtual std::string constant_op_expression(const SPIRConstantOp &cop); virtual std::string constant_expression_vector(const SPIRConstant &c, uint32_t vector); virtual void emit_fixup(); @@ -419,7 +475,7 @@ protected: TextureFunctionArguments() = default; TextureFunctionBaseArguments base; uint32_t coord = 0, coord_components = 0, dref = 0; - uint32_t grad_x = 0, grad_y = 0, lod = 0, coffset = 0, offset = 0; + uint32_t grad_x = 0, grad_y = 0, lod = 0, offset = 0; uint32_t bias = 0, component = 0, sample = 0, sparse_texel = 0, min_lod = 0; bool nonuniform_expression = false; }; @@ -436,6 +492,8 @@ protected: virtual bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const; + virtual bool is_user_type_structured(uint32_t id) const; + void emit_copy_logical_type(uint32_t lhs_id, uint32_t lhs_type_id, uint32_t rhs_id, uint32_t rhs_type_id, SmallVector chain); @@ -495,6 +553,8 @@ protected: // on a single line separated by comma. SmallVector *redirect_statement = nullptr; const SPIRBlock *current_continue_block = nullptr; + bool block_temporary_hoisting = false; + bool block_debug_directives = false; void begin_scope(); void end_scope(); @@ -522,7 +582,8 @@ protected: bool member_is_remapped_physical_type(const SPIRType &type, uint32_t index) const; bool member_is_packed_physical_type(const SPIRType &type, uint32_t index) const; virtual std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, - uint32_t physical_type_id, bool is_packed); + uint32_t physical_type_id, bool is_packed, + bool relaxed = false); std::unordered_set local_variable_names; std::unordered_set resource_names; @@ -559,6 +620,7 @@ protected: const char *uint16_t_literal_suffix = "us"; const char *nonuniform_qualifier = "nonuniformEXT"; const char *boolean_mix_function = "mix"; + SPIRType::BaseType boolean_in_struct_remapped_type = SPIRType::Boolean; bool swizzle_is_function = false; bool shared_is_implied = false; bool unsized_array_supported = true; @@ -572,12 +634,13 @@ protected: bool allow_precision_qualifiers = false; bool can_swizzle_scalar = false; bool force_gl_in_out_block = false; + bool force_merged_mesh_block = false; bool can_return_array = true; bool allow_truncated_access_chain = false; bool supports_extensions = false; bool supports_empty_struct = false; bool array_is_value_type = true; - bool buffer_offset_array_is_value_type = true; + bool array_is_value_type_in_buffer_blocks = true; bool comparison_image_samples_scalar = false; bool native_pointers = false; bool support_small_type_sampling_result = false; @@ -587,16 +650,21 @@ protected: bool support_pointer_to_pointer = false; bool support_precise_qualifier = false; bool support_64bit_switch = false; + bool workgroup_size_is_hidden = false; + bool requires_relaxed_precision_analysis = false; + bool implicit_c_integer_promotion_rules = false; } backend; void emit_struct(SPIRType &type); void emit_resources(); void emit_extension_workarounds(spv::ExecutionModel model); + void emit_subgroup_arithmetic_workaround(const std::string &func, spv::Op op, spv::GroupOperation group_op); + void emit_polyfills(uint32_t polyfills, bool relaxed); void emit_buffer_block_native(const SPIRVariable &var); void emit_buffer_reference_block(uint32_t type_id, bool forward_declaration); void emit_buffer_block_legacy(const SPIRVariable &var); void emit_buffer_block_flattened(const SPIRVariable &type); - void fixup_implicit_builtin_block_names(); + void fixup_implicit_builtin_block_names(spv::ExecutionModel model); void emit_declared_builtin_block(spv::StorageClass storage, spv::ExecutionModel model); bool should_force_emit_builtin_block(spv::StorageClass storage); void emit_push_constant_block_vulkan(const SPIRVariable &var); @@ -610,6 +678,7 @@ protected: void emit_block_chain(SPIRBlock &block); void emit_hoisted_temporaries(SmallVector> &temporaries); std::string constant_value_macro_name(uint32_t id); + int get_constant_mapping_to_workgroup_component(const SPIRConstant &constant) const; void emit_constant(const SPIRConstant &constant); void emit_specialization_constant_op(const SPIRConstantOp &constant); std::string emit_continue_block(uint32_t continue_block, bool follow_true_block, bool follow_false_block); @@ -628,6 +697,7 @@ protected: bool should_suppress_usage_tracking(uint32_t id) const; void emit_mix_op(uint32_t result_type, uint32_t id, uint32_t left, uint32_t right, uint32_t lerp); void emit_nminmax_op(uint32_t result_type, uint32_t id, uint32_t op0, uint32_t op1, GLSLstd450 op); + void emit_emulated_ahyper_op(uint32_t result_type, uint32_t result_id, uint32_t op0, GLSLstd450 op); bool to_trivial_mix_op(const SPIRType &type, std::string &op, uint32_t left, uint32_t right, uint32_t lerp); void emit_quaternary_func_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, uint32_t op2, uint32_t op3, const char *op); @@ -658,7 +728,7 @@ protected: void emit_unrolled_binary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, bool negate, SPIRType::BaseType expected_type); void emit_binary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op, - SPIRType::BaseType input_type, bool skip_cast_if_equal_type); + SPIRType::BaseType input_type, bool skip_cast_if_equal_type, bool implicit_integer_promotion); SPIRType binary_op_bitcast_helper(std::string &cast_op0, std::string &cast_op1, SPIRType::BaseType &input_type, uint32_t op0, uint32_t op1, bool skip_cast_if_equal_type); @@ -669,6 +739,8 @@ protected: uint32_t false_value); void emit_unary_op(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); + void emit_unary_op_cast(uint32_t result_type, uint32_t result_id, uint32_t op0, const char *op); + virtual void emit_mesh_tasks(SPIRBlock &block); bool expression_is_forwarded(uint32_t id) const; bool expression_suppresses_usage_tracking(uint32_t id) const; bool expression_read_implies_multiple_reads(uint32_t id) const; @@ -684,7 +756,8 @@ protected: spv::StorageClass get_expression_effective_storage_class(uint32_t ptr); virtual bool access_chain_needs_stage_io_builtin_translation(uint32_t base); - virtual void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, + virtual void check_physical_type_cast(std::string &expr, const SPIRType *type, uint32_t physical_type); + virtual bool prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage, bool &is_packed); std::string access_chain(uint32_t base, const uint32_t *indices, uint32_t count, const SPIRType &target_type, @@ -716,8 +789,8 @@ protected: void append_global_func_args(const SPIRFunction &func, uint32_t index, SmallVector &arglist); std::string to_non_uniform_aware_expression(uint32_t id); std::string to_expression(uint32_t id, bool register_expression_read = true); - std::string to_composite_constructor_expression(uint32_t id, bool uses_buffer_offset); - std::string to_rerolled_array_expression(const std::string &expr, const SPIRType &type); + std::string to_composite_constructor_expression(const SPIRType &parent_type, uint32_t id, bool block_like_type); + std::string to_rerolled_array_expression(const SPIRType &parent_type, const std::string &expr, const SPIRType &type); std::string to_enclosed_expression(uint32_t id, bool register_expression_read = true); std::string to_unpacked_expression(uint32_t id, bool register_expression_read = true); std::string to_unpacked_row_major_matrix_expression(uint32_t id); @@ -728,17 +801,18 @@ protected: std::string to_extract_component_expression(uint32_t id, uint32_t index); std::string to_extract_constant_composite_expression(uint32_t result_type, const SPIRConstant &c, const uint32_t *chain, uint32_t length); + static bool needs_enclose_expression(const std::string &expr); std::string enclose_expression(const std::string &expr); std::string dereference_expression(const SPIRType &expression_type, const std::string &expr); std::string address_of_expression(const std::string &expr); void strip_enclosed_expression(std::string &expr); std::string to_member_name(const SPIRType &type, uint32_t index); - virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain); + virtual std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain_is_resolved); std::string to_multi_member_reference(const SPIRType &type, const SmallVector &indices); std::string type_to_glsl_constructor(const SPIRType &type); std::string argument_decl(const SPIRFunction::Parameter &arg); virtual std::string to_qualifiers_glsl(uint32_t id); - void fixup_io_block_patch_qualifiers(const SPIRVariable &var); + void fixup_io_block_patch_primitive_qualifiers(const SPIRVariable &var); void emit_output_variable_initializer(const SPIRVariable &var); std::string to_precision_qualifiers_glsl(uint32_t id); virtual const char *to_storage_qualifiers_glsl(const SPIRVariable &var); @@ -749,7 +823,7 @@ protected: std::string layout_for_variable(const SPIRVariable &variable); std::string to_combined_image_sampler(VariableID image_id, VariableID samp_id); virtual bool skip_argument(uint32_t id) const; - virtual void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id, + virtual bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, spv::StorageClass lhs_storage, spv::StorageClass rhs_storage); virtual void emit_block_hints(const SPIRBlock &block); virtual std::string to_initializer_expression(const SPIRVariable &var); @@ -789,6 +863,10 @@ protected: void replace_fragment_outputs(); std::string legacy_tex_op(const std::string &op, const SPIRType &imgtype, uint32_t id); + void forward_relaxed_precision(uint32_t dst_id, const uint32_t *args, uint32_t length); + void analyze_precision_requirements(uint32_t type_id, uint32_t dst_id, uint32_t *args, uint32_t length); + Options::Precision analyze_expression_precision(const uint32_t *args, uint32_t length) const; + uint32_t indent = 0; std::unordered_set emitted_functions; @@ -842,10 +920,25 @@ protected: return !options.es && options.version < 130; } - bool requires_transpose_2x2 = false; - bool requires_transpose_3x3 = false; - bool requires_transpose_4x4 = false; + enum Polyfill : uint32_t + { + PolyfillTranspose2x2 = 1 << 0, + PolyfillTranspose3x3 = 1 << 1, + PolyfillTranspose4x4 = 1 << 2, + PolyfillDeterminant2x2 = 1 << 3, + PolyfillDeterminant3x3 = 1 << 4, + PolyfillDeterminant4x4 = 1 << 5, + PolyfillMatrixInverse2x2 = 1 << 6, + PolyfillMatrixInverse3x3 = 1 << 7, + PolyfillMatrixInverse4x4 = 1 << 8, + }; + + uint32_t required_polyfills = 0; + uint32_t required_polyfills_relaxed = 0; + void require_polyfill(Polyfill polyfill, bool relaxed); + bool ray_tracing_is_khr = false; + bool barycentric_is_nv = false; void ray_tracing_khr_fixup_locations(); bool args_will_forward(uint32_t id, const uint32_t *args, uint32_t num_args, bool pure); @@ -879,8 +972,14 @@ protected: void check_function_call_constraints(const uint32_t *args, uint32_t length); void handle_invalid_expression(uint32_t id); + void force_temporary_and_recompile(uint32_t id); void find_static_extensions(); + uint32_t consume_temporary_in_precision_context(uint32_t type_id, uint32_t id, Options::Precision precision); + std::unordered_map temporary_to_mirror_precision_alias; + std::unordered_set composite_insert_overwritten; + std::unordered_set block_composite_insert_overwrite; + std::string emit_for_loop_initializers(const SPIRBlock &block); void emit_while_loop_initializers(const SPIRBlock &block); bool for_loop_initializers_are_same_type(const SPIRBlock &block); @@ -889,8 +988,6 @@ protected: bool type_is_empty(const SPIRType &type); - virtual void declare_undefined_values(); - bool can_use_io_location(spv::StorageClass storage, bool block); const Instruction *get_next_instruction_in_block(const Instruction &instr); static uint32_t mask_relevant_memory_semantics(uint32_t semantics); @@ -904,6 +1001,7 @@ protected: // Builtins in GLSL are always specific signedness, but the SPIR-V can declare them // as either unsigned or signed. // Sometimes we will need to automatically perform casts on load and store to make this work. + virtual SPIRType::BaseType get_builtin_basetype(spv::BuiltIn builtin, SPIRType::BaseType default_type); virtual void cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type); virtual void cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type); void unroll_array_from_complex_load(uint32_t target_id, uint32_t source_id, std::string &expr); @@ -926,6 +1024,8 @@ protected: void fixup_type_alias(); void reorder_type_alias(); + void fixup_anonymous_struct_names(); + void fixup_anonymous_struct_names(std::unordered_set &visited, const SPIRType &type); static const char *vector_swizzle(int vecsize, int index); @@ -933,13 +1033,24 @@ protected: bool is_stage_output_builtin_masked(spv::BuiltIn builtin) const; bool is_stage_output_variable_masked(const SPIRVariable &var) const; bool is_stage_output_block_member_masked(const SPIRVariable &var, uint32_t index, bool strip_array) const; + bool is_per_primitive_variable(const SPIRVariable &var) const; uint32_t get_accumulated_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const; uint32_t get_declared_member_location(const SPIRVariable &var, uint32_t mbr_idx, bool strip_array) const; std::unordered_set masked_output_locations; std::unordered_set masked_output_builtins; + FloatFormatter *float_formatter = nullptr; + std::string format_float(float value) const; + std::string format_double(double value) const; + private: void init(); + + SmallVector get_composite_constant_ids(ConstantID const_id); + void fill_composite_constant(SPIRConstant &constant, TypeID type_id, const SmallVector &initializers); + void set_composite_constant(ConstantID const_id, TypeID type_id, const SmallVector &initializers); + TypeID get_composite_member_type(TypeID type_id, uint32_t member_idx); + std::unordered_map> const_composite_insert_ids; }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/src/libraries/spirv_cross/spirv_hlsl.cpp b/src/libraries/spirv_cross/spirv_hlsl.cpp index bdcb6dd37..9b8349365 100644 --- a/src/libraries/spirv_cross/spirv_hlsl.cpp +++ b/src/libraries/spirv_cross/spirv_hlsl.cpp @@ -462,6 +462,10 @@ string CompilerHLSL::type_to_glsl(const SPIRType &type, uint32_t id) if (hlsl_options.shader_model < 60) SPIRV_CROSS_THROW("64-bit integers only supported in SM 6.0."); return "uint64_t"; + case SPIRType::AccelerationStructure: + return "RaytracingAccelerationStructure"; + case SPIRType::RayQuery: + return "RayQuery"; default: return "???"; } @@ -599,50 +603,158 @@ void CompilerHLSL::emit_builtin_outputs_in_struct() break; case BuiltInClipDistance: + { + static const char *types[] = { "float", "float2", "float3", "float4" }; + // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors. - for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) + if (execution.model == ExecutionModelMeshEXT) { - uint32_t to_declare = clip_distance_count - clip; - if (to_declare > 4) - to_declare = 4; + if (clip_distance_count > 4) + SPIRV_CROSS_THROW("Clip distance count > 4 not supported for mesh shaders."); - uint32_t semantic_index = clip / 4; + if (clip_distance_count == 1) + { + // Avoids having to hack up access_chain code. Makes it trivially indexable. + statement("float gl_ClipDistance[1] : SV_ClipDistance;"); + } + else + { + // Replace array with vector directly, avoids any weird fixup path. + statement(types[clip_distance_count - 1], " gl_ClipDistance : SV_ClipDistance;"); + } + } + else + { + for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) + { + uint32_t to_declare = clip_distance_count - clip; + if (to_declare > 4) + to_declare = 4; - static const char *types[] = { "float", "float2", "float3", "float4" }; - statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index, - " : SV_ClipDistance", semantic_index, ";"); + uint32_t semantic_index = clip / 4; + + statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index, + " : SV_ClipDistance", semantic_index, ";"); + } } break; + } case BuiltInCullDistance: + { + static const char *types[] = { "float", "float2", "float3", "float4" }; + // HLSL is a bit weird here, use SV_CullDistance0, SV_CullDistance1 and so on with vectors. - for (uint32_t cull = 0; cull < cull_distance_count; cull += 4) + if (execution.model == ExecutionModelMeshEXT) { - uint32_t to_declare = cull_distance_count - cull; - if (to_declare > 4) - to_declare = 4; + if (cull_distance_count > 4) + SPIRV_CROSS_THROW("Cull distance count > 4 not supported for mesh shaders."); - uint32_t semantic_index = cull / 4; + if (cull_distance_count == 1) + { + // Avoids having to hack up access_chain code. Makes it trivially indexable. + statement("float gl_CullDistance[1] : SV_CullDistance;"); + } + else + { + // Replace array with vector directly, avoids any weird fixup path. + statement(types[cull_distance_count - 1], " gl_CullDistance : SV_CullDistance;"); + } + } + else + { + for (uint32_t cull = 0; cull < cull_distance_count; cull += 4) + { + uint32_t to_declare = cull_distance_count - cull; + if (to_declare > 4) + to_declare = 4; - static const char *types[] = { "float", "float2", "float3", "float4" }; - statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index, - " : SV_CullDistance", semantic_index, ";"); + uint32_t semantic_index = cull / 4; + + statement(types[to_declare - 1], " ", builtin_to_glsl(builtin, StorageClassOutput), semantic_index, + " : SV_CullDistance", semantic_index, ";"); + } } break; + } case BuiltInPointSize: // If point_size_compat is enabled, just ignore PointSize. // PointSize does not exist in HLSL, but some code bases might want to be able to use these shaders, // even if it means working around the missing feature. - if (hlsl_options.point_size_compat) - break; - else + if (legacy) + { + type = "float"; + semantic = "PSIZE"; + } + else if (!hlsl_options.point_size_compat) SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); + break; + + case BuiltInLayer: + case BuiltInPrimitiveId: + case BuiltInViewportIndex: + case BuiltInPrimitiveShadingRateKHR: + case BuiltInCullPrimitiveEXT: + // per-primitive attributes handled separatly + break; + + case BuiltInPrimitivePointIndicesEXT: + case BuiltInPrimitiveLineIndicesEXT: + case BuiltInPrimitiveTriangleIndicesEXT: + // meshlet local-index buffer handled separatly + break; default: SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); } + if (type && semantic) + statement(type, " ", builtin_to_glsl(builtin, StorageClassOutput), " : ", semantic, ";"); + }); +} + +void CompilerHLSL::emit_builtin_primitive_outputs_in_struct() +{ + active_output_builtins.for_each_bit([&](uint32_t i) { + const char *type = nullptr; + const char *semantic = nullptr; + auto builtin = static_cast(i); + switch (builtin) + { + case BuiltInLayer: + { + if (hlsl_options.shader_model < 50) + SPIRV_CROSS_THROW("Render target array index output is only supported in SM 5.0 or higher."); + type = "uint"; + semantic = "SV_RenderTargetArrayIndex"; + break; + } + + case BuiltInPrimitiveId: + type = "uint"; + semantic = "SV_PrimitiveID"; + break; + + case BuiltInViewportIndex: + type = "uint"; + semantic = "SV_ViewportArrayIndex"; + break; + + case BuiltInPrimitiveShadingRateKHR: + type = "uint"; + semantic = "SV_ShadingRate"; + break; + + case BuiltInCullPrimitiveEXT: + type = "bool"; + semantic = "SV_CullPrimitive"; + break; + + default: + break; + } + if (type && semantic) statement(type, " ", builtin_to_glsl(builtin, StorageClassOutput), " : ", semantic, ";"); }); @@ -670,6 +782,11 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() semantic = "SV_VertexID"; break; + case BuiltInPrimitiveId: + type = "uint"; + semantic = "SV_PrimitiveID"; + break; + case BuiltInInstanceId: case BuiltInInstanceIndex: if (legacy) @@ -717,6 +834,13 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() semantic = "SV_IsFrontFace"; break; + case BuiltInViewIndex: + if (hlsl_options.shader_model < 61 || (get_entry_point().model != ExecutionModelVertex && get_entry_point().model != ExecutionModelFragment)) + SPIRV_CROSS_THROW("View Index input is only supported in VS and PS 6.1 or higher."); + type = "uint"; + semantic = "SV_ViewID"; + break; + case BuiltInNumWorkgroups: case BuiltInSubgroupSize: case BuiltInSubgroupLocalInvocationId: @@ -725,9 +849,16 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() case BuiltInSubgroupLeMask: case BuiltInSubgroupGtMask: case BuiltInSubgroupGeMask: + case BuiltInBaseVertex: + case BuiltInBaseInstance: // Handled specially. break; + case BuiltInHelperInvocation: + if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment) + SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher."); + break; + case BuiltInClipDistance: // HLSL is a bit weird here, use SV_ClipDistance0, SV_ClipDistance1 and so on with vectors. for (uint32_t clip = 0; clip < clip_distance_count; clip += 4) @@ -767,6 +898,13 @@ void CompilerHLSL::emit_builtin_inputs_in_struct() else SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); + case BuiltInLayer: + if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment) + SPIRV_CROSS_THROW("Render target array index input is only supported in PS 5.0 or higher."); + type = "uint"; + semantic = "SV_RenderTargetArrayIndex"; + break; + default: SPIRV_CROSS_THROW("Unsupported builtin in HLSL."); } @@ -880,6 +1018,7 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord string binding; bool use_location_number = true; + bool need_matrix_unroll = false; bool legacy = hlsl_options.shader_model <= 30; if (execution.model == ExecutionModelFragment && var.storage == StorageClassOutput) { @@ -895,6 +1034,12 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord if (legacy) // COLOR must be a four-component vector on legacy shader model targets (HLSL ERR_COLOR_4COMP) type.vecsize = 4; } + else if (var.storage == StorageClassInput && execution.model == ExecutionModelVertex) + { + need_matrix_unroll = true; + if (legacy) // Inputs must be floating-point in legacy targets. + type.basetype = SPIRType::Float; + } const auto get_vacant_location = [&]() -> uint32_t { for (uint32_t i = 0; i < 64; i++) @@ -903,8 +1048,6 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord SPIRV_CROSS_THROW("All locations from 0 to 63 are exhausted."); }; - bool need_matrix_unroll = var.storage == StorageClassInput && execution.model == ExecutionModelVertex; - auto name = to_name(var.self); if (use_location_number) { @@ -944,17 +1087,25 @@ void CompilerHLSL::emit_interface_block_in_struct(const SPIRVariable &var, unord } else { - statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)), variable_decl(type, name), " : ", + auto decl_type = type; + if (execution.model == ExecutionModelMeshEXT) + { + decl_type.array.erase(decl_type.array.begin()); + decl_type.array_size_literal.erase(decl_type.array_size_literal.begin()); + } + statement(to_interpolation_qualifiers(get_decoration_bitset(var.self)), variable_decl(decl_type, name), " : ", semantic, ";"); // Structs and arrays should consume more locations. - uint32_t consumed_locations = type_to_consumed_locations(type); + uint32_t consumed_locations = type_to_consumed_locations(decl_type); for (uint32_t i = 0; i < consumed_locations; i++) active_locations.insert(location_number + i); } } else + { statement(variable_decl(type, name), " : ", binding, ";"); + } } std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClass storage) @@ -984,6 +1135,8 @@ std::string CompilerHLSL::builtin_to_glsl(spv::BuiltIn builtin, spv::StorageClas return "WaveGetLaneIndex()"; case BuiltInSubgroupSize: return "WaveGetLaneCount()"; + case BuiltInHelperInvocation: + return "IsHelperLane()"; default: return CompilerGLSL::builtin_to_glsl(builtin, storage); @@ -995,32 +1148,49 @@ void CompilerHLSL::emit_builtin_variables() Bitset builtins = active_input_builtins; builtins.merge_or(active_output_builtins); - bool need_base_vertex_info = false; - std::unordered_map builtin_to_initializer; - ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { - if (!is_builtin_variable(var) || var.storage != StorageClassOutput || !var.initializer) - return; - auto *c = this->maybe_get(var.initializer); - if (!c) + // We need to declare sample mask with the same type that module declares it. + // Sample mask is somewhat special in that SPIR-V has an array, and we can copy that array, so we need to + // match sign. + SPIRType::BaseType sample_mask_in_basetype = SPIRType::Void; + SPIRType::BaseType sample_mask_out_basetype = SPIRType::Void; + + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + if (!is_builtin_variable(var)) return; auto &type = this->get(var.basetype); - if (type.basetype == SPIRType::Struct) + auto builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); + + if (var.storage == StorageClassInput && builtin == BuiltInSampleMask) + sample_mask_in_basetype = type.basetype; + else if (var.storage == StorageClassOutput && builtin == BuiltInSampleMask) + sample_mask_out_basetype = type.basetype; + + if (var.initializer && var.storage == StorageClassOutput) { - uint32_t member_count = uint32_t(type.member_types.size()); - for (uint32_t i = 0; i < member_count; i++) + auto *c = this->maybe_get(var.initializer); + if (!c) + return; + + if (type.basetype == SPIRType::Struct) { - if (has_member_decoration(type.self, i, DecorationBuiltIn)) + uint32_t member_count = uint32_t(type.member_types.size()); + for (uint32_t i = 0; i < member_count; i++) { - builtin_to_initializer[get_member_decoration(type.self, i, DecorationBuiltIn)] = - c->subconstants[i]; + if (has_member_decoration(type.self, i, DecorationBuiltIn)) + { + builtin_to_initializer[get_member_decoration(type.self, i, DecorationBuiltIn)] = + c->subconstants[i]; + } } } + else if (has_decoration(var.self, DecorationBuiltIn)) + { + builtin_to_initializer[builtin] = var.initializer; + } } - else if (has_decoration(var.self, DecorationBuiltIn)) - builtin_to_initializer[get_decoration(var.self, DecorationBuiltIn)] = var.initializer; }); // Emit global variables for the interface variables which are statically used by the shader. @@ -1034,6 +1204,18 @@ void CompilerHLSL::emit_builtin_variables() if (init_itr != builtin_to_initializer.end()) init_expr = join(" = ", to_expression(init_itr->second)); + if (get_execution_model() == ExecutionModelMeshEXT) + { + if (builtin == BuiltInPosition || builtin == BuiltInPointSize || builtin == BuiltInClipDistance || + builtin == BuiltInCullDistance || builtin == BuiltInLayer || builtin == BuiltInPrimitiveId || + builtin == BuiltInViewportIndex || builtin == BuiltInCullPrimitiveEXT || + builtin == BuiltInPrimitiveShadingRateKHR || builtin == BuiltInPrimitivePointIndicesEXT || + builtin == BuiltInPrimitiveLineIndicesEXT || builtin == BuiltInPrimitiveTriangleIndicesEXT) + { + return; + } + } + switch (builtin) { case BuiltInFragCoord: @@ -1050,7 +1232,13 @@ void CompilerHLSL::emit_builtin_variables() case BuiltInInstanceIndex: type = "int"; if (hlsl_options.support_nonzero_base_vertex_base_instance) - need_base_vertex_info = true; + base_vertex_info.used = true; + break; + + case BuiltInBaseVertex: + case BuiltInBaseInstance: + type = "int"; + base_vertex_info.used = true; break; case BuiltInInstanceId: @@ -1059,7 +1247,7 @@ void CompilerHLSL::emit_builtin_variables() break; case BuiltInPointSize: - if (hlsl_options.point_size_compat) + if (hlsl_options.point_size_compat || hlsl_options.shader_model <= 30) { // Just emit the global variable, it will be ignored. type = "float"; @@ -1103,6 +1291,11 @@ void CompilerHLSL::emit_builtin_variables() type = "uint4"; break; + case BuiltInHelperInvocation: + if (hlsl_options.shader_model < 50) + SPIRV_CROSS_THROW("Need SM 5.0 for Helper Invocation."); + break; + case BuiltInClipDistance: array_size = clip_distance_count; type = "float"; @@ -1114,7 +1307,24 @@ void CompilerHLSL::emit_builtin_variables() break; case BuiltInSampleMask: - type = "int"; + if (active_input_builtins.get(BuiltInSampleMask)) + type = sample_mask_in_basetype == SPIRType::UInt ? "uint" : "int"; + else + type = sample_mask_out_basetype == SPIRType::UInt ? "uint" : "int"; + array_size = 1; + break; + + case BuiltInPrimitiveId: + case BuiltInViewIndex: + case BuiltInLayer: + type = "uint"; + break; + + case BuiltInViewportIndex: + case BuiltInPrimitiveShadingRateKHR: + case BuiltInPrimitiveLineIndicesEXT: + case BuiltInCullPrimitiveEXT: + type = "uint"; break; default: @@ -1135,13 +1345,25 @@ void CompilerHLSL::emit_builtin_variables() // declared the input variable and we need to add the output one now. if (builtin == BuiltInSampleMask && storage == StorageClassInput && this->active_output_builtins.get(i)) { - statement("static ", type, " ", this->builtin_to_glsl(builtin, StorageClassOutput), init_expr, ";"); + type = sample_mask_out_basetype == SPIRType::UInt ? "uint" : "int"; + if (array_size) + statement("static ", type, " ", this->builtin_to_glsl(builtin, StorageClassOutput), "[", array_size, "]", init_expr, ";"); + else + statement("static ", type, " ", this->builtin_to_glsl(builtin, StorageClassOutput), init_expr, ";"); } }); - if (need_base_vertex_info) + if (base_vertex_info.used) { - statement("cbuffer SPIRV_Cross_VertexInfo"); + string binding_info; + if (base_vertex_info.explicit_binding) + { + binding_info = join(" : register(b", base_vertex_info.register_index); + if (base_vertex_info.register_space) + binding_info += join(", space", base_vertex_info.register_space); + binding_info += ")"; + } + statement("cbuffer SPIRV_Cross_VertexInfo", binding_info); begin_scope(); statement("int SPIRV_Cross_BaseVertex;"); statement("int SPIRV_Cross_BaseInstance;"); @@ -1150,6 +1372,30 @@ void CompilerHLSL::emit_builtin_variables() } } +void CompilerHLSL::set_hlsl_aux_buffer_binding(HLSLAuxBinding binding, uint32_t register_index, uint32_t register_space) +{ + if (binding == HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE) + { + base_vertex_info.explicit_binding = true; + base_vertex_info.register_space = register_space; + base_vertex_info.register_index = register_index; + } +} + +void CompilerHLSL::unset_hlsl_aux_buffer_binding(HLSLAuxBinding binding) +{ + if (binding == HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE) + base_vertex_info.explicit_binding = false; +} + +bool CompilerHLSL::is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const +{ + if (binding == HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE) + return base_vertex_info.used; + else + return false; +} + void CompilerHLSL::emit_composite_constants() { // HLSL cannot declare structs or arrays inline, so we must move them out to @@ -1167,6 +1413,7 @@ void CompilerHLSL::emit_composite_constants() if (type.basetype == SPIRType::Struct || !type.array.empty()) { + add_resource_name(c.self); auto name = to_name(c.self); statement("static const ", variable_decl(type, name), " = ", constant_expression(c), ";"); emitted = true; @@ -1196,7 +1443,7 @@ void CompilerHLSL::emit_specialization_constants_and_structs() }); auto loop_lock = ir.create_loop_hard_lock(); - for (auto &id_ : ir.ids_for_constant_or_type) + for (auto &id_ : ir.ids_for_constant_undef_or_type) { auto &id = ir.ids[id_]; @@ -1213,16 +1460,23 @@ void CompilerHLSL::emit_specialization_constants_and_structs() else if (c.specialization) { auto &type = get(c.constant_type); + add_resource_name(c.self); auto name = to_name(c.self); - // HLSL does not support specialization constants, so fallback to macros. - c.specialization_constant_macro_name = - constant_value_macro_name(get_decoration(c.self, DecorationSpecId)); + if (has_decoration(c.self, DecorationSpecId)) + { + // HLSL does not support specialization constants, so fallback to macros. + c.specialization_constant_macro_name = + constant_value_macro_name(get_decoration(c.self, DecorationSpecId)); + + statement("#ifndef ", c.specialization_constant_macro_name); + statement("#define ", c.specialization_constant_macro_name, " ", constant_expression(c)); + statement("#endif"); + statement("static const ", variable_decl(type, name), " = ", c.specialization_constant_macro_name, ";"); + } + else + statement("static const ", variable_decl(type, name), " = ", constant_expression(c), ";"); - statement("#ifndef ", c.specialization_constant_macro_name); - statement("#define ", c.specialization_constant_macro_name, " ", constant_expression(c)); - statement("#endif"); - statement("static const ", variable_decl(type, name), " = ", c.specialization_constant_macro_name, ";"); emitted = true; } } @@ -1230,6 +1484,7 @@ void CompilerHLSL::emit_specialization_constants_and_structs() { auto &c = id.get(); auto &type = get(c.basetype); + add_resource_name(c.self); auto name = to_name(c.self); statement("static const ", variable_decl(type, name), " = ", constant_op_expression(c), ";"); emitted = true; @@ -1250,6 +1505,21 @@ void CompilerHLSL::emit_specialization_constants_and_structs() emit_struct(type); } } + else if (id.get_type() == TypeUndef) + { + auto &undef = id.get(); + auto &type = this->get(undef.basetype); + // OpUndef can be void for some reason ... + if (type.basetype == SPIRType::Void) + return; + + string initializer; + if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) + initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); + + statement("static ", variable_decl(type, to_name(undef.self), undef.self), initializer, ";"); + emitted = true; + } } if (emitted) @@ -1260,32 +1530,49 @@ void CompilerHLSL::replace_illegal_names() { static const unordered_set keywords = { // Additional HLSL specific keywords. - "line", "linear", "matrix", "point", "row_major", "sampler", "vector" + // From https://docs.microsoft.com/en-US/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords + "AppendStructuredBuffer", "asm", "asm_fragment", + "BlendState", "bool", "break", "Buffer", "ByteAddressBuffer", + "case", "cbuffer", "centroid", "class", "column_major", "compile", + "compile_fragment", "CompileShader", "const", "continue", "ComputeShader", + "ConsumeStructuredBuffer", + "default", "DepthStencilState", "DepthStencilView", "discard", "do", + "double", "DomainShader", "dword", + "else", "export", "false", "float", "for", "fxgroup", + "GeometryShader", "groupshared", "half", "HullShader", + "indices", "if", "in", "inline", "inout", "InputPatch", "int", "interface", + "line", "lineadj", "linear", "LineStream", + "matrix", "min16float", "min10float", "min16int", "min16uint", + "namespace", "nointerpolation", "noperspective", "NULL", + "out", "OutputPatch", + "payload", "packoffset", "pass", "pixelfragment", "PixelShader", "point", + "PointStream", "precise", "RasterizerState", "RenderTargetView", + "return", "register", "row_major", "RWBuffer", "RWByteAddressBuffer", + "RWStructuredBuffer", "RWTexture1D", "RWTexture1DArray", "RWTexture2D", + "RWTexture2DArray", "RWTexture3D", "sample", "sampler", "SamplerState", + "SamplerComparisonState", "shared", "snorm", "stateblock", "stateblock_state", + "static", "string", "struct", "switch", "StructuredBuffer", "tbuffer", + "technique", "technique10", "technique11", "texture", "Texture1D", + "Texture1DArray", "Texture2D", "Texture2DArray", "Texture2DMS", "Texture2DMSArray", + "Texture3D", "TextureCube", "TextureCubeArray", "true", "typedef", "triangle", + "triangleadj", "TriangleStream", "uint", "uniform", "unorm", "unsigned", + "vector", "vertexfragment", "VertexShader", "vertices", "void", "volatile", "while", }; CompilerGLSL::replace_illegal_names(keywords); CompilerGLSL::replace_illegal_names(); } -void CompilerHLSL::declare_undefined_values() +SPIRType::BaseType CompilerHLSL::get_builtin_basetype(BuiltIn builtin, SPIRType::BaseType default_type) { - bool emitted = false; - ir.for_each_typed_id([&](uint32_t, const SPIRUndef &undef) { - auto &type = this->get(undef.basetype); - // OpUndef can be void for some reason ... - if (type.basetype == SPIRType::Void) - return; - - string initializer; - if (options.force_zero_initialized_variables && type_can_zero_initialize(type)) - initializer = join(" = ", to_zero_initialized_expression(undef.basetype)); - - statement("static ", variable_decl(type, to_name(undef.self), undef.self), initializer, ";"); - emitted = true; - }); - - if (emitted) - statement(""); + switch (builtin) + { + case BuiltInSampleMask: + // We declare sample mask array with module type, so always use default_type here. + return default_type; + default: + return CompilerGLSL::get_builtin_basetype(builtin, default_type); + } } void CompilerHLSL::emit_resources() @@ -1294,6 +1581,19 @@ void CompilerHLSL::emit_resources() replace_illegal_names(); + switch (execution.model) + { + case ExecutionModelGeometry: + case ExecutionModelTessellationControl: + case ExecutionModelTessellationEvaluation: + case ExecutionModelMeshEXT: + fixup_implicit_builtin_block_names(execution.model); + break; + + default: + break; + } + emit_specialization_constants_and_structs(); emit_composite_constants(); @@ -1326,7 +1626,8 @@ void CompilerHLSL::emit_resources() } }); - if (execution.model == ExecutionModelVertex && hlsl_options.shader_model <= 30) + if (execution.model == ExecutionModelVertex && hlsl_options.shader_model <= 30 && + active_output_builtins.get(BuiltInPosition)) { statement("uniform float4 gl_HalfPixel;"); emitted = true; @@ -1365,18 +1666,21 @@ void CompilerHLSL::emit_resources() // Emit builtin input and output variables here. emit_builtin_variables(); - ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { - auto &type = this->get(var.basetype); + if (execution.model != ExecutionModelMeshEXT) + { + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + auto &type = this->get(var.basetype); - if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer && - (var.storage == StorageClassInput || var.storage == StorageClassOutput) && !is_builtin_variable(var) && - interface_variable_exists_in_entry_point(var.self)) - { - // Builtin variables are handled separately. - emit_interface_block_globally(var); - emitted = true; - } - }); + if (var.storage != StorageClassFunction && !var.remapped_variable && type.pointer && + (var.storage == StorageClassInput || var.storage == StorageClassOutput) && !is_builtin_variable(var) && + interface_variable_exists_in_entry_point(var.self)) + { + // Builtin variables are handled separately. + emit_interface_block_globally(var); + emitted = true; + } + }); + } if (emitted) statement(""); @@ -1490,23 +1794,48 @@ void CompilerHLSL::emit_resources() statement(""); } + const bool is_mesh_shader = execution.model == ExecutionModelMeshEXT; if (!output_variables.empty() || !active_output_builtins.empty()) { - require_output = true; - statement("struct SPIRV_Cross_Output"); - - begin_scope(); sort(output_variables.begin(), output_variables.end(), variable_compare); + require_output = !is_mesh_shader; + + statement(is_mesh_shader ? "struct gl_MeshPerVertexEXT" : "struct SPIRV_Cross_Output"); + begin_scope(); for (auto &var : output_variables) { - if (var.block) + if (is_per_primitive_variable(*var.var)) + continue; + if (var.block && is_mesh_shader && var.block_member_index != 0) + continue; + if (var.block && !is_mesh_shader) emit_interface_block_member_in_struct(*var.var, var.block_member_index, var.location, active_outputs); else emit_interface_block_in_struct(*var.var, active_outputs); } emit_builtin_outputs_in_struct(); + if (!is_mesh_shader) + emit_builtin_primitive_outputs_in_struct(); end_scope_decl(); statement(""); + + if (is_mesh_shader) + { + statement("struct gl_MeshPerPrimitiveEXT"); + begin_scope(); + for (auto &var : output_variables) + { + if (!is_per_primitive_variable(*var.var)) + continue; + if (var.block && var.block_member_index != 0) + continue; + + emit_interface_block_in_struct(*var.var, active_outputs); + } + emit_builtin_primitive_outputs_in_struct(); + end_scope_decl(); + statement(""); + } } // Global variables. @@ -1516,6 +1845,9 @@ void CompilerHLSL::emit_resources() if (is_hidden_variable(var, true)) continue; + if (var.storage == StorageClassTaskPayloadWorkgroupEXT && is_mesh_shader) + continue; + if (var.storage != StorageClassOutput) { if (!variable_is_lut(var)) @@ -1526,6 +1858,7 @@ void CompilerHLSL::emit_resources() switch (var.storage) { case StorageClassWorkgroup: + case StorageClassTaskPayloadWorkgroupEXT: storage = "groupshared"; break; @@ -1550,8 +1883,6 @@ void CompilerHLSL::emit_resources() if (emitted) statement(""); - declare_undefined_values(); - if (requires_op_fmod) { static const char *types[] = { @@ -1962,6 +2293,20 @@ void CompilerHLSL::emit_resources() end_scope(); statement(""); } + + if (is_mesh_shader && options.vertex.flip_vert_y) + { + statement("float4 spvFlipVertY(float4 v)"); + begin_scope(); + statement("return float4(v.x, -v.y, v.z, v.w);"); + end_scope(); + statement(""); + statement("float spvFlipVertY(float v)"); + begin_scope(); + statement("return -v;"); + end_scope(); + statement(""); + } } void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char *vecsize_qualifier, bool uav, @@ -2042,6 +2387,194 @@ void CompilerHLSL::emit_texture_size_variants(uint64_t variant_mask, const char } } +void CompilerHLSL::analyze_meshlet_writes() +{ + uint32_t id_per_vertex = 0; + uint32_t id_per_primitive = 0; + bool need_per_primitive = false; + bool need_per_vertex = false; + + ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + auto &type = this->get(var.basetype); + bool block = has_decoration(type.self, DecorationBlock); + if (var.storage == StorageClassOutput && block && is_builtin_variable(var)) + { + auto flags = get_buffer_block_flags(var.self); + if (flags.get(DecorationPerPrimitiveEXT)) + id_per_primitive = var.self; + else + id_per_vertex = var.self; + } + else if (var.storage == StorageClassOutput) + { + Bitset flags; + if (block) + flags = get_buffer_block_flags(var.self); + else + flags = get_decoration_bitset(var.self); + + if (flags.get(DecorationPerPrimitiveEXT)) + need_per_primitive = true; + else + need_per_vertex = true; + } + }); + + // If we have per-primitive outputs, and no per-primitive builtins, + // empty version of gl_MeshPerPrimitiveEXT will be emitted. + // If we don't use block IO for vertex output, we'll also need to synthesize the PerVertex block. + + const auto generate_block = [&](const char *block_name, const char *instance_name, bool per_primitive) -> uint32_t { + auto &execution = get_entry_point(); + + uint32_t op_type = ir.increase_bound_by(4); + uint32_t op_arr = op_type + 1; + uint32_t op_ptr = op_type + 2; + uint32_t op_var = op_type + 3; + + auto &type = set(op_type, OpTypeStruct); + type.basetype = SPIRType::Struct; + set_name(op_type, block_name); + set_decoration(op_type, DecorationBlock); + if (per_primitive) + set_decoration(op_type, DecorationPerPrimitiveEXT); + + auto &arr = set(op_arr, type); + arr.parent_type = type.self; + arr.array.push_back(per_primitive ? execution.output_primitives : execution.output_vertices); + arr.array_size_literal.push_back(true); + + auto &ptr = set(op_ptr, arr); + ptr.parent_type = arr.self; + ptr.pointer = true; + ptr.pointer_depth++; + ptr.storage = StorageClassOutput; + set_decoration(op_ptr, DecorationBlock); + set_name(op_ptr, block_name); + + auto &var = set(op_var, op_ptr, StorageClassOutput); + if (per_primitive) + set_decoration(op_var, DecorationPerPrimitiveEXT); + set_name(op_var, instance_name); + execution.interface_variables.push_back(var.self); + + return op_var; + }; + + if (id_per_vertex == 0 && need_per_vertex) + id_per_vertex = generate_block("gl_MeshPerVertexEXT", "gl_MeshVerticesEXT", false); + if (id_per_primitive == 0 && need_per_primitive) + id_per_primitive = generate_block("gl_MeshPerPrimitiveEXT", "gl_MeshPrimitivesEXT", true); + + unordered_set processed_func_ids; + analyze_meshlet_writes(ir.default_entry_point, id_per_vertex, id_per_primitive, processed_func_ids); +} + +void CompilerHLSL::analyze_meshlet_writes(uint32_t func_id, uint32_t id_per_vertex, uint32_t id_per_primitive, + std::unordered_set &processed_func_ids) +{ + // Avoid processing a function more than once + if (processed_func_ids.find(func_id) != processed_func_ids.end()) + return; + processed_func_ids.insert(func_id); + + auto &func = get(func_id); + // Recursively establish global args added to functions on which we depend. + for (auto& block : func.blocks) + { + auto &b = get(block); + for (auto &i : b.ops) + { + auto ops = stream(i); + auto op = static_cast(i.op); + + switch (op) + { + case OpFunctionCall: + { + // Then recurse into the function itself to extract globals used internally in the function + uint32_t inner_func_id = ops[2]; + analyze_meshlet_writes(inner_func_id, id_per_vertex, id_per_primitive, processed_func_ids); + auto &inner_func = get(inner_func_id); + for (auto &iarg : inner_func.arguments) + { + if (!iarg.alias_global_variable) + continue; + + bool already_declared = false; + for (auto &arg : func.arguments) + { + if (arg.id == iarg.id) + { + already_declared = true; + break; + } + } + + if (!already_declared) + { + // basetype is effectively ignored here since we declare the argument + // with explicit types. Just pass down a valid type. + func.arguments.push_back({ expression_type_id(iarg.id), iarg.id, + iarg.read_count, iarg.write_count, true }); + } + } + break; + } + + case OpStore: + case OpLoad: + case OpInBoundsAccessChain: + case OpAccessChain: + case OpPtrAccessChain: + case OpInBoundsPtrAccessChain: + case OpArrayLength: + { + auto *var = maybe_get(ops[op == OpStore ? 0 : 2]); + if (var && (var->storage == StorageClassOutput || var->storage == StorageClassTaskPayloadWorkgroupEXT)) + { + bool already_declared = false; + auto builtin_type = BuiltIn(get_decoration(var->self, DecorationBuiltIn)); + + uint32_t var_id = var->self; + if (var->storage != StorageClassTaskPayloadWorkgroupEXT && + builtin_type != BuiltInPrimitivePointIndicesEXT && + builtin_type != BuiltInPrimitiveLineIndicesEXT && + builtin_type != BuiltInPrimitiveTriangleIndicesEXT) + { + var_id = is_per_primitive_variable(*var) ? id_per_primitive : id_per_vertex; + } + + for (auto &arg : func.arguments) + { + if (arg.id == var_id) + { + already_declared = true; + break; + } + } + + if (!already_declared) + { + // basetype is effectively ignored here since we declare the argument + // with explicit types. Just pass down a valid type. + uint32_t type_id = expression_type_id(var_id); + if (var->storage == StorageClassTaskPayloadWorkgroupEXT) + func.arguments.push_back({ type_id, var_id, 1u, 0u, true }); + else + func.arguments.push_back({ type_id, var_id, 1u, 1u, true }); + } + } + break; + } + + default: + break; + } + } + } +} + string CompilerHLSL::layout_for_member(const SPIRType &type, uint32_t index) { auto &flags = get_member_decoration_bitset(type.self, index); @@ -2087,23 +2620,66 @@ void CompilerHLSL::emit_struct_member(const SPIRType &type, uint32_t member_type variable_decl(membertype, to_member_name(type, index)), packing_offset, ";"); } +void CompilerHLSL::emit_rayquery_function(const char *commited, const char *candidate, const uint32_t *ops) +{ + flush_variable_declaration(ops[0]); + uint32_t is_commited = evaluate_constant_u32(ops[3]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), is_commited ? commited : candidate), false); +} + +void CompilerHLSL::emit_mesh_tasks(SPIRBlock &block) +{ + if (block.mesh.payload != 0) + { + statement("DispatchMesh(", to_unpacked_expression(block.mesh.groups[0]), ", ", to_unpacked_expression(block.mesh.groups[1]), ", ", + to_unpacked_expression(block.mesh.groups[2]), ", ", to_unpacked_expression(block.mesh.payload), ");"); + } + else + { + SPIRV_CROSS_THROW("Amplification shader in HLSL must have payload"); + } +} + void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) { auto &type = get(var.basetype); bool is_uav = var.storage == StorageClassStorageBuffer || has_decoration(type.self, DecorationBufferBlock); - if (is_uav) + if (flattened_buffer_blocks.count(var.self)) + { + emit_buffer_block_flattened(var); + } + else if (is_uav) { Bitset flags = ir.get_buffer_block_flags(var); bool is_readonly = flags.get(DecorationNonWritable) && !is_hlsl_force_storage_buffer_as_uav(var.self); bool is_coherent = flags.get(DecorationCoherent) && !is_readonly; bool is_interlocked = interlocked_resources.count(var.self) > 0; - const char *type_name = "ByteAddressBuffer "; - if (!is_readonly) - type_name = is_interlocked ? "RasterizerOrderedByteAddressBuffer " : "RWByteAddressBuffer "; + + auto to_structuredbuffer_subtype_name = [this](const SPIRType &parent_type) -> std::string + { + if (parent_type.basetype == SPIRType::Struct && parent_type.member_types.size() == 1) + { + // Use type of first struct member as a StructuredBuffer will have only one '._m0' field in SPIR-V + const auto &member0_type = this->get(parent_type.member_types.front()); + return this->type_to_glsl(member0_type); + } + else + { + // Otherwise, this StructuredBuffer only has a basic subtype, e.g. StructuredBuffer + return this->type_to_glsl(parent_type); + } + }; + + std::string type_name; + if (is_user_type_structured(var.self)) + type_name = join(is_readonly ? "" : is_interlocked ? "RasterizerOrdered" : "RW", "StructuredBuffer<", to_structuredbuffer_subtype_name(type), ">"); + else + type_name = is_readonly ? "ByteAddressBuffer" : is_interlocked ? "RasterizerOrderedByteAddressBuffer" : "RWByteAddressBuffer"; + add_resource_name(var.self); - statement(is_coherent ? "globallycoherent " : "", type_name, to_name(var.self), type_to_array_glsl(type), + statement(is_coherent ? "globallycoherent " : "", type_name, " ", to_name(var.self), type_to_array_glsl(type), to_resource_binding(var), ";"); } else @@ -2198,7 +2774,11 @@ void CompilerHLSL::emit_buffer_block(const SPIRVariable &var) void CompilerHLSL::emit_push_constant_block(const SPIRVariable &var) { - if (root_constants_layout.empty()) + if (flattened_buffer_blocks.count(var.self)) + { + emit_buffer_block_flattened(var); + } + else if (root_constants_layout.empty()) { emit_buffer_block(var); } @@ -2305,12 +2885,36 @@ string CompilerHLSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32 return arg_str; } +string CompilerHLSL::get_inner_entry_point_name() const +{ + auto &execution = get_entry_point(); + + if (hlsl_options.use_entry_point_name) + { + auto name = join(execution.name, "_inner"); + ParsedIR::sanitize_underscores(name); + return name; + } + + if (execution.model == ExecutionModelVertex) + return "vert_main"; + else if (execution.model == ExecutionModelFragment) + return "frag_main"; + else if (execution.model == ExecutionModelGLCompute) + return "comp_main"; + else if (execution.model == ExecutionModelMeshEXT) + return "mesh_main"; + else if (execution.model == ExecutionModelTaskEXT) + return "task_main"; + else + SPIRV_CROSS_THROW("Unsupported execution model."); +} + void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &return_flags) { if (func.self != ir.default_entry_point) add_function_overload(func); - auto &execution = get_entry_point(); // Avoid shadow declarations. local_variable_names = resource_names; @@ -2331,14 +2935,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret if (func.self == ir.default_entry_point) { - if (execution.model == ExecutionModelVertex) - decl += "vert_main"; - else if (execution.model == ExecutionModelFragment) - decl += "frag_main"; - else if (execution.model == ExecutionModelGLCompute) - decl += "comp_main"; - else - SPIRV_CROSS_THROW("Unsupported execution model."); + decl += get_inner_entry_point_name(); processing_entry_point = true; } else @@ -2356,7 +2953,7 @@ void CompilerHLSL::emit_function_prototype(SPIRFunction &func, const Bitset &ret out_argument += " "; out_argument += "spvReturnValue"; out_argument += type_to_array_glsl(type); - arglist.push_back(move(out_argument)); + arglist.push_back(std::move(out_argument)); } for (auto &arg : func.arguments) @@ -2422,8 +3019,58 @@ void CompilerHLSL::emit_hlsl_entry_point() switch (execution.model) { + case ExecutionModelTaskEXT: + case ExecutionModelMeshEXT: case ExecutionModelGLCompute: { + if (execution.model == ExecutionModelMeshEXT) + { + if (execution.flags.get(ExecutionModeOutputTrianglesEXT)) + statement("[outputtopology(\"triangle\")]"); + else if (execution.flags.get(ExecutionModeOutputLinesEXT)) + statement("[outputtopology(\"line\")]"); + else if (execution.flags.get(ExecutionModeOutputPoints)) + SPIRV_CROSS_THROW("Topology mode \"points\" is not supported in DirectX"); + + auto &func = get(ir.default_entry_point); + for (auto &arg : func.arguments) + { + auto &var = get(arg.id); + auto &base_type = get(var.basetype); + bool block = has_decoration(base_type.self, DecorationBlock); + if (var.storage == StorageClassTaskPayloadWorkgroupEXT) + { + arguments.push_back("in payload " + variable_decl(var)); + } + else if (block) + { + auto flags = get_buffer_block_flags(var.self); + if (flags.get(DecorationPerPrimitiveEXT) || has_decoration(arg.id, DecorationPerPrimitiveEXT)) + { + arguments.push_back("out primitives gl_MeshPerPrimitiveEXT gl_MeshPrimitivesEXT[" + + std::to_string(execution.output_primitives) + "]"); + } + else + { + arguments.push_back("out vertices gl_MeshPerVertexEXT gl_MeshVerticesEXT[" + + std::to_string(execution.output_vertices) + "]"); + } + } + else + { + if (execution.flags.get(ExecutionModeOutputTrianglesEXT)) + { + arguments.push_back("out indices uint3 gl_PrimitiveTriangleIndicesEXT[" + + std::to_string(execution.output_primitives) + "]"); + } + else + { + arguments.push_back("out indices uint2 gl_PrimitiveLineIndicesEXT[" + + std::to_string(execution.output_primitives) + "]"); + } + } + } + } SpecializationConstant wg_x, wg_y, wg_z; get_work_group_size_specialization_constants(wg_x, wg_y, wg_z); @@ -2431,6 +3078,16 @@ void CompilerHLSL::emit_hlsl_entry_point() uint32_t y = execution.workgroup_size.y; uint32_t z = execution.workgroup_size.z; + if (!execution.workgroup_size.constant && execution.flags.get(ExecutionModeLocalSizeId)) + { + if (execution.workgroup_size.id_x) + x = get(execution.workgroup_size.id_x).scalar(); + if (execution.workgroup_size.id_y) + y = get(execution.workgroup_size.id_y).scalar(); + if (execution.workgroup_size.id_z) + z = get(execution.workgroup_size.id_z).scalar(); + } + auto x_expr = wg_x.id ? get(wg_x.id).specialization_constant_macro_name : to_string(x); auto y_expr = wg_y.id ? get(wg_y.id).specialization_constant_macro_name : to_string(y); auto z_expr = wg_z.id ? get(wg_z.id).specialization_constant_macro_name : to_string(z); @@ -2446,7 +3103,13 @@ void CompilerHLSL::emit_hlsl_entry_point() break; } - statement(require_output ? "SPIRV_Cross_Output " : "void ", "main(", merge(arguments), ")"); + const char *entry_point_name; + if (hlsl_options.use_entry_point_name) + entry_point_name = get_entry_point().name.c_str(); + else + entry_point_name = "main"; + + statement(require_output ? "SPIRV_Cross_Output " : "void ", entry_point_name, "(", merge(arguments), ")"); begin_scope(); bool legacy = hlsl_options.shader_model <= 30; @@ -2484,15 +3147,28 @@ void CompilerHLSL::emit_hlsl_entry_point() statement(builtin, " = int(stage_input.", builtin, ");"); break; + case BuiltInBaseVertex: + statement(builtin, " = SPIRV_Cross_BaseVertex;"); + break; + + case BuiltInBaseInstance: + statement(builtin, " = SPIRV_Cross_BaseInstance;"); + break; + case BuiltInInstanceId: // D3D semantics are uint, but shader wants int. statement(builtin, " = int(stage_input.", builtin, ");"); break; + case BuiltInSampleMask: + statement(builtin, "[0] = stage_input.", builtin, ";"); + break; + case BuiltInNumWorkgroups: case BuiltInPointCoord: case BuiltInSubgroupSize: case BuiltInSubgroupLocalInvocationId: + case BuiltInHelperInvocation: break; case BuiltInSubgroupEqMask: @@ -2618,12 +3294,22 @@ void CompilerHLSL::emit_hlsl_entry_point() }); // Run the shader. - if (execution.model == ExecutionModelVertex) - statement("vert_main();"); - else if (execution.model == ExecutionModelFragment) - statement("frag_main();"); - else if (execution.model == ExecutionModelGLCompute) - statement("comp_main();"); + if (execution.model == ExecutionModelVertex || + execution.model == ExecutionModelFragment || + execution.model == ExecutionModelGLCompute || + execution.model == ExecutionModelMeshEXT || + execution.model == ExecutionModelTaskEXT) + { + // For mesh shaders, we receive special arguments that we must pass down as function arguments. + // HLSL does not support proper reference types for passing these IO blocks, + // but DXC post-inlining seems to magically fix it up anyways *shrug*. + SmallVector arglist; + auto &func = get(ir.default_entry_point); + // The arguments are marked out, avoid detecting reads and emitting inout. + for (auto &arg : func.arguments) + arglist.push_back(to_expression(arg.id, false)); + statement(get_inner_entry_point_name(), "(", merge(arglist), ");"); + } else SPIRV_CROSS_THROW("Unsupported shader stage."); @@ -2634,8 +3320,8 @@ void CompilerHLSL::emit_hlsl_entry_point() // Copy builtins from globals to return struct. active_output_builtins.for_each_bit([&](uint32_t i) { - // PointSize doesn't exist in HLSL. - if (i == BuiltInPointSize) + // PointSize doesn't exist in HLSL SM 4+. + if (i == BuiltInPointSize && !legacy) return; switch (static_cast(i)) @@ -2652,6 +3338,10 @@ void CompilerHLSL::emit_hlsl_entry_point() cull, "];"); break; + case BuiltInSampleMask: + statement("stage_output.gl_SampleMask = gl_SampleMask[0];"); + break; + default: { auto builtin_expr = builtin_to_glsl(static_cast(i), StorageClassOutput); @@ -2712,7 +3402,7 @@ void CompilerHLSL::emit_hlsl_entry_point() void CompilerHLSL::emit_fixup() { - if (is_vertex_like_shader()) + if (is_vertex_like_shader() && active_output_builtins.get(BuiltInPosition)) { // Do various mangling on the gl_Position. if (hlsl_options.shader_model <= 30) @@ -2901,9 +3591,9 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse) else { auto &imgformat = get(imgtype.image.type); - if (imgformat.basetype != SPIRType::Float) + if (hlsl_options.shader_model < 67 && imgformat.basetype != SPIRType::Float) { - SPIRV_CROSS_THROW("Sampling non-float textures is not supported in HLSL."); + SPIRV_CROSS_THROW("Sampling non-float textures is not supported in HLSL SM < 6.7."); } if (hlsl_options.shader_model >= 40) @@ -2914,7 +3604,7 @@ void CompilerHLSL::emit_texture_op(const Instruction &i, bool sparse) { if (gather) { - SPIRV_CROSS_THROW("GatherCmp does not exist in HLSL."); + texop += ".GatherCmp"; } else if (lod || grad_x || grad_y) { @@ -3248,6 +3938,11 @@ string CompilerHLSL::to_resource_binding(const SPIRVariable &var) resource_flags = HLSL_BINDING_AUTO_SAMPLER_BIT; break; + case SPIRType::AccelerationStructure: + space = 't'; // SRV + resource_flags = HLSL_BINDING_AUTO_SRV_BIT; + break; + case SPIRType::Struct: { auto storage = type.storage; @@ -3483,6 +4178,18 @@ string CompilerHLSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &i } return "spvPackFloat2x16"; } + else if (out_type.basetype == SPIRType::UShort && in_type.basetype == SPIRType::Half) + { + if (hlsl_options.shader_model < 40) + SPIRV_CROSS_THROW("Half to UShort requires Shader Model 4."); + return "(" + type_to_glsl(out_type) + ")f32tof16"; + } + else if (out_type.basetype == SPIRType::Half && in_type.basetype == SPIRType::UShort) + { + if (hlsl_options.shader_model < 40) + SPIRV_CROSS_THROW("UShort to Half requires Shader Model 4."); + return "(" + type_to_glsl(out_type) + ")f16tof32"; + } else return ""; } @@ -3496,6 +4203,8 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, auto int_type = to_signed_basetype(integer_width); auto uint_type = to_unsigned_basetype(integer_width); + op = get_remapped_glsl_op(op); + switch (op) { case GLSLstd450InverseSqrt: @@ -3512,10 +4221,16 @@ void CompilerHLSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, emit_unary_func_op(result_type, id, args[0], "round"); break; + case GLSLstd450Trunc: + emit_unary_func_op(result_type, id, args[0], "trunc"); + break; + case GLSLstd450Acosh: case GLSLstd450Asinh: case GLSLstd450Atanh: - SPIRV_CROSS_THROW("Inverse hyperbolics are not supported on HLSL."); + // These are not supported in HLSL, always emulate them. + emit_emulated_ahyper_op(result_type, id, args[0], op); + break; case GLSLstd450FMix: case GLSLstd450IMix: @@ -3793,7 +4508,7 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR { auto &type = get(chain.basetype); - SPIRType target_type; + SPIRType target_type { is_scalar(type) ? OpTypeInt : type.op }; target_type.basetype = SPIRType::UInt; target_type.vecsize = type.vecsize; target_type.columns = type.columns; @@ -3968,7 +4683,7 @@ void CompilerHLSL::read_access_chain(string *expr, const string &lhs, const SPIR if (lhs.empty()) { assert(expr); - *expr = move(load_expr); + *expr = std::move(load_expr); } else statement(lhs, " = ", load_expr, ";"); @@ -4028,14 +4743,19 @@ void CompilerHLSL::emit_load(const Instruction &instruction) void CompilerHLSL::write_access_chain_array(const SPIRAccessChain &chain, uint32_t value, const SmallVector &composite_chain) { - auto &type = get(chain.basetype); + auto *ptype = &get(chain.basetype); + while (ptype->pointer) + { + ptype = &get(ptype->basetype); + } + auto &type = *ptype; // Need to use a reserved identifier here since it might shadow an identifier in the access chain input or other loops. auto ident = get_unique_identifier(); uint32_t id = ir.increase_bound_by(2); uint32_t int_type_id = id + 1; - SPIRType int_type; + SPIRType int_type { OpTypeInt }; int_type.basetype = SPIRType::Int; int_type.width = 32; set(int_type_id, int_type); @@ -4123,7 +4843,7 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val // Make sure we trigger a read of the constituents in the access chain. track_expression_read(chain.self); - SPIRType target_type; + SPIRType target_type { is_scalar(type) ? OpTypeInt : type.op }; target_type.basetype = SPIRType::UInt; target_type.vecsize = type.vecsize; target_type.columns = type.columns; @@ -4296,6 +5016,19 @@ void CompilerHLSL::write_access_chain(const SPIRAccessChain &chain, uint32_t val void CompilerHLSL::emit_store(const Instruction &instruction) { auto ops = stream(instruction); + if (options.vertex.flip_vert_y) + { + auto *expr = maybe_get(ops[0]); + if (expr != nullptr && expr->access_meshlet_position_y) + { + auto lhs = to_dereferenced_expression(ops[0]); + auto rhs = to_unpacked_expression(ops[1]); + statement(lhs, " = spvFlipVertY(", rhs, ");"); + register_write(ops[0]); + return; + } + } + auto *chain = maybe_get(ops[0]); if (chain) write_access_chain(*chain, ops[1], {}); @@ -4334,6 +5067,12 @@ void CompilerHLSL::emit_access_chain(const Instruction &instruction) auto *backing_variable = maybe_get_backing_variable(ops[2]); + if (backing_variable != nullptr && is_user_type_structured(backing_variable->self)) + { + CompilerGLSL::emit_instruction(instruction); + return; + } + string base; if (to_plain_buffer_length != 0) base = access_chain(ops[2], &ops[3], to_plain_buffer_length, get(ops[0])); @@ -4599,9 +5338,9 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i) case OpGroupNonUniformBallotBitCount: { auto operation = static_cast(ops[3]); + bool forward = should_forward(ops[4]); if (operation == GroupOperationReduce) { - bool forward = should_forward(ops[4]); auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x) + countbits(", to_enclosed_expression(ops[4]), ".y)"); auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z) + countbits(", @@ -4610,9 +5349,31 @@ void CompilerHLSL::emit_subgroup_op(const Instruction &i) inherit_expression_dependencies(id, ops[4]); } else if (operation == GroupOperationInclusiveScan) - SPIRV_CROSS_THROW("Cannot trivially implement BallotBitCount Inclusive Scan in HLSL."); + { + auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLeMask.x) + countbits(", + to_enclosed_expression(ops[4]), ".y & gl_SubgroupLeMask.y)"); + auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLeMask.z) + countbits(", + to_enclosed_expression(ops[4]), ".w & gl_SubgroupLeMask.w)"); + emit_op(result_type, id, join(left, " + ", right), forward); + if (!active_input_builtins.get(BuiltInSubgroupLeMask)) + { + active_input_builtins.set(BuiltInSubgroupLeMask); + force_recompile_guarantee_forward_progress(); + } + } else if (operation == GroupOperationExclusiveScan) - SPIRV_CROSS_THROW("Cannot trivially implement BallotBitCount Exclusive Scan in HLSL."); + { + auto left = join("countbits(", to_enclosed_expression(ops[4]), ".x & gl_SubgroupLtMask.x) + countbits(", + to_enclosed_expression(ops[4]), ".y & gl_SubgroupLtMask.y)"); + auto right = join("countbits(", to_enclosed_expression(ops[4]), ".z & gl_SubgroupLtMask.z) + countbits(", + to_enclosed_expression(ops[4]), ".w & gl_SubgroupLtMask.w)"); + emit_op(result_type, id, join(left, " + ", right), forward); + if (!active_input_builtins.get(BuiltInSubgroupLtMask)) + { + active_input_builtins.set(BuiltInSubgroupLtMask); + force_recompile_guarantee_forward_progress(); + } + } else SPIRV_CROSS_THROW("Invalid BitCount operation."); break; @@ -4749,7 +5510,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) #define HLSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op) #define HLSL_BOP_CAST(op, type) \ - emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode)) + emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode), false) #define HLSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op) #define HLSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op) #define HLSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op) @@ -4764,6 +5525,8 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) auto int_type = to_signed_basetype(integer_width); auto uint_type = to_unsigned_basetype(integer_width); + opcode = get_remapped_spirv_op(opcode); + switch (opcode) { case OpAccessChain: @@ -5314,7 +6077,7 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) image_format_to_components(get(var->basetype).image.format), imgexpr); } - if (var && var->forwardable) + if (var) { bool forward = forced_temporaries.find(id) == end(forced_temporaries); auto &e = emit_op(result_type, id, imgexpr, forward); @@ -5372,6 +6135,11 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) break; } + case OpAtomicFAddEXT: + case OpAtomicFMinEXT: + case OpAtomicFMaxEXT: + SPIRV_CROSS_THROW("Floating-point atomics are not supported in HLSL."); + case OpAtomicCompareExchange: case OpAtomicExchange: case OpAtomicISub: @@ -5558,7 +6326,12 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) } case OpIsHelperInvocationEXT: - SPIRV_CROSS_THROW("helperInvocationEXT() is not supported in HLSL."); + if (hlsl_options.shader_model < 50 || get_entry_point().model != ExecutionModelFragment) + SPIRV_CROSS_THROW("Helper Invocation input is only supported in PS 5.0 or higher."); + // Helper lane state with demote is volatile by nature. + // Do not forward this. + emit_op(ops[0], ops[1], "IsHelperLane()", false); + break; case OpBeginInvocationInterlockEXT: case OpEndInvocationInterlockEXT: @@ -5566,6 +6339,148 @@ void CompilerHLSL::emit_instruction(const Instruction &instruction) SPIRV_CROSS_THROW("Rasterizer order views require Shader Model 5.1."); break; // Nothing to do in the body + case OpRayQueryInitializeKHR: + { + flush_variable_declaration(ops[0]); + + std::string ray_desc_name = get_unique_identifier(); + statement("RayDesc ", ray_desc_name, " = {", to_expression(ops[4]), ", ", to_expression(ops[5]), ", ", + to_expression(ops[6]), ", ", to_expression(ops[7]), "};"); + + statement(to_expression(ops[0]), ".TraceRayInline(", + to_expression(ops[1]), ", ", // acc structure + to_expression(ops[2]), ", ", // ray flags + to_expression(ops[3]), ", ", // mask + ray_desc_name, ");"); // ray + break; + } + case OpRayQueryProceedKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".Proceed()"), false); + break; + } + case OpRayQueryTerminateKHR: + { + flush_variable_declaration(ops[0]); + statement(to_expression(ops[0]), ".Abort();"); + break; + } + case OpRayQueryGenerateIntersectionKHR: + { + flush_variable_declaration(ops[0]); + statement(to_expression(ops[0]), ".CommitProceduralPrimitiveHit(", to_expression(ops[1]), ");"); + break; + } + case OpRayQueryConfirmIntersectionKHR: + { + flush_variable_declaration(ops[0]); + statement(to_expression(ops[0]), ".CommitNonOpaqueTriangleHit();"); + break; + } + case OpRayQueryGetIntersectionTypeKHR: + { + emit_rayquery_function(".CommittedStatus()", ".CandidateType()", ops); + break; + } + case OpRayQueryGetIntersectionTKHR: + { + emit_rayquery_function(".CommittedRayT()", ".CandidateTriangleRayT()", ops); + break; + } + case OpRayQueryGetIntersectionInstanceCustomIndexKHR: + { + emit_rayquery_function(".CommittedInstanceID()", ".CandidateInstanceID()", ops); + break; + } + case OpRayQueryGetIntersectionInstanceIdKHR: + { + emit_rayquery_function(".CommittedInstanceIndex()", ".CandidateInstanceIndex()", ops); + break; + } + case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: + { + emit_rayquery_function(".CommittedInstanceContributionToHitGroupIndex()", + ".CandidateInstanceContributionToHitGroupIndex()", ops); + break; + } + case OpRayQueryGetIntersectionGeometryIndexKHR: + { + emit_rayquery_function(".CommittedGeometryIndex()", + ".CandidateGeometryIndex()", ops); + break; + } + case OpRayQueryGetIntersectionPrimitiveIndexKHR: + { + emit_rayquery_function(".CommittedPrimitiveIndex()", ".CandidatePrimitiveIndex()", ops); + break; + } + case OpRayQueryGetIntersectionBarycentricsKHR: + { + emit_rayquery_function(".CommittedTriangleBarycentrics()", ".CandidateTriangleBarycentrics()", ops); + break; + } + case OpRayQueryGetIntersectionFrontFaceKHR: + { + emit_rayquery_function(".CommittedTriangleFrontFace()", ".CandidateTriangleFrontFace()", ops); + break; + } + case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".CandidateProceduralPrimitiveNonOpaque()"), false); + break; + } + case OpRayQueryGetIntersectionObjectRayDirectionKHR: + { + emit_rayquery_function(".CommittedObjectRayDirection()", ".CandidateObjectRayDirection()", ops); + break; + } + case OpRayQueryGetIntersectionObjectRayOriginKHR: + { + flush_variable_declaration(ops[0]); + emit_rayquery_function(".CommittedObjectRayOrigin()", ".CandidateObjectRayOrigin()", ops); + break; + } + case OpRayQueryGetIntersectionObjectToWorldKHR: + { + emit_rayquery_function(".CommittedObjectToWorld4x3()", ".CandidateObjectToWorld4x3()", ops); + break; + } + case OpRayQueryGetIntersectionWorldToObjectKHR: + { + emit_rayquery_function(".CommittedWorldToObject4x3()", ".CandidateWorldToObject4x3()", ops); + break; + } + case OpRayQueryGetRayFlagsKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".RayFlags()"), false); + break; + } + case OpRayQueryGetRayTMinKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".RayTMin()"), false); + break; + } + case OpRayQueryGetWorldRayOriginKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".WorldRayOrigin()"), false); + break; + } + case OpRayQueryGetWorldRayDirectionKHR: + { + flush_variable_declaration(ops[0]); + emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".WorldRayDirection()"), false); + break; + } + case OpSetMeshOutputsEXT: + { + statement("SetMeshOutputCounts(", to_unpacked_expression(ops[0]), ", ", to_unpacked_expression(ops[1]), ");"); + break; + } default: CompilerGLSL::emit_instruction(instruction); break; @@ -5645,7 +6560,7 @@ void CompilerHLSL::require_texture_query_variant(uint32_t var_id) void CompilerHLSL::set_root_constant_layouts(std::vector layout) { - root_constants_layout = move(layout); + root_constants_layout = std::move(layout); } void CompilerHLSL::add_vertex_attribute_remap(const HLSLVertexAttributeRemap &vertex_attributes) @@ -5668,14 +6583,14 @@ VariableID CompilerHLSL::remap_num_workgroups_builtin() uint32_t block_pointer_type_id = offset + 2; uint32_t variable_id = offset + 3; - SPIRType uint_type; + SPIRType uint_type { OpTypeVector }; uint_type.basetype = SPIRType::UInt; uint_type.width = 32; uint_type.vecsize = 3; uint_type.columns = 1; set(uint_type_id, uint_type); - SPIRType block_type; + SPIRType block_type { OpTypeStruct }; block_type.basetype = SPIRType::Struct; block_type.member_types.push_back(uint_type_id); set(block_type_id, block_type); @@ -5766,10 +6681,13 @@ string CompilerHLSL::compile() backend.can_return_array = false; backend.nonuniform_qualifier = "NonUniformResourceIndex"; backend.support_case_fallthrough = false; + backend.force_merged_mesh_block = get_execution_model() == ExecutionModelMeshEXT; + backend.force_gl_in_out_block = backend.force_merged_mesh_block; // SM 4.1 does not support precise for some reason. backend.support_precise_qualifier = hlsl_options.shader_model >= 50 || hlsl_options.shader_model == 40; + fixup_anonymous_struct_names(); fixup_type_alias(); reorder_type_alias(); build_function_control_flow_graphs_and_analyze(); @@ -5777,6 +6695,8 @@ string CompilerHLSL::compile() update_active_builtins(); analyze_image_and_sampler_usage(); analyze_interlocked_resource_usage(); + if (get_execution_model() == ExecutionModelMeshEXT) + analyze_meshlet_writes(); // Subpass input needs SV_Position. if (need_subpass_input) @@ -5785,10 +6705,7 @@ string CompilerHLSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); // Move constructor for this type is broken on GCC 4.9 ... buffer.reset(); @@ -5881,7 +6798,16 @@ void CompilerHLSL::set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint3 force_uav_buffer_bindings.insert(pair); } -bool CompilerHLSL::builtin_translates_to_nonarray(spv::BuiltIn builtin) const +bool CompilerHLSL::is_user_type_structured(uint32_t id) const { - return (builtin == BuiltInSampleMask); + if (hlsl_options.preserve_structured_buffers) + { + // Compare left hand side of string only as these user types can contain more meta data such as their subtypes, + // e.g. "structuredbuffer:int" + const std::string &user_type = get_decoration_string(id, DecorationUserTypeGOOGLE); + return user_type.compare(0, 16, "structuredbuffer") == 0 || + user_type.compare(0, 18, "rwstructuredbuffer") == 0 || + user_type.compare(0, 33, "rasterizerorderedstructuredbuffer") == 0; + } + return false; } diff --git a/src/libraries/spirv_cross/spirv_hlsl.hpp b/src/libraries/spirv_cross/spirv_hlsl.hpp index 54a49dafa..bec458c61 100644 --- a/src/libraries/spirv_cross/spirv_hlsl.hpp +++ b/src/libraries/spirv_cross/spirv_hlsl.hpp @@ -98,6 +98,11 @@ struct HLSLResourceBinding } cbv, uav, srv, sampler; }; +enum HLSLAuxBinding +{ + HLSL_AUX_BINDING_BASE_VERTEX_INSTANCE = 0 +}; + class CompilerHLSL : public CompilerGLSL { public: @@ -105,7 +110,7 @@ public: { uint32_t shader_model = 30; // TODO: map ps_4_0_level_9_0,... somehow - // Allows the PointSize builtin, and ignores it, as PointSize is not supported in HLSL. + // Allows the PointSize builtin in SM 4.0+, and ignores it, as PointSize is not supported in SM 4+. bool point_size_compat = false; // Allows the PointCoord builtin, returns float2(0.5, 0.5), as PointCoord is not supported in HLSL. @@ -121,7 +126,7 @@ public: // By default, a readonly storage buffer will be declared as ByteAddressBuffer (SRV) instead. // Alternatively, use set_hlsl_force_storage_buffer_as_uav to specify individually. bool force_storage_buffer_as_uav = false; - + // Forces any storage image type marked as NonWritable to be considered an SRV instead. // For this to work with function call parameters, NonWritable must be considered to be part of the type system // so that NonWritable image arguments are also translated to Texture rather than RWTexture. @@ -137,6 +142,14 @@ public: // If add_vertex_attribute_remap is used and this feature is used, // the semantic name will be queried once per active location. bool flatten_matrix_vertex_input_semantics = false; + + // Rather than emitting main() for the entry point, use the name in SPIR-V. + bool use_entry_point_name = false; + + // Preserve (RW)StructuredBuffer types if the input source was HLSL. + // This relies on UserTypeGOOGLE to encode the buffer type either as "structuredbuffer" or "rwstructuredbuffer" + // whereas the type can be extended with an optional subtype, e.g. "structuredbuffer:int". + bool preserve_structured_buffers = false; }; explicit CompilerHLSL(std::vector spirv_) @@ -208,6 +221,11 @@ public: // Controls which storage buffer bindings will be forced to be declared as UAVs. void set_hlsl_force_storage_buffer_as_uav(uint32_t desc_set, uint32_t binding); + // By default, these magic buffers are not assigned a specific binding. + void set_hlsl_aux_buffer_binding(HLSLAuxBinding binding, uint32_t register_index, uint32_t register_space); + void unset_hlsl_aux_buffer_binding(HLSLAuxBinding binding); + bool is_hlsl_aux_buffer_binding_used(HLSLAuxBinding binding) const; + private: std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; std::string image_type_hlsl(const SPIRType &type, uint32_t id); @@ -217,14 +235,13 @@ private: void emit_hlsl_entry_point(); void emit_header() override; void emit_resources(); - void declare_undefined_values() override; void emit_interface_block_globally(const SPIRVariable &type); void emit_interface_block_in_struct(const SPIRVariable &var, std::unordered_set &active_locations); - void emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index, - uint32_t location, + void emit_interface_block_member_in_struct(const SPIRVariable &var, uint32_t member_index, uint32_t location, std::unordered_set &active_locations); void emit_builtin_inputs_in_struct(); void emit_builtin_outputs_in_struct(); + void emit_builtin_primitive_outputs_in_struct(); void emit_texture_op(const Instruction &i, bool sparse) override; void emit_instruction(const Instruction &instruction) override; void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, @@ -267,10 +284,14 @@ private: void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier, uint32_t base_offset = 0) override; + void emit_rayquery_function(const char *commited, const char *candidate, const uint32_t *ops); + void emit_mesh_tasks(SPIRBlock &block) override; const char *to_storage_qualifiers_glsl(const SPIRVariable &var) override; void replace_illegal_names() override; + SPIRType::BaseType get_builtin_basetype(spv::BuiltIn builtin, SPIRType::BaseType default_type) override; + bool is_hlsl_force_storage_buffer_as_uav(ID id) const; Options hlsl_options; @@ -341,6 +362,10 @@ private: TypeUnpackUint64 }; + void analyze_meshlet_writes(); + void analyze_meshlet_writes(uint32_t func_id, uint32_t id_per_vertex, uint32_t id_per_primitive, + std::unordered_set &processed_func_ids); + BitcastType get_bitcast_type(uint32_t result_type, uint32_t op0); void emit_builtin_variables(); @@ -369,10 +394,20 @@ private: std::unordered_set force_uav_buffer_bindings; - // Returns true for BuiltInSampleMask because gl_SampleMask[] is an array in SPIR-V, but SV_Coverage is a scalar in HLSL. - bool builtin_translates_to_nonarray(spv::BuiltIn builtin) const override; + struct + { + uint32_t register_index = 0; + uint32_t register_space = 0; + bool explicit_binding = false; + bool used = false; + } base_vertex_info; + + // Returns true if the specified ID has a UserTypeGOOGLE decoration for StructuredBuffer or RWStructuredBuffer resources. + bool is_user_type_structured(uint32_t id) const override; std::vector composite_selection_workaround_types; + + std::string get_inner_entry_point_name() const; }; } // namespace SPIRV_CROSS_NAMESPACE diff --git a/src/libraries/spirv_cross/spirv_msl.cpp b/src/libraries/spirv_cross/spirv_msl.cpp index ffa69bfe7..200167a2e 100644 --- a/src/libraries/spirv_cross/spirv_msl.cpp +++ b/src/libraries/spirv_cross/spirv_msl.cpp @@ -37,7 +37,7 @@ static const uint32_t k_unknown_component = ~0u; static const char *force_inline = "static inline __attribute__((always_inline))"; CompilerMSL::CompilerMSL(std::vector spirv_) - : CompilerGLSL(move(spirv_)) + : CompilerGLSL(std::move(spirv_)) { } @@ -56,13 +56,20 @@ CompilerMSL::CompilerMSL(ParsedIR &&ir_) { } -void CompilerMSL::add_msl_shader_input(const MSLShaderInput &si) +void CompilerMSL::add_msl_shader_input(const MSLShaderInterfaceVariable &si) { inputs_by_location[{si.location, si.component}] = si; if (si.builtin != BuiltInMax && !inputs_by_builtin.count(si.builtin)) inputs_by_builtin[si.builtin] = si; } +void CompilerMSL::add_msl_shader_output(const MSLShaderInterfaceVariable &so) +{ + outputs_by_location[{so.location, so.component}] = so; + if (so.builtin != BuiltInMax && !outputs_by_builtin.count(so.builtin)) + outputs_by_builtin[so.builtin] = so; +} + void CompilerMSL::add_msl_resource_binding(const MSLResourceBinding &binding) { StageSetBinding tuple = { binding.stage, binding.desc_set, binding.binding }; @@ -150,6 +157,13 @@ bool CompilerMSL::is_msl_shader_input_used(uint32_t location) location_inputs_in_use_fallback.count(location) == 0; } +bool CompilerMSL::is_msl_shader_output_used(uint32_t location) +{ + // Don't report internal location allocations to app. + return location_outputs_in_use.count(location) != 0 && + location_outputs_in_use_fallback.count(location) == 0; +} + uint32_t CompilerMSL::get_automatic_builtin_input_location(spv::BuiltIn builtin) const { auto itr = builtin_to_automatic_input_location.find(builtin); @@ -159,6 +173,15 @@ uint32_t CompilerMSL::get_automatic_builtin_input_location(spv::BuiltIn builtin) return itr->second; } +uint32_t CompilerMSL::get_automatic_builtin_output_location(spv::BuiltIn builtin) const +{ + auto itr = builtin_to_automatic_output_location.find(builtin); + if (itr == builtin_to_automatic_output_location.end()) + return k_unknown_location; + else + return itr->second; +} + bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t desc_set, uint32_t binding) const { StageSetBinding tuple = { model, desc_set, binding }; @@ -166,10 +189,21 @@ bool CompilerMSL::is_msl_resource_binding_used(ExecutionModel model, uint32_t de return itr != end(resource_bindings) && itr->second.second; } -// Returns the size of the array of resources used by the variable with the specified id. -// The returned value is retrieved from the resource binding added using add_msl_resource_binding(). -uint32_t CompilerMSL::get_resource_array_size(uint32_t id) const +bool CompilerMSL::is_var_runtime_size_array(const SPIRVariable &var) const { + auto& type = get_variable_data_type(var); + return is_runtime_size_array(type) && get_resource_array_size(type, var.self) == 0; +} + +// Returns the size of the array of resources used by the variable with the specified type and id. +// The size is first retrieved from the type, but in the case of runtime array sizing, +// the size is retrieved from the resource binding added using add_msl_resource_binding(). +uint32_t CompilerMSL::get_resource_array_size(const SPIRType &type, uint32_t id) const +{ + uint32_t array_size = to_array_size_literal(type); + if (array_size) + return array_size; + StageSetBinding tuple = { get_entry_point().model, get_decoration(id, DecorationDescriptorSet), get_decoration(id, DecorationBinding) }; auto itr = resource_bindings.find(tuple); @@ -211,7 +245,8 @@ void CompilerMSL::build_implicit_builtins() bool need_sample_pos = active_input_builtins.get(BuiltInSamplePosition); bool need_vertex_params = capture_output_to_buffer && get_execution_model() == ExecutionModelVertex && !msl_options.vertex_for_tessellation; - bool need_tesc_params = get_execution_model() == ExecutionModelTessellationControl; + bool need_tesc_params = is_tesc_shader(); + bool need_tese_params = is_tese_shader() && msl_options.raw_buffer_tese_input; bool need_subgroup_mask = active_input_builtins.get(BuiltInSubgroupEqMask) || active_input_builtins.get(BuiltInSubgroupGeMask) || active_input_builtins.get(BuiltInSubgroupGtMask) || active_input_builtins.get(BuiltInSubgroupLeMask) || @@ -234,9 +269,9 @@ void CompilerMSL::build_implicit_builtins() bool need_workgroup_size = msl_options.emulate_subgroups && active_input_builtins.get(BuiltInNumSubgroups); if (need_subpass_input || need_sample_pos || need_subgroup_mask || need_vertex_params || need_tesc_params || - need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params || needs_sample_id || - needs_subgroup_invocation_id || needs_subgroup_size || has_additional_fixed_sample_mask() || need_local_invocation_index || - need_workgroup_size) + need_tese_params || need_multiview || need_dispatch_base || need_vertex_base_params || need_grid_params || + needs_sample_id || needs_subgroup_invocation_id || needs_subgroup_size || needs_helper_invocation || + has_additional_fixed_sample_mask() || need_local_invocation_index || need_workgroup_size) { bool has_frag_coord = false; bool has_sample_id = false; @@ -250,6 +285,7 @@ void CompilerMSL::build_implicit_builtins() bool has_subgroup_size = false; bool has_view_idx = false; bool has_layer = false; + bool has_helper_invocation = false; bool has_local_invocation_index = false; bool has_workgroup_size = false; uint32_t workgroup_id_type = 0; @@ -342,23 +378,28 @@ void CompilerMSL::build_implicit_builtins() } } - if (need_tesc_params) + if (need_tesc_params && builtin == BuiltInInvocationId) { - switch (builtin) - { - case BuiltInInvocationId: - builtin_invocation_id_id = var.self; - mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self); - has_invocation_id = true; - break; - case BuiltInPrimitiveId: - builtin_primitive_id_id = var.self; - mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self); - has_primitive_id = true; - break; - default: - break; - } + builtin_invocation_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var.self); + has_invocation_id = true; + } + + if ((need_tesc_params || need_tese_params) && builtin == BuiltInPrimitiveId) + { + builtin_primitive_id_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInPrimitiveId, var.self); + has_primitive_id = true; + } + + if (need_tese_params && builtin == BuiltInTessLevelOuter) + { + tess_level_outer_var_id = var.self; + } + + if (need_tese_params && builtin == BuiltInTessLevelInner) + { + tess_level_inner_var_id = var.self; } if ((need_subgroup_mask || needs_subgroup_invocation_id) && builtin == BuiltInSubgroupLocalInvocationId) @@ -401,6 +442,13 @@ void CompilerMSL::build_implicit_builtins() } } + if (needs_helper_invocation && builtin == BuiltInHelperInvocation) + { + builtin_helper_invocation_id = var.self; + mark_implicit_builtin(StorageClassInput, BuiltInHelperInvocation, var.self); + has_helper_invocation = true; + } + if (need_local_invocation_index && builtin == BuiltInLocalInvocationIndex) { builtin_local_invocation_index_id = var.self; @@ -436,14 +484,14 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 2; // Create gl_FragCoord. - SPIRType vec4_type; + SPIRType vec4_type { OpTypeVector }; vec4_type.basetype = SPIRType::Float; vec4_type.width = 32; vec4_type.vecsize = 4; set(type_id, vec4_type); - SPIRType vec4_type_ptr; - vec4_type_ptr = vec4_type; + SPIRType vec4_type_ptr = vec4_type; + vec4_type_ptr.op = OpTypePointer; vec4_type_ptr.pointer = true; vec4_type_ptr.pointer_depth++; vec4_type_ptr.parent_type = type_id; @@ -464,8 +512,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_Layer. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -486,8 +534,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_ViewIndex. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -509,8 +557,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_SampleID. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -529,8 +577,8 @@ void CompilerMSL::build_implicit_builtins() { uint32_t type_ptr_id = ir.increase_bound_by(1); - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -589,8 +637,8 @@ void CompilerMSL::build_implicit_builtins() // Note that we can't just abuse gl_ViewIndex for this purpose: it's an input, but // gl_Layer is an output in vertex-pipeline shaders. uint32_t type_ptr_out_id = ir.increase_bound_by(2); - SPIRType uint_type_ptr_out; - uint_type_ptr_out = get_uint_type(); + SPIRType uint_type_ptr_out = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr_out.pointer = true; uint_type_ptr_out.pointer_depth++; uint_type_ptr_out.parent_type = get_uint_type_id(); @@ -617,12 +665,12 @@ void CompilerMSL::build_implicit_builtins() } if ((need_tesc_params && (msl_options.multi_patch_workgroup || !has_invocation_id || !has_primitive_id)) || - need_grid_params) + (need_tese_params && !has_primitive_id) || need_grid_params) { uint32_t type_ptr_id = ir.increase_bound_by(1); - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -630,7 +678,7 @@ void CompilerMSL::build_implicit_builtins() auto &ptr_type = set(type_ptr_id, uint_type_ptr); ptr_type.self = get_uint_type_id(); - if (msl_options.multi_patch_workgroup || need_grid_params) + if ((need_tesc_params && msl_options.multi_patch_workgroup) || need_grid_params) { uint32_t var_id = ir.increase_bound_by(1); @@ -651,7 +699,7 @@ void CompilerMSL::build_implicit_builtins() mark_implicit_builtin(StorageClassInput, BuiltInInvocationId, var_id); } - if (need_tesc_params && !has_primitive_id) + if ((need_tesc_params || need_tese_params) && !has_primitive_id) { uint32_t var_id = ir.increase_bound_by(1); @@ -681,8 +729,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_SubgroupInvocationID. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -703,8 +751,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_SubgroupSize. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -762,8 +810,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_SampleMask. - SPIRType uint_type_ptr_out; - uint_type_ptr_out = get_uint_type(); + SPIRType uint_type_ptr_out = get_uint_type(); + uint_type_ptr_out.op = OpTypePointer; uint_type_ptr_out.pointer = true; uint_type_ptr_out.pointer_depth++; uint_type_ptr_out.parent_type = get_uint_type_id(); @@ -777,6 +825,35 @@ void CompilerMSL::build_implicit_builtins() mark_implicit_builtin(StorageClassOutput, BuiltInSampleMask, var_id); } + if (!has_helper_invocation && needs_helper_invocation) + { + uint32_t offset = ir.increase_bound_by(3); + uint32_t type_id = offset; + uint32_t type_ptr_id = offset + 1; + uint32_t var_id = offset + 2; + + // Create gl_HelperInvocation. + SPIRType bool_type { OpTypeBool }; + bool_type.basetype = SPIRType::Boolean; + bool_type.width = 8; + bool_type.vecsize = 1; + set(type_id, bool_type); + + SPIRType bool_type_ptr_in = bool_type; + bool_type_ptr_in.op = spv::OpTypePointer; + bool_type_ptr_in.pointer = true; + bool_type_ptr_in.pointer_depth++; + bool_type_ptr_in.parent_type = type_id; + bool_type_ptr_in.storage = StorageClassInput; + + auto &ptr_in_type = set(type_ptr_id, bool_type_ptr_in); + ptr_in_type.self = type_id; + set(var_id, type_ptr_id, StorageClassInput); + set_decoration(var_id, DecorationBuiltIn, BuiltInHelperInvocation); + builtin_helper_invocation_id = var_id; + mark_implicit_builtin(StorageClassInput, BuiltInHelperInvocation, var_id); + } + if (need_local_invocation_index && !has_local_invocation_index) { uint32_t offset = ir.increase_bound_by(2); @@ -784,8 +861,8 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 1; // Create gl_LocalInvocationIndex. - SPIRType uint_type_ptr; - uint_type_ptr = get_uint_type(); + SPIRType uint_type_ptr = get_uint_type(); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = get_uint_type_id(); @@ -808,6 +885,7 @@ void CompilerMSL::build_implicit_builtins() // Create gl_WorkgroupSize. uint32_t type_id = build_extended_vector_type(get_uint_type_id(), 3); SPIRType uint_type_ptr = get(type_id); + uint_type_ptr.op = OpTypePointer; uint_type_ptr.pointer = true; uint_type_ptr.pointer_depth++; uint_type_ptr.parent_type = type_id; @@ -833,7 +911,7 @@ void CompilerMSL::build_implicit_builtins() swizzle_buffer_id = var_id; } - if (!buffers_requiring_array_length.empty()) + if (needs_buffer_size_buffer()) { uint32_t var_id = build_constant_uint_array_pointer(); set_name(var_id, "spvBufferSizeConstants"); @@ -868,11 +946,9 @@ void CompilerMSL::build_implicit_builtins() } // If we're returning a struct from a vertex-like entry point, we must return a position attribute. - bool need_position = - (get_execution_model() == ExecutionModelVertex || - get_execution_model() == ExecutionModelTessellationEvaluation) && - !capture_output_to_buffer && !get_is_rasterization_disabled() && - !active_output_builtins.get(BuiltInPosition); + bool need_position = (get_execution_model() == ExecutionModelVertex || is_tese_shader()) && + !capture_output_to_buffer && !get_is_rasterization_disabled() && + !active_output_builtins.get(BuiltInPosition); if (need_position) { @@ -917,14 +993,14 @@ void CompilerMSL::build_implicit_builtins() uint32_t var_id = offset + 2; // Create gl_Position. - SPIRType vec4_type; + SPIRType vec4_type { OpTypeVector }; vec4_type.basetype = SPIRType::Float; vec4_type.width = 32; vec4_type.vecsize = 4; set(type_id, vec4_type); - SPIRType vec4_type_ptr; - vec4_type_ptr = vec4_type; + SPIRType vec4_type_ptr = vec4_type; + vec4_type_ptr.op = OpTypePointer; vec4_type_ptr.pointer = true; vec4_type_ptr.pointer_depth++; vec4_type_ptr.parent_type = type_id; @@ -1001,6 +1077,7 @@ uint32_t CompilerMSL::build_constant_uint_array_pointer() // Create a buffer to hold extra data, including the swizzle constants. SPIRType uint_type_pointer = get_uint_type(); + uint_type_pointer.op = OpTypePointer; uint_type_pointer.pointer = true; uint_type_pointer.pointer_depth++; uint_type_pointer.parent_type = get_uint_type_id(); @@ -1062,7 +1139,7 @@ SPIRType &CompilerMSL::get_patch_stage_out_struct_type() std::string CompilerMSL::get_tess_factor_struct_name() { - if (get_entry_point().flags.get(ExecutionModeTriangles)) + if (is_tessellating_triangles()) return "MTLTriangleTessellationFactorsHalf"; return "MTLQuadTessellationFactorsHalf"; } @@ -1079,7 +1156,7 @@ uint32_t CompilerMSL::get_uint_type_id() uint_type_id = ir.increase_bound_by(1); - SPIRType type; + SPIRType type { OpTypeInt }; type.basetype = SPIRType::UInt; type.width = 32; set(uint_type_id, type); @@ -1205,8 +1282,7 @@ void CompilerMSL::emit_entry_point_declarations() args.push_back(join("max_anisotropy(", s.max_anisotropy, ")")); if (s.lod_clamp_enable) { - args.push_back(join("lod_clamp(", convert_to_string(s.lod_clamp_min, current_locale_radix_character), ", ", - convert_to_string(s.lod_clamp_max, current_locale_radix_character), ")")); + args.push_back(join("lod_clamp(", format_float(s.lod_clamp_min), ", ", format_float(s.lod_clamp_max), ")")); } // If we would emit no arguments, then omit the parentheses entirely. Otherwise, @@ -1248,7 +1324,7 @@ void CompilerMSL::emit_entry_point_declarations() else { is_using_builtin_array = true; - statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id), name, + statement(get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id, true), name, type_to_array_glsl(type), " ="); uint32_t dim = uint32_t(type.array.size()); @@ -1283,30 +1359,111 @@ void CompilerMSL::emit_entry_point_declarations() } else { - statement(get_argument_address_space(var), " auto& ", to_restrict(var_id), name, " = *(", + statement(get_argument_address_space(var), " auto& ", to_restrict(var_id, true), name, " = *(", get_argument_address_space(var), " ", type_to_glsl(type), "* ", to_restrict(var_id, false), ")((", get_argument_address_space(var), " char* ", to_restrict(var_id, false), ")", to_name(arg_id), ".", ensure_valid_name(name, "m"), " + ", to_name(dynamic_offsets_buffer_id), "[", base_index, "]);"); } } - // Emit buffer arrays here. - for (uint32_t array_id : buffer_arrays) + bool has_runtime_array_declaration = false; + for (SPIRVariable *arg : entry_point_bindings) { - const auto &var = get(array_id); + const auto &var = *arg; const auto &type = get_variable_data_type(var); const auto &buffer_type = get_variable_element_type(var); - string name = to_name(array_id); - statement(get_argument_address_space(var), " ", type_to_glsl(buffer_type), "* ", to_restrict(array_id), name, - "[] ="); - begin_scope(); - for (uint32_t i = 0; i < to_array_size_literal(type); ++i) - statement(name, "_", i, ","); - end_scope_decl(); - statement_no_indent(""); + const string name = to_name(var.self); + if (is_var_runtime_size_array(var)) + { + if (msl_options.argument_buffers_tier < Options::ArgumentBuffersTier::Tier2) + { + SPIRV_CROSS_THROW("Unsized array of descriptors requires argument buffer tier 2"); + } + switch (type.basetype) + { + case SPIRType::Image: + case SPIRType::Sampler: + case SPIRType::AccelerationStructure: + statement("spvDescriptorArray<", type_to_glsl(buffer_type), "> ", name, " {", name, "_};"); + break; + case SPIRType::SampledImage: + statement("spvDescriptorArray<", type_to_glsl(buffer_type), "> ", name, " {", name, "_};"); + statement("spvDescriptorArray ", name, "Smplr {", name, "Smplr_};"); + break; + case SPIRType::Struct: + statement("spvDescriptorArray<", get_argument_address_space(var), " ", type_to_glsl(buffer_type), "*> ", + name, " {", name, "_};"); + break; + default: + break; + } + has_runtime_array_declaration = true; + } + else if (!type.array.empty() && type.basetype == SPIRType::Struct) + { + // Emit only buffer arrays here. + statement(get_argument_address_space(var), " ", type_to_glsl(buffer_type), "* ", + to_restrict(var.self, true), name, "[] ="); + begin_scope(); + uint32_t array_size = get_resource_array_size(type, var.self); + for (uint32_t i = 0; i < array_size; ++i) + statement(name, "_", i, ","); + end_scope_decl(); + statement_no_indent(""); + } + } + + if (has_runtime_array_declaration) + statement_no_indent(""); + + // Emit buffer aliases here. + for (auto &var_id : buffer_aliases_discrete) + { + const auto &var = get(var_id); + const auto &type = get_variable_data_type(var); + auto addr_space = get_argument_address_space(var); + auto name = to_name(var_id); + + uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); + uint32_t desc_binding = get_decoration(var_id, DecorationBinding); + auto alias_name = join("spvBufferAliasSet", desc_set, "Binding", desc_binding); + + statement(addr_space, " auto& ", to_restrict(var_id, true), + name, + " = *(", addr_space, " ", type_to_glsl(type), "*)", alias_name, ";"); + } + // Discrete descriptors are processed in entry point emission every compiler iteration. + buffer_aliases_discrete.clear(); + + for (auto &var_pair : buffer_aliases_argument) + { + uint32_t var_id = var_pair.first; + uint32_t alias_id = var_pair.second; + + const auto &var = get(var_id); + const auto &type = get_variable_data_type(var); + auto addr_space = get_argument_address_space(var); + + if (type.array.empty()) + { + statement(addr_space, " auto& ", to_restrict(var_id, true), to_name(var_id), " = (", addr_space, " ", + type_to_glsl(type), "&)", ir.meta[alias_id].decoration.qualified_alias, ";"); + } + else + { + const char *desc_addr_space = descriptor_address_space(var_id, var.storage, "thread"); + + // Esoteric type cast. Reference to array of pointers. + // Auto here defers to UBO or SSBO. The address space of the reference needs to refer to the + // address space of the argument buffer itself, which is usually constant, but can be const device for + // large argument buffers. + is_using_builtin_array = true; + statement(desc_addr_space, " auto& ", to_restrict(var_id, true), to_name(var_id), " = (", addr_space, " ", + type_to_glsl(type), "* ", desc_addr_space, " (&)", + type_to_array_glsl(type), ")", ir.meta[alias_id].decoration.qualified_alias, ";"); + is_using_builtin_array = false; + } } - // For some reason, without this, we end up emitting the arrays twice. - buffer_arrays.clear(); // Emit disabled fragment outputs. std::sort(disabled_frag_outputs.begin(), disabled_frag_outputs.end()); @@ -1314,7 +1471,7 @@ void CompilerMSL::emit_entry_point_declarations() { auto &var = get(var_id); add_local_variable_name(var_id); - statement(variable_decl(var), ";"); + statement(CompilerGLSL::variable_decl(var), ";"); var.deferred_declaration = false; } } @@ -1339,8 +1496,6 @@ string CompilerMSL::compile() backend.basic_uint8_type = "uchar"; backend.basic_int16_type = "short"; backend.basic_uint16_type = "ushort"; - backend.discard_literal = "discard_fragment()"; - backend.demote_literal = "discard_fragment()"; backend.boolean_mix_function = "select"; backend.swizzle_is_function = false; backend.shared_is_implied = false; @@ -1356,13 +1511,15 @@ string CompilerMSL::compile() backend.support_small_type_sampling_result = true; backend.supports_empty_struct = true; backend.support_64bit_switch = true; + backend.boolean_in_struct_remapped_type = SPIRType::Short; // Allow Metal to use the array template unless we force it off. backend.can_return_array = !msl_options.force_native_arrays; backend.array_is_value_type = !msl_options.force_native_arrays; - // Arrays which are part of buffer objects are never considered to be native arrays. - backend.buffer_offset_array_is_value_type = false; + // Arrays which are part of buffer objects are never considered to be value types (just plain C-style). + backend.array_is_value_type_in_buffer_blocks = false; backend.support_pointer_to_pointer = true; + backend.implicit_c_integer_promotion_rules = true; capture_output_to_buffer = msl_options.capture_output_to_buffer; is_rasterization_disabled = msl_options.disable_rasterization || capture_output_to_buffer; @@ -1371,6 +1528,7 @@ string CompilerMSL::compile() for (auto &id : next_metal_resource_ids) id = 0; + fixup_anonymous_struct_names(); fixup_type_alias(); replace_illegal_names(); sync_entry_point_aliases_and_names(); @@ -1383,6 +1541,20 @@ string CompilerMSL::compile() preprocess_op_codes(); build_implicit_builtins(); + if (needs_manual_helper_invocation_updates() && + (active_input_builtins.get(BuiltInHelperInvocation) || needs_helper_invocation)) + { + string discard_expr = + join(builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput), " = true, discard_fragment()"); + backend.discard_literal = discard_expr; + backend.demote_literal = discard_expr; + } + else + { + backend.discard_literal = "discard_fragment()"; + backend.demote_literal = "discard_fragment()"; + } + fixup_image_load_store_access(); set_enabled_interface_variables(get_active_interface_variables()); @@ -1390,19 +1562,19 @@ string CompilerMSL::compile() activate_argument_buffer_resources(); if (swizzle_buffer_id) - active_interface_variables.insert(swizzle_buffer_id); + add_active_interface_variable(swizzle_buffer_id); if (buffer_size_buffer_id) - active_interface_variables.insert(buffer_size_buffer_id); + add_active_interface_variable(buffer_size_buffer_id); if (view_mask_buffer_id) - active_interface_variables.insert(view_mask_buffer_id); + add_active_interface_variable(view_mask_buffer_id); if (dynamic_offsets_buffer_id) - active_interface_variables.insert(dynamic_offsets_buffer_id); + add_active_interface_variable(dynamic_offsets_buffer_id); if (builtin_layer_id) - active_interface_variables.insert(builtin_layer_id); + add_active_interface_variable(builtin_layer_id); if (builtin_dispatch_base_id && !msl_options.supports_msl_version(1, 2)) - active_interface_variables.insert(builtin_dispatch_base_id); + add_active_interface_variable(builtin_dispatch_base_id); if (builtin_sample_mask_id) - active_interface_variables.insert(builtin_sample_mask_id); + add_active_interface_variable(builtin_sample_mask_id); // Create structs to hold input, output and uniform variables. // Do output first to ensure out. is declared at top of entry function. @@ -1410,10 +1582,10 @@ string CompilerMSL::compile() stage_out_var_id = add_interface_block(StorageClassOutput); patch_stage_out_var_id = add_interface_block(StorageClassOutput, true); stage_in_var_id = add_interface_block(StorageClassInput); - if (get_execution_model() == ExecutionModelTessellationEvaluation) + if (is_tese_shader()) patch_stage_in_var_id = add_interface_block(StorageClassInput, true); - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader()) stage_out_ptr_var_id = add_interface_block_pointer(stage_out_var_id, StorageClassOutput); if (is_tessellation_shader()) stage_in_ptr_var_id = add_interface_block_pointer(stage_in_var_id, StorageClassInput); @@ -1446,10 +1618,7 @@ string CompilerMSL::compile() uint32_t pass_count = 0; do { - if (pass_count >= 3) - SPIRV_CROSS_THROW("Over 3 compilation loops detected. Must be a bug!"); - - reset(); + reset(pass_count); // Start bindings at zero. next_metal_resource_index_buffer = 0; @@ -1490,13 +1659,13 @@ void CompilerMSL::preprocess_op_codes() // Before MSL 2.1 (2.2 for textures), Metal vertex functions that write to // resources must disable rasterization and return void. - if (preproc.uses_resource_write) + if ((preproc.uses_buffer_write && !msl_options.supports_msl_version(2, 1)) || + (preproc.uses_image_write && !msl_options.supports_msl_version(2, 2))) is_rasterization_disabled = true; // Tessellation control shaders are run as compute functions in Metal, and so // must capture their output to a buffer. - if (get_execution_model() == ExecutionModelTessellationControl || - (get_execution_model() == ExecutionModelVertex && msl_options.vertex_for_tessellation)) + if (is_tesc_shader() || (get_execution_model() == ExecutionModelVertex && msl_options.vertex_for_tessellation)) { is_rasterization_disabled = true; capture_output_to_buffer = true; @@ -1511,8 +1680,29 @@ void CompilerMSL::preprocess_op_codes() // that function would add gl_FragCoord. if (preproc.needs_sample_id || msl_options.force_sample_rate_shading || (is_sample_rate() && (active_input_builtins.get(BuiltInFragCoord) || - (need_subpass_input && !msl_options.use_framebuffer_fetch_subpasses)))) + (need_subpass_input_ms && !msl_options.use_framebuffer_fetch_subpasses)))) needs_sample_id = true; + if (preproc.needs_helper_invocation) + needs_helper_invocation = true; + + // OpKill is removed by the parser, so we need to identify those by inspecting + // blocks. + ir.for_each_typed_id([&preproc](uint32_t, SPIRBlock &block) { + if (block.terminator == SPIRBlock::Kill) + preproc.uses_discard = true; + }); + + // Fragment shaders that both write to storage resources and discard fragments + // need checks on the writes, to work around Metal allowing these writes despite + // the fragment being dead. + if (msl_options.check_discarded_frag_stores && preproc.uses_discard && + (preproc.uses_buffer_write || preproc.uses_image_write)) + { + frag_shader_needs_discard_checks = true; + needs_helper_invocation = true; + // Fragment discard store checks imply manual HelperInvocation updates. + msl_options.manual_helper_invocation_updates = true; + } if (is_intersection_query()) { @@ -1551,6 +1741,30 @@ void CompilerMSL::extract_global_variables_from_functions() // Uniforms unordered_set global_var_ids; ir.for_each_typed_id([&](uint32_t, SPIRVariable &var) { + // Some builtins resolve directly to a function call which does not need any declared variables. + // Skip these. + if (var.storage == StorageClassInput && has_decoration(var.self, DecorationBuiltIn)) + { + auto bi_type = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); + if (bi_type == BuiltInHelperInvocation && !needs_manual_helper_invocation_updates()) + return; + if (bi_type == BuiltInHelperInvocation && needs_manual_helper_invocation_updates()) + { + if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS."); + else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); + // Make sure this is declared and initialized. + // Force this to have the proper name. + set_name(var.self, builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput)); + auto &entry_func = this->get(ir.default_entry_point); + entry_func.add_local_variable(var.self); + vars_needing_early_declaration.push_back(var.self); + entry_func.fixup_hooks_in.push_back([this, &var]() + { statement(to_name(var.self), " = simd_is_helper_thread();"); }); + } + } + if (var.storage == StorageClassInput || var.storage == StorageClassOutput || var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) @@ -1664,6 +1878,9 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: if (global_var_ids.find(rvalue_id) != global_var_ids.end()) added_arg_ids.insert(rvalue_id); + if (needs_frag_discard_checks()) + added_arg_ids.insert(builtin_helper_invocation_id); + break; } @@ -1678,14 +1895,46 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: break; } + case OpAtomicExchange: + case OpAtomicCompareExchange: + case OpAtomicStore: + case OpAtomicIIncrement: + case OpAtomicIDecrement: + case OpAtomicIAdd: + case OpAtomicFAddEXT: + case OpAtomicISub: + case OpAtomicSMin: + case OpAtomicUMin: + case OpAtomicSMax: + case OpAtomicUMax: + case OpAtomicAnd: + case OpAtomicOr: + case OpAtomicXor: + case OpImageWrite: + { + if (needs_frag_discard_checks()) + added_arg_ids.insert(builtin_helper_invocation_id); + uint32_t ptr = 0; + if (op == OpAtomicStore || op == OpImageWrite) + ptr = ops[0]; + else + ptr = ops[2]; + if (global_var_ids.find(ptr) != global_var_ids.end()) + added_arg_ids.insert(ptr); + break; + } + // Emulate texture2D atomic operations case OpImageTexelPointer: { // When using the pointer, we need to know which variable it is actually loaded from. uint32_t base_id = ops[2]; auto *var = maybe_get_backing_variable(base_id); - if (var && atomic_image_vars.count(var->self)) + if (var && atomic_image_vars_emulated.count(var->self)) { + if (!get(var->basetype).array.empty()) + SPIRV_CROSS_THROW("Cannot emulate array of storage images with atomics. Use MSL 3.1 for native support."); + if (global_var_ids.find(base_id) != global_var_ids.end()) added_arg_ids.insert(base_id); } @@ -1759,10 +2008,64 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: break; } + case OpDemoteToHelperInvocation: + if (needs_manual_helper_invocation_updates() && + (active_input_builtins.get(BuiltInHelperInvocation) || needs_helper_invocation)) + added_arg_ids.insert(builtin_helper_invocation_id); + break; + + case OpIsHelperInvocationEXT: + if (needs_manual_helper_invocation_updates()) + added_arg_ids.insert(builtin_helper_invocation_id); + break; + + case OpRayQueryInitializeKHR: + case OpRayQueryProceedKHR: + case OpRayQueryTerminateKHR: + case OpRayQueryGenerateIntersectionKHR: + case OpRayQueryConfirmIntersectionKHR: + { + // Ray query accesses memory directly, need check pass down object if using Private storage class. + uint32_t base_id = ops[0]; + if (global_var_ids.find(base_id) != global_var_ids.end()) + added_arg_ids.insert(base_id); + break; + } + + case OpRayQueryGetRayTMinKHR: + case OpRayQueryGetRayFlagsKHR: + case OpRayQueryGetWorldRayOriginKHR: + case OpRayQueryGetWorldRayDirectionKHR: + case OpRayQueryGetIntersectionCandidateAABBOpaqueKHR: + case OpRayQueryGetIntersectionTypeKHR: + case OpRayQueryGetIntersectionTKHR: + case OpRayQueryGetIntersectionInstanceCustomIndexKHR: + case OpRayQueryGetIntersectionInstanceIdKHR: + case OpRayQueryGetIntersectionInstanceShaderBindingTableRecordOffsetKHR: + case OpRayQueryGetIntersectionGeometryIndexKHR: + case OpRayQueryGetIntersectionPrimitiveIndexKHR: + case OpRayQueryGetIntersectionBarycentricsKHR: + case OpRayQueryGetIntersectionFrontFaceKHR: + case OpRayQueryGetIntersectionObjectRayDirectionKHR: + case OpRayQueryGetIntersectionObjectRayOriginKHR: + case OpRayQueryGetIntersectionObjectToWorldKHR: + case OpRayQueryGetIntersectionWorldToObjectKHR: + { + // Ray query accesses memory directly, need check pass down object if using Private storage class. + uint32_t base_id = ops[2]; + if (global_var_ids.find(base_id) != global_var_ids.end()) + added_arg_ids.insert(base_id); + break; + } + default: break; } + if (needs_manual_helper_invocation_updates() && b.terminator == SPIRBlock::Kill && + (active_input_builtins.get(BuiltInHelperInvocation) || needs_helper_invocation)) + added_arg_ids.insert(builtin_helper_invocation_id); + // TODO: Add all other operations which can affect memory. // We should consider a more unified system here to reduce boiler-plate. // This kind of analysis is done in several places ... @@ -1789,9 +2092,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: bool is_patch = has_decoration(arg_id, DecorationPatch) || is_patch_block(*p_type); bool is_block = has_decoration(p_type->self, DecorationBlock); bool is_control_point_storage = - !is_patch && - ((is_tessellation_shader() && var.storage == StorageClassInput) || - (get_execution_model() == ExecutionModelTessellationControl && var.storage == StorageClassOutput)); + !is_patch && ((is_tessellation_shader() && var.storage == StorageClassInput) || + (is_tesc_shader() && var.storage == StorageClassOutput)); bool is_patch_block_storage = is_patch && is_block && var.storage == StorageClassOutput; bool is_builtin = is_builtin_variable(var); bool variable_is_stage_io = @@ -1807,8 +2109,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: if (is_redirected_to_global_stage_io) { - // Tessellation control shaders see inputs and per-vertex outputs as arrays. - // Similarly, tessellation evaluation shaders see per-vertex inputs as arrays. + // Tessellation control shaders see inputs and per-point outputs as arrays. + // Similarly, tessellation evaluation shaders see per-point inputs as arrays. // We collected them into a structure; we must pass the array of this // structure to the function. std::string name; @@ -1831,10 +2133,6 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: } } - // Tessellation control shaders see inputs and per-vertex outputs as arrays. - // Similarly, tessellation evaluation shaders see per-vertex inputs as arrays. - // We collected them into a structure; we must pass the array of this - // structure to the function. if (var.storage == StorageClassInput) { auto &added_in = is_patch ? patch_added_in : control_point_added_in; @@ -1858,6 +2156,8 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: set(next_id, type_id, StorageClassFunction, 0, arg_id); set_name(next_id, name); + if (is_tese_shader() && msl_options.raw_buffer_tese_input && var.storage == StorageClassInput) + set_decoration(next_id, DecorationNonWritable); } else if (is_builtin && has_decoration(p_type->self, DecorationBlock)) { @@ -1899,8 +2199,7 @@ void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std:: func.add_parameter(type_id, next_id, true); set(next_id, type_id, StorageClassFunction, 0, arg_id); - // Ensure the existing variable has a valid name and the new variable has all the same meta info - set_name(arg_id, ensure_valid_name(to_name(arg_id), "v")); + // Ensure the new variable has all the same meta info ir.meta[next_id] = ir.meta[arg_id]; } } @@ -1921,6 +2220,20 @@ void CompilerMSL::mark_packable_structs() (has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock))) mark_as_packable(type); } + + if (var.storage == StorageClassWorkgroup) + { + auto *type = &this->get(var.basetype); + if (type->basetype == SPIRType::Struct) + mark_as_workgroup_struct(*type); + } + }); + + // Physical storage buffer pointers can appear outside of the context of a variable, if the address + // is calculated from a ulong or uvec2 and cast to a pointer, so check if they need to be packed too. + ir.for_each_typed_id([&](uint32_t, SPIRType &type) { + if (type.basetype == SPIRType::Struct && type.pointer && type.storage == StorageClassPhysicalStorageBuffer) + mark_as_packable(type); }); } @@ -1935,7 +2248,8 @@ void CompilerMSL::mark_as_packable(SPIRType &type) return; } - if (type.basetype == SPIRType::Struct) + // Handle possible recursion when a struct contains a pointer to its own type nested somewhere. + if (type.basetype == SPIRType::Struct && !has_extended_decoration(type.self, SPIRVCrossDecorationBufferBlockRepacked)) { set_extended_decoration(type.self, SPIRVCrossDecorationBufferBlockRepacked); @@ -1955,19 +2269,63 @@ void CompilerMSL::mark_as_packable(SPIRType &type) } } +// If the specified type is a struct, it and any nested structs +// are marked as used with workgroup storage using the SPIRVCrossDecorationWorkgroupStruct decoration. +void CompilerMSL::mark_as_workgroup_struct(SPIRType &type) +{ + // If this is not the base type (eg. it's a pointer or array), tunnel down + if (type.parent_type) + { + mark_as_workgroup_struct(get(type.parent_type)); + return; + } + + // Handle possible recursion when a struct contains a pointer to its own type nested somewhere. + if (type.basetype == SPIRType::Struct && !has_extended_decoration(type.self, SPIRVCrossDecorationWorkgroupStruct)) + { + set_extended_decoration(type.self, SPIRVCrossDecorationWorkgroupStruct); + + // Recurse + uint32_t mbr_cnt = uint32_t(type.member_types.size()); + for (uint32_t mbr_idx = 0; mbr_idx < mbr_cnt; mbr_idx++) + { + uint32_t mbr_type_id = type.member_types[mbr_idx]; + auto &mbr_type = get(mbr_type_id); + mark_as_workgroup_struct(mbr_type); + if (mbr_type.type_alias) + { + auto &mbr_type_alias = get(mbr_type.type_alias); + mark_as_workgroup_struct(mbr_type_alias); + } + } + } +} + // If a shader input exists at the location, it is marked as being used by this shader void CompilerMSL::mark_location_as_used_by_shader(uint32_t location, const SPIRType &type, StorageClass storage, bool fallback) { - if (storage != StorageClassInput) - return; - uint32_t count = type_to_location_count(type); - for (uint32_t i = 0; i < count; i++) + switch (storage) { - location_inputs_in_use.insert(location + i); - if (fallback) - location_inputs_in_use_fallback.insert(location + i); + case StorageClassInput: + for (uint32_t i = 0; i < count; i++) + { + location_inputs_in_use.insert(location + i); + if (fallback) + location_inputs_in_use_fallback.insert(location + i); + } + break; + case StorageClassOutput: + for (uint32_t i = 0; i < count; i++) + { + location_outputs_in_use.insert(location + i); + if (fallback) + location_outputs_in_use_fallback.insert(location + i); + } + break; + default: + return; } } @@ -1982,9 +2340,27 @@ uint32_t CompilerMSL::get_target_components_for_fragment_location(uint32_t locat uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t components, SPIRType::BaseType basetype) { + assert(components > 1); uint32_t new_type_id = ir.increase_bound_by(1); - auto &old_type = get(type_id); - auto *type = &set(new_type_id, old_type); + const auto *p_old_type = &get(type_id); + const SPIRType *old_ptr_t = nullptr; + const SPIRType *old_array_t = nullptr; + + if (is_pointer(*p_old_type)) + { + old_ptr_t = p_old_type; + p_old_type = &get_pointee_type(*old_ptr_t); + } + + if (is_array(*p_old_type)) + { + old_array_t = p_old_type; + p_old_type = &get_type(old_array_t->parent_type); + } + + auto *type = &set(new_type_id, *p_old_type); + assert(is_scalar(*type) || is_vector(*type)); + type->op = OpTypeVector; type->vecsize = components; if (basetype != SPIRType::Unknown) type->basetype = basetype; @@ -1994,23 +2370,24 @@ uint32_t CompilerMSL::build_extended_vector_type(uint32_t type_id, uint32_t comp type->array_size_literal.clear(); type->pointer = false; - if (is_array(old_type)) + if (old_array_t) { uint32_t array_type_id = ir.increase_bound_by(1); type = &set(array_type_id, *type); + type->op = OpTypeArray; type->parent_type = new_type_id; - type->array = old_type.array; - type->array_size_literal = old_type.array_size_literal; + type->array = old_array_t->array; + type->array_size_literal = old_array_t->array_size_literal; new_type_id = array_type_id; } - if (old_type.pointer) + if (old_ptr_t) { uint32_t ptr_type_id = ir.increase_bound_by(1); type = &set(ptr_type_id, *type); - type->self = new_type_id; + type->op = OpTypePointer; type->parent_type = new_type_id; - type->storage = old_type.storage; + type->storage = old_ptr_t->storage; type->pointer = true; type->pointer_depth++; new_type_id = ptr_type_id; @@ -2063,7 +2440,7 @@ bool CompilerMSL::add_component_variable_to_interface_block(spv::StorageClass st if (pad_fragment_output) { uint32_t locn = get_decoration(var.self, DecorationLocation); - num_components = std::max(num_components, get_target_components_for_fragment_location(locn)); + num_components = max(num_components, get_target_components_for_fragment_location(locn)); } // We have already declared an IO block member as m_location_N. @@ -2268,6 +2645,12 @@ void CompilerMSL::add_plain_variable_to_interface_block(StorageClass storage, co set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, type, storage); } + else if (is_builtin && capture_output_to_buffer && storage == StorageClassOutput && outputs_by_builtin.count(builtin)) + { + uint32_t locn = outputs_by_builtin[builtin].location; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); + mark_location_as_used_by_shader(locn, type, storage); + } if (get_decoration_bitset(var.self).get(DecorationComponent)) { @@ -2433,6 +2816,12 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); mark_location_as_used_by_shader(locn, *usable_type, storage); } + else if (is_builtin && capture_output_to_buffer && storage == StorageClassOutput && outputs_by_builtin.count(builtin)) + { + uint32_t locn = outputs_by_builtin[builtin].location + i; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); + mark_location_as_used_by_shader(locn, *usable_type, storage); + } else if (is_builtin && (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance)) { // Declare the Clip/CullDistance as [[user(clip/cullN)]]. @@ -2511,12 +2900,15 @@ void CompilerMSL::add_composite_variable_to_interface_block(StorageClass storage } } -void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, - uint32_t mbr_idx, InterfaceBlockMeta &meta) +void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass storage, + const string &ib_var_ref, SPIRType &ib_type, + SPIRVariable &var, SPIRType &var_type, + uint32_t mbr_idx, InterfaceBlockMeta &meta, + const string &mbr_name_qual, + const string &var_chain_qual, + uint32_t &location, uint32_t &var_mbr_idx) { auto &entry_func = get(ir.default_entry_point); - auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); BuiltIn builtin = BuiltInMax; bool is_builtin = is_member_builtin(var_type, mbr_idx, &builtin); @@ -2531,13 +2923,15 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass uint32_t mbr_type_id = var_type.member_types[mbr_idx]; auto &mbr_type = get(mbr_type_id); - uint32_t elem_cnt = 0; + bool mbr_is_indexable = false; + uint32_t elem_cnt = 1; if (is_matrix(mbr_type)) { if (is_array(mbr_type)) SPIRV_CROSS_THROW("MSL cannot emit arrays-of-matrices in input and output variables."); + mbr_is_indexable = true; elem_cnt = mbr_type.columns; } else if (is_array(mbr_type)) @@ -2545,6 +2939,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass if (mbr_type.array.size() != 1) SPIRV_CROSS_THROW("MSL cannot emit arrays-of-arrays in input and output variables."); + mbr_is_indexable = true; elem_cnt = to_array_size_literal(mbr_type); } @@ -2575,6 +2970,27 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass return; } + // Recursively handle nested structures. + if (mbr_type.basetype == SPIRType::Struct) + { + for (uint32_t i = 0; i < elem_cnt; i++) + { + string mbr_name = append_member_name(mbr_name_qual, var_type, mbr_idx) + (mbr_is_indexable ? join("_", i) : ""); + string var_chain = join(var_chain_qual, ".", to_member_name(var_type, mbr_idx), (mbr_is_indexable ? join("[", i, "]") : "")); + uint32_t sub_mbr_cnt = uint32_t(mbr_type.member_types.size()); + for (uint32_t sub_mbr_idx = 0; sub_mbr_idx < sub_mbr_cnt; sub_mbr_idx++) + { + add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, + var, mbr_type, sub_mbr_idx, + meta, mbr_name, var_chain, + location, var_mbr_idx); + // FIXME: Recursive structs and tessellation breaks here. + var_mbr_idx++; + } + } + return; + } + for (uint32_t i = 0; i < elem_cnt; i++) { // Add a reference to the variable type to the interface struct. @@ -2585,26 +3001,47 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass ib_type.member_types.push_back(usable_type->self); // Give the member a name - string mbr_name = ensure_valid_name(join(to_qualified_member_name(var_type, mbr_idx), "_", i), "m"); + string mbr_name = ensure_valid_name(append_member_name(mbr_name_qual, var_type, mbr_idx) + (mbr_is_indexable ? join("_", i) : ""), "m"); set_member_name(ib_type.self, ib_mbr_idx, mbr_name); - if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) + // Once we determine the location of the first member within nested structures, + // from a var of the topmost structure, the remaining flattened members of + // the nested structures will have consecutive location values. At this point, + // we've recursively tunnelled into structs, arrays, and matrices, and are + // down to a single location for each member now. + if (!is_builtin && location != UINT32_MAX) { - uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation) + i; - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, *usable_type, storage); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, *usable_type, storage); + location++; + } + else if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) + { + location = get_member_decoration(var_type.self, mbr_idx, DecorationLocation) + i; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, *usable_type, storage); + location++; } else if (has_decoration(var.self, DecorationLocation)) { - uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i; - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, *usable_type, storage); + location = get_accumulated_member_location(var, mbr_idx, meta.strip_array) + i; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, *usable_type, storage); + location++; } else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin)) { - uint32_t locn = inputs_by_builtin[builtin].location + i; - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, *usable_type, storage); + location = inputs_by_builtin[builtin].location + i; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, *usable_type, storage); + location++; + } + else if (is_builtin && capture_output_to_buffer && storage == StorageClassOutput && outputs_by_builtin.count(builtin)) + { + location = outputs_by_builtin[builtin].location + i; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, *usable_type, storage); + location++; } else if (is_builtin && (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance)) { @@ -2614,7 +3051,7 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass } if (has_member_decoration(var_type.self, mbr_idx, DecorationComponent)) - SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays make little sense."); + SPIRV_CROSS_THROW("DecorationComponent on matrices and arrays is not supported."); if (storage != StorageClassInput || !pull_model_inputs.count(var.self)) { @@ -2630,47 +3067,36 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass } set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); - set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx); + set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, var_mbr_idx); // Unflatten or flatten from [[stage_in]] or [[stage_out]] as appropriate. if (!meta.strip_array && meta.allow_local_declaration) { + string var_chain = join(var_chain_qual, ".", to_member_name(var_type, mbr_idx), (mbr_is_indexable ? join("[", i, "]") : "")); switch (storage) { case StorageClassInput: - entry_func.fixup_hooks_in.push_back([=, &var, &var_type]() { + entry_func.fixup_hooks_in.push_back([=, &var]() { + string lerp_call; if (pull_model_inputs.count(var.self)) { - string lerp_call; if (is_centroid) lerp_call = ".interpolate_at_centroid()"; else if (is_sample) lerp_call = join(".interpolate_at_sample(", to_expression(builtin_sample_id_id), ")"); else lerp_call = ".interpolate_at_center()"; - statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref, - ".", mbr_name, lerp_call, ";"); - } - else - { - statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), "[", i, "] = ", ib_var_ref, - ".", mbr_name, ";"); } + statement(var_chain, " = ", ib_var_ref, ".", mbr_name, lerp_call, ";"); }); break; case StorageClassOutput: - entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() { + entry_func.fixup_hooks_out.push_back([=]() { if (flatten_from_ib_var) - { - statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i, - "];"); - } + statement(ib_var_ref, ".", mbr_name, " = ", ib_var_ref, ".", flatten_from_ib_mbr_name, "[", i, "];"); else - { - statement(ib_var_ref, ".", mbr_name, " = ", to_name(var.self), ".", - to_member_name(var_type, mbr_idx), "[", i, "];"); - } + statement(ib_var_ref, ".", mbr_name, " = ", var_chain, ";"); }); break; @@ -2681,11 +3107,14 @@ void CompilerMSL::add_composite_member_variable_to_interface_block(StorageClass } } -void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, const string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, uint32_t mbr_idx, - InterfaceBlockMeta &meta) +void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass storage, + const string &ib_var_ref, SPIRType &ib_type, + SPIRVariable &var, SPIRType &var_type, + uint32_t mbr_idx, InterfaceBlockMeta &meta, + const string &mbr_name_qual, + const string &var_chain_qual, + uint32_t &location, uint32_t &var_mbr_idx) { - auto &var_type = meta.strip_array ? get_variable_element_type(var) : get_variable_data_type(var); auto &entry_func = get(ir.default_entry_point); BuiltIn builtin = BuiltInMax; @@ -2710,7 +3139,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor ib_type.member_types.push_back(mbr_type_id); // Give the member a name - string mbr_name = ensure_valid_name(to_qualified_member_name(var_type, mbr_idx), "m"); + string mbr_name = ensure_valid_name(append_member_name(mbr_name_qual, var_type, mbr_idx), "m"); set_member_name(ib_type.self, ib_mbr_idx, mbr_name); // Update the original variable reference to include the structure reference @@ -2727,7 +3156,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor } bool flatten_stage_out = false; - + string var_chain = var_chain_qual + "." + to_member_name(var_type, mbr_idx); if (is_builtin && !meta.strip_array) { // For the builtin gl_PerVertex, we cannot treat it as a block anyways, @@ -2740,15 +3169,15 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor switch (storage) { case StorageClassInput: - entry_func.fixup_hooks_in.push_back([=, &var, &var_type]() { - statement(to_name(var.self), ".", to_member_name(var_type, mbr_idx), " = ", qual_var_name, ";"); + entry_func.fixup_hooks_in.push_back([=]() { + statement(var_chain, " = ", qual_var_name, ";"); }); break; case StorageClassOutput: flatten_stage_out = true; - entry_func.fixup_hooks_out.push_back([=, &var, &var_type]() { - statement(qual_var_name, " = ", to_name(var.self), ".", to_member_name(var_type, mbr_idx), ";"); + entry_func.fixup_hooks_out.push_back([=]() { + statement(qual_var_name, " = ", var_chain, ";"); }); break; @@ -2757,48 +3186,63 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor } } - // Copy the variable location from the original variable to the member - if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) + // Once we determine the location of the first member within nested structures, + // from a var of the topmost structure, the remaining flattened members of + // the nested structures will have consecutive location values. At this point, + // we've recursively tunnelled into structs, arrays, and matrices, and are + // down to a single location for each member now. + if (!is_builtin && location != UINT32_MAX) { - uint32_t locn = get_member_decoration(var_type.self, mbr_idx, DecorationLocation); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(mbr_type_id), storage); + location += type_to_location_count(get(mbr_type_id)); + } + else if (has_member_decoration(var_type.self, mbr_idx, DecorationLocation)) + { + location = get_member_decoration(var_type.self, mbr_idx, DecorationLocation); uint32_t comp = get_member_decoration(var_type.self, mbr_idx, DecorationComponent); if (storage == StorageClassInput) { - mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, comp, 0, meta.strip_array); + mbr_type_id = ensure_correct_input_type(mbr_type_id, location, comp, 0, meta.strip_array); var_type.member_types[mbr_idx] = mbr_type_id; if (storage == StorageClassInput && pull_model_inputs.count(var.self)) ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective); else ib_type.member_types[ib_mbr_idx] = mbr_type_id; } - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, get(mbr_type_id), storage); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(mbr_type_id), storage); + location += type_to_location_count(get(mbr_type_id)); } else if (has_decoration(var.self, DecorationLocation)) { - // The block itself might have a location and in this case, all members of the block - // receive incrementing locations. - uint32_t locn = get_accumulated_member_location(var, mbr_idx, meta.strip_array); + location = get_accumulated_member_location(var, mbr_idx, meta.strip_array); if (storage == StorageClassInput) { - mbr_type_id = ensure_correct_input_type(mbr_type_id, locn, 0, 0, meta.strip_array); + mbr_type_id = ensure_correct_input_type(mbr_type_id, location, 0, 0, meta.strip_array); var_type.member_types[mbr_idx] = mbr_type_id; if (storage == StorageClassInput && pull_model_inputs.count(var.self)) ib_type.member_types[ib_mbr_idx] = build_msl_interpolant_type(mbr_type_id, is_noperspective); else ib_type.member_types[ib_mbr_idx] = mbr_type_id; } - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, get(mbr_type_id), storage); + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(mbr_type_id), storage); + location += type_to_location_count(get(mbr_type_id)); } else if (is_builtin && is_tessellation_shader() && storage == StorageClassInput && inputs_by_builtin.count(builtin)) { - uint32_t locn = 0; - auto builtin_itr = inputs_by_builtin.find(builtin); - if (builtin_itr != end(inputs_by_builtin)) - locn = builtin_itr->second.location; - set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, locn); - mark_location_as_used_by_shader(locn, get(mbr_type_id), storage); + location = inputs_by_builtin[builtin].location; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(mbr_type_id), storage); + location += type_to_location_count(get(mbr_type_id)); + } + else if (is_builtin && capture_output_to_buffer && storage == StorageClassOutput && outputs_by_builtin.count(builtin)) + { + location = outputs_by_builtin[builtin].location; + set_member_decoration(ib_type.self, ib_mbr_idx, DecorationLocation, location); + mark_location_as_used_by_shader(location, get(mbr_type_id), storage); + location += type_to_location_count(get(mbr_type_id)); } // Copy the component location, if present. @@ -2857,7 +3301,7 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor } set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceOrigID, var.self); - set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, mbr_idx); + set_extended_member_decoration(ib_type.self, ib_mbr_idx, SPIRVCrossDecorationInterfaceMemberIndex, var_mbr_idx); } // In Metal, the tessellation levels are stored as tightly packed half-precision floating point values. @@ -2868,19 +3312,10 @@ void CompilerMSL::add_plain_member_variable_to_interface_block(StorageClass stor void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var) { - auto &entry_func = get(ir.default_entry_point); auto &var_type = get_variable_element_type(var); BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); - - // Force the variable to have the proper name. - string var_name = builtin_to_glsl(builtin, StorageClassFunction); - set_name(var.self, var_name); - - // We need to declare the variable early and at entry-point scope. - entry_func.add_local_variable(var.self); - vars_needing_early_declaration.push_back(var.self); - bool triangles = get_execution_mode_bitset().get(ExecutionModeTriangles); + bool triangles = is_tessellating_triangles(); string mbr_name; // Add a reference to the variable type to the interface struct. @@ -2926,7 +3361,7 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_ } else { - mbr_name = var_name; + mbr_name = builtin_to_glsl(builtin, StorageClassFunction); uint32_t type_id = build_extended_vector_type(var_type.self, builtin == BuiltInTessLevelOuter ? 4 : 2); @@ -2946,27 +3381,49 @@ void CompilerMSL::add_tess_level_input_to_interface_block(const std::string &ib_ mark_locations(new_var_type); } + add_tess_level_input(ib_var_ref, mbr_name, var); +} + +void CompilerMSL::add_tess_level_input(const std::string &base_ref, const std::string &mbr_name, SPIRVariable &var) +{ + auto &entry_func = get(ir.default_entry_point); + BuiltIn builtin = BuiltIn(get_decoration(var.self, DecorationBuiltIn)); + + // Force the variable to have the proper name. + string var_name = builtin_to_glsl(builtin, StorageClassFunction); + set_name(var.self, var_name); + + // We need to declare the variable early and at entry-point scope. + entry_func.add_local_variable(var.self); + vars_needing_early_declaration.push_back(var.self); + bool triangles = is_tessellating_triangles(); + if (builtin == BuiltInTessLevelOuter) { - entry_func.fixup_hooks_in.push_back([=]() { - statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".x;"); - statement(var_name, "[1] = ", ib_var_ref, ".", mbr_name, ".y;"); - statement(var_name, "[2] = ", ib_var_ref, ".", mbr_name, ".z;"); - if (!triangles) - statement(var_name, "[3] = ", ib_var_ref, ".", mbr_name, ".w;"); - }); + entry_func.fixup_hooks_in.push_back( + [=]() + { + statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[0];"); + statement(var_name, "[1] = ", base_ref, ".", mbr_name, "[1];"); + statement(var_name, "[2] = ", base_ref, ".", mbr_name, "[2];"); + if (!triangles) + statement(var_name, "[3] = ", base_ref, ".", mbr_name, "[3];"); + }); } else { entry_func.fixup_hooks_in.push_back([=]() { if (triangles) { - statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".w;"); + if (msl_options.raw_buffer_tese_input) + statement(var_name, "[0] = ", base_ref, ".", mbr_name, ";"); + else + statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[3];"); } else { - statement(var_name, "[0] = ", ib_var_ref, ".", mbr_name, ".x;"); - statement(var_name, "[1] = ", ib_var_ref, ".", mbr_name, ".y;"); + statement(var_name, "[0] = ", base_ref, ".", mbr_name, "[0];"); + statement(var_name, "[1] = ", base_ref, ".", mbr_name, "[1];"); } }); } @@ -2977,7 +3434,8 @@ bool CompilerMSL::variable_storage_requires_stage_io(spv::StorageClass storage) if (storage == StorageClassOutput) return !capture_output_to_buffer; else if (storage == StorageClassInput) - return !(get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup); + return !(is_tesc_shader() && msl_options.multi_patch_workgroup) && + !(is_tese_shader() && msl_options.raw_buffer_tese_input); else return false; } @@ -3006,9 +3464,6 @@ void CompilerMSL::emit_local_masked_variable(const SPIRVariable &masked_var, boo auto &type = get_variable_data_type(masked_var); add_local_variable_name(masked_var.self); - bool old_is_builtin = is_using_builtin_array; - is_using_builtin_array = true; - const uint32_t max_control_points_per_patch = 32u; uint32_t max_num_instances = (max_control_points_per_patch + get_entry_point().output_vertices - 1u) / @@ -3024,14 +3479,12 @@ void CompilerMSL::emit_local_masked_variable(const SPIRVariable &masked_var, boo // since Metal does not allow that. :( // FIXME: We will likely need an option to support passing down target workgroup size, // so we can emit appropriate size here. - statement("threadgroup ", type_to_glsl(type), " ", - "(&", to_name(masked_var.self), ")", - type_to_array_glsl(type), " = spvStorage", to_name(masked_var.self), "[", + statement("threadgroup auto ", + "&", to_name(masked_var.self), + " = spvStorage", to_name(masked_var.self), "[", "(", to_expression(builtin_invocation_id_id), ".x / ", get_entry_point().output_vertices, ") % ", max_num_instances, "];"); - - is_using_builtin_array = old_is_builtin; }); } else @@ -3089,9 +3542,21 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st return; } + if (storage == StorageClassInput && has_decoration(var.self, DecorationPerVertexKHR)) + SPIRV_CROSS_THROW("PerVertexKHR decoration is not supported in MSL."); + + // If variable names alias, they will end up with wrong names in the interface struct, because + // there might be aliases in the member name cache and there would be a mismatch in fixup_in code. + // Make sure to register the variables as unique resource names ahead of time. + // This would normally conflict with the name cache when emitting local variables, + // but this happens in the setup stage, before we hit compilation loops. + // The name cache is cleared before we actually emit code, so this is safe. + add_resource_name(var.self); + if (var_type.basetype == SPIRType::Struct) { - bool block_requires_flattening = variable_storage_requires_stage_io(storage) || is_block; + bool block_requires_flattening = + variable_storage_requires_stage_io(storage) || (is_block && var_type.array.empty()); bool needs_local_declaration = !is_builtin && block_requires_flattening && meta.allow_local_declaration; if (needs_local_declaration) @@ -3117,74 +3582,110 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st else { bool masked_block = false; - - // Flatten the struct members into the interface struct - for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(var_type.member_types.size()); mbr_idx++) + uint32_t location = UINT32_MAX; + uint32_t var_mbr_idx = 0; + uint32_t elem_cnt = 1; + if (is_matrix(var_type)) { - builtin = BuiltInMax; - is_builtin = is_member_builtin(var_type, mbr_idx, &builtin); - auto &mbr_type = get(var_type.member_types[mbr_idx]); + if (is_array(var_type)) + SPIRV_CROSS_THROW("MSL cannot emit arrays-of-matrices in input and output variables."); - if (storage == StorageClassOutput && is_stage_output_block_member_masked(var, mbr_idx, meta.strip_array)) + elem_cnt = var_type.columns; + } + else if (is_array(var_type)) + { + if (var_type.array.size() != 1) + SPIRV_CROSS_THROW("MSL cannot emit arrays-of-arrays in input and output variables."); + + elem_cnt = to_array_size_literal(var_type); + } + + for (uint32_t elem_idx = 0; elem_idx < elem_cnt; elem_idx++) + { + // Flatten the struct members into the interface struct + for (uint32_t mbr_idx = 0; mbr_idx < uint32_t(var_type.member_types.size()); mbr_idx++) { - if (is_block) - masked_block = true; + builtin = BuiltInMax; + is_builtin = is_member_builtin(var_type, mbr_idx, &builtin); + auto &mbr_type = get(var_type.member_types[mbr_idx]); - // Non-builtin block output variables are just ignored, since they will still access - // the block variable as-is. They're just not flattened. - if (is_builtin && !meta.strip_array) + if (storage == StorageClassOutput && is_stage_output_block_member_masked(var, mbr_idx, meta.strip_array)) { - // Emit a fake variable instead. - uint32_t ids = ir.increase_bound_by(2); - uint32_t ptr_type_id = ids + 0; - uint32_t var_id = ids + 1; + location = UINT32_MAX; // Skip this member and resolve location again on next var member - auto ptr_type = mbr_type; - ptr_type.pointer = true; - ptr_type.pointer_depth++; - ptr_type.parent_type = var_type.member_types[mbr_idx]; - ptr_type.storage = StorageClassOutput; + if (is_block) + masked_block = true; - uint32_t initializer = 0; - if (var.initializer) - if (auto *c = maybe_get(var.initializer)) - initializer = c->subconstants[mbr_idx]; + // Non-builtin block output variables are just ignored, since they will still access + // the block variable as-is. They're just not flattened. + if (is_builtin && !meta.strip_array) + { + // Emit a fake variable instead. + uint32_t ids = ir.increase_bound_by(2); + uint32_t ptr_type_id = ids + 0; + uint32_t var_id = ids + 1; - set(ptr_type_id, ptr_type); - set(var_id, ptr_type_id, StorageClassOutput, initializer); - entry_func.add_local_variable(var_id); - vars_needing_early_declaration.push_back(var_id); - set_name(var_id, builtin_to_glsl(builtin, StorageClassOutput)); - set_decoration(var_id, DecorationBuiltIn, builtin); + auto ptr_type = mbr_type; + ptr_type.pointer = true; + ptr_type.pointer_depth++; + ptr_type.parent_type = var_type.member_types[mbr_idx]; + ptr_type.storage = StorageClassOutput; + + uint32_t initializer = 0; + if (var.initializer) + if (auto *c = maybe_get(var.initializer)) + initializer = c->subconstants[mbr_idx]; + + set(ptr_type_id, ptr_type); + set(var_id, ptr_type_id, StorageClassOutput, initializer); + entry_func.add_local_variable(var_id); + vars_needing_early_declaration.push_back(var_id); + set_name(var_id, builtin_to_glsl(builtin, StorageClassOutput)); + set_decoration(var_id, DecorationBuiltIn, builtin); + } } - } - else if (!is_builtin || has_active_builtin(builtin, storage)) - { - bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type); - bool attribute_load_store = - storage == StorageClassInput && get_execution_model() != ExecutionModelFragment; - bool storage_is_stage_io = variable_storage_requires_stage_io(storage); - - // Clip/CullDistance always need to be declared as user attributes. - if (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance) - is_builtin = false; - - if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type) + else if (!is_builtin || has_active_builtin(builtin, storage)) { - add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, - meta); - } - else - { - add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, var, mbr_idx, meta); + bool is_composite_type = is_matrix(mbr_type) || is_array(mbr_type) || mbr_type.basetype == SPIRType::Struct; + bool attribute_load_store = + storage == StorageClassInput && get_execution_model() != ExecutionModelFragment; + bool storage_is_stage_io = variable_storage_requires_stage_io(storage); + + // Clip/CullDistance always need to be declared as user attributes. + if (builtin == BuiltInClipDistance || builtin == BuiltInCullDistance) + is_builtin = false; + + const string var_name = to_name(var.self); + string mbr_name_qual = var_name; + string var_chain_qual = var_name; + if (elem_cnt > 1) + { + mbr_name_qual += join("_", elem_idx); + var_chain_qual += join("[", elem_idx, "]"); + } + + if ((!is_builtin || attribute_load_store) && storage_is_stage_io && is_composite_type) + { + add_composite_member_variable_to_interface_block(storage, ib_var_ref, ib_type, + var, var_type, mbr_idx, meta, + mbr_name_qual, var_chain_qual, + location, var_mbr_idx); + } + else + { + add_plain_member_variable_to_interface_block(storage, ib_var_ref, ib_type, + var, var_type, mbr_idx, meta, + mbr_name_qual, var_chain_qual, + location, var_mbr_idx); + } } + var_mbr_idx++; } } // If we're redirecting a block, we might still need to access the original block // variable if we're masking some members. - if (masked_block && !needs_local_declaration && - (!is_builtin_variable(var) || get_execution_model() == ExecutionModelTessellationControl)) + if (masked_block && !needs_local_declaration && (!is_builtin_variable(var) || is_tesc_shader())) { if (is_builtin_variable(var)) { @@ -3205,8 +3706,8 @@ void CompilerMSL::add_variable_to_interface_block(StorageClass storage, const st } } } - else if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput && - !meta.strip_array && is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner)) + else if (is_tese_shader() && storage == StorageClassInput && !meta.strip_array && is_builtin && + (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner)) { add_tess_level_input_to_interface_block(ib_var_ref, ib_type, var); } @@ -3243,8 +3744,7 @@ void CompilerMSL::fix_up_interface_member_indices(StorageClass storage, uint32_t // Only needed for tessellation shaders and pull-model interpolants. // Need to redirect interface indices back to variables themselves. // For structs, each member of the struct need a separate instance. - if (get_execution_model() != ExecutionModelTessellationControl && - !(get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput) && + if (!is_tesc_shader() && !(is_tese_shader() && storage == StorageClassInput) && !(get_execution_model() == ExecutionModelFragment && storage == StorageClassInput && !pull_model_inputs.empty())) return; @@ -3327,15 +3827,14 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) bool builtin_is_stage_in_out = builtin_is_gl_in_out || bi_type == BuiltInLayer || bi_type == BuiltInViewportIndex || - bi_type == BuiltInBaryCoordNV || bi_type == BuiltInBaryCoordNoPerspNV || + bi_type == BuiltInBaryCoordKHR || bi_type == BuiltInBaryCoordNoPerspKHR || bi_type == BuiltInFragDepth || bi_type == BuiltInFragStencilRefEXT || bi_type == BuiltInSampleMask; // These builtins are part of the stage in/out structs. bool is_interface_block_builtin = - builtin_is_stage_in_out || - (get_execution_model() == ExecutionModelTessellationEvaluation && - (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner)); + builtin_is_stage_in_out || (is_tese_shader() && !msl_options.raw_buffer_tese_input && + (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner)); bool is_active = interface_variable_exists_in_entry_point(var.self); if (is_builtin && is_active) @@ -3384,7 +3883,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) } // Barycentric inputs must be emitted in stage-in, because they can have interpolation arguments. - if (is_active && (bi_type == BuiltInBaryCoordNV || bi_type == BuiltInBaryCoordNoPerspNV)) + if (is_active && (bi_type == BuiltInBaryCoordKHR || bi_type == BuiltInBaryCoordNoPerspKHR)) { if (has_seen_barycentric) SPIRV_CROSS_THROW("Cannot declare both BaryCoordNV and BaryCoordNoPerspNV in same shader in MSL."); @@ -3418,7 +3917,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) for (uint32_t location_offset = 0; location_offset < array_size; location_offset++) { auto &location_meta = meta.location_meta[location + location_offset]; - location_meta.num_components = std::max(location_meta.num_components, component + type.vecsize); + location_meta.num_components = max(location_meta.num_components, component + type.vecsize); // For variables sharing location, decorations and base type must match. location_meta.base_type_id = type.self; @@ -3431,12 +3930,29 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) } } } + + if (is_tese_shader() && msl_options.raw_buffer_tese_input && patch && storage == StorageClassInput && + (bi_type == BuiltInTessLevelOuter || bi_type == BuiltInTessLevelInner)) + { + // In this case, we won't add the builtin to the interface struct, + // but we still need the hook to run to populate the arrays. + string base_ref = join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id), "]"); + const char *mbr_name = + bi_type == BuiltInTessLevelOuter ? "edgeTessellationFactor" : "insideTessellationFactor"; + add_tess_level_input(base_ref, mbr_name, var); + if (inputs_by_builtin.count(bi_type)) + { + uint32_t locn = inputs_by_builtin[bi_type].location; + mark_location_as_used_by_shader(locn, type, StorageClassInput); + } + } }); // If no variables qualify, leave. // For patch input in a tessellation evaluation shader, the per-vertex stage inputs // are included in a special patch control point array. - if (vars.empty() && !(storage == StorageClassInput && patch && stage_in_var_id)) + if (vars.empty() && + !(!msl_options.raw_buffer_tese_input && storage == StorageClassInput && patch && stage_in_var_id)) return 0; // Add a new typed variable for this interface structure. @@ -3444,7 +3960,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) // declaraion is emitted, because it is cleared after each compilation pass. uint32_t next_id = ir.increase_bound_by(3); uint32_t ib_type_id = next_id++; - auto &ib_type = set(ib_type_id); + auto &ib_type = set(ib_type_id, OpTypeStruct); ib_type.basetype = SPIRType::Struct; ib_type.storage = storage; set_decoration(ib_type_id, DecorationBlock); @@ -3459,8 +3975,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) { case StorageClassInput: ib_var_ref = patch ? patch_stage_in_var_name : stage_in_var_name; - if (get_execution_model() == ExecutionModelTessellationControl) + switch (get_execution_model()) { + case ExecutionModelTessellationControl: // Add a hook to populate the shared workgroup memory containing the gl_in array. entry_func.fixup_hooks_in.push_back([=]() { // Can't use PatchVertices, PrimitiveId, or InvocationId yet; the hooks for those may not have run yet. @@ -3486,6 +4003,33 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) statement(" return;"); } }); + break; + case ExecutionModelTessellationEvaluation: + if (!msl_options.raw_buffer_tese_input) + break; + if (patch) + { + entry_func.fixup_hooks_in.push_back( + [=]() + { + statement("const device ", to_name(ir.default_entry_point), "_", ib_var_ref, "& ", ib_var_ref, + " = ", patch_input_buffer_var_name, "[", to_expression(builtin_primitive_id_id), + "];"); + }); + } + else + { + entry_func.fixup_hooks_in.push_back( + [=]() + { + statement("const device ", to_name(ir.default_entry_point), "_", ib_var_ref, "* gl_in = &", + input_buffer_var_name, "[", to_expression(builtin_primitive_id_id), " * ", + get_entry_point().output_vertices, "];"); + }); + } + break; + default: + break; } break; @@ -3611,58 +4155,72 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) for (auto *p_var : vars) { - bool strip_array = - (get_execution_model() == ExecutionModelTessellationControl || - (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput)) && - !patch; + bool strip_array = (is_tesc_shader() || (is_tese_shader() && storage == StorageClassInput)) && !patch; // Fixing up flattened stores in TESC is impossible since the memory is group shared either via // device (not masked) or threadgroup (masked) storage classes and it's race condition city. meta.strip_array = strip_array; - meta.allow_local_declaration = !strip_array && !(get_execution_model() == ExecutionModelTessellationControl && - storage == StorageClassOutput); + meta.allow_local_declaration = !strip_array && !(is_tesc_shader() && storage == StorageClassOutput); add_variable_to_interface_block(storage, ib_var_ref, ib_type, *p_var, meta); } - if (get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup && + if (((is_tesc_shader() && msl_options.multi_patch_workgroup) || + (is_tese_shader() && msl_options.raw_buffer_tese_input)) && storage == StorageClassInput) { - // For tessellation control inputs, add all outputs from the vertex shader to ensure + // For tessellation inputs, add all outputs from the previous stage to ensure // the struct containing them is the correct size and layout. for (auto &input : inputs_by_location) { if (location_inputs_in_use.count(input.first.location) != 0) continue; - // Create a fake variable to put at the location. - uint32_t offset = ir.increase_bound_by(4); - uint32_t type_id = offset; - uint32_t array_type_id = offset + 1; - uint32_t ptr_type_id = offset + 2; - uint32_t var_id = offset + 3; + if (patch != (input.second.rate == MSL_SHADER_VARIABLE_RATE_PER_PATCH)) + continue; - SPIRType type; + // Tessellation levels have their own struct, so there's no need to add them here. + if (input.second.builtin == BuiltInTessLevelOuter || input.second.builtin == BuiltInTessLevelInner) + continue; + + // Create a fake variable to put at the location. + uint32_t offset = ir.increase_bound_by(5); + uint32_t type_id = offset; + uint32_t vec_type_id = offset + 1; + uint32_t array_type_id = offset + 2; + uint32_t ptr_type_id = offset + 3; + uint32_t var_id = offset + 4; + + SPIRType type { OpTypeInt }; switch (input.second.format) { - case MSL_SHADER_INPUT_FORMAT_UINT16: - case MSL_SHADER_INPUT_FORMAT_ANY16: + case MSL_SHADER_VARIABLE_FORMAT_UINT16: + case MSL_SHADER_VARIABLE_FORMAT_ANY16: type.basetype = SPIRType::UShort; type.width = 16; break; - case MSL_SHADER_INPUT_FORMAT_ANY32: + case MSL_SHADER_VARIABLE_FORMAT_ANY32: default: type.basetype = SPIRType::UInt; type.width = 32; break; } - type.vecsize = input.second.vecsize; set(type_id, type); + if (input.second.vecsize > 1) + { + type.op = OpTypeVector; + type.vecsize = input.second.vecsize; + set(vec_type_id, type); + type_id = vec_type_id; + } + type.op = OpTypeArray; type.array.push_back(0); type.array_size_literal.push_back(true); type.parent_type = type_id; set(array_type_id, type); + type.self = type_id; + type.op = OpTypePointer; type.pointer = true; type.pointer_depth++; type.parent_type = array_type_id; @@ -3681,6 +4239,76 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) } } + if (capture_output_to_buffer && storage == StorageClassOutput) + { + // For captured output, add all inputs from the next stage to ensure + // the struct containing them is the correct size and layout. This is + // necessary for certain implicit builtins that may nonetheless be read, + // even when they aren't written. + for (auto &output : outputs_by_location) + { + if (location_outputs_in_use.count(output.first.location) != 0) + continue; + + // Create a fake variable to put at the location. + uint32_t offset = ir.increase_bound_by(5); + uint32_t type_id = offset; + uint32_t vec_type_id = offset + 1; + uint32_t array_type_id = offset + 2; + uint32_t ptr_type_id = offset + 3; + uint32_t var_id = offset + 4; + + SPIRType type { OpTypeInt }; + switch (output.second.format) + { + case MSL_SHADER_VARIABLE_FORMAT_UINT16: + case MSL_SHADER_VARIABLE_FORMAT_ANY16: + type.basetype = SPIRType::UShort; + type.width = 16; + break; + case MSL_SHADER_VARIABLE_FORMAT_ANY32: + default: + type.basetype = SPIRType::UInt; + type.width = 32; + break; + } + set(type_id, type); + if (output.second.vecsize > 1) + { + type.op = OpTypeVector; + type.vecsize = output.second.vecsize; + set(vec_type_id, type); + type_id = vec_type_id; + } + + if (is_tesc_shader()) + { + type.op = OpTypeArray; + type.array.push_back(0); + type.array_size_literal.push_back(true); + type.parent_type = type_id; + set(array_type_id, type); + } + + type.op = OpTypePointer; + type.pointer = true; + type.pointer_depth++; + type.parent_type = is_tesc_shader() ? array_type_id : type_id; + type.storage = storage; + auto &ptr_type = set(ptr_type_id, type); + ptr_type.self = type.parent_type; + + auto &fake_var = set(var_id, ptr_type_id, storage); + set_decoration(var_id, DecorationLocation, output.first.location); + if (output.first.component) + set_decoration(var_id, DecorationComponent, output.first.component); + + meta.strip_array = true; + meta.allow_local_declaration = false; + add_variable_to_interface_block(storage, ib_var_ref, ib_type, fake_var, meta); + } + } + // When multiple variables need to access same location, // unroll locations one by one and we will flatten output or input as necessary. for (auto &loc : meta.location_meta) @@ -3715,7 +4343,7 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) fix_up_interface_member_indices(storage, ib_type_id); // For patch inputs, add one more member, holding the array of control point data. - if (get_execution_model() == ExecutionModelTessellationEvaluation && storage == StorageClassInput && patch && + if (is_tese_shader() && !msl_options.raw_buffer_tese_input && storage == StorageClassInput && patch && stage_in_var_id) { uint32_t pcp_type_id = ir.increase_bound_by(1); @@ -3729,6 +4357,9 @@ uint32_t CompilerMSL::add_interface_block(StorageClass storage, bool patch) set_member_name(ib_type.self, mbr_idx, "gl_in"); } + if (storage == StorageClassInput) + set_decoration(ib_var_id, DecorationNonWritable); + return ib_var_id; } @@ -3740,19 +4371,22 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla uint32_t ib_ptr_var_id; uint32_t next_id = ir.increase_bound_by(3); auto &ib_type = expression_type(ib_var_id); - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader() || (is_tese_shader() && msl_options.raw_buffer_tese_input)) { // Tessellation control per-vertex I/O is presented as an array, so we must // do the same with our struct here. uint32_t ib_ptr_type_id = next_id++; auto &ib_ptr_type = set(ib_ptr_type_id, ib_type); + ib_ptr_type.op = OpTypePointer; ib_ptr_type.parent_type = ib_ptr_type.type_alias = ib_type.self; ib_ptr_type.pointer = true; ib_ptr_type.pointer_depth++; - ib_ptr_type.storage = - storage == StorageClassInput ? - (msl_options.multi_patch_workgroup ? StorageClassStorageBuffer : StorageClassWorkgroup) : - StorageClassStorageBuffer; + ib_ptr_type.storage = storage == StorageClassInput ? + ((is_tesc_shader() && msl_options.multi_patch_workgroup) || + (is_tese_shader() && msl_options.raw_buffer_tese_input) ? + StorageClassStorageBuffer : + StorageClassWorkgroup) : + StorageClassStorageBuffer; ir.meta[ib_ptr_type_id] = ir.meta[ib_type.self]; // To ensure that get_variable_data_type() doesn't strip off the pointer, // which we need, use another pointer. @@ -3766,6 +4400,8 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla ib_ptr_var_id = next_id; set(ib_ptr_var_id, ib_ptr_ptr_type_id, StorageClassFunction, 0); set_name(ib_ptr_var_id, storage == StorageClassInput ? "gl_in" : "gl_out"); + if (storage == StorageClassInput) + set_decoration(ib_ptr_var_id, DecorationNonWritable); } else { @@ -3796,23 +4432,24 @@ uint32_t CompilerMSL::add_interface_block_pointer(uint32_t ib_var_id, StorageCla uint32_t CompilerMSL::ensure_correct_builtin_type(uint32_t type_id, BuiltIn builtin) { auto &type = get(type_id); + auto &pointee_type = get_pointee_type(type); - if ((builtin == BuiltInSampleMask && is_array(type)) || + if ((builtin == BuiltInSampleMask && is_array(pointee_type)) || ((builtin == BuiltInLayer || builtin == BuiltInViewportIndex || builtin == BuiltInFragStencilRefEXT) && - type.basetype != SPIRType::UInt)) + pointee_type.basetype != SPIRType::UInt)) { - uint32_t next_id = ir.increase_bound_by(type.pointer ? 2 : 1); + uint32_t next_id = ir.increase_bound_by(type_is_pointer(type) ? 2 : 1); uint32_t base_type_id = next_id++; - auto &base_type = set(base_type_id); + auto &base_type = set(base_type_id, OpTypeInt); base_type.basetype = SPIRType::UInt; base_type.width = 32; - if (!type.pointer) + if (!type_is_pointer(type)) return base_type_id; uint32_t ptr_type_id = next_id++; - auto &ptr_type = set(ptr_type_id); - ptr_type = base_type; + auto &ptr_type = set(ptr_type_id, base_type); + ptr_type.op = spv::OpTypePointer; ptr_type.pointer = true; ptr_type.pointer_depth++; ptr_type.storage = type.storage; @@ -3850,7 +4487,7 @@ uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t locat switch (p_va->second.format) { - case MSL_SHADER_INPUT_FORMAT_UINT8: + case MSL_SHADER_VARIABLE_FORMAT_UINT8: { switch (type.basetype) { @@ -3874,7 +4511,7 @@ uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t locat } } - case MSL_SHADER_INPUT_FORMAT_UINT16: + case MSL_SHADER_VARIABLE_FORMAT_UINT16: { switch (type.basetype) { @@ -3905,6 +4542,10 @@ uint32_t CompilerMSL::ensure_correct_input_type(uint32_t type_id, uint32_t locat void CompilerMSL::mark_struct_members_packed(const SPIRType &type) { + // Handle possible recursion when a struct contains a pointer to its own type nested somewhere. + if (has_extended_decoration(type.self, SPIRVCrossDecorationPhysicalTypePacked)) + return; + set_extended_decoration(type.self, SPIRVCrossDecorationPhysicalTypePacked); // Problem case! Struct needs to be placed at an awkward alignment. @@ -3931,8 +4572,9 @@ void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type) uint32_t mbr_cnt = uint32_t(type.member_types.size()); for (uint32_t i = 0; i < mbr_cnt; i++) { + // Handle possible recursion when a struct contains a pointer to its own type nested somewhere. auto &mbr_type = get(type.member_types[i]); - if (mbr_type.basetype == SPIRType::Struct) + if (mbr_type.basetype == SPIRType::Struct && !(mbr_type.pointer && mbr_type.storage == StorageClassPhysicalStorageBuffer)) { auto *struct_type = &mbr_type; while (!struct_type->array.empty()) @@ -3965,7 +4607,7 @@ void CompilerMSL::mark_scalar_layout_structs(const SPIRType &type) for (uint32_t dim = 0; dim < dimensions; dim++) { uint32_t array_size = to_array_size_literal(mbr_type, dim); - array_stride /= max(array_size, 1u); + array_stride /= max(array_size, 1u); } // Set expected struct size based on ArrayStride. @@ -4144,8 +4786,10 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in // This case will be nightmare-ish to deal with. This could possibly happen if struct alignment does not quite // match up with what we want. Scalar block layout comes to mind here where we might have to work around the rule // that struct alignment == max alignment of all members and struct size depends on this alignment. + // Can't repack structs, but can repack pointers to structs. auto &mbr_type = get(ib_type.member_types[index]); - if (mbr_type.basetype == SPIRType::Struct) + bool is_buff_ptr = mbr_type.pointer && mbr_type.storage == StorageClassPhysicalStorageBuffer; + if (mbr_type.basetype == SPIRType::Struct && !is_buff_ptr) SPIRV_CROSS_THROW("Cannot perform any repacking for structs when it is used as a member of another struct."); // Perform remapping here. @@ -4170,18 +4814,39 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in // Hack off array-of-arrays until we find the array stride per element we must have to make it work. uint32_t dimensions = uint32_t(mbr_type.array.size() - 1); for (uint32_t dim = 0; dim < dimensions; dim++) - array_stride /= max(to_array_size_literal(mbr_type, dim), 1u); + array_stride /= max(to_array_size_literal(mbr_type, dim), 1u); - uint32_t elems_per_stride = array_stride / (mbr_type.width / 8); + // Pointers are 8 bytes + uint32_t mbr_width_in_bytes = is_buff_ptr ? 8 : (mbr_type.width / 8); + uint32_t elems_per_stride = array_stride / mbr_width_in_bytes; if (elems_per_stride == 3) SPIRV_CROSS_THROW("Cannot use ArrayStride of 3 elements in remapping scenarios."); - else if (elems_per_stride > 4) + else if (elems_per_stride > 4 && elems_per_stride != 8) SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL."); + if (elems_per_stride == 8) + { + if (mbr_type.width == 16) + add_spv_func_and_recompile(SPVFuncImplPaddedStd140); + else + SPIRV_CROSS_THROW("Unexpected type in std140 wide array resolve."); + } + auto physical_type = mbr_type; physical_type.vecsize = elems_per_stride; physical_type.parent_type = 0; + + // If this is a physical buffer pointer, replace type with a ulongn vector. + if (is_buff_ptr) + { + physical_type.width = 64; + physical_type.basetype = to_unsigned_basetype(physical_type.width); + physical_type.pointer = false; + physical_type.pointer_depth = false; + physical_type.forward_pointer = false; + } + uint32_t type_id = ir.increase_bound_by(1); set(type_id, physical_type); set_extended_member_decoration(ib_type.self, index, SPIRVCrossDecorationPhysicalTypeID, type_id); @@ -4199,13 +4864,20 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in if (elems_per_stride == 3) SPIRV_CROSS_THROW("Cannot use ArrayStride of 3 elements in remapping scenarios."); - else if (elems_per_stride > 4) + else if (elems_per_stride > 4 && elems_per_stride != 8) SPIRV_CROSS_THROW("Cannot represent vectors with more than 4 elements in MSL."); - bool row_major = has_member_decoration(ib_type.self, index, DecorationRowMajor); + if (elems_per_stride == 8) + { + if (mbr_type.basetype != SPIRType::Half) + SPIRV_CROSS_THROW("Unexpected type in std140 wide matrix stride resolve."); + add_spv_func_and_recompile(SPVFuncImplPaddedStd140); + } + bool row_major = has_member_decoration(ib_type.self, index, DecorationRowMajor); auto physical_type = mbr_type; physical_type.parent_type = 0; + if (row_major) physical_type.columns = elems_per_stride; else @@ -4267,6 +4939,7 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in { type.columns = 1; assert(type.array.empty()); + type.op = OpTypeArray; type.array.push_back(1); type.array_size_literal.push_back(true); } @@ -4283,6 +4956,7 @@ void CompilerMSL::ensure_member_packing_rules_msl(SPIRType &ib_type, uint32_t in type.vecsize = type.columns; type.columns = 1; assert(type.array.empty()); + type.op = OpTypeArray; type.array.push_back(1); type.array_size_literal.push_back(true); } @@ -4305,9 +4979,18 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp bool transpose = lhs_e && lhs_e->need_transpose; - // No physical type remapping, and no packed type, so can just emit a store directly. - if (!lhs_remapped_type && !lhs_packed_type) + if (has_decoration(lhs_expression, DecorationBuiltIn) && + BuiltIn(get_decoration(lhs_expression, DecorationBuiltIn)) == BuiltInSampleMask && + is_array(type)) { + // Storing an array to SampleMask, have to remove the array-ness before storing. + statement(to_expression(lhs_expression), " = ", to_enclosed_unpacked_expression(rhs_expression), "[0];"); + register_write(lhs_expression); + } + else if (!lhs_remapped_type && !lhs_packed_type) + { + // No physical type remapping, and no packed type, so can just emit a store directly. + // We might not be dealing with remapped physical types or packed types, // but we might be doing a clean store to a row-major matrix. // In this case, we just flip transpose states, and emit the store, a transpose must be in the RHS expression, if any. @@ -4368,6 +5051,11 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp auto &physical_type = get(physical_type_id); + string cast_addr_space = "thread"; + auto *p_var_lhs = maybe_get_backing_variable(lhs_expression); + if (p_var_lhs) + cast_addr_space = get_type_address_space(get(p_var_lhs->basetype), lhs_expression); + if (is_matrix(type)) { const char *packed_pfx = lhs_packed_type ? "packed_" : ""; @@ -4395,7 +5083,7 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp write_type.columns = 1; if (physical_type.columns != type.columns) - cast_expr = join("(device ", packed_pfx, type_to_glsl(write_type), "&)"); + cast_expr = join("(", cast_addr_space, " ", packed_pfx, type_to_glsl(write_type), "&)"); if (rhs_transpose) { @@ -4437,7 +5125,7 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp write_type.columns = 1; if (physical_type.vecsize != type.vecsize) - cast_expr = join("(device ", packed_pfx, type_to_glsl(write_type), "&)"); + cast_expr = join("(", cast_addr_space, " ", packed_pfx, type_to_glsl(write_type), "&)"); if (rhs_transpose) { @@ -4490,9 +5178,16 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp { auto lhs_expr = to_enclosed_expression(lhs_expression); auto column_index = lhs_expr.find_last_of('['); + + // Get rid of any ".data" half8 handling here, we're casting to scalar anyway. + auto end_column_index = lhs_expr.find_last_of(']'); + auto end_dot_index = lhs_expr.find_last_of('.'); + if (end_dot_index != string::npos && end_dot_index > end_column_index) + lhs_expr.resize(end_dot_index); + if (column_index != string::npos) { - statement("((device ", type_to_glsl(write_type), "*)&", + statement("((", cast_addr_space, " ", type_to_glsl(write_type), "*)&", lhs_expr.insert(column_index, join('[', c, ']', ")")), " = ", to_extract_component_expression(rhs_expression, c), ";"); } @@ -4500,7 +5195,9 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp lhs_e->need_transpose = true; } - else if ((is_matrix(physical_type) || is_array(physical_type)) && physical_type.vecsize > type.vecsize) + else if ((is_matrix(physical_type) || is_array(physical_type)) && + physical_type.vecsize <= 4 && + physical_type.vecsize > type.vecsize) { assert(type.vecsize >= 1 && type.vecsize <= 3); @@ -4515,7 +5212,7 @@ void CompilerMSL::emit_store_statement(uint32_t lhs_expression, uint32_t rhs_exp // Unpack the expression so we can store to it with a float or float2. // It's still an l-value, so it's fine. Most other unpacking of expressions turn them into r-values instead. - lhs = join("(device ", type_to_glsl(type), "&)", enclose_expression(lhs)); + lhs = join("(", cast_addr_space, " ", type_to_glsl(type), "&)", enclose_expression(lhs)); if (!optimize_read_modify_write(expression_type(rhs_expression), lhs, rhs)) statement(lhs, " = ", rhs, ";"); } @@ -4557,19 +5254,26 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type ".x", ".xy", ".xyz", + "", }; + // TODO: Move everything to the template wrapper? + bool uses_std140_wrapper = physical_type && physical_type->vecsize > 4; + if (physical_type && is_vector(*physical_type) && is_array(*physical_type) && + !uses_std140_wrapper && physical_type->vecsize > type.vecsize && !expression_ends_with(expr_str, swizzle_lut[type.vecsize - 1])) { // std140 array cases for vectors. assert(type.vecsize >= 1 && type.vecsize <= 3); return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1]; } - else if (physical_type && is_matrix(*physical_type) && is_vector(type) && physical_type->vecsize > type.vecsize) + else if (physical_type && is_matrix(*physical_type) && is_vector(type) && + !uses_std140_wrapper && + physical_type->vecsize > type.vecsize) { // Extract column from padded matrix. - assert(type.vecsize >= 1 && type.vecsize <= 3); + assert(type.vecsize >= 1 && type.vecsize <= 4); return enclose_expression(expr_str) + swizzle_lut[type.vecsize - 1]; } else if (is_matrix(type)) @@ -4591,6 +5295,7 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type string unpack_expr = join(base_type, columns, "x", vecsize, "("); const char *load_swiz = ""; + const char *data_swiz = physical_vecsize > 4 ? ".data" : ""; if (physical_vecsize != vecsize) load_swiz = swizzle_lut[vecsize - 1]; @@ -4603,7 +5308,7 @@ string CompilerMSL::unpack_expression_type(string expr_str, const SPIRType &type if (packed) unpack_expr += join(base_type, physical_vecsize, "(", expr_str, "[", i, "]", ")", load_swiz); else - unpack_expr += join(expr_str, "[", i, "]", load_swiz); + unpack_expr += join(expr_str, "[", i, "]", data_swiz, load_swiz); } unpack_expr += ")"; @@ -4666,6 +5371,10 @@ void CompilerMSL::add_typedef_line(const string &line) // Template struct like spvUnsafeArray<> need to be declared *before* any resources are declared void CompilerMSL::emit_custom_templates() { + static const char * const address_spaces[] = { + "thread", "constant", "device", "threadgroup", "threadgroup_imageblock", "ray_data", "object_data" + }; + for (const auto &spv_func : spv_function_implementations) { switch (spv_func) @@ -4711,6 +5420,122 @@ void CompilerMSL::emit_custom_templates() statement(""); break; + case SPVFuncImplStorageMatrix: + statement("template"); + statement("struct spvStorageMatrix"); + begin_scope(); + statement("vec columns[Cols];"); + statement(""); + for (size_t method_idx = 0; method_idx < sizeof(address_spaces) / sizeof(address_spaces[0]); ++method_idx) + { + // Some address spaces require particular features. + if (method_idx == 4) // threadgroup_imageblock + statement("#ifdef __HAVE_IMAGEBLOCKS__"); + else if (method_idx == 5) // ray_data + statement("#ifdef __HAVE_RAYTRACING__"); + else if (method_idx == 6) // object_data + statement("#ifdef __HAVE_MESH__"); + const string &method_as = address_spaces[method_idx]; + statement("spvStorageMatrix() ", method_as, " = default;"); + if (method_idx != 1) // constant + { + statement(method_as, " spvStorageMatrix& operator=(initializer_list> cols) ", + method_as); + begin_scope(); + statement("size_t i;"); + statement("thread vec* col;"); + statement("for (i = 0, col = cols.begin(); i < Cols; ++i, ++col)"); + statement(" columns[i] = *col;"); + statement("return *this;"); + end_scope(); + } + statement(""); + for (size_t param_idx = 0; param_idx < sizeof(address_spaces) / sizeof(address_spaces[0]); ++param_idx) + { + if (param_idx != method_idx) + { + if (param_idx == 4) // threadgroup_imageblock + statement("#ifdef __HAVE_IMAGEBLOCKS__"); + else if (param_idx == 5) // ray_data + statement("#ifdef __HAVE_RAYTRACING__"); + else if (param_idx == 6) // object_data + statement("#ifdef __HAVE_MESH__"); + } + const string ¶m_as = address_spaces[param_idx]; + statement("spvStorageMatrix(const ", param_as, " matrix& m) ", method_as); + begin_scope(); + statement("for (size_t i = 0; i < Cols; ++i)"); + statement(" columns[i] = m.columns[i];"); + end_scope(); + statement("spvStorageMatrix(const ", param_as, " spvStorageMatrix& m) ", method_as, " = default;"); + if (method_idx != 1) // constant + { + statement(method_as, " spvStorageMatrix& operator=(const ", param_as, + " matrix& m) ", method_as); + begin_scope(); + statement("for (size_t i = 0; i < Cols; ++i)"); + statement(" columns[i] = m.columns[i];"); + statement("return *this;"); + end_scope(); + statement(method_as, " spvStorageMatrix& operator=(const ", param_as, " spvStorageMatrix& m) ", + method_as, " = default;"); + } + if (param_idx != method_idx && param_idx >= 4) + statement("#endif"); + statement(""); + } + statement("operator matrix() const ", method_as); + begin_scope(); + statement("matrix m;"); + statement("for (int i = 0; i < Cols; ++i)"); + statement(" m.columns[i] = columns[i];"); + statement("return m;"); + end_scope(); + statement(""); + statement("vec operator[](size_t idx) const ", method_as); + begin_scope(); + statement("return columns[idx];"); + end_scope(); + if (method_idx != 1) // constant + { + statement(method_as, " vec& operator[](size_t idx) ", method_as); + begin_scope(); + statement("return columns[idx];"); + end_scope(); + } + if (method_idx >= 4) + statement("#endif"); + statement(""); + } + end_scope_decl(); + statement(""); + statement("template"); + statement("matrix transpose(spvStorageMatrix m)"); + begin_scope(); + statement("return transpose(matrix(m));"); + end_scope(); + statement(""); + statement("typedef spvStorageMatrix spvStorage_half2x2;"); + statement("typedef spvStorageMatrix spvStorage_half2x3;"); + statement("typedef spvStorageMatrix spvStorage_half2x4;"); + statement("typedef spvStorageMatrix spvStorage_half3x2;"); + statement("typedef spvStorageMatrix spvStorage_half3x3;"); + statement("typedef spvStorageMatrix spvStorage_half3x4;"); + statement("typedef spvStorageMatrix spvStorage_half4x2;"); + statement("typedef spvStorageMatrix spvStorage_half4x3;"); + statement("typedef spvStorageMatrix spvStorage_half4x4;"); + statement("typedef spvStorageMatrix spvStorage_float2x2;"); + statement("typedef spvStorageMatrix spvStorage_float2x3;"); + statement("typedef spvStorageMatrix spvStorage_float2x4;"); + statement("typedef spvStorageMatrix spvStorage_float3x2;"); + statement("typedef spvStorageMatrix spvStorage_float3x3;"); + statement("typedef spvStorageMatrix spvStorage_float3x4;"); + statement("typedef spvStorageMatrix spvStorage_float4x2;"); + statement("typedef spvStorageMatrix spvStorage_float4x3;"); + statement("typedef spvStorageMatrix spvStorage_float4x4;"); + statement(""); + break; + default: break; } @@ -4862,7 +5687,7 @@ void CompilerMSL::emit_custom_functions() for (uint32_t variant = 0; variant < 12; variant++) { - uint32_t dimensions = spv_func - SPVFuncImplArrayCopyMultidimBase; + uint8_t dimensions = spv_func - SPVFuncImplArrayCopyMultidimBase; string tmp = "template= max(absP.y, absP.z);"); + statement("bool yMajor = absP.y >= absP.z;"); + statement("float3 Q = xMajor ? P.yzx : (yMajor ? P.xzy : P);"); + statement("float3 dQdx = xMajor ? dPdx.yzx : (yMajor ? dPdx.xzy : dPdx);"); + statement("float3 dQdy = xMajor ? dPdy.yzx : (yMajor ? dPdy.xzy : dPdy);"); + statement_no_indent(""); + statement("// Skip a couple of operations compared to usual projection"); + statement("float4 d = float4(dQdx.xy, dQdy.xy) - (Q.xy / Q.z).xyxy * float4(dQdx.zz, dQdy.zz);"); + statement_no_indent(""); + statement("// Final swizzle to put the intermediate values into non-ignored components"); + statement("// X major: X and Z"); + statement("// Y major: X and Y"); + statement("// Z major: Y and Z"); + statement("return gradientcube(xMajor ? d.xxy : d.xyx, xMajor ? d.zzw : d.zwz);"); + end_scope(); + statement(""); + break; + // "fadd" intrinsic support case SPVFuncImplFAdd: statement("template"); @@ -5373,7 +6223,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupBroadcast(T value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_broadcast(value, lane);"); else statement("return simd_broadcast(value, lane);"); @@ -5382,7 +6232,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupBroadcast(bool value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_broadcast((ushort)value, lane);"); else statement("return !!simd_broadcast((ushort)value, lane);"); @@ -5391,7 +6241,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupBroadcast(vec value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_broadcast((vec)value, lane);"); else statement("return (vec)simd_broadcast((vec)value, lane);"); @@ -5403,7 +6253,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupBroadcastFirst(T value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_broadcast_first(value);"); else statement("return simd_broadcast_first(value);"); @@ -5412,7 +6262,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupBroadcastFirst(bool value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_broadcast_first((ushort)value);"); else statement("return !!simd_broadcast_first((ushort)value);"); @@ -5421,7 +6271,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupBroadcastFirst(vec value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_broadcast_first((vec)value);"); else statement("return (vec)simd_broadcast_first((vec)value);"); @@ -5432,7 +6282,7 @@ void CompilerMSL::emit_custom_functions() case SPVFuncImplSubgroupBallot: statement("inline uint4 spvSubgroupBallot(bool value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) { statement("return uint4((quad_vote::vote_t)quad_ballot(value), 0, 0, 0);"); } @@ -5560,7 +6410,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline bool spvSubgroupAllEqual(T value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_all(all(value == quad_broadcast_first(value)));"); else statement("return simd_all(all(value == simd_broadcast_first(value)));"); @@ -5569,7 +6419,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupAllEqual(bool value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_all(value) || !quad_any(value);"); else statement("return simd_all(value) || !simd_any(value);"); @@ -5578,7 +6428,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline bool spvSubgroupAllEqual(vec value)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_all(all(value == (vec)quad_broadcast_first((vec)value)));"); else statement("return simd_all(all(value == (vec)simd_broadcast_first((vec)value)));"); @@ -5590,7 +6440,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupShuffle(T value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_shuffle(value, lane);"); else statement("return simd_shuffle(value, lane);"); @@ -5599,7 +6449,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupShuffle(bool value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_shuffle((ushort)value, lane);"); else statement("return !!simd_shuffle((ushort)value, lane);"); @@ -5608,7 +6458,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupShuffle(vec value, ushort lane)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_shuffle((vec)value, lane);"); else statement("return (vec)simd_shuffle((vec)value, lane);"); @@ -5620,7 +6470,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupShuffleXor(T value, ushort mask)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_shuffle_xor(value, mask);"); else statement("return simd_shuffle_xor(value, mask);"); @@ -5629,7 +6479,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupShuffleXor(bool value, ushort mask)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_shuffle_xor((ushort)value, mask);"); else statement("return !!simd_shuffle_xor((ushort)value, mask);"); @@ -5638,7 +6488,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupShuffleXor(vec value, ushort mask)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_shuffle_xor((vec)value, mask);"); else statement("return (vec)simd_shuffle_xor((vec)value, mask);"); @@ -5650,7 +6500,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupShuffleUp(T value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_shuffle_up(value, delta);"); else statement("return simd_shuffle_up(value, delta);"); @@ -5659,7 +6509,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupShuffleUp(bool value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_shuffle_up((ushort)value, delta);"); else statement("return !!simd_shuffle_up((ushort)value, delta);"); @@ -5668,7 +6518,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupShuffleUp(vec value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_shuffle_up((vec)value, delta);"); else statement("return (vec)simd_shuffle_up((vec)value, delta);"); @@ -5680,7 +6530,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline T spvSubgroupShuffleDown(T value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return quad_shuffle_down(value, delta);"); else statement("return simd_shuffle_down(value, delta);"); @@ -5689,7 +6539,7 @@ void CompilerMSL::emit_custom_functions() statement("template<>"); statement("inline bool spvSubgroupShuffleDown(bool value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return !!quad_shuffle_down((ushort)value, delta);"); else statement("return !!simd_shuffle_down((ushort)value, delta);"); @@ -5698,7 +6548,7 @@ void CompilerMSL::emit_custom_functions() statement("template"); statement("inline vec spvSubgroupShuffleDown(vec value, ushort delta)"); begin_scope(); - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) statement("return (vec)quad_shuffle_down((vec)value, delta);"); else statement("return (vec)simd_shuffle_down((vec)value, delta);"); @@ -6496,6 +7346,109 @@ void CompilerMSL::emit_custom_functions() end_scope(); end_scope_decl(); statement(""); + break; + + case SPVFuncImplRayQueryIntersectionParams: + statement("intersection_params spvMakeIntersectionParams(uint flags)"); + begin_scope(); + statement("intersection_params ip;"); + statement("if ((flags & ", RayFlagsOpaqueKHRMask, ") != 0)"); + statement(" ip.force_opacity(forced_opacity::opaque);"); + statement("if ((flags & ", RayFlagsNoOpaqueKHRMask, ") != 0)"); + statement(" ip.force_opacity(forced_opacity::non_opaque);"); + statement("if ((flags & ", RayFlagsTerminateOnFirstHitKHRMask, ") != 0)"); + statement(" ip.accept_any_intersection(true);"); + // RayFlagsSkipClosestHitShaderKHRMask is not available in MSL + statement("if ((flags & ", RayFlagsCullBackFacingTrianglesKHRMask, ") != 0)"); + statement(" ip.set_triangle_cull_mode(triangle_cull_mode::back);"); + statement("if ((flags & ", RayFlagsCullFrontFacingTrianglesKHRMask, ") != 0)"); + statement(" ip.set_triangle_cull_mode(triangle_cull_mode::front);"); + statement("if ((flags & ", RayFlagsCullOpaqueKHRMask, ") != 0)"); + statement(" ip.set_opacity_cull_mode(opacity_cull_mode::opaque);"); + statement("if ((flags & ", RayFlagsCullNoOpaqueKHRMask, ") != 0)"); + statement(" ip.set_opacity_cull_mode(opacity_cull_mode::non_opaque);"); + statement("if ((flags & ", RayFlagsSkipTrianglesKHRMask, ") != 0)"); + statement(" ip.set_geometry_cull_mode(geometry_cull_mode::triangle);"); + statement("if ((flags & ", RayFlagsSkipAABBsKHRMask, ") != 0)"); + statement(" ip.set_geometry_cull_mode(geometry_cull_mode::bounding_box);"); + statement("return ip;"); + end_scope(); + statement(""); + break; + + case SPVFuncImplVariableDescriptor: + statement("template"); + statement("struct spvDescriptor"); + begin_scope(); + statement("T value;"); + end_scope_decl(); + statement(""); + break; + + case SPVFuncImplVariableSizedDescriptor: + statement("template"); + statement("struct spvBufferDescriptor"); + begin_scope(); + statement("T value;"); + statement("int length;"); + statement("const device T& operator -> () const device"); + begin_scope(); + statement("return value;"); + end_scope(); + statement("const device T& operator * () const device"); + begin_scope(); + statement("return value;"); + end_scope(); + end_scope_decl(); + statement(""); + break; + + case SPVFuncImplVariableDescriptorArray: + statement("template"); + statement("struct spvDescriptorArray"); + begin_scope(); + statement("spvDescriptorArray(const device spvDescriptor* ptr) : ptr(ptr)"); + begin_scope(); + end_scope(); + statement("const device T& operator [] (size_t i) const"); + begin_scope(); + statement("return ptr[i].value;"); + end_scope(); + statement("const device spvDescriptor* ptr;"); + end_scope_decl(); + statement(""); + + if (msl_options.runtime_array_rich_descriptor && + spv_function_implementations.count(SPVFuncImplVariableSizedDescriptor) != 0) + { + statement("template"); + statement("struct spvDescriptorArray"); + begin_scope(); + statement("spvDescriptorArray(const device spvBufferDescriptor* ptr) : ptr(ptr)"); + begin_scope(); + end_scope(); + statement("const device T* operator [] (size_t i) const"); + begin_scope(); + statement("return ptr[i].value;"); + end_scope(); + statement("const int length(int i) const"); + begin_scope(); + statement("return ptr[i].length;"); + end_scope(); + statement("const device spvBufferDescriptor* ptr;"); + end_scope_decl(); + statement(""); + } + break; + + case SPVFuncImplPaddedStd140: + // .data is used in access chain. + statement("template "); + statement("struct spvPaddedStd140 { alignas(16) T data; };"); + statement("template "); + statement("using spvPaddedStd140Matrix = spvPaddedStd140[n];"); + statement(""); + break; default: break; @@ -6516,7 +7469,7 @@ static string inject_top_level_storage_qualifier(const string &expr, const strin else if (last_pointer == string::npos) last_significant = last_reference; else - last_significant = std::max(last_reference, last_pointer); + last_significant = max(last_reference, last_pointer); if (last_significant == string::npos) return join(qualifier, " ", expr); @@ -6527,28 +7480,6 @@ static string inject_top_level_storage_qualifier(const string &expr, const strin } } -// Undefined global memory is not allowed in MSL. -// Declare constant and init to zeros. Use {}, as global constructors can break Metal. -void CompilerMSL::declare_undefined_values() -{ - bool emitted = false; - ir.for_each_typed_id([&](uint32_t, SPIRUndef &undef) { - auto &type = this->get(undef.basetype); - // OpUndef can be void for some reason ... - if (type.basetype == SPIRType::Void) - return; - - statement(inject_top_level_storage_qualifier( - variable_decl(type, to_name(undef.self), undef.self), - "constant"), - " = {};"); - emitted = true; - }); - - if (emitted) - statement(""); -} - void CompilerMSL::declare_constant_arrays() { bool fully_inlined = ir.ids_for_type[TypeFunction].size() == 1; @@ -6566,8 +7497,9 @@ void CompilerMSL::declare_constant_arrays() // FIXME: However, hoisting constants to main() means we need to pass down constant arrays to leaf functions if they are used there. // If there are multiple functions in the module, drop this case to avoid breaking use cases which do not need to // link into Metal libraries. This is hacky. - if (!type.array.empty() && (!fully_inlined || is_scalar(type) || is_vector(type))) + if (is_array(type) && (!fully_inlined || is_scalar(type) || is_vector(type))) { + add_resource_name(c.self); auto name = to_name(c.self); statement(inject_top_level_storage_qualifier(variable_decl(type, name), "constant"), " = ", constant_expression(c), ";"); @@ -6597,8 +7529,9 @@ void CompilerMSL::declare_complex_constant_arrays() return; auto &type = this->get(c.constant_type); - if (!type.array.empty() && !(is_scalar(type) || is_vector(type))) + if (is_array(type) && !(is_scalar(type) || is_vector(type))) { + add_resource_name(c.self); auto name = to_name(c.self); statement("", variable_decl(type, name), " = ", constant_expression(c), ";"); emitted = true; @@ -6612,7 +7545,6 @@ void CompilerMSL::declare_complex_constant_arrays() void CompilerMSL::emit_resources() { declare_constant_arrays(); - declare_undefined_values(); // Emit the special [[stage_in]] and [[stage_out]] interface blocks which we created. emit_interface_block(stage_out_var_id); @@ -6656,7 +7588,35 @@ void CompilerMSL::emit_specialization_constants_and_structs() // these types for purpose of iterating over them in ir.ids_for_type and friends. auto loop_lock = ir.create_loop_soft_lock(); - for (auto &id_ : ir.ids_for_constant_or_type) + // Physical storage buffer pointers can have cyclical references, + // so emit forward declarations of them before other structs. + // Ignore type_id because we want the underlying struct type from the pointer. + ir.for_each_typed_id([&](uint32_t /* type_id */, const SPIRType &type) { + if (type.basetype == SPIRType::Struct && + type.pointer && type.storage == StorageClassPhysicalStorageBuffer && + declared_structs.count(type.self) == 0) + { + statement("struct ", to_name(type.self), ";"); + declared_structs.insert(type.self); + emitted = true; + } + }); + if (emitted) + statement(""); + + emitted = false; + declared_structs.clear(); + + // It is possible to have multiple spec constants that use the same spec constant ID. + // The most common cause of this is defining spec constants in GLSL while also declaring + // the workgroup size to use those spec constants. But, Metal forbids declaring more than + // one variable with the same function constant ID. + // In this case, we must only declare one variable with the [[function_constant(id)]] + // attribute, and use its initializer to initialize all the spec constants with + // that ID. + std::unordered_map unique_func_constants; + + for (auto &id_ : ir.ids_for_constant_undef_or_type) { auto &id = ir.ids[id_]; @@ -6677,8 +7637,8 @@ void CompilerMSL::emit_specialization_constants_and_structs() { auto &type = get(c.constant_type); string sc_type_name = type_to_glsl(type); + add_resource_name(c.self); string sc_name = to_name(c.self); - string sc_tmp_name = sc_name + "_tmp"; // Function constants are only supported in MSL 1.2 and later. // If we don't support it just declare the "default" directly. @@ -6688,12 +7648,18 @@ void CompilerMSL::emit_specialization_constants_and_structs() if (msl_options.supports_msl_version(1, 2) && has_decoration(c.self, DecorationSpecId) && !c.is_used_as_array_length) { - uint32_t constant_id = get_decoration(c.self, DecorationSpecId); // Only scalar, non-composite values can be function constants. - statement("constant ", sc_type_name, " ", sc_tmp_name, " [[function_constant(", constant_id, - ")]];"); + uint32_t constant_id = get_decoration(c.self, DecorationSpecId); + if (!unique_func_constants.count(constant_id)) + unique_func_constants.insert(make_pair(constant_id, c.self)); + SPIRType::BaseType sc_tmp_type = expression_type(unique_func_constants[constant_id]).basetype; + string sc_tmp_name = to_name(unique_func_constants[constant_id]) + "_tmp"; + if (unique_func_constants[constant_id] == c.self) + statement("constant ", sc_type_name, " ", sc_tmp_name, " [[function_constant(", constant_id, + ")]];"); statement("constant ", sc_type_name, " ", sc_name, " = is_function_constant_defined(", sc_tmp_name, - ") ? ", sc_tmp_name, " : ", constant_expression(c), ";"); + ") ? ", bitcast_expression(type, sc_tmp_type, sc_tmp_name), " : ", constant_expression(c), + ";"); } else if (has_decoration(c.self, DecorationSpecId)) { @@ -6719,6 +7685,7 @@ void CompilerMSL::emit_specialization_constants_and_structs() { auto &c = id.get(); auto &type = get(c.basetype); + add_resource_name(c.self); auto name = to_name(c.self); statement("constant ", variable_decl(type, name), " = ", constant_op_expression(c), ";"); emitted = true; @@ -6767,12 +7734,44 @@ void CompilerMSL::emit_specialization_constants_and_structs() emit_struct(get(type_id)); } } + else if (id.get_type() == TypeUndef) + { + auto &undef = id.get(); + auto &type = get(undef.basetype); + // OpUndef can be void for some reason ... + if (type.basetype == SPIRType::Void) + return; + + // Undefined global memory is not allowed in MSL. + // Declare constant and init to zeros. Use {}, as global constructors can break Metal. + statement( + inject_top_level_storage_qualifier(variable_decl(type, to_name(undef.self), undef.self), "constant"), + " = {};"); + emitted = true; + } } if (emitted) statement(""); } +void CompilerMSL::emit_binary_ptr_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) +{ + bool forward = should_forward(op0) && should_forward(op1); + emit_op(result_type, result_id, join(to_ptr_expression(op0), " ", op, " ", to_ptr_expression(op1)), forward); + inherit_expression_dependencies(result_id, op0); + inherit_expression_dependencies(result_id, op1); +} + +string CompilerMSL::to_ptr_expression(uint32_t id, bool register_expression_read) +{ + auto *e = maybe_get(id); + auto expr = enclose_expression(e && e->need_transpose ? e->expression : to_expression(id, register_expression_read)); + if (!should_dereference(id)) + expr = address_of_expression(expr); + return expr; +} + void CompilerMSL::emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op) { @@ -6793,7 +7792,7 @@ bool CompilerMSL::emit_tessellation_io_load(uint32_t result_type_id, uint32_t id auto &result_type = get(result_type_id); if (ptr_type.storage != StorageClassInput && ptr_type.storage != StorageClassOutput) return false; - if (ptr_type.storage == StorageClassOutput && get_execution_model() == ExecutionModelTessellationEvaluation) + if (ptr_type.storage == StorageClassOutput && is_tese_shader()) return false; if (has_decoration(ptr, DecorationPatch)) @@ -7115,21 +8114,22 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l bool flatten_composites = false; bool is_block = false; - - if (var) - is_block = has_decoration(get_variable_data_type(*var).self, DecorationBlock); + bool is_arrayed = false; if (var) { + auto &type = get_variable_data_type(*var); + is_block = has_decoration(type.self, DecorationBlock); + is_arrayed = !type.array.empty(); + flatten_composites = variable_storage_requires_stage_io(var->storage); - patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(get_variable_data_type(*var)); + patch = has_decoration(ops[2], DecorationPatch) || is_patch_block(type); // Should match strip_array in add_interface_block. - flat_data = var->storage == StorageClassInput || - (var->storage == StorageClassOutput && get_execution_model() == ExecutionModelTessellationControl); + flat_data = var->storage == StorageClassInput || (var->storage == StorageClassOutput && is_tesc_shader()); // Patch inputs are treated as normal block IO variables, so they don't deal with this path at all. - if (patch && (!is_block || var->storage == StorageClassInput)) + if (patch && (!is_block || is_arrayed || var->storage == StorageClassInput)) flat_data = false; // We might have a chained access chain, where @@ -7268,8 +8268,9 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l // We're not going to emit the actual member name, we let any further OpLoad take care of that. // Tag the access chain with the member index we're referencing. - bool defer_access_chain = flatten_composites && (is_matrix(result_ptr_type) || is_array(result_ptr_type) || - result_ptr_type.basetype == SPIRType::Struct); + auto &result_pointee_type = get_pointee_type(result_ptr_type); + bool defer_access_chain = flatten_composites && (is_matrix(result_pointee_type) || is_array(result_pointee_type) || + result_pointee_type.basetype == SPIRType::Struct); if (!defer_access_chain) { @@ -7367,7 +8368,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l expr_type->vecsize > result_ptr_type.vecsize) e += vector_swizzle(result_ptr_type.vecsize, 0); - auto &expr = set(ops[1], move(e), ops[0], should_forward(ops[2])); + auto &expr = set(ops[1], std::move(e), ops[0], should_forward(ops[2])); expr.loaded_from = var->self; expr.need_transpose = meta.need_transpose; expr.access_chain = true; @@ -7410,8 +8411,8 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l // Don't do this if the index is a constant 1, though. We need to drop stores // to that one. auto *m = ir.find_meta(var ? var->self : ID(0)); - if (get_execution_model() == ExecutionModelTessellationControl && var && m && - m->decoration.builtin_type == BuiltInTessLevelInner && get_entry_point().flags.get(ExecutionModeTriangles)) + if (is_tesc_shader() && var && m && m->decoration.builtin_type == BuiltInTessLevelInner && + is_tessellating_triangles()) { auto *c = maybe_get(ops[3]); if (c && c->scalar() == 1) @@ -7428,7 +8429,7 @@ bool CompilerMSL::emit_tessellation_access_chain(const uint32_t *ops, uint32_t l bool CompilerMSL::is_out_of_bounds_tessellation_level(uint32_t id_lhs) { - if (!get_entry_point().flags.get(ExecutionModeTriangles)) + if (!is_tessellating_triangles()) return false; // In SPIR-V, TessLevelInner always has two elements and TessLevelOuter always has @@ -7438,7 +8439,7 @@ bool CompilerMSL::is_out_of_bounds_tessellation_level(uint32_t id_lhs) // In Metal, however, only the first element of TessLevelInner and the first three // of TessLevelOuter are accessible. This stems from how in Metal, the tessellation // levels must be stored to a dedicated buffer in a particular format that depends - // on the patch type. Therefore, in Triangles mode, any access to the second + // on the patch type. Therefore, in Triangles mode, any store to the second // inner level or the fourth outer level must be dropped. const auto *e = maybe_get(id_lhs); if (!e || !e->access_chain) @@ -7453,7 +8454,7 @@ bool CompilerMSL::is_out_of_bounds_tessellation_level(uint32_t id_lhs) (builtin == BuiltInTessLevelOuter && c->scalar() == 3); } -void CompilerMSL::prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, +bool CompilerMSL::prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage, bool &is_packed) { // If there is any risk of writes happening with the access chain in question, @@ -7467,7 +8468,10 @@ void CompilerMSL::prepare_access_chain_for_scalar_access(std::string &expr, cons // Further indexing should happen with packed rules (array index, not swizzle). is_packed = true; + return true; } + else + return false; } bool CompilerMSL::access_chain_needs_stage_io_builtin_translation(uint32_t base) @@ -7480,8 +8484,7 @@ bool CompilerMSL::access_chain_needs_stage_io_builtin_translation(uint32_t base) // Avoid overriding it back to just gl_ClipDistance. // This can only happen in scenarios where we cannot flatten/unflatten access chains, so, the only case // where this triggers is evaluation shader inputs. - bool redirect_builtin = get_execution_model() == ExecutionModelTessellationEvaluation ? - var->storage == StorageClassOutput : false; + bool redirect_builtin = is_tese_shader() ? var->storage == StorageClassOutput : false; return redirect_builtin; } @@ -7540,12 +8543,31 @@ void CompilerMSL::fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t set_extended_decoration(ops[1], SPIRVCrossDecorationInterfaceMemberIndex, interface_index); } + +// If the physical type of a physical buffer pointer has been changed +// to a ulong or ulongn vector, add a cast back to the pointer type. +void CompilerMSL::check_physical_type_cast(std::string &expr, const SPIRType *type, uint32_t physical_type) +{ + auto *p_physical_type = maybe_get(physical_type); + if (p_physical_type && + p_physical_type->storage == StorageClassPhysicalStorageBuffer && + p_physical_type->basetype == to_unsigned_basetype(64)) + { + if (p_physical_type->vecsize > 1) + expr += ".x"; + + expr = join("((", type_to_glsl(*type), ")", expr, ")"); + } +} + // Override for MSL-specific syntax instructions void CompilerMSL::emit_instruction(const Instruction &instruction) { #define MSL_BOP(op) emit_binary_op(ops[0], ops[1], ops[2], ops[3], #op) +#define MSL_PTR_BOP(op) emit_binary_ptr_op(ops[0], ops[1], ops[2], ops[3], #op) + // MSL does care about implicit integer promotion, but those cases are all handled in common code. #define MSL_BOP_CAST(op, type) \ - emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode)) + emit_binary_op_cast(ops[0], ops[1], ops[2], ops[3], #op, type, opcode_is_sign_invariant(opcode), false) #define MSL_UOP(op) emit_unary_op(ops[0], ops[1], ops[2], #op) #define MSL_QFOP(op) emit_quaternary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], ops[5], #op) #define MSL_TFOP(op) emit_trinary_func_op(ops[0], ops[1], ops[2], ops[3], ops[4], #op) @@ -7558,6 +8580,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) auto ops = stream(instruction); auto opcode = static_cast(instruction.op); + opcode = get_remapped_spirv_op(opcode); + // If we need to do implicit bitcasts, make sure we do it with the correct type. uint32_t integer_width = get_integer_width_for_instruction(instruction); auto int_type = to_signed_basetype(integer_width); @@ -7600,6 +8624,10 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) case OpLogicalNotEqual: case OpFOrdNotEqual: + // TODO: Should probably negate the == result here. + // Typically OrdNotEqual comes from GLSL which itself does not really specify what + // happens with NaN. + // Consider fixing this if we run into real issues. MSL_BOP(!=); break; @@ -7656,7 +8684,9 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; case OpFUnordNotEqual: - MSL_UNORD_BOP(!=); + // not equal in MSL generates une opcodes to begin with. + // Since unordered not equal is how it works in C, just inherit that behavior. + MSL_BOP(!=); break; case OpFUnordGreaterThan: @@ -7675,6 +8705,19 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) MSL_UNORD_BOP(<=); break; + // Pointer math + case OpPtrEqual: + MSL_PTR_BOP(==); + break; + + case OpPtrNotEqual: + MSL_PTR_BOP(!=); + break; + + case OpPtrDiff: + MSL_PTR_BOP(-); + break; + // Derivatives case OpDPdx: case OpDPdxFine: @@ -7763,7 +8806,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t ptr = ops[2]; uint32_t mem_sem = ops[4]; uint32_t val = ops[5]; - emit_atomic_func_op(result_type, id, "atomic_exchange_explicit", mem_sem, mem_sem, false, ptr, val); + emit_atomic_func_op(result_type, id, "atomic_exchange", opcode, mem_sem, mem_sem, false, ptr, val); break; } @@ -7776,7 +8819,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t mem_sem_fail = ops[5]; uint32_t val = ops[6]; uint32_t comp = ops[7]; - emit_atomic_func_op(result_type, id, "atomic_compare_exchange_weak_explicit", mem_sem_pass, mem_sem_fail, true, + emit_atomic_func_op(result_type, id, "atomic_compare_exchange_weak", opcode, + mem_sem_pass, mem_sem_fail, true, ptr, comp, true, false, val); break; } @@ -7790,7 +8834,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t id = ops[1]; uint32_t ptr = ops[2]; uint32_t mem_sem = ops[4]; - emit_atomic_func_op(result_type, id, "atomic_load_explicit", mem_sem, mem_sem, false, ptr, 0); + check_atomic_image(ptr); + emit_atomic_func_op(result_type, id, "atomic_load", opcode, mem_sem, mem_sem, false, ptr, 0); break; } @@ -7801,7 +8846,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t ptr = ops[0]; uint32_t mem_sem = ops[2]; uint32_t val = ops[3]; - emit_atomic_func_op(result_type, id, "atomic_store_explicit", mem_sem, mem_sem, false, ptr, val); + check_atomic_image(ptr); + emit_atomic_func_op(result_type, id, "atomic_store", opcode, mem_sem, mem_sem, false, ptr, val); break; } @@ -7813,7 +8859,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t ptr = ops[2]; \ uint32_t mem_sem = ops[4]; \ uint32_t val = valsrc; \ - emit_atomic_func_op(result_type, id, "atomic_fetch_" #op "_explicit", mem_sem, mem_sem, false, ptr, val, \ + emit_atomic_func_op(result_type, id, "atomic_fetch_" #op, opcode, \ + mem_sem, mem_sem, false, ptr, val, \ false, valconst); \ } while (false) @@ -7829,6 +8876,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; case OpAtomicIAdd: + case OpAtomicFAddEXT: MSL_AFMO(add); break; @@ -7866,9 +8914,9 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) // Mark that this shader reads from this image uint32_t img_id = ops[2]; auto &type = expression_type(img_id); + auto *p_var = maybe_get_backing_variable(img_id); if (type.image.dim != DimSubpassData) { - auto *p_var = maybe_get_backing_variable(img_id); if (p_var && has_decoration(p_var->self, DecorationNonReadable)) { unset_decoration(p_var->self, DecorationNonReadable); @@ -7876,6 +8924,10 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) } } + // Metal requires explicit fences to break up RAW hazards, even within the same shader invocation + if (msl_options.readwrite_texture_fences && p_var && !has_decoration(p_var->self, DecorationNonWritable)) + statement(to_expression(img_id), ".fence();"); + emit_texture_op(instruction, false); break; } @@ -7885,7 +8937,7 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) { // When using the pointer, we need to know which variable it is actually loaded from. auto *var = maybe_get_backing_variable(ops[2]); - if (var && atomic_image_vars.count(var->self)) + if (var && atomic_image_vars_emulated.count(var->self)) { uint32_t result_type = ops[0]; uint32_t id = ops[1]; @@ -7905,8 +8957,14 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) { uint32_t result_type = ops[0]; uint32_t id = ops[1]; + + // Virtual expression. Split this up in the actual image atomic. + // In GLSL and HLSL we are able to resolve the dereference inline, but MSL has + // image.op(coord, ...) syntax. auto &e = - set(id, join(to_expression(ops[2]), ", ", to_expression(ops[3])), result_type, true); + set(id, join(to_expression(ops[2]), "@", + bitcast_expression(SPIRType::UInt, ops[3])), + result_type, true); // When using the pointer, we need to know which variable it is actually loaded from. e.loaded_from = var ? var->self : ID(0); @@ -7968,9 +9026,16 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) args.base.is_fetch = true; args.coord = coord_id; args.lod = lod; - statement(join(to_expression(img_id), ".write(", - remap_swizzle(store_type, texel_type.vecsize, to_expression(texel_id)), ", ", - CompilerMSL::to_function_args(args, &forward), ");")); + + string expr; + if (needs_frag_discard_checks()) + expr = join("(", builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput), " ? ((void)0) : "); + expr += join(to_expression(img_id), ".write(", + remap_swizzle(store_type, texel_type.vecsize, to_expression(texel_id)), ", ", + CompilerMSL::to_function_args(args, &forward), ")"); + if (needs_frag_discard_checks()) + expr += ")"; + statement(expr, ";"); if (p_var && variable_storage_is_aliased(*p_var)) flush_all_aliased_variables(); @@ -8125,14 +9190,34 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; case OpStore: + { + const auto &type = expression_type(ops[0]); + if (is_out_of_bounds_tessellation_level(ops[0])) break; - if (maybe_emit_array_assignment(ops[0], ops[1])) - break; - - CompilerGLSL::emit_instruction(instruction); + if (needs_frag_discard_checks() && + (type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform)) + { + // If we're in a continue block, this kludge will make the block too complex + // to emit normally. + assert(current_emitting_block); + auto cont_type = continue_block_type(*current_emitting_block); + if (cont_type != SPIRBlock::ContinueNone && cont_type != SPIRBlock::ComplexLoop) + { + current_emitting_block->complex_continue = true; + force_recompile(); + } + statement("if (!", builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput), ")"); + begin_scope(); + } + if (!maybe_emit_array_assignment(ops[0], ops[1])) + CompilerGLSL::emit_instruction(instruction); + if (needs_frag_discard_checks() && + (type.storage == StorageClassStorageBuffer || type.storage == StorageClassUniform)) + end_scope(); break; + } // Compute barriers case OpMemoryBarrier: @@ -8289,12 +9374,33 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) uint32_t op0 = ops[2]; uint32_t op1 = ops[3]; auto &type = get(result_type); + auto input_type = opcode == OpSMulExtended ? int_type : uint_type; + auto &output_type = get_type(result_type); + string cast_op0, cast_op1; + + auto expected_type = binary_op_bitcast_helper(cast_op0, cast_op1, input_type, op0, op1, false); + emit_uninitialized_temporary_expression(result_type, result_id); - statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", - to_enclosed_unpacked_expression(op0), " * ", to_enclosed_unpacked_expression(op1), ";"); - statement(to_expression(result_id), ".", to_member_name(type, 1), " = mulhi(", - to_unpacked_expression(op0), ", ", to_unpacked_expression(op1), ");"); + string mullo_expr, mulhi_expr; + mullo_expr = join(cast_op0, " * ", cast_op1); + mulhi_expr = join("mulhi(", cast_op0, ", ", cast_op1, ")"); + + auto &low_type = get_type(output_type.member_types[0]); + auto &high_type = get_type(output_type.member_types[1]); + if (low_type.basetype != input_type) + { + expected_type.basetype = input_type; + mullo_expr = join(bitcast_glsl_op(low_type, expected_type), "(", mullo_expr, ")"); + } + if (high_type.basetype != input_type) + { + expected_type.basetype = input_type; + mulhi_expr = join(bitcast_glsl_op(high_type, expected_type), "(", mulhi_expr, ")"); + } + + statement(to_expression(result_id), ".", to_member_name(type, 0), " = ", mullo_expr, ";"); + statement(to_expression(result_id), ".", to_member_name(type, 1), " = ", mulhi_expr, ";"); break; } @@ -8309,6 +9415,16 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) break; } + // Legacy sub-group stuff ... + case OpSubgroupBallotKHR: + case OpSubgroupFirstInvocationKHR: + case OpSubgroupReadInvocationKHR: + case OpSubgroupAllKHR: + case OpSubgroupAnyKHR: + case OpSubgroupAllEqualKHR: + emit_subgroup_op(instruction); + break; + // SPV_INTEL_shader_integer_functions2 case OpUCountLeadingZerosINTEL: MSL_UFOP(clz); @@ -8379,7 +9495,10 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 2.3 on iOS."); else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) SPIRV_CROSS_THROW("simd_is_helper_thread() requires MSL 2.1 on macOS."); - emit_op(ops[0], ops[1], "simd_is_helper_thread()", false); + emit_op(ops[0], ops[1], + needs_manual_helper_invocation_updates() ? builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput) : + "simd_is_helper_thread()", + false); break; case OpBeginInvocationInterlockEXT: @@ -8396,15 +9515,18 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) case OpRayQueryInitializeKHR: { flush_variable_declaration(ops[0]); + register_write(ops[0]); + add_spv_func_and_recompile(SPVFuncImplRayQueryIntersectionParams); statement(to_expression(ops[0]), ".reset(", "ray(", to_expression(ops[4]), ", ", to_expression(ops[6]), ", ", - to_expression(ops[5]), ", ", to_expression(ops[7]), "), ", to_expression(ops[1]), - ", intersection_params());"); + to_expression(ops[5]), ", ", to_expression(ops[7]), "), ", to_expression(ops[1]), ", ", to_expression(ops[3]), + ", spvMakeIntersectionParams(", to_expression(ops[2]), "));"); break; } case OpRayQueryProceedKHR: { flush_variable_declaration(ops[0]); + register_write(ops[2]); emit_op(ops[0], ops[1], join(to_expression(ops[2]), ".next()"), false); break; } @@ -8429,8 +9551,8 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) #define MSL_RAY_QUERY_IS_OP2(op, msl_op) MSL_RAY_QUERY_OP_INNER2(op, .is, msl_op) MSL_RAY_QUERY_GET_OP(RayTMin, ray_min_distance); - MSL_RAY_QUERY_GET_OP(WorldRayOrigin, world_space_ray_direction); - MSL_RAY_QUERY_GET_OP(WorldRayDirection, world_space_ray_origin); + MSL_RAY_QUERY_GET_OP(WorldRayOrigin, world_space_ray_origin); + MSL_RAY_QUERY_GET_OP(WorldRayDirection, world_space_ray_direction); MSL_RAY_QUERY_GET_OP2(IntersectionInstanceId, instance_id); MSL_RAY_QUERY_GET_OP2(IntersectionInstanceCustomIndex, user_instance_id); MSL_RAY_QUERY_GET_OP2(IntersectionBarycentrics, triangle_barycentric_coord); @@ -8465,14 +9587,17 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) } case OpRayQueryConfirmIntersectionKHR: flush_variable_declaration(ops[0]); + register_write(ops[0]); statement(to_expression(ops[0]), ".commit_triangle_intersection();"); break; case OpRayQueryGenerateIntersectionKHR: flush_variable_declaration(ops[0]); + register_write(ops[0]); statement(to_expression(ops[0]), ".commit_bounding_box_intersection(", to_expression(ops[1]), ");"); break; case OpRayQueryTerminateKHR: flush_variable_declaration(ops[0]); + register_write(ops[0]); statement(to_expression(ops[0]), ".abort();"); break; #undef MSL_RAY_QUERY_GET_OP @@ -8480,6 +9605,34 @@ void CompilerMSL::emit_instruction(const Instruction &instruction) #undef MSL_RAY_QUERY_IS_OP2 #undef MSL_RAY_QUERY_GET_OP2 #undef MSL_RAY_QUERY_OP_INNER2 + + case OpConvertPtrToU: + case OpConvertUToPtr: + case OpBitcast: + { + auto &type = get(ops[0]); + auto &input_type = expression_type(ops[2]); + + if (opcode != OpBitcast || type.pointer || input_type.pointer) + { + string op; + + if (type.vecsize == 1 && input_type.vecsize == 1) + op = join("reinterpret_cast<", type_to_glsl(type), ">(", to_unpacked_expression(ops[2]), ")"); + else if (input_type.vecsize == 2) + op = join("reinterpret_cast<", type_to_glsl(type), ">(as_type(", to_unpacked_expression(ops[2]), "))"); + else + op = join("as_type<", type_to_glsl(type), ">(reinterpret_cast(", to_unpacked_expression(ops[2]), "))"); + + emit_op(ops[0], ops[1], op, should_forward(ops[2])); + inherit_expression_dependencies(ops[1], ops[2]); + } + else + CompilerGLSL::emit_instruction(instruction); + + break; + } + default: CompilerGLSL::emit_instruction(instruction); break; @@ -8521,7 +9674,7 @@ void CompilerMSL::emit_texture_op(const Instruction &i, bool sparse) void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem) { - if (get_execution_model() != ExecutionModelGLCompute && get_execution_model() != ExecutionModelTessellationControl) + if (get_execution_model() != ExecutionModelGLCompute && !is_tesc_shader()) return; uint32_t exe_scope = id_exe_scope ? evaluate_constant_u32(id_exe_scope) : uint32_t(ScopeInvocation); @@ -8548,13 +9701,12 @@ void CompilerMSL::emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uin string mem_flags = ""; // For tesc shaders, this also affects objects in the Output storage class. // Since in Metal, these are placed in a device buffer, we have to sync device memory here. - if (get_execution_model() == ExecutionModelTessellationControl || + if (is_tesc_shader() || (mem_sem & (MemorySemanticsUniformMemoryMask | MemorySemanticsCrossWorkgroupMemoryMask))) mem_flags += "mem_flags::mem_device"; // Fix tessellation patch function processing - if (get_execution_model() == ExecutionModelTessellationControl || - (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask))) + if (is_tesc_shader() || (mem_sem & (MemorySemanticsSubgroupMemoryMask | MemorySemanticsWorkgroupMemoryMask))) { if (!mem_flags.empty()) mem_flags += " | "; @@ -8612,7 +9764,7 @@ static bool storage_class_array_is_thread(StorageClass storage) } } -void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t rhs_id, +bool CompilerMSL::emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, StorageClass lhs_storage, StorageClass rhs_storage) { // Allow Metal to use the array template to make arrays a value type. @@ -8620,8 +9772,8 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r bool lhs_is_thread_storage = storage_class_array_is_thread(lhs_storage); bool rhs_is_thread_storage = storage_class_array_is_thread(rhs_storage); - bool lhs_is_array_template = lhs_is_thread_storage; - bool rhs_is_array_template = rhs_is_thread_storage; + bool lhs_is_array_template = lhs_is_thread_storage || lhs_storage == StorageClassWorkgroup; + bool rhs_is_array_template = rhs_is_thread_storage || rhs_storage == StorageClassWorkgroup; // Special considerations for stage IO variables. // If the variable is actually backed by non-user visible device storage, we use array templates for those. @@ -8636,25 +9788,34 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r auto *lhs_var = maybe_get_backing_variable(lhs_id); if (lhs_var && lhs_storage == StorageClassStorageBuffer && storage_class_array_is_thread(lhs_var->storage)) lhs_is_array_template = true; - else if (lhs_var && (lhs_storage == StorageClassFunction || lhs_storage == StorageClassPrivate) && - type_is_block_like(get(lhs_var->basetype))) + else if (lhs_var && lhs_storage != StorageClassGeneric && type_is_block_like(get(lhs_var->basetype))) lhs_is_array_template = false; auto *rhs_var = maybe_get_backing_variable(rhs_id); if (rhs_var && rhs_storage == StorageClassStorageBuffer && storage_class_array_is_thread(rhs_var->storage)) rhs_is_array_template = true; - else if (rhs_var && (rhs_storage == StorageClassFunction || rhs_storage == StorageClassPrivate) && - type_is_block_like(get(rhs_var->basetype))) + else if (rhs_var && rhs_storage != StorageClassGeneric && type_is_block_like(get(rhs_var->basetype))) rhs_is_array_template = false; // If threadgroup storage qualifiers are *not* used: // Avoid spvCopy* wrapper functions; Otherwise, spvUnsafeArray<> template cannot be used with that storage qualifier. if (lhs_is_array_template && rhs_is_array_template && !using_builtin_array()) { - statement(lhs, " = ", to_expression(rhs_id), ";"); + // Fall back to normal copy path. + return false; } else { + // Ensure the LHS variable has been declared + if (lhs_var) + flush_variable_declaration(lhs_var->self); + + string lhs; + if (expr) + lhs = expr; + else + lhs = to_expression(lhs_id); + // Assignment from an array initializer is fine. auto &type = expression_type(rhs_id); auto *var = maybe_get_backing_variable(rhs_id); @@ -8671,7 +9832,7 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r { is_constant = true; } - else if (rhs_storage == StorageClassUniform) + else if (rhs_storage == StorageClassUniform || rhs_storage == StorageClassUniformConstant) { is_constant = true; } @@ -8728,11 +9889,13 @@ void CompilerMSL::emit_array_copy(const string &lhs, uint32_t lhs_id, uint32_t r else statement("spvArrayCopy", tag, type.array.size(), "(", lhs, ", ", to_expression(rhs_id), ");"); } + + return true; } uint32_t CompilerMSL::get_physical_tess_level_array_size(spv::BuiltIn builtin) const { - if (get_execution_mode_bitset().get(ExecutionModeTriangles)) + if (is_tessellating_triangles()) return builtin == BuiltInTessLevelInner ? 1 : 3; else return builtin == BuiltInTessLevelInner ? 2 : 4; @@ -8745,8 +9908,8 @@ uint32_t CompilerMSL::get_physical_tess_level_array_size(spv::BuiltIn builtin) c bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs) { // We only care about assignments of an entire array - auto &type = expression_type(id_rhs); - if (type.array.size() == 0) + auto &type = expression_type(id_lhs); + if (!is_array(get_pointee_type(type))) return false; auto *var = maybe_get(id_lhs); @@ -8766,8 +9929,7 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs) return true; } - if (get_execution_model() == ExecutionModelTessellationControl && - has_decoration(id_lhs, DecorationBuiltIn)) + if (is_tesc_shader() && has_decoration(id_lhs, DecorationBuiltIn)) { auto builtin = BuiltIn(get_decoration(id_lhs, DecorationBuiltIn)); // Need to manually unroll the array store. @@ -8785,99 +9947,220 @@ bool CompilerMSL::maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs) } } - // Ensure the LHS variable has been declared - auto *p_v_lhs = maybe_get_backing_variable(id_lhs); - if (p_v_lhs) - flush_variable_declaration(p_v_lhs->self); - auto lhs_storage = get_expression_effective_storage_class(id_lhs); auto rhs_storage = get_expression_effective_storage_class(id_rhs); - emit_array_copy(to_expression(id_lhs), id_lhs, id_rhs, lhs_storage, rhs_storage); + if (!emit_array_copy(nullptr, id_lhs, id_rhs, lhs_storage, rhs_storage)) + return false; + register_write(id_lhs); return true; } // Emits one of the atomic functions. In MSL, the atomic functions operate on pointers -void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1, - uint32_t mem_order_2, bool has_mem_order_2, uint32_t obj, uint32_t op1, +void CompilerMSL::emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, Op opcode, + uint32_t mem_order_1, uint32_t mem_order_2, bool has_mem_order_2, uint32_t obj, uint32_t op1, bool op1_is_pointer, bool op1_is_literal, uint32_t op2) { - string exp = string(op) + "("; + string exp; auto &type = get_pointee_type(expression_type(obj)); - exp += "("; + auto expected_type = type.basetype; + if (opcode == OpAtomicUMax || opcode == OpAtomicUMin) + expected_type = to_unsigned_basetype(type.width); + else if (opcode == OpAtomicSMax || opcode == OpAtomicSMin) + expected_type = to_signed_basetype(type.width); + + bool use_native_image_atomic; + if (msl_options.supports_msl_version(3, 1)) + use_native_image_atomic = check_atomic_image(obj); + else + use_native_image_atomic = false; + + if (type.width == 64) + SPIRV_CROSS_THROW("MSL currently does not support 64-bit atomics."); + + auto remapped_type = type; + remapped_type.basetype = expected_type; + auto *var = maybe_get_backing_variable(obj); if (!var) SPIRV_CROSS_THROW("No backing variable for atomic operation."); - - // Emulate texture2D atomic operations const auto &res_type = get(var->basetype); - if (res_type.storage == StorageClassUniformConstant && res_type.basetype == SPIRType::Image) - { - exp += "device"; - } - else - { - exp += get_argument_address_space(*var); - } - - exp += " atomic_"; - exp += type_to_glsl(type); - exp += "*)"; - - exp += "&"; - exp += to_enclosed_expression(obj); bool is_atomic_compare_exchange_strong = op1_is_pointer && op1; + bool check_discard = opcode != OpAtomicLoad && needs_frag_discard_checks() && + ((res_type.storage == StorageClassUniformConstant && res_type.basetype == SPIRType::Image) || + var->storage == StorageClassStorageBuffer || var->storage == StorageClassUniform); + + // Even compare exchange atomics are vec4 on metal for ... reasons :v + uint32_t vec4_temporary_id = 0; + if (use_native_image_atomic && is_atomic_compare_exchange_strong) + { + uint32_t &tmp_id = extra_sub_expressions[result_id]; + if (!tmp_id) + { + tmp_id = ir.increase_bound_by(2); + + auto vec4_type = get(result_type); + vec4_type.vecsize = 4; + set(tmp_id + 1, vec4_type); + } + + vec4_temporary_id = tmp_id; + } + + if (check_discard) + { + if (is_atomic_compare_exchange_strong) + { + // We're already emitting a CAS loop here; a conditional won't hurt. + emit_uninitialized_temporary_expression(result_type, result_id); + if (vec4_temporary_id) + emit_uninitialized_temporary_expression(vec4_temporary_id + 1, vec4_temporary_id); + statement("if (!", builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput), ")"); + begin_scope(); + } + else + exp = join("(!", builtin_to_glsl(BuiltInHelperInvocation, StorageClassInput), " ? "); + } + + if (use_native_image_atomic) + { + auto obj_expression = to_expression(obj); + auto split_index = obj_expression.find_first_of('@'); + + // Will only be false if we're in "force recompile later" mode. + if (split_index != string::npos) + exp += join(obj_expression.substr(0, split_index), ".", op, "(", obj_expression.substr(split_index + 1)); + else + exp += obj_expression; + } + else + { + exp += string(op) + "_explicit("; + exp += "("; + // Emulate texture2D atomic operations + if (res_type.storage == StorageClassUniformConstant && res_type.basetype == SPIRType::Image) + { + exp += "device"; + } + else + { + exp += get_argument_address_space(*var); + } + + exp += " atomic_"; + // For signed and unsigned min/max, we can signal this through the pointer type. + // There is no other way, since C++ does not have explicit signage for atomics. + exp += type_to_glsl(remapped_type); + exp += "*)"; + + exp += "&"; + exp += to_enclosed_expression(obj); + } + if (is_atomic_compare_exchange_strong) { - assert(strcmp(op, "atomic_compare_exchange_weak_explicit") == 0); + assert(strcmp(op, "atomic_compare_exchange_weak") == 0); assert(op2); assert(has_mem_order_2); exp += ", &"; - exp += to_name(result_id); + exp += to_name(vec4_temporary_id ? vec4_temporary_id : result_id); exp += ", "; exp += to_expression(op2); - exp += ", "; - exp += get_memory_order(mem_order_1); - exp += ", "; - exp += get_memory_order(mem_order_2); + + if (!use_native_image_atomic) + { + exp += ", "; + exp += get_memory_order(mem_order_1); + exp += ", "; + exp += get_memory_order(mem_order_2); + } exp += ")"; // MSL only supports the weak atomic compare exchange, so emit a CAS loop here. // The MSL function returns false if the atomic write fails OR the comparison test fails, // so we must validate that it wasn't the comparison test that failed before continuing // the CAS loop, otherwise it will loop infinitely, with the comparison test always failing. - // The function updates the comparitor value from the memory value, so the additional + // The function updates the comparator value from the memory value, so the additional // comparison test evaluates the memory value against the expected value. - emit_uninitialized_temporary_expression(result_type, result_id); + if (!check_discard) + { + emit_uninitialized_temporary_expression(result_type, result_id); + if (vec4_temporary_id) + emit_uninitialized_temporary_expression(vec4_temporary_id + 1, vec4_temporary_id); + } + statement("do"); begin_scope(); - statement(to_name(result_id), " = ", to_expression(op1), ";"); - end_scope_decl(join("while (!", exp, " && ", to_name(result_id), " == ", to_enclosed_expression(op1), ")")); + + string scalar_expression; + if (vec4_temporary_id) + scalar_expression = join(to_expression(vec4_temporary_id), ".x"); + else + scalar_expression = to_expression(result_id); + + statement(scalar_expression, " = ", to_expression(op1), ";"); + end_scope_decl(join("while (!", exp, " && ", scalar_expression, " == ", to_enclosed_expression(op1), ")")); + if (vec4_temporary_id) + statement(to_expression(result_id), " = ", scalar_expression, ";"); + + // Vulkan: (section 9.29: ... and values returned by atomic instructions in helper invocations are undefined) + if (check_discard) + { + end_scope(); + statement("else"); + begin_scope(); + statement(to_expression(result_id), " = {};"); + end_scope(); + } } else { - assert(strcmp(op, "atomic_compare_exchange_weak_explicit") != 0); + assert(strcmp(op, "atomic_compare_exchange_weak") != 0); + if (op1) { + exp += ", "; if (op1_is_literal) - exp += join(", ", op1); + exp += to_string(op1); else - exp += ", " + to_expression(op1); + exp += bitcast_expression(expected_type, op1); } + if (op2) exp += ", " + to_expression(op2); - exp += string(", ") + get_memory_order(mem_order_1); - if (has_mem_order_2) - exp += string(", ") + get_memory_order(mem_order_2); + if (!use_native_image_atomic) + { + exp += string(", ") + get_memory_order(mem_order_1); + if (has_mem_order_2) + exp += string(", ") + get_memory_order(mem_order_2); + } exp += ")"; - if (strcmp(op, "atomic_store_explicit") != 0) + // For some particular reason, atomics return vec4 in Metal ... + if (use_native_image_atomic) + exp += ".x"; + + // Vulkan: (section 9.29: ... and values returned by atomic instructions in helper invocations are undefined) + if (check_discard) + { + exp += " : "; + if (strcmp(op, "atomic_store") != 0) + exp += join(type_to_glsl(get(result_type)), "{}"); + else + exp += "((void)0)"; + exp += ")"; + } + + if (expected_type != type.basetype) + exp = bitcast_expression(type, expected_type, exp); + + if (strcmp(op, "atomic_store") != 0) emit_op(result_type, result_id, exp, false); else statement(exp, ";"); @@ -8903,6 +10186,8 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, auto int_type = to_signed_basetype(integer_width); auto uint_type = to_unsigned_basetype(integer_width); + op = get_remapped_glsl_op(op); + switch (op) { case GLSLstd450Sinh: @@ -9147,14 +10432,19 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, break; case GLSLstd450Normalize: + { + auto &exp_type = expression_type(args[0]); // MSL does not support scalar versions here. + // MSL has no implementation for normalize in the fast:: namespace for half2 and half3 // Returns -1 or 1 for valid input, sign() does the job. - if (expression_type(args[0]).vecsize == 1) + if (exp_type.vecsize == 1) emit_unary_func_op(result_type, id, args[0], "sign"); + else if (exp_type.vecsize <= 3 && exp_type.basetype == SPIRType::Half) + emit_unary_func_op(result_type, id, args[0], "normalize"); else emit_unary_func_op(result_type, id, args[0], "fast::normalize"); break; - + } case GLSLstd450Reflect: if (get(result_type).vecsize == 1) emit_binary_func_op(result_type, id, args[0], args[1], "spvReflect"); @@ -9210,6 +10500,11 @@ void CompilerMSL::emit_glsl_op(uint32_t result_type, uint32_t id, uint32_t eop, break; } + case GLSLstd450Pow: + // powr makes x < 0.0 undefined, just like SPIR-V. + emit_binary_func_op(result_type, id, args[0], args[1], "powr"); + break; + default: CompilerGLSL::emit_glsl_op(result_type, id, eop, args, count); break; @@ -9313,6 +10608,9 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) else decl += entry_point_args_classic(!func.arguments.empty()); + // append entry point args to avoid conflicts in local variable names. + local_variable_names.insert(resource_names.begin(), resource_names.end()); + // If entry point function has variables that require early declaration, // ensure they each have an empty initializer, creating one if needed. // This is done at this late stage because the initialization expression @@ -9364,7 +10662,21 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) // Manufacture automatic sampler arg for SampledImage texture if (arg_type.image.dim != DimBuffer) - decl += join(", thread const ", sampler_type(arg_type, arg.id), " ", to_sampler_expression(arg.id)); + { + if (arg_type.array.empty() || (var ? is_var_runtime_size_array(*var) : is_runtime_size_array(arg_type))) + { + decl += join(", ", sampler_type(arg_type, arg.id), " ", to_sampler_expression(name_id)); + } + else + { + const char *sampler_address_space = + descriptor_address_space(name_id, + StorageClassUniformConstant, + "thread const"); + decl += join(", ", sampler_address_space, " ", sampler_type(arg_type, name_id), "& ", + to_sampler_expression(name_id)); + } + } } // Manufacture automatic swizzle arg. @@ -9372,10 +10684,10 @@ void CompilerMSL::emit_function_prototype(SPIRFunction &func, const Bitset &) !is_dynamic_img_sampler) { bool arg_is_array = !arg_type.array.empty(); - decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(arg.id)); + decl += join(", constant uint", arg_is_array ? "* " : "& ", to_swizzle_expression(name_id)); } - if (buffers_requiring_array_length.count(name_id)) + if (buffer_requires_array_length(name_id)) { bool arg_is_array = !arg_type.array.empty(); decl += join(", constant uint", arg_is_array ? "* " : "& ", to_buffer_size_expression(name_id)); @@ -9547,7 +10859,7 @@ string CompilerMSL::to_function_name(const TextureFunctionNameArguments &args) string CompilerMSL::convert_to_f32(const string &expr, uint32_t components) { - SPIRType t; + SPIRType t { components > 1 ? OpTypeVector : OpTypeFloat }; t.basetype = SPIRType::Float; t.vecsize = components; t.columns = 1; @@ -9739,25 +11051,24 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool break; } - if (args.base.is_fetch && (args.offset || args.coffset)) + if (args.base.is_fetch && args.offset) { - uint32_t offset_expr = args.offset ? args.offset : args.coffset; // Fetch offsets must be applied directly to the coordinate. - forward = forward && should_forward(offset_expr); - auto &type = expression_type(offset_expr); + forward = forward && should_forward(args.offset); + auto &type = expression_type(args.offset); if (imgtype.image.dim == Dim1D && msl_options.texture_1D_as_2D) { if (type.basetype != SPIRType::UInt) - tex_coords += join(" + uint2(", bitcast_expression(SPIRType::UInt, offset_expr), ", 0)"); + tex_coords += join(" + uint2(", bitcast_expression(SPIRType::UInt, args.offset), ", 0)"); else - tex_coords += join(" + uint2(", to_enclosed_expression(offset_expr), ", 0)"); + tex_coords += join(" + uint2(", to_enclosed_expression(args.offset), ", 0)"); } else { if (type.basetype != SPIRType::UInt) - tex_coords += " + " + bitcast_expression(SPIRType::UInt, offset_expr); + tex_coords += " + " + bitcast_expression(SPIRType::UInt, args.offset); else - tex_coords += " + " + to_enclosed_expression(offset_expr); + tex_coords += " + " + to_enclosed_expression(args.offset); } } @@ -9862,7 +11173,8 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool // We will detect a compile-time constant 0 value for gradient and promote that to level(0) on MSL. bool constant_zero_x = !grad_x || expression_is_constant_null(grad_x); bool constant_zero_y = !grad_y || expression_is_constant_null(grad_y); - if (constant_zero_x && constant_zero_y) + if (constant_zero_x && constant_zero_y && + (!imgtype.image.arrayed || !msl_options.sample_dref_lod_array_as_grad)) { lod = 0; grad_x = 0; @@ -9908,6 +11220,64 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool { farg_str += ", " + to_expression(lod); } + else if (msl_options.sample_dref_lod_array_as_grad && args.dref && imgtype.image.arrayed) + { + if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("Using non-constant 0.0 gradient() qualifier for sample_compare. This is not " + "supported on macOS prior to MSL 2.3."); + // Some Metal devices have a bug where the LoD is erroneously biased upward + // when using a level() argument. Since this doesn't happen as much with gradient2d(), + // if we perform the LoD calculation in reverse, we can pass a gradient + // instead. + // lod = log2(rhoMax/eta) -> exp2(lod) = rhoMax/eta + // If we make all of the scale factors the same, eta will be 1 and + // exp2(lod) = rho. + // rhoX = dP/dx * extent; rhoY = dP/dy * extent + // Therefore, dP/dx = dP/dy = exp2(lod)/extent. + // (Subtracting 0.5 before exponentiation gives better results.) + string grad_opt, extent, grad_coord; + VariableID base_img = img; + if (auto *combined = maybe_get(img)) + base_img = combined->image; + switch (imgtype.image.dim) + { + case Dim1D: + grad_opt = "gradient2d"; + extent = join("float2(", to_expression(base_img), ".get_width(), 1.0)"); + break; + case Dim2D: + grad_opt = "gradient2d"; + extent = join("float2(", to_expression(base_img), ".get_width(), ", to_expression(base_img), ".get_height())"); + break; + case DimCube: + if (imgtype.image.arrayed && msl_options.emulate_cube_array) + { + grad_opt = "gradient2d"; + extent = join("float2(", to_expression(base_img), ".get_width())"); + } + else + { + if (msl_options.agx_manual_cube_grad_fixup) + { + add_spv_func_and_recompile(SPVFuncImplGradientCube); + grad_opt = "spvGradientCube"; + grad_coord = tex_coords + ", "; + } + else + { + grad_opt = "gradientcube"; + } + extent = join("float3(", to_expression(base_img), ".get_width())"); + } + break; + default: + grad_opt = "unsupported_gradient_dimension"; + extent = "float3(1.0)"; + break; + } + farg_str += join(", ", grad_opt, "(", grad_coord, "exp2(", to_expression(lod), " - 0.5) / ", extent, + ", exp2(", to_expression(lod), " - 0.5) / ", extent, ")"); + } else { farg_str += ", level(" + to_expression(lod) + ")"; @@ -9926,27 +11296,37 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool { forward = forward && should_forward(grad_x); forward = forward && should_forward(grad_y); - string grad_opt; + string grad_opt, grad_coord; switch (imgtype.image.dim) { case Dim1D: case Dim2D: - grad_opt = "2d"; + grad_opt = "gradient2d"; break; case Dim3D: - grad_opt = "3d"; + grad_opt = "gradient3d"; break; case DimCube: if (imgtype.image.arrayed && msl_options.emulate_cube_array) - grad_opt = "2d"; + { + grad_opt = "gradient2d"; + } + else if (msl_options.agx_manual_cube_grad_fixup) + { + add_spv_func_and_recompile(SPVFuncImplGradientCube); + grad_opt = "spvGradientCube"; + grad_coord = tex_coords + ", "; + } else - grad_opt = "cube"; + { + grad_opt = "gradientcube"; + } break; default: grad_opt = "unsupported_gradient_dimension"; break; } - farg_str += ", gradient" + grad_opt + "(" + to_expression(grad_x) + ", " + to_expression(grad_y) + ")"; + farg_str += join(", ", grad_opt, "(", grad_coord, to_expression(grad_x), ", ", to_expression(grad_y), ")"); } if (args.min_lod) @@ -9961,13 +11341,7 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool // Add offsets string offset_expr; const SPIRType *offset_type = nullptr; - if (args.coffset && !args.base.is_fetch) - { - forward = forward && should_forward(args.coffset); - offset_expr = to_expression(args.coffset); - offset_type = &expression_type(args.coffset); - } - else if (args.offset && !args.base.is_fetch) + if (args.offset && !args.base.is_fetch) { forward = forward && should_forward(args.offset); offset_expr = to_expression(args.offset); @@ -10047,7 +11421,7 @@ string CompilerMSL::to_function_args(const TextureFunctionArguments &args, bool // If the texture coordinates are floating point, invokes MSL round() function to round them. string CompilerMSL::round_fp_tex_coords(string tex_coords, bool coord_is_fp) { - return coord_is_fp ? ("round(" + tex_coords + ")") : tex_coords; + return coord_is_fp ? ("rint(" + tex_coords + ")") : tex_coords; } // Returns a string to use in an image sampling function argument. @@ -10313,6 +11687,10 @@ string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_ constants.push_back(id); } } + // Dereference pointer variables where needed. + // FIXME: This dereference is actually backwards. We should really just support passing pointer variables between functions. + else if (should_dereference(id)) + arg_str += dereference_expression(type, CompilerGLSL::to_func_call_arg(arg, id)); else arg_str += CompilerGLSL::to_func_call_arg(arg, id); @@ -10408,7 +11786,7 @@ string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_ else if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type)) arg_str += ", " + to_swizzle_expression(var_id ? var_id : id); - if (buffers_requiring_array_length.count(var_id)) + if (buffer_requires_array_length(var_id)) arg_str += ", " + to_buffer_size_expression(var_id ? var_id : id); if (is_dynamic_img_sampler) @@ -10417,7 +11795,7 @@ string CompilerMSL::to_func_call_arg(const SPIRFunction::Parameter &arg, uint32_ // Emulate texture2D atomic operations auto *backing_var = maybe_get_backing_variable(var_id); - if (backing_var && atomic_image_vars.count(backing_var->self)) + if (backing_var && atomic_image_vars_emulated.count(backing_var->self)) { arg_str += ", " + to_expression(var_id) + "_atomic"; } @@ -10492,6 +11870,18 @@ string CompilerMSL::to_buffer_size_expression(uint32_t id) { auto buffer_expr = expr.substr(0, index); auto array_expr = expr.substr(index); + if (auto var = maybe_get_backing_variable(id)) + { + if (is_var_runtime_size_array(*var)) + { + if (!msl_options.runtime_array_rich_descriptor) + SPIRV_CROSS_THROW("OpArrayLength requires rich descriptor format"); + + auto last_pos = array_expr.find_last_of(']'); + if (last_pos != std::string::npos) + return buffer_expr + ".length(" + array_expr.substr(1, last_pos - 1) + ")"; + } + } return buffer_expr + buffer_size_name_suffix + array_expr; } } @@ -10528,11 +11918,11 @@ bool CompilerMSL::member_is_non_native_row_major_matrix(const SPIRType &type, ui } string CompilerMSL::convert_row_major_matrix(string exp_str, const SPIRType &exp_type, uint32_t physical_type_id, - bool is_packed) + bool is_packed, bool relaxed) { if (!is_matrix(exp_type)) { - return CompilerGLSL::convert_row_major_matrix(move(exp_str), exp_type, physical_type_id, is_packed); + return CompilerGLSL::convert_row_major_matrix(std::move(exp_str), exp_type, physical_type_id, is_packed, relaxed); } else { @@ -10561,6 +11951,7 @@ void CompilerMSL::emit_fixup() string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const string &qualifier) { + uint32_t orig_member_type_id = member_type_id; if (member_is_remapped_physical_type(type, index)) member_type_id = get_extended_member_decoration(type.self, index, SPIRVCrossDecorationPhysicalTypeID); auto &physical_type = get(member_type_id); @@ -10577,7 +11968,7 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ if (is_matrix(physical_type)) row_major = has_member_decoration(type.self, index, DecorationRowMajor); - SPIRType row_major_physical_type; + SPIRType row_major_physical_type { OpTypeMatrix }; const SPIRType *declared_type = &physical_type; // If a struct is being declared with physical layout, @@ -10623,19 +12014,33 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ else if (!is_scalar(physical_type)) // scalar type is already packed. pack_pfx = "packed_"; } - else if (row_major) + else if (is_matrix(physical_type)) { - // Need to declare type with flipped vecsize/columns. - row_major_physical_type = physical_type; - swap(row_major_physical_type.vecsize, row_major_physical_type.columns); - declared_type = &row_major_physical_type; + if (!msl_options.supports_msl_version(3, 0) && + has_extended_decoration(type.self, SPIRVCrossDecorationWorkgroupStruct)) + { + pack_pfx = "spvStorage_"; + add_spv_func_and_recompile(SPVFuncImplStorageMatrix); + // The pack prefix causes problems with array wrappers. + is_using_builtin_array = true; + } + if (row_major) + { + // Need to declare type with flipped vecsize/columns. + row_major_physical_type = physical_type; + swap(row_major_physical_type.vecsize, row_major_physical_type.columns); + declared_type = &row_major_physical_type; + } } - // Very specifically, image load-store in argument buffers are disallowed on MSL on iOS. - if (msl_options.is_ios() && physical_type.basetype == SPIRType::Image && physical_type.image.sampled == 2) + // iOS Tier 1 argument buffers do not support writable images. + if (physical_type.basetype == SPIRType::Image && + physical_type.image.sampled == 2 && + msl_options.is_ios() && + msl_options.argument_buffers_tier <= Options::ArgumentBuffersTier::Tier1 && + !has_decoration(orig_id, DecorationNonWritable)) { - if (!has_decoration(orig_id, DecorationNonWritable)) - SPIRV_CROSS_THROW("Writable images are not allowed in argument buffers on iOS."); + SPIRV_CROSS_THROW("Writable images are not allowed on Tier1 argument buffers on iOS."); } // Array information is baked into these types. @@ -10658,8 +12063,25 @@ string CompilerMSL::to_struct_member(const SPIRType &type, uint32_t member_type_ array_type = type_to_array_glsl(physical_type); } - auto result = join(pack_pfx, type_to_glsl(*declared_type, orig_id), " ", qualifier, to_member_name(type, index), - member_attribute_qualifier(type, index), array_type, ";"); + string decl_type; + if (declared_type->vecsize > 4) + { + auto orig_type = get(orig_member_type_id); + if (is_matrix(orig_type) && row_major) + swap(orig_type.vecsize, orig_type.columns); + orig_type.columns = 1; + decl_type = type_to_glsl(orig_type, orig_id, true); + + if (declared_type->columns > 1) + decl_type = join("spvPaddedStd140Matrix<", decl_type, ", ", declared_type->columns, ">"); + else + decl_type = join("spvPaddedStd140<", decl_type, ">"); + } + else + decl_type = type_to_glsl(*declared_type, orig_id, true); + + auto result = join(pack_pfx, decl_type, " ", qualifier, + to_member_name(type, index), member_attribute_qualifier(type, index), array_type, ";"); is_using_builtin_array = false; return result; @@ -10750,8 +12172,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in } // Vertex and tessellation evaluation function outputs - if (((execution.model == ExecutionModelVertex && !msl_options.vertex_for_tessellation) || - execution.model == ExecutionModelTessellationEvaluation) && + if (((execution.model == ExecutionModelVertex && !msl_options.vertex_for_tessellation) || is_tese_shader()) && type.storage == StorageClassOutput) { if (is_builtin) @@ -10794,8 +12215,18 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in return join(" [[", loc_qual, "]]"); } + if (execution.model == ExecutionModelVertex && msl_options.vertex_for_tessellation && type.storage == StorageClassOutput) + { + // For this type of shader, we always arrange for it to capture its + // output to a buffer. For this reason, qualifiers are irrelevant here. + if (is_builtin) + // We still have to assign a location so the output struct will sort correctly. + get_or_allocate_builtin_output_member_location(builtin, type.self, index); + return ""; + } + // Tessellation control function inputs - if (execution.model == ExecutionModelTessellationControl && type.storage == StorageClassInput) + if (is_tesc_shader() && type.storage == StorageClassInput) { if (is_builtin) { @@ -10832,15 +12263,18 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in } // Tessellation control function outputs - if (execution.model == ExecutionModelTessellationControl && type.storage == StorageClassOutput) + if (is_tesc_shader() && type.storage == StorageClassOutput) { // For this type of shader, we always arrange for it to capture its // output to a buffer. For this reason, qualifiers are irrelevant here. + if (is_builtin) + // We still have to assign a location so the output struct will sort correctly. + get_or_allocate_builtin_output_member_location(builtin, type.self, index); return ""; } // Tessellation evaluation function inputs - if (execution.model == ExecutionModelTessellationEvaluation && type.storage == StorageClassInput) + if (is_tese_shader() && type.storage == StorageClassInput) { if (is_builtin) { @@ -10856,6 +12290,10 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in break; } } + + if (msl_options.raw_buffer_tese_input) + return ""; + // The special control point array must not be marked with an attribute. if (get_type(type.member_types[index]).basetype == SPIRType::ControlPointArray) return ""; @@ -10890,8 +12328,8 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in case BuiltInSampleId: case BuiltInSampleMask: case BuiltInLayer: - case BuiltInBaryCoordNV: - case BuiltInBaryCoordNoPerspNV: + case BuiltInBaryCoordKHR: + case BuiltInBaryCoordNoPerspKHR: quals = builtin_qualifier(builtin); break; @@ -10907,7 +12345,7 @@ string CompilerMSL::member_attribute_qualifier(const SPIRType &type, uint32_t in else quals = member_location_attribute_qualifier(type, index); - if (builtin == BuiltInBaryCoordNV || builtin == BuiltInBaryCoordNoPerspNV) + if (builtin == BuiltInBaryCoordKHR || builtin == BuiltInBaryCoordNoPerspKHR) { if (has_member_decoration(type.self, index, DecorationFlat) || has_member_decoration(type.self, index, DecorationCentroid) || @@ -11113,7 +12551,7 @@ uint32_t CompilerMSL::get_or_allocate_builtin_input_member_location(spv::BuiltIn // Triangle tess level inputs are shared in one packed float4, // mark both builtins as sharing one location. - if (get_execution_mode_bitset().get(ExecutionModeTriangles) && + if (!msl_options.raw_buffer_tese_input && is_tessellating_triangles() && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) { builtin_to_automatic_input_location[BuiltInTessLevelInner] = loc; @@ -11126,6 +12564,49 @@ uint32_t CompilerMSL::get_or_allocate_builtin_input_member_location(spv::BuiltIn return loc; } +uint32_t CompilerMSL::get_or_allocate_builtin_output_member_location(spv::BuiltIn builtin, + uint32_t type_id, uint32_t index, + uint32_t *comp) +{ + uint32_t loc = get_member_location(type_id, index, comp); + if (loc != k_unknown_location) + return loc; + loc = 0; + + if (comp) + *comp = k_unknown_component; + + // Late allocation. Find a location which is unused by the application. + // This can happen for built-in outputs in tessellation which are mixed and matched with user inputs. + auto &mbr_type = get(get(type_id).member_types[index]); + uint32_t count = type_to_location_count(mbr_type); + + const auto location_range_in_use = [this](uint32_t location, uint32_t location_count) -> bool { + for (uint32_t i = 0; i < location_count; i++) + if (location_outputs_in_use.count(location + i) != 0) + return true; + return false; + }; + + while (location_range_in_use(loc, count)) + loc++; + + set_member_decoration(type_id, index, DecorationLocation, loc); + + // Triangle tess level inputs are shared in one packed float4; + // mark both builtins as sharing one location. + if (is_tessellating_triangles() && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) + { + builtin_to_automatic_output_location[BuiltInTessLevelInner] = loc; + builtin_to_automatic_output_location[BuiltInTessLevelOuter] = loc; + } + else + builtin_to_automatic_output_location[builtin] = loc; + + mark_location_as_used_by_shader(loc, mbr_type, StorageClassOutput, true); + return loc; +} + // Returns the type declaration for a function, including the // entry type if the current function is the entry point function string CompilerMSL::func_type_decl(SPIRType &type) @@ -11156,10 +12637,9 @@ string CompilerMSL::func_type_decl(SPIRType &type) if (execution.flags.get(ExecutionModeIsolines)) SPIRV_CROSS_THROW("Metal does not support isoline tessellation."); if (msl_options.is_ios()) - entry_type = - join("[[ patch(", execution.flags.get(ExecutionModeTriangles) ? "triangle" : "quad", ") ]] vertex"); + entry_type = join("[[ patch(", is_tessellating_triangles() ? "triangle" : "quad", ") ]] vertex"); else - entry_type = join("[[ patch(", execution.flags.get(ExecutionModeTriangles) ? "triangle" : "quad", ", ", + entry_type = join("[[ patch(", is_tessellating_triangles() ? "triangle" : "quad", ", ", execution.output_vertices, ") ]] vertex"); break; case ExecutionModelFragment: @@ -11183,6 +12663,16 @@ string CompilerMSL::func_type_decl(SPIRType &type) return entry_type + " " + return_type; } +bool CompilerMSL::is_tesc_shader() const +{ + return get_execution_model() == ExecutionModelTessellationControl; +} + +bool CompilerMSL::is_tese_shader() const +{ + return get_execution_model() == ExecutionModelTessellationEvaluation; +} + bool CompilerMSL::uses_explicit_early_fragment_test() { auto &ep_flags = get_entry_point().flags; @@ -11215,6 +12705,7 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo break; case StorageClassStorageBuffer: + case StorageClassPhysicalStorageBuffer: { // For arguments from variable pointers, we use the write count deduction, so // we should not assume any constness here. Only for global SSBOs. @@ -11253,9 +12744,20 @@ string CompilerMSL::get_type_address_space(const SPIRType &type, uint32_t id, bo break; case StorageClassInput: - if (get_execution_model() == ExecutionModelTessellationControl && var && - var->basevariable == stage_in_ptr_var_id) - addr_space = msl_options.multi_patch_workgroup ? "constant" : "threadgroup"; + if (is_tesc_shader() && var && var->basevariable == stage_in_ptr_var_id) + addr_space = msl_options.multi_patch_workgroup ? "const device" : "threadgroup"; + // Don't pass tessellation levels in the device AS; we load and convert them + // to float manually. + if (is_tese_shader() && msl_options.raw_buffer_tese_input && var) + { + bool is_stage_in = var->basevariable == stage_in_ptr_var_id; + bool is_patch_stage_in = has_decoration(var->self, DecorationPatch); + bool is_builtin = has_decoration(var->self, DecorationBuiltIn); + BuiltIn builtin = (BuiltIn)get_decoration(var->self, DecorationBuiltIn); + bool is_tess_level = is_builtin && (builtin == BuiltInTessLevelOuter || builtin == BuiltInTessLevelInner); + if (is_stage_in || (is_patch_stage_in && !is_tess_level)) + addr_space = "const device"; + } if (get_execution_model() == ExecutionModelFragment && var && var->basevariable == stage_in_var_id) addr_space = "thread"; break; @@ -11313,19 +12815,21 @@ const char *CompilerMSL::to_restrict(uint32_t id, bool space) else flags = get_decoration_bitset(id); - return flags.get(DecorationRestrict) ? (space ? "restrict " : "restrict") : ""; + return flags.get(DecorationRestrict) || flags.get(DecorationRestrictPointerEXT) ? + (space ? "__restrict " : "__restrict") : ""; } string CompilerMSL::entry_point_arg_stage_in() { string decl; - if (get_execution_model() == ExecutionModelTessellationControl && msl_options.multi_patch_workgroup) + if ((is_tesc_shader() && msl_options.multi_patch_workgroup) || + (is_tese_shader() && msl_options.raw_buffer_tese_input)) return decl; // Stage-in structure uint32_t stage_in_id; - if (get_execution_model() == ExecutionModelTessellationEvaluation) + if (is_tese_shader()) stage_in_id = patch_stage_in_var_id; else stage_in_id = stage_in_var_id; @@ -11365,7 +12869,7 @@ bool CompilerMSL::is_direct_input_builtin(BuiltIn bi_type) return false; case BuiltInInvocationId: case BuiltInPrimitiveId: - return get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup; + return !is_tesc_shader() || !msl_options.multi_patch_workgroup; // Tess. evaluation function in case BuiltInTessLevelInner: case BuiltInTessLevelOuter: @@ -11373,8 +12877,8 @@ bool CompilerMSL::is_direct_input_builtin(BuiltIn bi_type) // Fragment function in case BuiltInSamplePosition: case BuiltInHelperInvocation: - case BuiltInBaryCoordNV: - case BuiltInBaryCoordNoPerspNV: + case BuiltInBaryCoordKHR: + case BuiltInBaryCoordNoPerspKHR: return false; case BuiltInViewIndex: return get_execution_model() == ExecutionModelFragment && msl_options.multiview && @@ -11409,7 +12913,7 @@ bool CompilerMSL::is_sample_rate() const return get_execution_model() == ExecutionModelFragment && (msl_options.force_sample_rate_shading || std::find(caps.begin(), caps.end(), CapabilitySampleRateShading) != caps.end() || - (msl_options.use_framebuffer_fetch_subpasses && need_subpass_input)); + (msl_options.use_framebuffer_fetch_subpasses && need_subpass_input_ms)); } bool CompilerMSL::is_intersection_query() const @@ -11449,8 +12953,14 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) // Handle HLSL-style 0-based vertex/instance index. builtin_declaration = true; - ep_args += builtin_type_decl(bi_type, var_id) + " " + to_expression(var_id); - ep_args += " [[" + builtin_qualifier(bi_type); + + // Handle different MSL gl_TessCoord types. (float2, float3) + if (bi_type == BuiltInTessCoord && get_entry_point().flags.get(ExecutionModeQuads)) + ep_args += "float2 " + to_expression(var_id) + "In"; + else + ep_args += builtin_type_decl(bi_type, var_id) + " " + to_expression(var_id); + + ep_args += string(" [[") + builtin_qualifier(bi_type); if (bi_type == BuiltInSampleMask && get_entry_point().flags.get(ExecutionModePostDepthCoverage)) { if (!msl_options.supports_msl_version(2)) @@ -11514,7 +13024,7 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) " [[buffer(", msl_options.shader_output_buffer_index, ")]]"); } - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader()) { if (!ep_args.empty()) ep_args += ", "; @@ -11556,7 +13066,7 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) // a buffer to hold the per-patch data, a buffer to hold the per-patch // tessellation levels, and a block of workgroup memory to hold the // input control point data. - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader()) { if (patch_stage_out_var_id) { @@ -11590,20 +13100,22 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) if (outer_factor_initializer_id && (c = maybe_get(outer_factor_initializer_id))) { auto &entry_func = get(ir.default_entry_point); - entry_func.fixup_hooks_in.push_back([=]() { - uint32_t components = get_execution_mode_bitset().get(ExecutionModeTriangles) ? 3 : 4; - for (uint32_t i = 0; i < components; i++) - { - statement(builtin_to_glsl(BuiltInTessLevelOuter, StorageClassOutput), "[", i, "] = ", - "half(", to_expression(c->subconstants[i]), ");"); - } - }); + entry_func.fixup_hooks_in.push_back( + [=]() + { + uint32_t components = is_tessellating_triangles() ? 3 : 4; + for (uint32_t i = 0; i < components; i++) + { + statement(builtin_to_glsl(BuiltInTessLevelOuter, StorageClassOutput), "[", i, + "] = ", "half(", to_expression(c->subconstants[i]), ");"); + } + }); } if (inner_factor_initializer_id && (c = maybe_get(inner_factor_initializer_id))) { auto &entry_func = get(ir.default_entry_point); - if (get_execution_mode_bitset().get(ExecutionModeTriangles)) + if (is_tessellating_triangles()) { entry_func.fixup_hooks_in.push_back([=]() { statement(builtin_to_glsl(BuiltInTessLevelInner, StorageClassOutput), " = ", "half(", @@ -11639,6 +13151,36 @@ void CompilerMSL::entry_point_args_builtin(string &ep_args) } } } + // Tessellation evaluation shaders get three additional parameters: + // a buffer for the per-patch data, a buffer for the per-patch + // tessellation levels, and a buffer for the control point data. + if (is_tese_shader() && msl_options.raw_buffer_tese_input) + { + if (patch_stage_in_var_id) + { + if (!ep_args.empty()) + ep_args += ", "; + ep_args += + join("const device ", type_to_glsl(get_patch_stage_in_struct_type()), "* ", patch_input_buffer_var_name, + " [[buffer(", convert_to_string(msl_options.shader_patch_input_buffer_index), ")]]"); + } + + if (tess_level_inner_var_id || tess_level_outer_var_id) + { + if (!ep_args.empty()) + ep_args += ", "; + ep_args += join("const device ", get_tess_factor_struct_name(), "* ", tess_factor_buffer_var_name, + " [[buffer(", convert_to_string(msl_options.shader_tess_factor_buffer_index), ")]]"); + } + + if (stage_in_var_id) + { + if (!ep_args.empty()) + ep_args += ", "; + ep_args += join("const device ", type_to_glsl(get_stage_in_struct_type()), "* ", input_buffer_var_name, + " [[buffer(", convert_to_string(msl_options.shader_input_buffer_index), ")]]"); + } + } } string CompilerMSL::entry_point_args_argument_buffer(bool append_comma) @@ -11679,7 +13221,7 @@ string CompilerMSL::entry_point_args_argument_buffer(bool append_comma) claimed_bindings.set(buffer_binding); - ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_restrict(id) + to_name(id); + ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_restrict(id, true) + to_name(id); ep_args += " [[buffer(" + convert_to_string(buffer_binding) + ")]]"; next_metal_resource_index_buffer = max(next_metal_resource_index_buffer, buffer_binding + 1); @@ -11724,6 +13266,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) struct Resource { SPIRVariable *var; + SPIRVariable *descriptor_alias; string name; SPIRType::BaseType basetype; uint32_t index; @@ -11733,6 +13276,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) SmallVector resources; + entry_point_bindings.clear(); ir.for_each_typed_id([&](uint32_t var_id, SPIRVariable &var) { if ((var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant || var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer) && @@ -11747,6 +13291,33 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) return; } + // Handle descriptor aliasing. We can handle aliasing of buffers by casting pointers, + // but not for typed resources. + SPIRVariable *descriptor_alias = nullptr; + if (var.storage == StorageClassUniform || var.storage == StorageClassStorageBuffer) + { + for (auto &resource : resources) + { + if (get_decoration(resource.var->self, DecorationDescriptorSet) == + get_decoration(var_id, DecorationDescriptorSet) && + get_decoration(resource.var->self, DecorationBinding) == + get_decoration(var_id, DecorationBinding) && + resource.basetype == SPIRType::Struct && type.basetype == SPIRType::Struct && + (resource.var->storage == StorageClassUniform || + resource.var->storage == StorageClassStorageBuffer)) + { + descriptor_alias = resource.var; + // Self-reference marks that we should declare the resource, + // and it's being used as an alias (so we can emit void* instead). + resource.descriptor_alias = resource.var; + // Need to promote interlocked usage so that the primary declaration is correct. + if (interlocked_resources.count(var_id)) + interlocked_resources.insert(resource.var->self); + break; + } + } + } + const MSLConstexprSampler *constexpr_sampler = nullptr; if (type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::Sampler) { @@ -11760,7 +13331,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) // Emulate texture2D atomic operations uint32_t secondary_index = 0; - if (atomic_image_vars.count(var.self)) + if (atomic_image_vars_emulated.count(var.self)) { secondary_index = get_metal_resource_index(var, SPIRType::AtomicCounter, 0); } @@ -11773,13 +13344,14 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) if (constexpr_sampler && constexpr_sampler->ycbcr_conversion_enable) plane_count = constexpr_sampler->planes; + entry_point_bindings.push_back(&var); for (uint32_t i = 0; i < plane_count; i++) - resources.push_back({ &var, to_name(var_id), SPIRType::Image, + resources.push_back({ &var, descriptor_alias, to_name(var_id), SPIRType::Image, get_metal_resource_index(var, SPIRType::Image, i), i, secondary_index }); if (type.image.dim != DimBuffer && !constexpr_sampler) { - resources.push_back({ &var, to_sampler_expression(var_id), SPIRType::Sampler, + resources.push_back({ &var, descriptor_alias, to_sampler_expression(var_id), SPIRType::Sampler, get_metal_resource_index(var, SPIRType::Sampler), 0, 0 }); } } @@ -11787,15 +13359,22 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) { // constexpr samplers are not declared as resources. add_resource_name(var_id); - resources.push_back({ &var, to_name(var_id), type.basetype, - get_metal_resource_index(var, type.basetype), 0, secondary_index }); + + // Don't allocate resource indices for aliases. + uint32_t resource_index = ~0u; + if (!descriptor_alias) + resource_index = get_metal_resource_index(var, type.basetype); + + entry_point_bindings.push_back(&var); + resources.push_back({ &var, descriptor_alias, to_name(var_id), type.basetype, + resource_index, 0, secondary_index }); } } }); - sort(resources.begin(), resources.end(), [](const Resource &lhs, const Resource &rhs) { - return tie(lhs.basetype, lhs.index) < tie(rhs.basetype, rhs.index); - }); + stable_sort(resources.begin(), resources.end(), + [](const Resource &lhs, const Resource &rhs) + { return tie(lhs.basetype, lhs.index) < tie(rhs.basetype, rhs.index); }); for (auto &r : resources) { @@ -11811,41 +13390,86 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) auto &m = ir.meta[type.self]; if (m.members.size() == 0) break; - if (!type.array.empty()) + + if (r.descriptor_alias) + { + if (r.var == r.descriptor_alias) + { + auto primary_name = join("spvBufferAliasSet", + get_decoration(var_id, DecorationDescriptorSet), + "Binding", + get_decoration(var_id, DecorationBinding)); + + // Declare the primary alias as void* + if (!ep_args.empty()) + ep_args += ", "; + ep_args += get_argument_address_space(var) + " void* " + primary_name; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; + } + + buffer_aliases_discrete.push_back(r.var->self); + } + else if (!type.array.empty()) { if (type.array.size() > 1) SPIRV_CROSS_THROW("Arrays of arrays of buffers are not supported."); - // Metal doesn't directly support this, so we must expand the - // array. We'll declare a local array to hold these elements - // later. - uint32_t array_size = to_array_size_literal(type); - - if (array_size == 0) - SPIRV_CROSS_THROW("Unsized arrays of buffers are not supported in MSL."); - - // Allow Metal to use the array template to make arrays a value type is_using_builtin_array = true; - buffer_arrays.push_back(var_id); - for (uint32_t i = 0; i < array_size; ++i) + if (is_var_runtime_size_array(var)) { + add_spv_func_and_recompile(SPVFuncImplVariableDescriptorArray); if (!ep_args.empty()) ep_args += ", "; - ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "* " + to_restrict(var_id) + - r.name + "_" + convert_to_string(i); - ep_args += " [[buffer(" + convert_to_string(r.index + i) + ")"; + const bool ssbo = has_decoration(type.self, DecorationBufferBlock); + if ((var.storage == spv::StorageClassStorageBuffer || ssbo) && + msl_options.runtime_array_rich_descriptor) + { + add_spv_func_and_recompile(SPVFuncImplVariableSizedDescriptor); + ep_args += "const device spvBufferDescriptor<" + get_argument_address_space(var) + " " + + type_to_glsl(type) + "*>* "; + } + else + { + ep_args += "const device spvDescriptor<" + get_argument_address_space(var) + " " + + type_to_glsl(type) + "*>* "; + } + ep_args += to_restrict(var_id, true) + r.name + "_"; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")"; if (interlocked_resources.count(var_id)) ep_args += ", raster_order_group(0)"; ep_args += "]]"; } + else + { + uint32_t array_size = get_resource_array_size(type, var_id); + for (uint32_t i = 0; i < array_size; ++i) + { + if (!ep_args.empty()) + ep_args += ", "; + ep_args += get_argument_address_space(var) + " " + type_to_glsl(type) + "* " + + to_restrict(var_id, true) + r.name + "_" + convert_to_string(i); + ep_args += " [[buffer(" + convert_to_string(r.index + i) + ")"; + if (interlocked_resources.count(var_id)) + ep_args += ", raster_order_group(0)"; + ep_args += "]]"; + } + } is_using_builtin_array = false; } else { if (!ep_args.empty()) ep_args += ", "; - ep_args += - get_argument_address_space(var) + " " + type_to_glsl(type) + "& " + to_restrict(var_id) + r.name; + ep_args += get_argument_address_space(var) + " "; + + if (recursive_inputs.count(type.self)) + ep_args += string("void* ") + to_restrict(var_id, true) + r.name + "_vp"; + else + ep_args += type_to_glsl(type) + "& " + to_restrict(var_id, true) + r.name; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")"; if (interlocked_resources.count(var_id)) ep_args += ", raster_order_group(0)"; @@ -11857,7 +13481,10 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) if (!ep_args.empty()) ep_args += ", "; ep_args += sampler_type(type, var_id) + " " + r.name; - ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]"; + if (is_var_runtime_size_array(var)) + ep_args += "_ [[buffer(" + convert_to_string(r.index) + ")]]"; + else + ep_args += " [[sampler(" + convert_to_string(r.index) + ")]]"; break; case SPIRType::Image: { @@ -11871,7 +13498,12 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) ep_args += image_type_glsl(type, var_id) + " " + r.name; if (r.plane > 0) ep_args += join(plane_name_suffix, r.plane); - ep_args += " [[texture(" + convert_to_string(r.index) + ")"; + + if (is_var_runtime_size_array(var)) + ep_args += "_ [[buffer(" + convert_to_string(r.index) + ")"; + else + ep_args += " [[texture(" + convert_to_string(r.index) + ")"; + if (interlocked_resources.count(var_id)) ep_args += ", raster_order_group(0)"; ep_args += "]]"; @@ -11885,7 +13517,7 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) } // Emulate texture2D atomic operations - if (atomic_image_vars.count(var.self)) + if (atomic_image_vars_emulated.count(var.self)) { ep_args += ", device atomic_" + type_to_glsl(get(basetype.image.type), 0); ep_args += "* " + r.name + "_atomic"; @@ -11897,9 +13529,26 @@ void CompilerMSL::entry_point_args_discrete_descriptors(string &ep_args) break; } case SPIRType::AccelerationStructure: - ep_args += ", " + type_to_glsl(type, var_id) + " " + r.name; - ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]"; + { + if (is_var_runtime_size_array(var)) + { + add_spv_func_and_recompile(SPVFuncImplVariableDescriptor); + const auto &parent_type = get(type.parent_type); + if (!ep_args.empty()) + ep_args += ", "; + ep_args += "const device spvDescriptor<" + type_to_glsl(parent_type) + ">* " + + to_restrict(var_id, true) + r.name + "_"; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]"; + } + else + { + if (!ep_args.empty()) + ep_args += ", "; + ep_args += type_to_glsl(type, var_id) + " " + r.name; + ep_args += " [[buffer(" + convert_to_string(r.index) + ")]]"; + } break; + } default: if (!ep_args.empty()) ep_args += ", "; @@ -11982,29 +13631,44 @@ void CompilerMSL::fix_up_shader_inputs_outputs() else if ((var.storage == StorageClassStorageBuffer || (var.storage == StorageClassUniform && ssbo)) && !is_hidden_variable(var)) { - if (buffers_requiring_array_length.count(var.self)) + if (buffer_requires_array_length(var.self)) { - entry_func.fixup_hooks_in.push_back([this, &type, &var, var_id]() { - bool is_array_type = !type.array.empty(); + entry_func.fixup_hooks_in.push_back( + [this, &type, &var, var_id]() + { + bool is_array_type = !type.array.empty() && !is_var_runtime_size_array(var); - uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); - if (descriptor_set_is_argument_buffer(desc_set)) - { - statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id), - is_array_type ? " = &" : " = ", to_name(argument_buffer_ids[desc_set]), - ".spvBufferSizeConstants", "[", - convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];"); - } - else - { - // If we have an array of images, we need to be able to index into it, so take a pointer instead. - statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id), - is_array_type ? " = &" : " = ", to_name(buffer_size_buffer_id), "[", - convert_to_string(get_metal_resource_index(var, type.basetype)), "];"); - } - }); + uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); + if (descriptor_set_is_argument_buffer(desc_set)) + { + statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id), + is_array_type ? " = &" : " = ", to_name(argument_buffer_ids[desc_set]), + ".spvBufferSizeConstants", "[", + convert_to_string(get_metal_resource_index(var, SPIRType::Image)), "];"); + } + else + { + // If we have an array of images, we need to be able to index into it, so take a pointer instead. + statement("constant uint", is_array_type ? "* " : "& ", to_buffer_size_expression(var_id), + is_array_type ? " = &" : " = ", to_name(buffer_size_buffer_id), "[", + convert_to_string(get_metal_resource_index(var, type.basetype)), "];"); + } + }); } } + + if (msl_options.replace_recursive_inputs && type_contains_recursion(type) && + (var.storage == StorageClassUniform || var.storage == StorageClassUniformConstant || + var.storage == StorageClassPushConstant || var.storage == StorageClassStorageBuffer)) + { + recursive_inputs.insert(type.self); + entry_func.fixup_hooks_in.push_back([this, &type, &var, var_id]() { + auto addr_space = get_argument_address_space(var); + auto var_name = to_name(var_id); + statement(addr_space, " auto& ", to_restrict(var_id, true), var_name, + " = *(", addr_space, " ", type_to_glsl(type), "*)", var_name, "_vp;"); + }); + } }); // Builtin variables @@ -12036,19 +13700,9 @@ void CompilerMSL::fix_up_shader_inputs_outputs() }); } break; - case BuiltInHelperInvocation: - if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) - SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS."); - else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) - SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); - - entry_func.fixup_hooks_in.push_back([=]() { - statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = simd_is_helper_thread();"); - }); - break; case BuiltInInvocationId: // This is direct-mapped without multi-patch workgroups. - if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup) + if (!is_tesc_shader() || !msl_options.multi_patch_workgroup) break; entry_func.fixup_hooks_in.push_back([=]() { @@ -12060,7 +13714,7 @@ void CompilerMSL::fix_up_shader_inputs_outputs() case BuiltInPrimitiveId: // This is natively supported by fragment and tessellation evaluation shaders. // In tessellation control shaders, this is direct-mapped without multi-patch workgroups. - if (get_execution_model() != ExecutionModelTessellationControl || !msl_options.multi_patch_workgroup) + if (!is_tesc_shader() || !msl_options.multi_patch_workgroup) break; entry_func.fixup_hooks_in.push_back([=]() { @@ -12070,20 +13724,47 @@ void CompilerMSL::fix_up_shader_inputs_outputs() }); break; case BuiltInPatchVertices: - if (get_execution_model() == ExecutionModelTessellationEvaluation) - entry_func.fixup_hooks_in.push_back([=]() { - statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ", - to_expression(patch_stage_in_var_id), ".gl_in.size();"); - }); + if (is_tese_shader()) + { + if (msl_options.raw_buffer_tese_input) + { + entry_func.fixup_hooks_in.push_back( + [=]() { + statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ", + get_entry_point().output_vertices, ";"); + }); + } + else + { + entry_func.fixup_hooks_in.push_back( + [=]() + { + statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = ", + to_expression(patch_stage_in_var_id), ".gl_in.size();"); + }); + } + } else + { entry_func.fixup_hooks_in.push_back([=]() { statement(builtin_type_decl(bi_type), " ", to_expression(var_id), " = spvIndirectParams[0];"); }); + } break; case BuiltInTessCoord: + if (get_entry_point().flags.get(ExecutionModeQuads)) + { + // The entry point will only have a float2 TessCoord variable. + // Pad to float3. + entry_func.fixup_hooks_in.push_back([=]() { + auto name = builtin_to_glsl(BuiltInTessCoord, StorageClassInput); + statement("float3 " + name + " = float3(" + name + "In.x, " + name + "In.y, 0.0);"); + }); + } + // Emit a fixup to account for the shifted domain. Don't do this for triangles; // MoltenVK will just reverse the winding order instead. - if (msl_options.tess_domain_origin_lower_left && !get_entry_point().flags.get(ExecutionModeTriangles)) + if (msl_options.tess_domain_origin_lower_left && !is_tessellating_triangles()) { string tc = to_expression(var_id); entry_func.fixup_hooks_in.push_back([=]() { statement(tc, ".y = 1.0 - ", tc, ".y;"); }); @@ -12577,8 +14258,6 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base for (uint32_t i = 0; i < uint32_t(type.array.size()); i++) binding_stride *= to_array_size_literal(type, i); - assert(binding_stride != 0); - // If a binding has not been specified, revert to incrementing resource indices. uint32_t resource_index; @@ -12590,6 +14269,11 @@ uint32_t CompilerMSL::get_metal_resource_index(SPIRVariable &var, SPIRType::Base } else { + if (is_var_runtime_size_array(var)) + { + basetype = SPIRType::Struct; + binding_stride = 1; + } // Allocate from plain bindings which are allocated per resource type. switch (basetype) { @@ -12636,13 +14320,45 @@ bool CompilerMSL::type_is_pointer_to_pointer(const SPIRType &type) const return type.pointer_depth > parent_type.pointer_depth && type_is_pointer(parent_type); } +const char *CompilerMSL::descriptor_address_space(uint32_t id, StorageClass storage, const char *plain_address_space) const +{ + if (msl_options.argument_buffers) + { + bool storage_class_is_descriptor = storage == StorageClassUniform || + storage == StorageClassStorageBuffer || + storage == StorageClassUniformConstant; + + uint32_t desc_set = get_decoration(id, DecorationDescriptorSet); + if (storage_class_is_descriptor && descriptor_set_is_argument_buffer(desc_set)) + { + // An awkward case where we need to emit *more* address space declarations (yay!). + // An example is where we pass down an array of buffer pointers to leaf functions. + // It's a constant array containing pointers to constants. + // The pointer array is always constant however. E.g. + // device SSBO * constant (&array)[N]. + // const device SSBO * constant (&array)[N]. + // constant SSBO * constant (&array)[N]. + // However, this only matters for argument buffers, since for MSL 1.0 style codegen, + // we emit the buffer array on stack instead, and that seems to work just fine apparently. + + // If the argument was marked as being in device address space, any pointer to member would + // be const device, not constant. + if (argument_buffer_device_storage_mask & (1u << desc_set)) + return "const device"; + else + return "constant"; + } + } + + return plain_address_space; +} + string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) { auto &var = get(arg.id); auto &type = get_variable_data_type(var); auto &var_type = get(arg.type); StorageClass type_storage = var_type.storage; - bool is_pointer = var_type.pointer; // If we need to modify the name of the variable, make sure we use the original variable. // Our alias is just a shadow variable. @@ -12650,19 +14366,19 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) if (arg.alias_global_variable && var.basevariable) name_id = var.basevariable; - bool constref = !arg.alias_global_variable && is_pointer && arg.write_count == 0; + bool constref = !arg.alias_global_variable && is_pointer(var_type) && arg.write_count == 0; // Framebuffer fetch is plain value, const looks out of place, but it is not wrong. if (type_is_msl_framebuffer_fetch(type)) constref = false; + else if (type_storage == StorageClassUniformConstant) + constref = true; bool type_is_image = type.basetype == SPIRType::Image || type.basetype == SPIRType::SampledImage || type.basetype == SPIRType::Sampler; + bool type_is_tlas = type.basetype == SPIRType::AccelerationStructure; - // Arrays of images/samplers in MSL are always const. - if (!type.array.empty() && type_is_image) - constref = true; - - const char *cv_qualifier = constref ? "const " : ""; + // For opaque types we handle const later due to descriptor address spaces. + const char *cv_qualifier = (constref && !type_is_image) ? "const " : ""; string decl; // If this is a combined image-sampler for a 2D image with floating-point type, @@ -12679,9 +14395,6 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) bool builtin = has_decoration(var.self, DecorationBuiltIn); auto builtin_type = BuiltIn(get_decoration(arg.id, DecorationBuiltIn)); - if (address_space == "threadgroup") - is_using_builtin_array = true; - if (var.basevariable && (var.basevariable == stage_in_ptr_var_id || var.basevariable == stage_out_ptr_var_id)) decl = join(cv_qualifier, type_to_glsl(type, arg.id)); else if (builtin) @@ -12710,6 +14423,18 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) else decl = join(cv_qualifier, type_to_glsl(type, arg.id)); } + else if (is_var_runtime_size_array(var)) + { + const auto *parent_type = &get(type.parent_type); + auto type_name = type_to_glsl(*parent_type, arg.id); + if (type.basetype == SPIRType::AccelerationStructure) + decl = join("spvDescriptorArray<", type_name, ">"); + else if (type_is_image) + decl = join("spvDescriptorArray<", cv_qualifier, type_name, ">"); + else + decl = join("spvDescriptorArray<", address_space, " ", type_name, "*>"); + address_space = "const"; + } else if ((type_storage == StorageClassUniform || type_storage == StorageClassStorageBuffer) && is_array(type)) { is_using_builtin_array = true; @@ -12731,12 +14456,12 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) decl += join(" ", cv_qualifier); } else + { decl = join(cv_qualifier, type_to_glsl(type, arg.id)); + } } - bool opaque_handle = type_storage == StorageClassUniformConstant; - - if (!builtin && !opaque_handle && !is_pointer && + if (!builtin && !is_pointer(var_type) && (type_storage == StorageClassFunction || type_storage == StorageClassGeneric)) { // If the argument is a pure value and not an opaque type, we will pass by value. @@ -12751,7 +14476,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) // non-constant arrays, but we can create thread const from constant. decl = string("thread const ") + decl; decl += " (&"; - const char *restrict_kw = to_restrict(name_id); + const char *restrict_kw = to_restrict(name_id, true); if (*restrict_kw) { decl += " "; @@ -12771,37 +14496,19 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) } else if (is_array(type) && !type_is_image) { - // Arrays of images and samplers are special cased. + // Arrays of opaque types are special cased. if (!address_space.empty()) decl = join(address_space, " ", decl); - if (msl_options.argument_buffers) + const char *argument_buffer_space = descriptor_address_space(name_id, type_storage, nullptr); + if (argument_buffer_space) { - uint32_t desc_set = get_decoration(name_id, DecorationDescriptorSet); - if ((type_storage == StorageClassUniform || type_storage == StorageClassStorageBuffer) && - descriptor_set_is_argument_buffer(desc_set)) - { - // An awkward case where we need to emit *more* address space declarations (yay!). - // An example is where we pass down an array of buffer pointers to leaf functions. - // It's a constant array containing pointers to constants. - // The pointer array is always constant however. E.g. - // device SSBO * constant (&array)[N]. - // const device SSBO * constant (&array)[N]. - // constant SSBO * constant (&array)[N]. - // However, this only matters for argument buffers, since for MSL 1.0 style codegen, - // we emit the buffer array on stack instead, and that seems to work just fine apparently. - - // If the argument was marked as being in device address space, any pointer to member would - // be const device, not constant. - if (argument_buffer_device_storage_mask & (1u << desc_set)) - decl += " const device"; - else - decl += " constant"; - } + decl += " "; + decl += argument_buffer_space; } // Special case, need to override the array size here if we're using tess level as an argument. - if (get_execution_model() == ExecutionModelTessellationControl && builtin && + if (is_tesc_shader() && builtin && (builtin_type == BuiltInTessLevelInner || builtin_type == BuiltInTessLevelOuter)) { uint32_t array_size = get_physical_tess_level_array_size(builtin_type); @@ -12818,6 +14525,10 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) decl += join("[", array_size, "]"); } } + else if (is_var_runtime_size_array(var)) + { + decl += " " + to_expression(name_id); + } else { auto array_size_decl = type_to_array_glsl(type); @@ -12826,7 +14537,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) else decl += " (&"; - const char *restrict_kw = to_restrict(name_id); + const char *restrict_kw = to_restrict(name_id, true); if (*restrict_kw) { decl += " "; @@ -12841,7 +14552,8 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) } } } - else if (!opaque_handle && (!pull_model_inputs.count(var.basevariable) || type.basetype == SPIRType::Struct)) + else if (!type_is_image && !type_is_tlas && + (!pull_model_inputs.count(var.basevariable) || type.basetype == SPIRType::Struct)) { // If this is going to be a reference to a variable pointer, the address space // for the reference has to go before the '&', but after the '*'. @@ -12858,9 +14570,34 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) } decl += "&"; decl += " "; - decl += to_restrict(name_id); + decl += to_restrict(name_id, true); decl += to_expression(name_id); } + else if (type_is_image || type_is_tlas) + { + if (is_var_runtime_size_array(var)) + { + decl = address_space + " " + decl + " " + to_expression(name_id); + } + else if (type.array.empty()) + { + // For non-arrayed types we can just pass opaque descriptors by value. + // This fixes problems if descriptors are passed by value from argument buffers and plain descriptors + // in same shader. + // There is no address space we can actually use, but value will work. + // This will break if applications attempt to pass down descriptor arrays as arguments, but + // fortunately that is extremely unlikely ... + decl += " "; + decl += to_expression(name_id); + } + else + { + const char *img_address_space = descriptor_address_space(name_id, type_storage, "thread const"); + decl = join(img_address_space, " ", decl); + decl += "& "; + decl += to_expression(name_id); + } + } else { if (!address_space.empty()) @@ -12871,7 +14608,7 @@ string CompilerMSL::argument_decl(const SPIRFunction::Parameter &arg) // Emulate texture2D atomic operations auto *backing_var = maybe_get_backing_variable(name_id); - if (backing_var && atomic_image_vars.count(backing_var->self)) + if (backing_var && atomic_image_vars_emulated.count(backing_var->self)) { decl += ", device atomic_" + type_to_glsl(get(var_type.image.type), 0); decl += "* " + to_expression(name_id) + "_atomic"; @@ -12895,8 +14632,8 @@ string CompilerMSL::to_name(uint32_t id, bool allow_alias) const return Compiler::to_name(id, allow_alias); } -// Returns a name that combines the name of the struct with the name of the member, except for Builtins -string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t index) +// Appends the name of the member to the variable qualifier string, except for Builtins. +string CompilerMSL::append_member_name(const string &qualifier, const SPIRType &type, uint32_t index) { // Don't qualify Builtin names because they are unique and are treated as such when building expressions BuiltIn builtin = BuiltInMax; @@ -12907,7 +14644,7 @@ string CompilerMSL::to_qualified_member_name(const SPIRType &type, uint32_t inde string mbr_name = to_member_name(type, index); size_t startPos = mbr_name.find_first_not_of("_"); mbr_name = (startPos != string::npos) ? mbr_name.substr(startPos) : ""; - return join(to_name(type.self), "_", mbr_name); + return join(qualifier, "_", mbr_name); } // Ensures that the specified name is permanently usable by prepending a prefix @@ -12924,6 +14661,8 @@ const std::unordered_set &CompilerMSL::get_reserved_keyword_set() "vertex", "fragment", "compute", + "constant", + "device", "bias", "level", "gradient2d", @@ -13050,6 +14789,8 @@ const std::unordered_set &CompilerMSL::get_reserved_keyword_set() "M_SQRT2", "M_SQRT1_2", "quad_broadcast", + "thread", + "threadgroup", }; return keywords; @@ -13063,6 +14804,7 @@ const std::unordered_set &CompilerMSL::get_illegal_func_names() "assert", "fmin3", "fmax3", + "divide", "VARIABLE_TRACEPOINT", "STATIC_DATA_TRACEPOINT", "STATIC_DATA_TRACEPOINT_V", @@ -13251,9 +14993,9 @@ void CompilerMSL::sync_entry_point_aliases_and_names() entry.second.name = ir.meta[entry.first].decoration.alias; } -string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain) +string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain_is_resolved) { - auto *var = maybe_get(base); + auto *var = maybe_get_backing_variable(base); // If this is a buffer array, we have to dereference the buffer pointers. // Otherwise, if this is a pointer expression, dereference it. @@ -13263,14 +15005,15 @@ string CompilerMSL::to_member_reference(uint32_t base, const SPIRType &type, uin { // Only allow -> dereference for block types. This is so we get expressions like // buffer[i]->first_member.second_member, rather than buffer[i]->first->second. - bool is_block = has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock); + const bool is_block = + has_decoration(type.self, DecorationBlock) || has_decoration(type.self, DecorationBufferBlock); bool is_buffer_variable = is_block && (var->storage == StorageClassUniform || var->storage == StorageClassStorageBuffer); - declared_as_pointer = is_buffer_variable && is_array(get(var->basetype)); + declared_as_pointer = is_buffer_variable && is_array(get_pointee_type(var->basetype)); } - if (declared_as_pointer || (!ptr_chain && should_dereference(base))) + if (declared_as_pointer || (!ptr_chain_is_resolved && should_dereference(base))) return join("->", to_member_name(type, index)); else return join(".", to_member_name(type, index)); @@ -13292,19 +15035,19 @@ string CompilerMSL::to_qualifiers_glsl(uint32_t id) // The optional id parameter indicates the object whose type we are trying // to find the description for. It is optional. Most type descriptions do not // depend on a specific object's use of that type. -string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) +string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id, bool member) { string type_name; // Pointer? - if (type.pointer) + if (is_pointer(type) || type_is_array_of_pointers(type)) { assert(type.pointer_depth > 0); const char *restrict_kw; auto type_address_space = get_type_address_space(type, id); - auto type_decl = type_to_glsl(get(type.parent_type), id); + const auto *p_parent_type = &get(type.parent_type); // Work around C pointer qualifier rules. If glsl_type is a pointer type as well // we'll need to emit the address space to the right. @@ -13312,9 +15055,26 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) // Prefer emitting thread T *foo over T thread* foo since it's more readable, // but we'll have to emit thread T * thread * T constant bar; for example. if (type_is_pointer_to_pointer(type)) - type_name = join(type_decl, " ", type_address_space, " "); + type_name = join(type_to_glsl(*p_parent_type, id), " ", type_address_space, " "); else - type_name = join(type_address_space, " ", type_decl); + { + // Since this is not a pointer-to-pointer, ensure we've dug down to the base type. + // Some situations chain pointers even though they are not formally pointers-of-pointers. + while (type_is_pointer(*p_parent_type)) + p_parent_type = &get(p_parent_type->parent_type); + + // If we're emitting BDA, just use the templated type. + // Emitting builtin arrays need a lot of cooperation with other code to ensure + // the C-style nesting works right. + // FIXME: This is somewhat of a hack. + bool old_is_using_builtin_array = is_using_builtin_array; + if (is_physical_pointer(type)) + is_using_builtin_array = false; + + type_name = join(type_address_space, " ", type_to_glsl(*p_parent_type, id)); + + is_using_builtin_array = old_is_using_builtin_array; + } switch (type.basetype) { @@ -13326,7 +15086,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) default: // Anything else can be a raw pointer. type_name += "*"; - restrict_kw = to_restrict(id); + restrict_kw = to_restrict(id, false); if (*restrict_kw) { type_name += " "; @@ -13375,9 +15135,7 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) // Need to special-case threadgroup booleans. They are supposed to be logical // storage, but MSL compilers will sometimes crash if you use threadgroup bool. // Workaround this by using 16-bit types instead and fixup on load-store to this data. - // FIXME: We have no sane way of working around this problem if a struct member is boolean - // and that struct is used as a threadgroup variable, but ... sigh. - if ((var && var->storage == StorageClassWorkgroup) || type.storage == StorageClassWorkgroup) + if ((var && var->storage == StorageClassWorkgroup) || type.storage == StorageClassWorkgroup || member) type_name = "short"; else type_name = "bool"; @@ -13424,14 +15182,14 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) break; case SPIRType::AccelerationStructure: if (msl_options.supports_msl_version(2, 4)) - type_name = "acceleration_structure"; + type_name = "raytracing::acceleration_structure"; else if (msl_options.supports_msl_version(2, 3)) - type_name = "instance_acceleration_structure"; + type_name = "raytracing::instance_acceleration_structure"; else SPIRV_CROSS_THROW("Acceleration Structure Type is supported in MSL 2.3 and above."); break; case SPIRType::RayQuery: - return "intersection_query"; + return "raytracing::intersection_query"; default: return "unknown_type"; @@ -13439,7 +15197,24 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) // Matrix? if (type.columns > 1) + { + auto *var = maybe_get_backing_variable(id); + if (var && var->basevariable) + var = &get(var->basevariable); + + // Need to special-case threadgroup matrices. Due to an oversight, Metal's + // matrix struct prior to Metal 3 lacks constructors in the threadgroup AS, + // preventing us from default-constructing or initializing matrices in threadgroup storage. + // Work around this by using our own type as storage. + if (((var && var->storage == StorageClassWorkgroup) || type.storage == StorageClassWorkgroup) && + !msl_options.supports_msl_version(3, 0)) + { + add_spv_func_and_recompile(SPVFuncImplStorageMatrix); + type_name = "spvStorage_" + type_name; + } + type_name += to_string(type.columns) + "x"; + } // Vector or Matrix? if (type.vecsize > 1) @@ -13469,6 +15244,11 @@ string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) } } +string CompilerMSL::type_to_glsl(const SPIRType &type, uint32_t id) +{ + return type_to_glsl(type, id, false); +} + string CompilerMSL::type_to_array_glsl(const SPIRType &type) { // Allow Metal to use the array template to make arrays a value type @@ -13477,17 +15257,14 @@ string CompilerMSL::type_to_array_glsl(const SPIRType &type) case SPIRType::AtomicCounter: case SPIRType::ControlPointArray: case SPIRType::RayQuery: - { return CompilerGLSL::type_to_array_glsl(type); - } + default: - { - if (using_builtin_array()) + if (type_is_array_of_pointers(type) || using_builtin_array()) return CompilerGLSL::type_to_array_glsl(type); else return ""; } - } } string CompilerMSL::constant_op_expression(const SPIRConstantOp &cop) @@ -13509,23 +15286,25 @@ bool CompilerMSL::variable_decl_is_remapped_storage(const SPIRVariable &variable if (storage == StorageClassWorkgroup) { - auto model = get_execution_model(); - // Specially masked IO block variable. // Normally, we will never access IO blocks directly here. // The only scenario which that should occur is with a masked IO block. - if (model == ExecutionModelTessellationControl && variable.storage == StorageClassOutput && + if (is_tesc_shader() && variable.storage == StorageClassOutput && has_decoration(get(variable.basetype).self, DecorationBlock)) { return true; } - return variable.storage == StorageClassOutput && - model == ExecutionModelTessellationControl && - is_stage_output_variable_masked(variable); + return variable.storage == StorageClassOutput && is_tesc_shader() && is_stage_output_variable_masked(variable); } else if (storage == StorageClassStorageBuffer) { + // These builtins are passed directly; we don't want to use remapping + // for them. + auto builtin = (BuiltIn)get_decoration(variable.self, DecorationBuiltIn); + if (is_tese_shader() && is_builtin_variable(variable) && (builtin == BuiltInTessCoord || builtin == BuiltInPrimitiveId)) + return false; + // We won't be able to catch writes to control point outputs here since variable // refers to a function local pointer. // This is fine, as there cannot be concurrent writers to that memory anyways, @@ -13541,19 +15320,6 @@ bool CompilerMSL::variable_decl_is_remapped_storage(const SPIRVariable &variable } } -std::string CompilerMSL::variable_decl(const SPIRVariable &variable) -{ - bool old_is_using_builtin_array = is_using_builtin_array; - - // Threadgroup arrays can't have a wrapper type. - if (variable_decl_is_remapped_storage(variable, StorageClassWorkgroup)) - is_using_builtin_array = true; - - std::string expr = CompilerGLSL::variable_decl(variable); - is_using_builtin_array = old_is_using_builtin_array; - return expr; -} - // GCC workaround of lambdas calling protected funcs std::string CompilerMSL::variable_decl(const SPIRType &type, const std::string &name, uint32_t id) { @@ -13579,12 +15345,16 @@ std::string CompilerMSL::sampler_type(const SPIRType &type, uint32_t id) // Arrays of samplers in MSL must be declared with a special array syntax ala C++11 std::array. // If we have a runtime array, it could be a variable-count descriptor set binding. - uint32_t array_size = to_array_size_literal(type); + uint32_t array_size = get_resource_array_size(type, id); if (array_size == 0) - array_size = get_resource_array_size(id); - - if (array_size == 0) - SPIRV_CROSS_THROW("Unsized array of samplers is not supported in MSL."); + { + add_spv_func_and_recompile(SPVFuncImplVariableDescriptor); + add_spv_func_and_recompile(SPVFuncImplVariableDescriptorArray); + auto &parent = get(get_pointee_type(type).parent_type); + if (processing_entry_point) + return join("const device spvDescriptor<", sampler_type(parent, id), ">*"); + return join("const spvDescriptorArray<", sampler_type(parent, id), ">"); + } auto &parent = get(get_pointee_type(type).parent_type); return join("array<", sampler_type(parent, id), ", ", array_size, ">"); @@ -13625,12 +15395,14 @@ string CompilerMSL::image_type_glsl(const SPIRType &type, uint32_t id) // Arrays of images in MSL must be declared with a special array syntax ala C++11 std::array. // If we have a runtime array, it could be a variable-count descriptor set binding. - uint32_t array_size = to_array_size_literal(type); + uint32_t array_size = get_resource_array_size(type, id); if (array_size == 0) - array_size = get_resource_array_size(id); - - if (array_size == 0) - SPIRV_CROSS_THROW("Unsized array of images is not supported in MSL."); + { + add_spv_func_and_recompile(SPVFuncImplVariableDescriptor); + add_spv_func_and_recompile(SPVFuncImplVariableDescriptorArray); + auto &parent = get(get_pointee_type(type).parent_type); + return join("const device spvDescriptor<", image_type_glsl(parent, id), ">*"); + } auto &parent = get(get_pointee_type(type).parent_type); return join("array<", image_type_glsl(parent, id), ", ", array_size, ">"); @@ -13846,6 +15618,10 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) case OpGroupNonUniformBallotFindLSB: case OpGroupNonUniformBallotFindMSB: case OpGroupNonUniformBallotBitCount: + case OpSubgroupBallotKHR: + case OpSubgroupAllKHR: + case OpSubgroupAnyKHR: + case OpSubgroupAllEqualKHR: if (!msl_options.supports_msl_version(2, 2)) SPIRV_CROSS_THROW("Ballot ops on iOS requires Metal 2.2 and up."); break; @@ -13856,6 +15632,7 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) case OpGroupNonUniformShuffleDown: case OpGroupNonUniformQuadSwap: case OpGroupNonUniformQuadBroadcast: + case OpSubgroupReadInvocationKHR: break; } } @@ -13871,68 +15648,88 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) case OpGroupNonUniformShuffleXor: case OpGroupNonUniformShuffleUp: case OpGroupNonUniformShuffleDown: + case OpSubgroupReadInvocationKHR: break; } } - uint32_t result_type = ops[0]; - uint32_t id = ops[1]; + uint32_t op_idx = 0; + uint32_t result_type = ops[op_idx++]; + uint32_t id = ops[op_idx++]; - auto scope = static_cast(evaluate_constant_u32(ops[2])); + Scope scope; + switch (op) + { + case OpSubgroupBallotKHR: + case OpSubgroupFirstInvocationKHR: + case OpSubgroupReadInvocationKHR: + case OpSubgroupAllKHR: + case OpSubgroupAnyKHR: + case OpSubgroupAllEqualKHR: + // These earlier instructions don't have the scope operand. + scope = ScopeSubgroup; + break; + default: + scope = static_cast(evaluate_constant_u32(ops[op_idx++])); + break; + } if (scope != ScopeSubgroup) SPIRV_CROSS_THROW("Only subgroup scope is supported."); switch (op) { case OpGroupNonUniformElect: - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) + if (msl_options.use_quadgroup_operation()) emit_op(result_type, id, "quad_is_first()", false); else emit_op(result_type, id, "simd_is_first()", false); break; case OpGroupNonUniformBroadcast: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupBroadcast"); + case OpSubgroupReadInvocationKHR: + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupBroadcast"); break; case OpGroupNonUniformBroadcastFirst: - emit_unary_func_op(result_type, id, ops[3], "spvSubgroupBroadcastFirst"); + case OpSubgroupFirstInvocationKHR: + emit_unary_func_op(result_type, id, ops[op_idx], "spvSubgroupBroadcastFirst"); break; case OpGroupNonUniformBallot: - emit_unary_func_op(result_type, id, ops[3], "spvSubgroupBallot"); + case OpSubgroupBallotKHR: + emit_unary_func_op(result_type, id, ops[op_idx], "spvSubgroupBallot"); break; case OpGroupNonUniformInverseBallot: - emit_binary_func_op(result_type, id, ops[3], builtin_subgroup_invocation_id_id, "spvSubgroupBallotBitExtract"); + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_invocation_id_id, "spvSubgroupBallotBitExtract"); break; case OpGroupNonUniformBallotBitExtract: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupBallotBitExtract"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupBallotBitExtract"); break; case OpGroupNonUniformBallotFindLSB: - emit_binary_func_op(result_type, id, ops[3], builtin_subgroup_size_id, "spvSubgroupBallotFindLSB"); + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_size_id, "spvSubgroupBallotFindLSB"); break; case OpGroupNonUniformBallotFindMSB: - emit_binary_func_op(result_type, id, ops[3], builtin_subgroup_size_id, "spvSubgroupBallotFindMSB"); + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_size_id, "spvSubgroupBallotFindMSB"); break; case OpGroupNonUniformBallotBitCount: { - auto operation = static_cast(ops[3]); + auto operation = static_cast(ops[op_idx++]); switch (operation) { case GroupOperationReduce: - emit_binary_func_op(result_type, id, ops[4], builtin_subgroup_size_id, "spvSubgroupBallotBitCount"); + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_size_id, "spvSubgroupBallotBitCount"); break; case GroupOperationInclusiveScan: - emit_binary_func_op(result_type, id, ops[4], builtin_subgroup_invocation_id_id, + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_invocation_id_id, "spvSubgroupBallotInclusiveBitCount"); break; case GroupOperationExclusiveScan: - emit_binary_func_op(result_type, id, ops[4], builtin_subgroup_invocation_id_id, + emit_binary_func_op(result_type, id, ops[op_idx], builtin_subgroup_invocation_id_id, "spvSubgroupBallotExclusiveBitCount"); break; default: @@ -13942,57 +15739,60 @@ void CompilerMSL::emit_subgroup_op(const Instruction &i) } case OpGroupNonUniformShuffle: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupShuffle"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupShuffle"); break; case OpGroupNonUniformShuffleXor: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupShuffleXor"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupShuffleXor"); break; case OpGroupNonUniformShuffleUp: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupShuffleUp"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupShuffleUp"); break; case OpGroupNonUniformShuffleDown: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvSubgroupShuffleDown"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvSubgroupShuffleDown"); break; case OpGroupNonUniformAll: - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) - emit_unary_func_op(result_type, id, ops[3], "quad_all"); + case OpSubgroupAllKHR: + if (msl_options.use_quadgroup_operation()) + emit_unary_func_op(result_type, id, ops[op_idx], "quad_all"); else - emit_unary_func_op(result_type, id, ops[3], "simd_all"); + emit_unary_func_op(result_type, id, ops[op_idx], "simd_all"); break; case OpGroupNonUniformAny: - if (msl_options.is_ios() && !msl_options.ios_use_simdgroup_functions) - emit_unary_func_op(result_type, id, ops[3], "quad_any"); + case OpSubgroupAnyKHR: + if (msl_options.use_quadgroup_operation()) + emit_unary_func_op(result_type, id, ops[op_idx], "quad_any"); else - emit_unary_func_op(result_type, id, ops[3], "simd_any"); + emit_unary_func_op(result_type, id, ops[op_idx], "simd_any"); break; case OpGroupNonUniformAllEqual: - emit_unary_func_op(result_type, id, ops[3], "spvSubgroupAllEqual"); + case OpSubgroupAllEqualKHR: + emit_unary_func_op(result_type, id, ops[op_idx], "spvSubgroupAllEqual"); break; // clang-format off #define MSL_GROUP_OP(op, msl_op) \ case OpGroupNonUniform##op: \ { \ - auto operation = static_cast(ops[3]); \ + auto operation = static_cast(ops[op_idx++]); \ if (operation == GroupOperationReduce) \ - emit_unary_func_op(result_type, id, ops[4], "simd_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "simd_" #msl_op); \ else if (operation == GroupOperationInclusiveScan) \ - emit_unary_func_op(result_type, id, ops[4], "simd_prefix_inclusive_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "simd_prefix_inclusive_" #msl_op); \ else if (operation == GroupOperationExclusiveScan) \ - emit_unary_func_op(result_type, id, ops[4], "simd_prefix_exclusive_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "simd_prefix_exclusive_" #msl_op); \ else if (operation == GroupOperationClusteredReduce) \ { \ /* Only cluster sizes of 4 are supported. */ \ - uint32_t cluster_size = evaluate_constant_u32(ops[5]); \ + uint32_t cluster_size = evaluate_constant_u32(ops[op_idx + 1]); \ if (cluster_size != 4) \ SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \ - emit_unary_func_op(result_type, id, ops[4], "quad_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "quad_" #msl_op); \ } \ else \ SPIRV_CROSS_THROW("Invalid group operation."); \ @@ -14008,9 +15808,9 @@ case OpGroupNonUniform##op: \ #define MSL_GROUP_OP(op, msl_op) \ case OpGroupNonUniform##op: \ { \ - auto operation = static_cast(ops[3]); \ + auto operation = static_cast(ops[op_idx++]); \ if (operation == GroupOperationReduce) \ - emit_unary_func_op(result_type, id, ops[4], "simd_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "simd_" #msl_op); \ else if (operation == GroupOperationInclusiveScan) \ SPIRV_CROSS_THROW("Metal doesn't support InclusiveScan for OpGroupNonUniform" #op "."); \ else if (operation == GroupOperationExclusiveScan) \ @@ -14018,10 +15818,10 @@ case OpGroupNonUniform##op: \ else if (operation == GroupOperationClusteredReduce) \ { \ /* Only cluster sizes of 4 are supported. */ \ - uint32_t cluster_size = evaluate_constant_u32(ops[5]); \ + uint32_t cluster_size = evaluate_constant_u32(ops[op_idx + 1]); \ if (cluster_size != 4) \ SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \ - emit_unary_func_op(result_type, id, ops[4], "quad_" #msl_op); \ + emit_unary_func_op(result_type, id, ops[op_idx], "quad_" #msl_op); \ } \ else \ SPIRV_CROSS_THROW("Invalid group operation."); \ @@ -14031,9 +15831,9 @@ case OpGroupNonUniform##op: \ #define MSL_GROUP_OP_CAST(op, msl_op, type) \ case OpGroupNonUniform##op: \ { \ - auto operation = static_cast(ops[3]); \ + auto operation = static_cast(ops[op_idx++]); \ if (operation == GroupOperationReduce) \ - emit_unary_func_op_cast(result_type, id, ops[4], "simd_" #msl_op, type, type); \ + emit_unary_func_op_cast(result_type, id, ops[op_idx], "simd_" #msl_op, type, type); \ else if (operation == GroupOperationInclusiveScan) \ SPIRV_CROSS_THROW("Metal doesn't support InclusiveScan for OpGroupNonUniform" #op "."); \ else if (operation == GroupOperationExclusiveScan) \ @@ -14041,10 +15841,10 @@ case OpGroupNonUniform##op: \ else if (operation == GroupOperationClusteredReduce) \ { \ /* Only cluster sizes of 4 are supported. */ \ - uint32_t cluster_size = evaluate_constant_u32(ops[5]); \ + uint32_t cluster_size = evaluate_constant_u32(ops[op_idx + 1]); \ if (cluster_size != 4) \ SPIRV_CROSS_THROW("Metal only supports quad ClusteredReduce."); \ - emit_unary_func_op_cast(result_type, id, ops[4], "quad_" #msl_op, type, type); \ + emit_unary_func_op_cast(result_type, id, ops[op_idx], "quad_" #msl_op, type, type); \ } \ else \ SPIRV_CROSS_THROW("Invalid group operation."); \ @@ -14068,11 +15868,11 @@ case OpGroupNonUniform##op: \ #undef MSL_GROUP_OP_CAST case OpGroupNonUniformQuadSwap: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvQuadSwap"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvQuadSwap"); break; case OpGroupNonUniformQuadBroadcast: - emit_binary_func_op(result_type, id, ops[3], ops[4], "spvQuadBroadcast"); + emit_binary_func_op(result_type, id, ops[op_idx], ops[op_idx + 1], "spvQuadBroadcast"); break; default: @@ -14099,17 +15899,14 @@ string CompilerMSL::bitcast_glsl_op(const SPIRType &out_type, const SPIRType &in // size (eg. short shift right becomes int), which means chaining integer ops // together may introduce size variations that SPIR-V doesn't know about. if (same_size_cast && !integral_cast) - { return "as_type<" + type_to_glsl(out_type) + ">"; - } else - { return type_to_glsl(out_type); - } } bool CompilerMSL::emit_complex_bitcast(uint32_t, uint32_t, uint32_t) { + // This is handled from the outside where we deal with PtrToU/UToPtr and friends. return false; } @@ -14248,7 +16045,7 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) case BuiltInClipDistance: case BuiltInCullDistance: case BuiltInLayer: - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader()) break; if (storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point) && !is_stage_output_builtin_masked(builtin)) @@ -14273,15 +16070,15 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) return stage_out_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin, storage); break; - case BuiltInBaryCoordNV: - case BuiltInBaryCoordNoPerspNV: + case BuiltInBaryCoordKHR: + case BuiltInBaryCoordNoPerspKHR: if (storage == StorageClassInput && current_function && (current_function->self == ir.default_entry_point)) return stage_in_var_name + "." + CompilerGLSL::builtin_to_glsl(builtin, storage); break; case BuiltInTessLevelOuter: - if (get_execution_model() == ExecutionModelTessellationControl && - storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point)) + if (is_tesc_shader() && storage != StorageClassInput && current_function && + (current_function->self == ir.default_entry_point)) { return join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id), "].edgeTessellationFactor"); @@ -14289,14 +16086,24 @@ string CompilerMSL::builtin_to_glsl(BuiltIn builtin, StorageClass storage) break; case BuiltInTessLevelInner: - if (get_execution_model() == ExecutionModelTessellationControl && - storage != StorageClassInput && current_function && (current_function->self == ir.default_entry_point)) + if (is_tesc_shader() && storage != StorageClassInput && current_function && + (current_function->self == ir.default_entry_point)) { return join(tess_factor_buffer_var_name, "[", to_expression(builtin_primitive_id_id), "].insideTessellationFactor"); } break; + case BuiltInHelperInvocation: + if (needs_manual_helper_invocation_updates()) + break; + if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.3 on iOS."); + else if (msl_options.is_macos() && !msl_options.supports_msl_version(2, 1)) + SPIRV_CROSS_THROW("simd_is_helper_thread() requires version 2.1 on macOS."); + // In SPIR-V 1.6 with Volatile HelperInvocation, we cannot emit a fixup early. + return "simd_is_helper_thread()"; + default: break; } @@ -14463,7 +16270,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin) SPIRV_CROSS_THROW("NumSubgroups is handled specially with emulation."); if (!msl_options.supports_msl_version(2)) SPIRV_CROSS_THROW("Subgroup builtins require Metal 2.0."); - return msl_options.is_ios() ? "quadgroups_per_threadgroup" : "simdgroups_per_threadgroup"; + return msl_options.use_quadgroup_operation() ? "quadgroups_per_threadgroup" : "simdgroups_per_threadgroup"; case BuiltInSubgroupId: if (msl_options.emulate_subgroups) @@ -14471,7 +16278,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin) SPIRV_CROSS_THROW("SubgroupId is handled specially with emulation."); if (!msl_options.supports_msl_version(2)) SPIRV_CROSS_THROW("Subgroup builtins require Metal 2.0."); - return msl_options.is_ios() ? "quadgroup_index_in_threadgroup" : "simdgroup_index_in_threadgroup"; + return msl_options.use_quadgroup_operation() ? "quadgroup_index_in_threadgroup" : "simdgroup_index_in_threadgroup"; case BuiltInSubgroupLocalInvocationId: if (msl_options.emulate_subgroups) @@ -14490,7 +16297,7 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin) // We are generating a Metal kernel function. if (!msl_options.supports_msl_version(2)) SPIRV_CROSS_THROW("Subgroup builtins in kernel functions require Metal 2.0."); - return msl_options.is_ios() ? "thread_index_in_quadgroup" : "thread_index_in_simdgroup"; + return msl_options.use_quadgroup_operation() ? "thread_index_in_quadgroup" : "thread_index_in_simdgroup"; } else SPIRV_CROSS_THROW("Subgroup builtins are not available in this type of function."); @@ -14503,16 +16310,14 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin) // Shouldn't be reached. SPIRV_CROSS_THROW("Subgroup ballot masks are handled specially in MSL."); - case BuiltInBaryCoordNV: - // TODO: AMD barycentrics as well? Seem to have different swizzle and 2 components rather than 3. + case BuiltInBaryCoordKHR: if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) SPIRV_CROSS_THROW("Barycentrics are only supported in MSL 2.3 and above on iOS."); else if (!msl_options.supports_msl_version(2, 2)) SPIRV_CROSS_THROW("Barycentrics are only supported in MSL 2.2 and above on macOS."); return "barycentric_coord, center_perspective"; - case BuiltInBaryCoordNoPerspNV: - // TODO: AMD barycentrics as well? Seem to have different swizzle and 2 components rather than 3. + case BuiltInBaryCoordNoPerspKHR: if (msl_options.is_ios() && !msl_options.supports_msl_version(2, 3)) SPIRV_CROSS_THROW("Barycentrics are only supported in MSL 2.3 and above on iOS."); else if (!msl_options.supports_msl_version(2, 2)) @@ -14527,7 +16332,6 @@ string CompilerMSL::builtin_qualifier(BuiltIn builtin) // Returns an MSL string type declaration for a SPIR-V builtin string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id) { - const SPIREntryPoint &execution = get_entry_point(); switch (builtin) { // Vertex function in @@ -14571,17 +16375,17 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id) // Tess. control function out case BuiltInTessLevelInner: - if (execution.model == ExecutionModelTessellationEvaluation) - return !execution.flags.get(ExecutionModeTriangles) ? "float2" : "float"; + if (is_tese_shader()) + return (msl_options.raw_buffer_tese_input || is_tessellating_triangles()) ? "float" : "float2"; return "half"; case BuiltInTessLevelOuter: - if (execution.model == ExecutionModelTessellationEvaluation) - return !execution.flags.get(ExecutionModeTriangles) ? "float4" : "float"; + if (is_tese_shader()) + return (msl_options.raw_buffer_tese_input || is_tessellating_triangles()) ? "float" : "float4"; return "half"; // Tess. evaluation function in case BuiltInTessCoord: - return execution.flags.get(ExecutionModeTriangles) ? "float3" : "float2"; + return "float3"; // Fragment function in case BuiltInFrontFacing: @@ -14602,8 +16406,8 @@ string CompilerMSL::builtin_type_decl(BuiltIn builtin, uint32_t id) case BuiltInHelperInvocation: return "bool"; - case BuiltInBaryCoordNV: - case BuiltInBaryCoordNoPerspNV: + case BuiltInBaryCoordKHR: + case BuiltInBaryCoordNoPerspKHR: // Use the type as declared, can be 1, 2 or 3 components. return type_to_glsl(get_variable_data_type(get(id))); @@ -14651,8 +16455,8 @@ string CompilerMSL::built_in_func_arg(BuiltIn builtin, bool prefix_comma) // Handle HLSL-style 0-based vertex/instance index. builtin_declaration = true; bi_arg += builtin_type_decl(builtin); - bi_arg += " " + builtin_to_glsl(builtin, StorageClassInput); - bi_arg += " [[" + builtin_qualifier(builtin) + "]]"; + bi_arg += string(" ") + builtin_to_glsl(builtin, StorageClassInput); + bi_arg += string(" [[") + builtin_qualifier(builtin) + string("]]"); builtin_declaration = false; return bi_arg; @@ -14700,7 +16504,7 @@ uint32_t CompilerMSL::get_declared_type_array_stride_msl(const SPIRType &type, b for (uint32_t dim = 0; dim < dimensions; dim++) { uint32_t array_size = to_array_size_literal(type, dim); - value_size *= max(array_size, 1u); + value_size *= max(array_size, 1u); } return value_size; @@ -14777,6 +16581,25 @@ uint32_t CompilerMSL::get_declared_struct_size_msl(const SPIRType &struct_type, // Returns the byte size of a struct member. uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_packed, bool row_major) const { + // Pointers take 8 bytes each + if (type.pointer && type.storage == StorageClassPhysicalStorageBuffer) + { + uint32_t type_size = 8 * (type.vecsize == 3 ? 4 : type.vecsize); + + // Work our way through potentially layered arrays, + // stopping when we hit a pointer that is not also an array. + int32_t dim_idx = (int32_t)type.array.size() - 1; + auto *p_type = &type; + while (!type_is_pointer(*p_type) && dim_idx >= 0) + { + type_size *= to_array_size_literal(*p_type, dim_idx); + p_type = &get(p_type->parent_type); + dim_idx--; + } + + return type_size; + } + switch (type.basetype) { case SPIRType::Unknown: @@ -14792,7 +16615,7 @@ uint32_t CompilerMSL::get_declared_type_size_msl(const SPIRType &type, bool is_p if (!type.array.empty()) { uint32_t array_size = to_array_size_literal(type); - return get_declared_type_array_stride_msl(type, is_packed, row_major) * max(array_size, 1u); + return get_declared_type_array_stride_msl(type, is_packed, row_major) * max(array_size, 1u); } if (type.basetype == SPIRType::Struct) @@ -14836,6 +16659,10 @@ uint32_t CompilerMSL::get_declared_input_size_msl(const SPIRType &type, uint32_t // Returns the byte alignment of a type. uint32_t CompilerMSL::get_declared_type_alignment_msl(const SPIRType &type, bool is_packed, bool row_major) const { + // Pointers aligns on multiples of 8 bytes + if (type.pointer && type.storage == StorageClassPhysicalStorageBuffer) + return 8 * (type.vecsize == 3 ? 4 : type.vecsize); + switch (type.basetype) { case SPIRType::Unknown: @@ -14983,17 +16810,23 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui suppress_missing_prototypes = true; break; + case OpDemoteToHelperInvocationEXT: + uses_discard = true; + break; + // Emulate texture2D atomic operations case OpImageTexelPointer: { - auto *var = compiler.maybe_get_backing_variable(args[2]); - image_pointers[args[1]] = var ? var->self : ID(0); + if (!compiler.msl_options.supports_msl_version(3, 1)) + { + auto *var = compiler.maybe_get_backing_variable(args[2]); + image_pointers_emulated[args[1]] = var ? var->self : ID(0); + } break; } case OpImageWrite: - if (!compiler.msl_options.supports_msl_version(2, 2)) - uses_resource_write = true; + uses_image_write = true; break; case OpStore: @@ -15007,6 +16840,7 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui case OpAtomicIIncrement: case OpAtomicIDecrement: case OpAtomicIAdd: + case OpAtomicFAddEXT: case OpAtomicISub: case OpAtomicSMin: case OpAtomicUMin: @@ -15017,34 +16851,38 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui case OpAtomicXor: { uses_atomics = true; - auto it = image_pointers.find(args[2]); - if (it != image_pointers.end()) + auto it = image_pointers_emulated.find(args[2]); + if (it != image_pointers_emulated.end()) { - compiler.atomic_image_vars.insert(it->second); + uses_image_write = true; + compiler.atomic_image_vars_emulated.insert(it->second); } - check_resource_write(args[2]); + else + check_resource_write(args[2]); break; } case OpAtomicStore: { uses_atomics = true; - auto it = image_pointers.find(args[0]); - if (it != image_pointers.end()) + auto it = image_pointers_emulated.find(args[0]); + if (it != image_pointers_emulated.end()) { - compiler.atomic_image_vars.insert(it->second); + compiler.atomic_image_vars_emulated.insert(it->second); + uses_image_write = true; } - check_resource_write(args[0]); + else + check_resource_write(args[0]); break; } case OpAtomicLoad: { uses_atomics = true; - auto it = image_pointers.find(args[2]); - if (it != image_pointers.end()) + auto it = image_pointers_emulated.find(args[2]); + if (it != image_pointers_emulated.end()) { - compiler.atomic_image_vars.insert(it->second); + compiler.atomic_image_vars_emulated.insert(it->second); } break; } @@ -15068,8 +16906,11 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui case OpArrayLength: { auto *var = compiler.maybe_get_backing_variable(args[2]); - if (var) - compiler.buffers_requiring_array_length.insert(var->self); + if (var != nullptr) + { + if (!compiler.is_var_runtime_size_array(*var)) + compiler.buffers_requiring_array_length.insert(var->self); + } break; } @@ -15137,6 +16978,11 @@ bool CompilerMSL::OpCodePreprocessor::handle(Op opcode, const uint32_t *args, ui break; } + case OpIsHelperInvocationEXT: + if (compiler.needs_manual_helper_invocation_updates()) + needs_helper_invocation = true; + break; + default: break; } @@ -15154,9 +17000,8 @@ void CompilerMSL::OpCodePreprocessor::check_resource_write(uint32_t var_id) { auto *p_var = compiler.maybe_get_backing_variable(var_id); StorageClass sc = p_var ? p_var->storage : StorageClassMax; - if (!compiler.msl_options.supports_msl_version(2, 1) && - (sc == StorageClassUniform || sc == StorageClassStorageBuffer)) - uses_resource_write = true; + if (sc == StorageClassUniform || sc == StorageClassStorageBuffer) + uses_buffer_write = true; } // Returns an enumeration of a SPIR-V function that needs to be output for certain Op codes. @@ -15204,6 +17049,7 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o case OpAtomicIIncrement: case OpAtomicIDecrement: case OpAtomicIAdd: + case OpAtomicFAddEXT: case OpAtomicISub: case OpAtomicSMin: case OpAtomicUMin: @@ -15215,8 +17061,8 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o case OpAtomicLoad: case OpAtomicStore: { - auto it = image_pointers.find(args[opcode == OpAtomicStore ? 0 : 2]); - if (it != image_pointers.end()) + auto it = image_pointers_emulated.find(args[opcode == OpAtomicStore ? 0 : 2]); + if (it != image_pointers_emulated.end()) { uint32_t tid = compiler.get(it->second).basetype; if (tid && compiler.get(tid).image.dim == Dim2D) @@ -15301,12 +17147,15 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o } case OpGroupNonUniformBroadcast: + case OpSubgroupReadInvocationKHR: return SPVFuncImplSubgroupBroadcast; case OpGroupNonUniformBroadcastFirst: + case OpSubgroupFirstInvocationKHR: return SPVFuncImplSubgroupBroadcastFirst; case OpGroupNonUniformBallot: + case OpSubgroupBallotKHR: return SPVFuncImplSubgroupBallot; case OpGroupNonUniformInverseBallot: @@ -15323,6 +17172,7 @@ CompilerMSL::SPVFuncImpl CompilerMSL::OpCodePreprocessor::get_spv_func_impl(Op o return SPVFuncImplSubgroupBallotBitCount; case OpGroupNonUniformAllEqual: + case OpSubgroupAllEqualKHR: return SPVFuncImplSubgroupAllEqual; case OpGroupNonUniformShuffle: @@ -15448,17 +17298,65 @@ void CompilerMSL::remap_constexpr_sampler_by_binding(uint32_t desc_set, uint32_t void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) { + bool is_packed = has_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypePacked); + auto *source_expr = maybe_get(source_id); auto *var = maybe_get_backing_variable(source_id); + const SPIRType *var_type = nullptr, *phys_type = nullptr; + + if (uint32_t phys_id = get_extended_decoration(source_id, SPIRVCrossDecorationPhysicalTypeID)) + phys_type = &get(phys_id); + else + phys_type = &expr_type; + if (var) + { source_id = var->self; + var_type = &get_variable_data_type(*var); + } + + bool rewrite_boolean_load = + expr_type.basetype == SPIRType::Boolean && + (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct)); // Type fixups for workgroup variables if they are booleans. - if (var && var->storage == StorageClassWorkgroup && expr_type.basetype == SPIRType::Boolean) - expr = join(type_to_glsl(expr_type), "(", expr, ")"); + if (rewrite_boolean_load) + { + if (is_array(expr_type)) + expr = to_rerolled_array_expression(expr_type, expr, expr_type); + else + expr = join(type_to_glsl(expr_type), "(", expr, ")"); + } - // Only interested in standalone builtin variables. + // Type fixups for workgroup variables if they are matrices. + // Don't do fixup for packed types; those are handled specially. + // FIXME: Maybe use a type like spvStorageMatrix for packed matrices? + if (!msl_options.supports_msl_version(3, 0) && var && + (var->storage == StorageClassWorkgroup || + (var_type->basetype == SPIRType::Struct && + has_extended_decoration(var_type->self, SPIRVCrossDecorationWorkgroupStruct) && !is_packed)) && + expr_type.columns > 1) + { + SPIRType matrix_type = *phys_type; + if (source_expr && source_expr->need_transpose) + swap(matrix_type.vecsize, matrix_type.columns); + matrix_type.array.clear(); + matrix_type.array_size_literal.clear(); + expr = join(type_to_glsl(matrix_type), "(", expr, ")"); + } + + // Only interested in standalone builtin variables in the switch below. if (!has_decoration(source_id, DecorationBuiltIn)) + { + // If the backing variable does not match our expected sign, we can fix it up here. + // See ensure_correct_input_type(). + if (var && var->storage == StorageClassInput) + { + auto &base_type = get(var->basetype); + if (base_type.basetype != SPIRType::Struct && expr_type.basetype != base_type.basetype) + expr = join(type_to_glsl(expr_type), "(", expr, ")"); + } return; + } auto builtin = static_cast(get_decoration(source_id, DecorationBuiltIn)); auto expected_type = expr_type.basetype; @@ -15482,13 +17380,14 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, case BuiltInInstanceIndex: case BuiltInBaseInstance: case BuiltInBaseVertex: + case BuiltInSampleMask: expected_type = SPIRType::UInt; expected_width = 32; break; case BuiltInTessLevelInner: case BuiltInTessLevelOuter: - if (get_execution_model() == ExecutionModelTessellationControl) + if (is_tesc_shader()) { expected_type = SPIRType::Half; expected_width = 16; @@ -15499,9 +17398,17 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, break; } - if (expected_type != expr_type.basetype) + if (is_array(expr_type) && builtin == BuiltInSampleMask) { - if (!expr_type.array.empty() && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) + // Needs special handling. + auto wrap_expr = join(type_to_glsl(expr_type), "({ "); + wrap_expr += join(type_to_glsl(get(expr_type.parent_type)), "(", expr, ")"); + wrap_expr += " })"; + expr = std::move(wrap_expr); + } + else if (expected_type != expr_type.basetype) + { + if (is_array(expr_type) && (builtin == BuiltInTessLevelInner || builtin == BuiltInTessLevelOuter)) { // Triggers when loading TessLevel directly as an array. // Need explicit padding + cast. @@ -15518,7 +17425,7 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, wrap_expr += ", "; } - if (get_execution_mode_bitset().get(ExecutionModeTriangles)) + if (is_tessellating_triangles()) wrap_expr += ", 0.0"; wrap_expr += " })"; @@ -15533,27 +17440,58 @@ void CompilerMSL::cast_from_variable_load(uint32_t source_id, std::string &expr, expr = bitcast_expression(expr_type, expected_type, expr); } } - - if (builtin == BuiltInTessCoord && get_entry_point().flags.get(ExecutionModeQuads) && expr_type.vecsize == 3) - { - // In SPIR-V, this is always a vec3, even for quads. In Metal, though, it's a float2 for quads. - // The code is expecting a float3, so we need to widen this. - expr = join("float3(", expr, ", 0)"); - } } void CompilerMSL::cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) { + bool is_packed = has_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypePacked); + auto *target_expr = maybe_get(target_id); auto *var = maybe_get_backing_variable(target_id); - if (var) - target_id = var->self; + const SPIRType *var_type = nullptr, *phys_type = nullptr; - // Type fixups for workgroup variables if they are booleans. - if (var && var->storage == StorageClassWorkgroup && expr_type.basetype == SPIRType::Boolean) + if (uint32_t phys_id = get_extended_decoration(target_id, SPIRVCrossDecorationPhysicalTypeID)) + phys_type = &get(phys_id); + else + phys_type = &expr_type; + + if (var) { - auto short_type = expr_type; - short_type.basetype = SPIRType::Short; - expr = join(type_to_glsl(short_type), "(", expr, ")"); + target_id = var->self; + var_type = &get_variable_data_type(*var); + } + + bool rewrite_boolean_store = + expr_type.basetype == SPIRType::Boolean && + (var && (var->storage == StorageClassWorkgroup || var_type->basetype == SPIRType::Struct)); + + // Type fixups for workgroup variables or struct members if they are booleans. + if (rewrite_boolean_store) + { + if (is_array(expr_type)) + { + expr = to_rerolled_array_expression(*var_type, expr, expr_type); + } + else + { + auto short_type = expr_type; + short_type.basetype = SPIRType::Short; + expr = join(type_to_glsl(short_type), "(", expr, ")"); + } + } + + // Type fixups for workgroup variables if they are matrices. + // Don't do fixup for packed types; those are handled specially. + // FIXME: Maybe use a type like spvStorageMatrix for packed matrices? + if (!msl_options.supports_msl_version(3, 0) && var && + (var->storage == StorageClassWorkgroup || + (var_type->basetype == SPIRType::Struct && + has_extended_decoration(var_type->self, SPIRVCrossDecorationWorkgroupStruct) && !is_packed)) && + expr_type.columns > 1) + { + SPIRType matrix_type = *phys_type; + if (target_expr && target_expr->need_transpose) + swap(matrix_type.vecsize, matrix_type.columns); + expr = join("spvStorage_", type_to_glsl(matrix_type), "(", expr, ")"); } // Only interested in standalone builtin variables. @@ -15640,13 +17578,14 @@ bool CompilerMSL::descriptor_set_is_argument_buffer(uint32_t desc_set) const bool CompilerMSL::is_supported_argument_buffer_type(const SPIRType &type) const { - // Very specifically, image load-store in argument buffers are disallowed on MSL on iOS. - // But we won't know when the argument buffer is encoded whether this image will have - // a NonWritable decoration. So just use discrete arguments for all storage images - // on iOS. - bool is_storage_image = type.basetype == SPIRType::Image && type.image.sampled == 2; - bool is_supported_type = !msl_options.is_ios() || !is_storage_image; - return !type_is_msl_framebuffer_fetch(type) && is_supported_type; + // iOS Tier 1 argument buffers do not support writable images. + // When the argument buffer is encoded, we don't know whether this image will have a + // NonWritable decoration, so just use discrete arguments for all storage images on iOS. + bool is_supported_type = !(type.basetype == SPIRType::Image && + type.image.sampled == 2 && + msl_options.is_ios() && + msl_options.argument_buffers_tier <= Options::ArgumentBuffersTier::Tier1); + return is_supported_type && !type_is_msl_framebuffer_fetch(type); } void CompilerMSL::analyze_argument_buffers() @@ -15665,6 +17604,7 @@ void CompilerMSL::analyze_argument_buffers() struct Resource { SPIRVariable *var; + SPIRVariable *descriptor_alias; string name; SPIRType::BaseType basetype; uint32_t index; @@ -15704,6 +17644,32 @@ void CompilerMSL::analyze_argument_buffers() } } + // Handle descriptor aliasing as well as we can. + // We can handle aliasing of buffers by casting pointers, but not for typed resources. + // Inline UBOs cannot be handled since it's not a pointer, but inline data. + SPIRVariable *descriptor_alias = nullptr; + if (var.storage == StorageClassUniform || var.storage == StorageClassStorageBuffer) + { + for (auto &resource : resources_in_set[desc_set]) + { + if (get_decoration(resource.var->self, DecorationBinding) == + get_decoration(var_id, DecorationBinding) && + resource.basetype == SPIRType::Struct && type.basetype == SPIRType::Struct && + (resource.var->storage == StorageClassUniform || + resource.var->storage == StorageClassStorageBuffer)) + { + descriptor_alias = resource.var; + // Self-reference marks that we should declare the resource, + // and it's being used as an alias (so we can emit void* instead). + resource.descriptor_alias = resource.var; + // Need to promote interlocked usage so that the primary declaration is correct. + if (interlocked_resources.count(var_id)) + interlocked_resources.insert(resource.var->self); + break; + } + } + } + uint32_t binding = get_decoration(var_id, DecorationBinding); if (type.basetype == SPIRType::SampledImage) { @@ -15717,14 +17683,14 @@ void CompilerMSL::analyze_argument_buffers() { uint32_t image_resource_index = get_metal_resource_index(var, SPIRType::Image, i); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::Image, image_resource_index, i }); + { &var, descriptor_alias, to_name(var_id), SPIRType::Image, image_resource_index, i }); } if (type.image.dim != DimBuffer && !constexpr_sampler) { uint32_t sampler_resource_index = get_metal_resource_index(var, SPIRType::Sampler); resources_in_set[desc_set].push_back( - { &var, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 }); + { &var, descriptor_alias, to_sampler_expression(var_id), SPIRType::Sampler, sampler_resource_index, 0 }); } } else if (inline_uniform_blocks.count(SetBindingPair{ desc_set, binding })) @@ -15736,22 +17702,27 @@ void CompilerMSL::analyze_argument_buffers() // constexpr samplers are not declared as resources. // Inline uniform blocks are always emitted at the end. add_resource_name(var_id); + + uint32_t resource_index = ~0u; + if (!descriptor_alias) + resource_index = get_metal_resource_index(var, type.basetype); + resources_in_set[desc_set].push_back( - { &var, to_name(var_id), type.basetype, get_metal_resource_index(var, type.basetype), 0 }); + { &var, descriptor_alias, to_name(var_id), type.basetype, resource_index, 0 }); // Emulate texture2D atomic operations - if (atomic_image_vars.count(var.self)) + if (atomic_image_vars_emulated.count(var.self)) { uint32_t buffer_resource_index = get_metal_resource_index(var, SPIRType::AtomicCounter, 0); resources_in_set[desc_set].push_back( - { &var, to_name(var_id) + "_atomic", SPIRType::Struct, buffer_resource_index, 0 }); + { &var, descriptor_alias, to_name(var_id) + "_atomic", SPIRType::Struct, buffer_resource_index, 0 }); } } // Check if this descriptor set needs a swizzle buffer. if (needs_swizzle_buffer_def && is_sampled_image_type(type)) set_needs_swizzle_buffer[desc_set] = true; - else if (buffers_requiring_array_length.count(var_id) != 0) + else if (buffer_requires_array_length(var_id)) { set_needs_buffer_sizes[desc_set] = true; needs_buffer_sizes = true; @@ -15775,6 +17746,7 @@ void CompilerMSL::analyze_argument_buffers() // Create a buffer to hold extra data, including the swizzle constants. SPIRType uint_type_pointer = get_uint_type(); + uint_type_pointer.op = OpTypePointer; uint_type_pointer.pointer = true; uint_type_pointer.pointer_depth++; uint_type_pointer.parent_type = get_uint_type_id(); @@ -15791,7 +17763,7 @@ void CompilerMSL::analyze_argument_buffers() set_decoration(var_id, DecorationDescriptorSet, desc_set); set_decoration(var_id, DecorationBinding, kSwizzleBufferBinding); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); + { &var, nullptr, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); } if (set_needs_buffer_sizes[desc_set]) @@ -15802,7 +17774,7 @@ void CompilerMSL::analyze_argument_buffers() set_decoration(var_id, DecorationDescriptorSet, desc_set); set_decoration(var_id, DecorationBinding, kBufferSizeBufferBinding); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); + { &var, nullptr, to_name(var_id), SPIRType::UInt, get_metal_resource_index(var, SPIRType::UInt), 0 }); } } } @@ -15814,7 +17786,7 @@ void CompilerMSL::analyze_argument_buffers() uint32_t desc_set = get_decoration(var_id, DecorationDescriptorSet); add_resource_name(var_id); resources_in_set[desc_set].push_back( - { &var, to_name(var_id), SPIRType::Struct, get_metal_resource_index(var, SPIRType::Struct), 0 }); + { &var, nullptr, to_name(var_id), SPIRType::Struct, get_metal_resource_index(var, SPIRType::Struct), 0 }); } for (uint32_t desc_set = 0; desc_set < kMaxArgumentBuffers; desc_set++) @@ -15830,7 +17802,7 @@ void CompilerMSL::analyze_argument_buffers() uint32_t ptr_type_id = next_id + 2; argument_buffer_ids[desc_set] = next_id; - auto &buffer_type = set(type_id); + auto &buffer_type = set(type_id, OpTypeStruct); buffer_type.basetype = SPIRType::Struct; @@ -15847,8 +17819,9 @@ void CompilerMSL::analyze_argument_buffers() set_name(type_id, join("spvDescriptorSetBuffer", desc_set)); - auto &ptr_type = set(ptr_type_id); + auto &ptr_type = set(ptr_type_id, OpTypePointer); ptr_type = buffer_type; + ptr_type.op = spv::OpTypePointer; ptr_type.pointer = true; ptr_type.pointer_depth++; ptr_type.parent_type = type_id; @@ -15858,7 +17831,7 @@ void CompilerMSL::analyze_argument_buffers() set_name(buffer_variable_id, join("spvDescriptorSet", desc_set)); // Ids must be emitted in ID order. - sort(begin(resources), end(resources), [&](const Resource &lhs, const Resource &rhs) -> bool { + stable_sort(begin(resources), end(resources), [&](const Resource &lhs, const Resource &rhs) -> bool { return tie(lhs.index, lhs.basetype) < tie(rhs.index, rhs.basetype); }); @@ -15873,51 +17846,51 @@ void CompilerMSL::analyze_argument_buffers() // member_index and next_arg_buff_index are incremented when padding members are added. if (msl_options.pad_argument_buffer_resources) { - while (resource.index > next_arg_buff_index) + auto &rez_bind = get_argument_buffer_resource(desc_set, next_arg_buff_index); + if (!resource.descriptor_alias) { - auto &rez_bind = get_argument_buffer_resource(desc_set, next_arg_buff_index); - switch (rez_bind.basetype) + while (resource.index > next_arg_buff_index) { - case SPIRType::Void: - case SPIRType::Boolean: - case SPIRType::SByte: - case SPIRType::UByte: - case SPIRType::Short: - case SPIRType::UShort: - case SPIRType::Int: - case SPIRType::UInt: - case SPIRType::Int64: - case SPIRType::UInt64: - case SPIRType::AtomicCounter: - case SPIRType::Half: - case SPIRType::Float: - case SPIRType::Double: - add_argument_buffer_padding_buffer_type(buffer_type, member_index, next_arg_buff_index, rez_bind); - break; - case SPIRType::Image: - add_argument_buffer_padding_image_type(buffer_type, member_index, next_arg_buff_index, rez_bind); - break; - case SPIRType::Sampler: - add_argument_buffer_padding_sampler_type(buffer_type, member_index, next_arg_buff_index, rez_bind); - break; - case SPIRType::SampledImage: - if (next_arg_buff_index == rez_bind.msl_sampler) - add_argument_buffer_padding_sampler_type(buffer_type, member_index, next_arg_buff_index, rez_bind); - else + switch (rez_bind.basetype) + { + case SPIRType::Void: + case SPIRType::Boolean: + case SPIRType::SByte: + case SPIRType::UByte: + case SPIRType::Short: + case SPIRType::UShort: + case SPIRType::Int: + case SPIRType::UInt: + case SPIRType::Int64: + case SPIRType::UInt64: + case SPIRType::AtomicCounter: + case SPIRType::Half: + case SPIRType::Float: + case SPIRType::Double: + add_argument_buffer_padding_buffer_type(buffer_type, member_index, next_arg_buff_index, rez_bind); + break; + case SPIRType::Image: add_argument_buffer_padding_image_type(buffer_type, member_index, next_arg_buff_index, rez_bind); - break; - default: - break; + break; + case SPIRType::Sampler: + add_argument_buffer_padding_sampler_type(buffer_type, member_index, next_arg_buff_index, rez_bind); + break; + case SPIRType::SampledImage: + if (next_arg_buff_index == rez_bind.msl_sampler) + add_argument_buffer_padding_sampler_type(buffer_type, member_index, next_arg_buff_index, rez_bind); + else + add_argument_buffer_padding_image_type(buffer_type, member_index, next_arg_buff_index, rez_bind); + break; + default: + break; + } } } // Adjust the number of slots consumed by current member itself. - // If actual member is an array, allow runtime array resolution as well. - uint32_t elem_cnt = type.array.empty() ? 1 : to_array_size_literal(type); - if (elem_cnt == 0) - elem_cnt = get_resource_array_size(var.self); - - next_arg_buff_index += elem_cnt; + // Use the count value from the app, instead of the shader, in case the + // shader is only accesing part, or even one element, of the array. + next_arg_buff_index += rez_bind.count; } string mbr_name = ensure_valid_name(resource.name, "m"); @@ -15931,14 +17904,14 @@ void CompilerMSL::analyze_argument_buffers() bool type_is_array = !type.array.empty(); uint32_t sampler_type_id = ir.increase_bound_by(type_is_array ? 2 : 1); - auto &new_sampler_type = set(sampler_type_id); + auto &new_sampler_type = set(sampler_type_id, OpTypeSampler); new_sampler_type.basetype = SPIRType::Sampler; new_sampler_type.storage = StorageClassUniformConstant; if (type_is_array) { uint32_t sampler_type_array_id = sampler_type_id + 1; - auto &sampler_type_array = set(sampler_type_array_id); + auto &sampler_type_array = set(sampler_type_array_id, OpTypeArray); sampler_type_array = new_sampler_type; sampler_type_array.array = type.array; sampler_type_array.array_size_literal = type.array_size_literal; @@ -15963,17 +17936,23 @@ void CompilerMSL::analyze_argument_buffers() } else if (buffers_requiring_dynamic_offset.count(pair)) { + if (resource.descriptor_alias) + SPIRV_CROSS_THROW("Descriptor aliasing is currently not supported with dynamic offsets."); + // Don't set the qualified name here; we'll define a variable holding the corrected buffer address later. buffer_type.member_types.push_back(var.basetype); buffers_requiring_dynamic_offset[pair].second = var.self; } else if (inline_uniform_blocks.count(pair)) { + if (resource.descriptor_alias) + SPIRV_CROSS_THROW("Descriptor aliasing is currently not supported with inline UBOs."); + // Put the buffer block itself into the argument buffer. buffer_type.member_types.push_back(get_variable_data_type_id(var)); set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name)); } - else if (atomic_image_vars.count(var.self)) + else if (atomic_image_vars_emulated.count(var.self)) { // Emulate texture2D atomic operations. // Don't set the qualified name: it's already set for this variable, @@ -15983,12 +17962,13 @@ void CompilerMSL::analyze_argument_buffers() uint32_t atomic_type_id = offset; uint32_t type_ptr_id = offset + 1; - SPIRType atomic_type; + SPIRType atomic_type { OpTypeInt }; atomic_type.basetype = SPIRType::AtomicCounter; atomic_type.width = 32; atomic_type.vecsize = 1; set(atomic_type_id, atomic_type); + atomic_type.op = OpTypePointer; atomic_type.pointer = true; atomic_type.pointer_depth++; atomic_type.parent_type = atomic_type_id; @@ -16000,9 +17980,12 @@ void CompilerMSL::analyze_argument_buffers() } else { - // Resources will be declared as pointers not references, so automatically dereference as appropriate. - buffer_type.member_types.push_back(var.basetype); - if (type.array.empty()) + if (!resource.descriptor_alias || resource.descriptor_alias == resource.var) + buffer_type.member_types.push_back(var.basetype); + + if (resource.descriptor_alias && resource.descriptor_alias != resource.var) + buffer_aliases_argument.push_back({ var.self, resource.descriptor_alias->self }); + else if (type.array.empty()) set_qualified_name(var.self, join("(*", to_name(buffer_variable_id), ".", mbr_name, ")")); else set_qualified_name(var.self, join(to_name(buffer_variable_id), ".", mbr_name)); @@ -16046,13 +18029,14 @@ void CompilerMSL::add_argument_buffer_padding_buffer_type(SPIRType &struct_type, if (!argument_buffer_padding_buffer_type_id) { uint32_t buff_type_id = ir.increase_bound_by(2); - auto &buff_type = set(buff_type_id); + auto &buff_type = set(buff_type_id, OpNop); buff_type.basetype = rez_bind.basetype; buff_type.storage = StorageClassUniformConstant; uint32_t ptr_type_id = buff_type_id + 1; - auto &ptr_type = set(ptr_type_id); + auto &ptr_type = set(ptr_type_id, OpTypePointer); ptr_type = buff_type; + ptr_type.op = spv::OpTypePointer; ptr_type.pointer = true; ptr_type.pointer_depth++; ptr_type.parent_type = buff_type_id; @@ -16060,8 +18044,7 @@ void CompilerMSL::add_argument_buffer_padding_buffer_type(SPIRType &struct_type, argument_buffer_padding_buffer_type_id = ptr_type_id; } - for (uint32_t rez_idx = 0; rez_idx < rez_bind.count; rez_idx++) - add_argument_buffer_padding_type(argument_buffer_padding_buffer_type_id, struct_type, mbr_idx, arg_buff_index, 1); + add_argument_buffer_padding_type(argument_buffer_padding_buffer_type_id, struct_type, mbr_idx, arg_buff_index, rez_bind.count); } // Adds an argument buffer padding argument image type as a member of the struct type at the member index. @@ -16071,12 +18054,12 @@ void CompilerMSL::add_argument_buffer_padding_image_type(SPIRType &struct_type, if (!argument_buffer_padding_image_type_id) { uint32_t base_type_id = ir.increase_bound_by(2); - auto &base_type = set(base_type_id); + auto &base_type = set(base_type_id, OpTypeFloat); base_type.basetype = SPIRType::Float; base_type.width = 32; uint32_t img_type_id = base_type_id + 1; - auto &img_type = set(img_type_id); + auto &img_type = set(img_type_id, OpTypeImage); img_type.basetype = SPIRType::Image; img_type.storage = StorageClassUniformConstant; @@ -16102,7 +18085,7 @@ void CompilerMSL::add_argument_buffer_padding_sampler_type(SPIRType &struct_type if (!argument_buffer_padding_sampler_type_id) { uint32_t samp_type_id = ir.increase_bound_by(1); - auto &samp_type = set(samp_type_id); + auto &samp_type = set(samp_type_id, OpTypeSampler); samp_type.basetype = SPIRType::Sampler; samp_type.storage = StorageClassUniformConstant; @@ -16121,8 +18104,8 @@ void CompilerMSL::add_argument_buffer_padding_type(uint32_t mbr_type_id, SPIRTyp if (count > 1) { uint32_t ary_type_id = ir.increase_bound_by(1); - auto &ary_type = set(ary_type_id); - ary_type = get(type_id); + auto &ary_type = set(ary_type_id, get(type_id)); + ary_type.op = OpTypeArray; ary_type.array.push_back(count); ary_type.array_size_literal.push_back(true); ary_type.parent_type = type_id; @@ -16146,7 +18129,7 @@ void CompilerMSL::activate_argument_buffer_resources() uint32_t desc_set = get_decoration(self, DecorationDescriptorSet); if (descriptor_set_is_argument_buffer(desc_set)) - active_interface_variables.insert(self); + add_active_interface_variable(self); }); } @@ -16172,6 +18155,20 @@ void CompilerMSL::emit_block_hints(const SPIRBlock &) string CompilerMSL::additional_fixed_sample_mask_str() const { char print_buffer[32]; +#ifdef _MSC_VER + // snprintf does not exist or is buggy on older MSVC versions, some of + // them being used by MinGW. Use sprintf instead and disable + // corresponding warning. +#pragma warning(push) +#pragma warning(disable : 4996) +#endif +#if _WIN32 sprintf(print_buffer, "0x%x", msl_options.additional_fixed_sample_mask); +#else + snprintf(print_buffer, sizeof(print_buffer), "0x%x", msl_options.additional_fixed_sample_mask); +#endif +#ifdef _MSC_VER +#pragma warning(pop) +#endif return print_buffer; } diff --git a/src/libraries/spirv_cross/spirv_msl.hpp b/src/libraries/spirv_cross/spirv_msl.hpp index f01cceaf7..45109d88f 100644 --- a/src/libraries/spirv_cross/spirv_msl.hpp +++ b/src/libraries/spirv_cross/spirv_msl.hpp @@ -34,36 +34,53 @@ namespace SPIRV_CROSS_NAMESPACE { -// Indicates the format of a shader input. Currently limited to specifying +// Indicates the format of a shader interface variable. Currently limited to specifying // if the input is an 8-bit unsigned integer, 16-bit unsigned integer, or // some other format. -enum MSLShaderInputFormat +enum MSLShaderVariableFormat { - MSL_SHADER_INPUT_FORMAT_OTHER = 0, - MSL_SHADER_INPUT_FORMAT_UINT8 = 1, - MSL_SHADER_INPUT_FORMAT_UINT16 = 2, - MSL_SHADER_INPUT_FORMAT_ANY16 = 3, - MSL_SHADER_INPUT_FORMAT_ANY32 = 4, + MSL_SHADER_VARIABLE_FORMAT_OTHER = 0, + MSL_SHADER_VARIABLE_FORMAT_UINT8 = 1, + MSL_SHADER_VARIABLE_FORMAT_UINT16 = 2, + MSL_SHADER_VARIABLE_FORMAT_ANY16 = 3, + MSL_SHADER_VARIABLE_FORMAT_ANY32 = 4, // Deprecated aliases. - MSL_VERTEX_FORMAT_OTHER = MSL_SHADER_INPUT_FORMAT_OTHER, - MSL_VERTEX_FORMAT_UINT8 = MSL_SHADER_INPUT_FORMAT_UINT8, - MSL_VERTEX_FORMAT_UINT16 = MSL_SHADER_INPUT_FORMAT_UINT16, + MSL_VERTEX_FORMAT_OTHER = MSL_SHADER_VARIABLE_FORMAT_OTHER, + MSL_VERTEX_FORMAT_UINT8 = MSL_SHADER_VARIABLE_FORMAT_UINT8, + MSL_VERTEX_FORMAT_UINT16 = MSL_SHADER_VARIABLE_FORMAT_UINT16, + MSL_SHADER_INPUT_FORMAT_OTHER = MSL_SHADER_VARIABLE_FORMAT_OTHER, + MSL_SHADER_INPUT_FORMAT_UINT8 = MSL_SHADER_VARIABLE_FORMAT_UINT8, + MSL_SHADER_INPUT_FORMAT_UINT16 = MSL_SHADER_VARIABLE_FORMAT_UINT16, + MSL_SHADER_INPUT_FORMAT_ANY16 = MSL_SHADER_VARIABLE_FORMAT_ANY16, + MSL_SHADER_INPUT_FORMAT_ANY32 = MSL_SHADER_VARIABLE_FORMAT_ANY32, - MSL_SHADER_INPUT_FORMAT_INT_MAX = 0x7fffffff + MSL_SHADER_VARIABLE_FORMAT_INT_MAX = 0x7fffffff }; -// Defines MSL characteristics of an input variable at a particular location. +// Indicates the rate at which a variable changes value, one of: per-vertex, +// per-primitive, or per-patch. +enum MSLShaderVariableRate +{ + MSL_SHADER_VARIABLE_RATE_PER_VERTEX = 0, + MSL_SHADER_VARIABLE_RATE_PER_PRIMITIVE = 1, + MSL_SHADER_VARIABLE_RATE_PER_PATCH = 2, + + MSL_SHADER_VARIABLE_RATE_INT_MAX = 0x7fffffff, +}; + +// Defines MSL characteristics of a shader interface variable at a particular location. // After compilation, it is possible to query whether or not this location was used. // If vecsize is nonzero, it must be greater than or equal to the vecsize declared in the shader, // or behavior is undefined. -struct MSLShaderInput +struct MSLShaderInterfaceVariable { uint32_t location = 0; uint32_t component = 0; - MSLShaderInputFormat format = MSL_SHADER_INPUT_FORMAT_OTHER; + MSLShaderVariableFormat format = MSL_SHADER_VARIABLE_FORMAT_OTHER; spv::BuiltIn builtin = spv::BuiltInMax; uint32_t vecsize = 0; + MSLShaderVariableRate rate = MSL_SHADER_VARIABLE_RATE_PER_VERTEX; }; // Matches the binding index of a MSL resource for a binding within a descriptor set. @@ -301,6 +318,7 @@ public: uint32_t dynamic_offsets_buffer_index = 23; uint32_t shader_input_buffer_index = 22; uint32_t shader_index_buffer_index = 21; + uint32_t shader_patch_input_buffer_index = 20; uint32_t shader_input_wg_index = 0; uint32_t device_index = 0; uint32_t enable_frag_output_mask = 0xffffffff; @@ -321,10 +339,28 @@ public: bool dispatch_base = false; bool texture_1D_as_2D = false; - // Enable use of MSL 2.0 indirect argument buffers. + // Enable use of Metal argument buffers. // MSL 2.0 must also be enabled. bool argument_buffers = false; + // Defines Metal argument buffer tier levels. + // Uses same values as Metal MTLArgumentBuffersTier enumeration. + enum class ArgumentBuffersTier + { + Tier1 = 0, + Tier2 = 1, + }; + + // When using Metal argument buffers, indicates the Metal argument buffer tier level supported by the Metal platform. + // Ignored when Options::argument_buffers is disabled. + // - Tier1 supports writable images on macOS, but not on iOS. + // - Tier2 supports writable images on macOS and iOS, and higher resource count limits. + // Tier capabilities based on recommendations from Apple engineering. + ArgumentBuffersTier argument_buffers_tier = ArgumentBuffersTier::Tier1; + + // Enables specifick argument buffer format with extra information to track SSBO-length + bool runtime_array_rich_descriptor = false; + // Ensures vertex and instance indices start at zero. This reflects the behavior of HLSL with SV_VertexID and SV_InstanceID. bool enable_base_index_zero = false; @@ -382,6 +418,11 @@ public: // builtins are processed, but should result in more efficient usage of the GPU. bool multi_patch_workgroup = false; + // Use storage buffers instead of vertex-style attributes for tessellation evaluation + // input. This may require conversion of inputs in the generated post-tessellation + // vertex shader, but allows the use of nested arrays. + bool raw_buffer_tese_input = false; + // If set, a vertex shader will be compiled as part of a tessellation pipeline. // It will be translated as a compute kernel, so it can use the global invocation ID // to index the output buffer. @@ -393,7 +434,7 @@ public: // and will be addressed using the current ViewIndex. bool arrayed_subpass_input = false; - // Whether to use SIMD-group or quadgroup functions to implement group nnon-uniform + // Whether to use SIMD-group or quadgroup functions to implement group non-uniform // operations. Some GPUs on iOS do not support the SIMD-group functions, only the // quadgroup functions. bool ios_use_simdgroup_functions = false; @@ -435,6 +476,49 @@ public: // the extra threads away. bool force_sample_rate_shading = false; + // If set, gl_HelperInvocation will be set manually whenever a fragment is discarded. + // Some Metal devices have a bug where simd_is_helper_thread() does not return true + // after a fragment has been discarded. This is a workaround that is only expected to be needed + // until the bug is fixed in Metal; it is provided as an option to allow disabling it when that occurs. + bool manual_helper_invocation_updates = true; + + // If set, extra checks will be emitted in fragment shaders to prevent writes + // from discarded fragments. Some Metal devices have a bug where writes to storage resources + // from discarded fragment threads continue to occur, despite the fragment being + // discarded. This is a workaround that is only expected to be needed until the + // bug is fixed in Metal; it is provided as an option so it can be enabled + // only when the bug is present. + bool check_discarded_frag_stores = false; + + // If set, Lod operands to OpImageSample*DrefExplicitLod for 1D and 2D array images + // will be implemented using a gradient instead of passing the level operand directly. + // Some Metal devices have a bug where the level() argument to depth2d_array::sample_compare() + // in a fragment shader is biased by some unknown amount, possibly dependent on the + // partial derivatives of the texture coordinates. This is a workaround that is only + // expected to be needed until the bug is fixed in Metal; it is provided as an option + // so it can be enabled only when the bug is present. + bool sample_dref_lod_array_as_grad = false; + + // MSL doesn't guarantee coherence between writes and subsequent reads of read_write textures. + // This inserts fences before each read of a read_write texture to ensure coherency. + // If you're sure you never rely on this, you can set this to false for a possible performance improvement. + // Note: Only Apple's GPU compiler takes advantage of the lack of coherency, so make sure to test on Apple GPUs if you disable this. + bool readwrite_texture_fences = true; + + // Metal 3.1 introduced a Metal regression bug which causes infinite recursion during + // Metal's analysis of an entry point input structure that is itself recursive. Enabling + // this option will replace the recursive input declaration with a alternate variable of + // type void*, and then cast to the correct type at the top of the entry point function. + // The bug has been reported to Apple, and will hopefully be fixed in future releases. + bool replace_recursive_inputs = false; + + // If set, manual fixups of gradient vectors for cube texture lookups will be performed. + // All released Apple Silicon GPUs to date behave incorrectly when sampling a cube texture + // with explicit gradients. They will ignore one of the three partial derivatives based + // on the selected major axis, and expect the remaining derivatives to be partially + // transformed. + bool agx_manual_cube_grad_fixup = false; + bool is_ios() const { return platform == iOS; @@ -445,6 +529,11 @@ public: return platform == macOS; } + bool use_quadgroup_operation() const + { + return is_ios() && !ios_use_simdgroup_functions; + } + void set_msl_version(uint32_t major, uint32_t minor = 0, uint32_t patch = 0) { msl_version = make_msl_version(major, minor, patch); @@ -494,6 +583,11 @@ public: return !buffers_requiring_array_length.empty(); } + bool buffer_requires_array_length(VariableID id) const + { + return buffers_requiring_array_length.count(id) != 0; + } + // Provide feedback to calling API to allow it to pass a buffer // containing the view mask for the current multiview subpass. bool needs_view_mask_buffer() const @@ -534,10 +628,15 @@ public: explicit CompilerMSL(const ParsedIR &ir); explicit CompilerMSL(ParsedIR &&ir); - // input is a shader input description used to fix up shader input variables. + // input is a shader interface variable description used to fix up shader input variables. // If shader inputs are provided, is_msl_shader_input_used() will return true after - // calling ::compile() if the location was used by the MSL code. - void add_msl_shader_input(const MSLShaderInput &input); + // calling ::compile() if the location were used by the MSL code. + void add_msl_shader_input(const MSLShaderInterfaceVariable &input); + + // output is a shader interface variable description used to fix up shader output variables. + // If shader outputs are provided, is_msl_shader_output_used() will return true after + // calling ::compile() if the location were used by the MSL code. + void add_msl_shader_output(const MSLShaderInterfaceVariable &output); // resource is a resource binding to indicate the MSL buffer, // texture or sampler index to use for a particular SPIR-V description set @@ -572,6 +671,9 @@ public: // Query after compilation is done. This allows you to check if an input location was used by the shader. bool is_msl_shader_input_used(uint32_t location); + // Query after compilation is done. This allows you to check if an output location were used by the shader. + bool is_msl_shader_output_used(uint32_t location); + // If not using add_msl_shader_input, it's possible // that certain builtin attributes need to be automatically assigned locations. // This is typical for tessellation builtin inputs such as tess levels, gl_Position, etc. @@ -579,6 +681,13 @@ public: // add_msl_shader_input or the builtin is not used, otherwise returns N in [[attribute(N)]]. uint32_t get_automatic_builtin_input_location(spv::BuiltIn builtin) const; + // If not using add_msl_shader_output, it's possible + // that certain builtin attributes need to be automatically assigned locations. + // This is typical for tessellation builtin outputs such as tess levels, gl_Position, etc. + // This returns k_unknown_location if the location were explicitly assigned with + // add_msl_shader_output or the builtin were not used, otherwise returns N in [[attribute(N)]]. + uint32_t get_automatic_builtin_output_location(spv::BuiltIn builtin) const; + // NOTE: Only resources which are remapped using add_msl_resource_binding will be reported here. // Constexpr samplers are always assumed to be emitted. // No specific MSLResourceBinding remapping is required for constexpr samplers as long as they are remapped @@ -633,7 +742,7 @@ public: protected: // An enum of SPIR-V functions that are implemented in additional // source code that is added to the shader if necessary. - enum SPVFuncImpl + enum SPVFuncImpl : uint8_t { SPVFuncImplNone, SPVFuncImplMod, @@ -654,12 +763,14 @@ protected: SPVFuncImplArrayOfArrayCopy6Dim = SPVFuncImplArrayCopyMultidimBase + 6, SPVFuncImplTexelBufferCoords, SPVFuncImplImage2DAtomicCoords, // Emulate texture2D atomic operations + SPVFuncImplGradientCube, SPVFuncImplFMul, SPVFuncImplFAdd, SPVFuncImplFSub, SPVFuncImplQuantizeToF16, SPVFuncImplCubemapTo2DArrayFace, SPVFuncImplUnsafeArray, // Allow Metal to use the array template to make arrays a value type + SPVFuncImplStorageMatrix, // Allow threadgroup construction of matrices SPVFuncImplInverse4x4, SPVFuncImplInverse3x3, SPVFuncImplInverse2x2, @@ -708,11 +819,18 @@ protected: SPVFuncImplConvertYCbCrBT601, SPVFuncImplConvertYCbCrBT2020, SPVFuncImplDynamicImageSampler, + SPVFuncImplRayQueryIntersectionParams, + SPVFuncImplVariableDescriptor, + SPVFuncImplVariableSizedDescriptor, + SPVFuncImplVariableDescriptorArray, + SPVFuncImplPaddedStd140 }; // If the underlying resource has been used for comparison then duplicate loads of that resource must be too // Use Metal's native frame-buffer fetch API for subpass inputs. void emit_texture_op(const Instruction &i, bool sparse) override; + void emit_binary_ptr_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); + std::string to_ptr_expression(uint32_t id, bool register_expression_read = true); void emit_binary_unord_op(uint32_t result_type, uint32_t result_id, uint32_t op0, uint32_t op1, const char *op); void emit_instruction(const Instruction &instr) override; void emit_glsl_op(uint32_t result_type, uint32_t result_id, uint32_t op, const uint32_t *args, @@ -731,6 +849,7 @@ protected: void emit_struct_member(const SPIRType &type, uint32_t member_type_id, uint32_t index, const std::string &qualifier = "", uint32_t base_offset = 0) override; void emit_struct_padding_target(const SPIRType &type) override; + std::string type_to_glsl(const SPIRType &type, uint32_t id, bool member); std::string type_to_glsl(const SPIRType &type, uint32_t id = 0) override; void emit_block_hints(const SPIRBlock &block) override; @@ -738,9 +857,6 @@ protected: std::string type_to_array_glsl(const SPIRType &type) override; std::string constant_op_expression(const SPIRConstantOp &cop) override; - // Threadgroup arrays can't have a wrapper type - std::string variable_decl(const SPIRVariable &variable) override; - bool variable_decl_is_remapped_storage(const SPIRVariable &variable, spv::StorageClass storage) const override; // GCC workaround of lambdas calling protected functions (for older GCC versions) @@ -765,10 +881,9 @@ protected: std::string bitcast_glsl_op(const SPIRType &result_type, const SPIRType &argument_type) override; bool emit_complex_bitcast(uint32_t result_id, uint32_t id, uint32_t op0) override; bool skip_argument(uint32_t id) const override; - std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain) override; + std::string to_member_reference(uint32_t base, const SPIRType &type, uint32_t index, bool ptr_chain_is_resolved) override; std::string to_qualifiers_glsl(uint32_t id) override; void replace_illegal_names() override; - void declare_undefined_values() override; void declare_constant_arrays(); void replace_illegal_entry_point_names(); @@ -784,13 +899,17 @@ protected: bool is_non_native_row_major_matrix(uint32_t id) override; bool member_is_non_native_row_major_matrix(const SPIRType &type, uint32_t index) override; std::string convert_row_major_matrix(std::string exp_str, const SPIRType &exp_type, uint32_t physical_type_id, - bool is_packed) override; + bool is_packed, bool relaxed) override; + + bool is_tesc_shader() const; + bool is_tese_shader() const; void preprocess_op_codes(); void localize_global_variables(); void extract_global_variables_from_functions(); void mark_packable_structs(); void mark_as_packable(SPIRType &type); + void mark_as_workgroup_struct(SPIRType &type); std::unordered_map> function_global_vars; void extract_global_variables_from_function(uint32_t func_id, std::set &added_arg_ids, @@ -826,13 +945,22 @@ protected: bool add_component_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, SPIRVariable &var, const SPIRType &type, InterfaceBlockMeta &meta); - void add_plain_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, uint32_t index, - InterfaceBlockMeta &meta); - void add_composite_member_variable_to_interface_block(spv::StorageClass storage, const std::string &ib_var_ref, - SPIRType &ib_type, SPIRVariable &var, uint32_t index, - InterfaceBlockMeta &meta); + void add_plain_member_variable_to_interface_block(spv::StorageClass storage, + const std::string &ib_var_ref, SPIRType &ib_type, + SPIRVariable &var, SPIRType &var_type, + uint32_t mbr_idx, InterfaceBlockMeta &meta, + const std::string &mbr_name_qual, + const std::string &var_chain_qual, + uint32_t &location, uint32_t &var_mbr_idx); + void add_composite_member_variable_to_interface_block(spv::StorageClass storage, + const std::string &ib_var_ref, SPIRType &ib_type, + SPIRVariable &var, SPIRType &var_type, + uint32_t mbr_idx, InterfaceBlockMeta &meta, + const std::string &mbr_name_qual, + const std::string &var_chain_qual, + uint32_t &location, uint32_t &var_mbr_idx); void add_tess_level_input_to_interface_block(const std::string &ib_var_ref, SPIRType &ib_type, SPIRVariable &var); + void add_tess_level_input(const std::string &base_ref, const std::string &mbr_name, SPIRVariable &var); void fix_up_interface_member_indices(spv::StorageClass storage, uint32_t ib_type_id); @@ -848,7 +976,8 @@ protected: void emit_specialization_constants_and_structs(); void emit_interface_block(uint32_t ib_var_id); bool maybe_emit_array_assignment(uint32_t id_lhs, uint32_t id_rhs); - uint32_t get_resource_array_size(uint32_t id) const; + bool is_var_runtime_size_array(const SPIRVariable &var) const; + uint32_t get_resource_array_size(const SPIRType &type, uint32_t id) const; void fix_up_shader_inputs_outputs(); @@ -858,7 +987,7 @@ protected: std::string entry_point_arg_stage_in(); void entry_point_args_builtin(std::string &args); void entry_point_args_discrete_descriptors(std::string &args); - std::string to_qualified_member_name(const SPIRType &type, uint32_t index); + std::string append_member_name(const std::string &qualifier, const SPIRType &type, uint32_t index); std::string ensure_valid_name(std::string name, std::string pfx); std::string to_sampler_expression(uint32_t id); std::string to_swizzle_expression(uint32_t id); @@ -872,11 +1001,14 @@ protected: std::string member_attribute_qualifier(const SPIRType &type, uint32_t index); std::string member_location_attribute_qualifier(const SPIRType &type, uint32_t index); std::string argument_decl(const SPIRFunction::Parameter &arg); + const char *descriptor_address_space(uint32_t id, spv::StorageClass storage, const char *plain_address_space) const; std::string round_fp_tex_coords(std::string tex_coords, bool coord_is_fp); uint32_t get_metal_resource_index(SPIRVariable &var, SPIRType::BaseType basetype, uint32_t plane = 0); uint32_t get_member_location(uint32_t type_id, uint32_t index, uint32_t *comp = nullptr) const; uint32_t get_or_allocate_builtin_input_member_location(spv::BuiltIn builtin, uint32_t type_id, uint32_t index, uint32_t *comp = nullptr); + uint32_t get_or_allocate_builtin_output_member_location(spv::BuiltIn builtin, + uint32_t type_id, uint32_t index, uint32_t *comp = nullptr); uint32_t get_physical_tess_level_array_size(spv::BuiltIn builtin) const; @@ -912,7 +1044,7 @@ protected: bool validate_member_packing_rules_msl(const SPIRType &type, uint32_t index) const; std::string get_argument_address_space(const SPIRVariable &argument); std::string get_type_address_space(const SPIRType &type, uint32_t id, bool argument = false); - const char *to_restrict(uint32_t id, bool space = true); + const char *to_restrict(uint32_t id, bool space); SPIRType &get_stage_in_struct_type(); SPIRType &get_stage_out_struct_type(); SPIRType &get_patch_stage_in_struct_type(); @@ -920,14 +1052,14 @@ protected: std::string get_tess_factor_struct_name(); SPIRType &get_uint_type(); uint32_t get_uint_type_id(); - void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, uint32_t mem_order_1, - uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0, + void emit_atomic_func_op(uint32_t result_type, uint32_t result_id, const char *op, spv::Op opcode, + uint32_t mem_order_1, uint32_t mem_order_2, bool has_mem_order_2, uint32_t op0, uint32_t op1 = 0, bool op1_is_pointer = false, bool op1_is_literal = false, uint32_t op2 = 0); const char *get_memory_order(uint32_t spv_mem_sem); void add_pragma_line(const std::string &line); void add_typedef_line(const std::string &line); void emit_barrier(uint32_t id_exe_scope, uint32_t id_mem_scope, uint32_t id_mem_sem); - void emit_array_copy(const std::string &lhs, uint32_t lhs_id, uint32_t rhs_id, + bool emit_array_copy(const char *expr, uint32_t lhs_id, uint32_t rhs_id, spv::StorageClass lhs_storage, spv::StorageClass rhs_storage) override; void build_implicit_builtins(); uint32_t build_constant_uint_array_pointer(); @@ -937,6 +1069,7 @@ protected: uint32_t builtin_frag_coord_id = 0; uint32_t builtin_sample_id_id = 0; uint32_t builtin_sample_mask_id = 0; + uint32_t builtin_helper_invocation_id = 0; uint32_t builtin_vertex_idx_id = 0; uint32_t builtin_base_vertex_id = 0; uint32_t builtin_instance_idx_id = 0; @@ -961,6 +1094,7 @@ protected: uint32_t argument_buffer_padding_sampler_type_id = 0; bool does_shader_write_sample_mask = false; + bool frag_shader_needs_discard_checks = false; void cast_to_variable_store(uint32_t target_id, std::string &expr, const SPIRType &expr_type) override; void cast_from_variable_load(uint32_t source_id, std::string &expr, const SPIRType &expr_type) override; @@ -969,9 +1103,11 @@ protected: void analyze_sampled_image_usage(); bool access_chain_needs_stage_io_builtin_translation(uint32_t base) override; - void prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage, + bool prepare_access_chain_for_scalar_access(std::string &expr, const SPIRType &type, spv::StorageClass storage, bool &is_packed) override; void fix_up_interpolant_access_chain(const uint32_t *ops, uint32_t length); + void check_physical_type_cast(std::string &expr, const SPIRType *type, uint32_t physical_type) override; + bool emit_tessellation_access_chain(const uint32_t *ops, uint32_t length); bool emit_tessellation_io_load(uint32_t result_type, uint32_t id, uint32_t ptr); bool is_out_of_bounds_tessellation_level(uint32_t id_lhs); @@ -985,12 +1121,17 @@ protected: Options msl_options; std::set spv_function_implementations; // Must be ordered to ensure declarations are in a specific order. - std::map inputs_by_location; - std::unordered_map inputs_by_builtin; + std::map inputs_by_location; + std::unordered_map inputs_by_builtin; + std::map outputs_by_location; + std::unordered_map outputs_by_builtin; std::unordered_set location_inputs_in_use; std::unordered_set location_inputs_in_use_fallback; + std::unordered_set location_outputs_in_use; + std::unordered_set location_outputs_in_use_fallback; std::unordered_map fragment_output_components; std::unordered_map builtin_to_automatic_input_location; + std::unordered_map builtin_to_automatic_output_location; std::set pragma_lines; std::set typedef_lines; SmallVector vars_needing_early_declaration; @@ -1010,6 +1151,8 @@ protected: VariableID patch_stage_out_var_id = 0; VariableID stage_in_ptr_var_id = 0; VariableID stage_out_ptr_var_id = 0; + VariableID tess_level_inner_var_id = 0; + VariableID tess_level_outer_var_id = 0; VariableID stage_out_masked_builtin_type_id = 0; // Handle HLSL-style 0-based vertex/instance index. @@ -1036,6 +1179,7 @@ protected: bool needs_subgroup_invocation_id = false; bool needs_subgroup_size = false; bool needs_sample_id = false; + bool needs_helper_invocation = false; std::string qual_pos_var_name; std::string stage_in_var_name = "in"; std::string stage_out_var_name = "out"; @@ -1048,6 +1192,7 @@ protected: std::string input_wg_var_name = "gl_in"; std::string input_buffer_var_name = "spvIn"; std::string output_buffer_var_name = "spvOut"; + std::string patch_input_buffer_var_name = "spvPatchIn"; std::string patch_output_buffer_var_name = "spvPatchOut"; std::string tess_factor_buffer_var_name = "spvTessLevel"; std::string index_buffer_var_name = "spvIndices"; @@ -1059,9 +1204,13 @@ protected: const MSLConstexprSampler *find_constexpr_sampler(uint32_t id) const; std::unordered_set buffers_requiring_array_length; - SmallVector buffer_arrays; - std::unordered_set atomic_image_vars; // Emulate texture2D atomic operations + SmallVector> buffer_aliases_argument; + SmallVector buffer_aliases_discrete; + std::unordered_set atomic_image_vars_emulated; // Emulate texture2D atomic operations std::unordered_set pull_model_inputs; + std::unordered_set recursive_inputs; + + SmallVector entry_point_bindings; // Must be ordered since array is in a specific order. std::map> buffers_requiring_dynamic_offset; @@ -1100,6 +1249,16 @@ protected: bool variable_storage_requires_stage_io(spv::StorageClass storage) const; + bool needs_manual_helper_invocation_updates() const + { + return msl_options.manual_helper_invocation_updates && msl_options.supports_msl_version(2, 3); + } + bool needs_frag_discard_checks() const + { + return get_execution_model() == spv::ExecutionModelFragment && msl_options.supports_msl_version(2, 3) && + msl_options.check_discarded_frag_stores && frag_shader_needs_discard_checks; + } + bool has_additional_fixed_sample_mask() const { return msl_options.additional_fixed_sample_mask != 0xffffffff; } std::string additional_fixed_sample_mask_str() const; @@ -1117,13 +1276,16 @@ protected: CompilerMSL &compiler; std::unordered_map result_types; - std::unordered_map image_pointers; // Emulate texture2D atomic operations + std::unordered_map image_pointers_emulated; // Emulate texture2D atomic operations bool suppress_missing_prototypes = false; bool uses_atomics = false; - bool uses_resource_write = false; + bool uses_image_write = false; + bool uses_buffer_write = false; + bool uses_discard = false; bool needs_subgroup_invocation_id = false; bool needs_subgroup_size = false; bool needs_sample_id = false; + bool needs_helper_invocation = false; }; // OpcodeHandler that scans for uses of sampled images diff --git a/src/libraries/spirv_cross/spirv_parser.cpp b/src/libraries/spirv_cross/spirv_parser.cpp index 4faf3ca08..6108dbb65 100644 --- a/src/libraries/spirv_cross/spirv_parser.cpp +++ b/src/libraries/spirv_cross/spirv_parser.cpp @@ -31,7 +31,7 @@ namespace SPIRV_CROSS_NAMESPACE { Parser::Parser(vector spirv) { - ir.spirv = move(spirv); + ir.spirv = std::move(spirv); } Parser::Parser(const uint32_t *spirv_data, size_t word_count) @@ -68,6 +68,7 @@ static bool is_valid_spirv_version(uint32_t version) case 0x10300: // SPIR-V 1.3 case 0x10400: // SPIR-V 1.4 case 0x10500: // SPIR-V 1.5 + case 0x10600: // SPIR-V 1.6 return true; default: @@ -182,6 +183,15 @@ void Parser::parse(const Instruction &instruction) auto op = static_cast(instruction.op); uint32_t length = instruction.length; + // HACK for glslang that might emit OpEmitMeshTasksEXT followed by return / branch. + // Instead of failing hard, just ignore it. + if (ignore_trailing_block_opcodes) + { + ignore_trailing_block_opcodes = false; + if (op == OpReturn || op == OpBranch || op == OpUnreachable) + return; + } + switch (op) { case OpSourceContinued: @@ -258,29 +268,37 @@ void Parser::parse(const Instruction &instruction) case OpExtension: { auto ext = extract_string(ir.spirv, instruction.offset); - ir.declared_extensions.push_back(move(ext)); + ir.declared_extensions.push_back(std::move(ext)); break; } case OpExtInstImport: { uint32_t id = ops[0]; + + SPIRExtension::Extension spirv_ext = SPIRExtension::Unsupported; + auto ext = extract_string(ir.spirv, instruction.offset + 1); if (ext == "GLSL.std.450") - set(id, SPIRExtension::GLSL); + spirv_ext = SPIRExtension::GLSL; else if (ext == "DebugInfo") - set(id, SPIRExtension::SPV_debug_info); + spirv_ext = SPIRExtension::SPV_debug_info; else if (ext == "SPV_AMD_shader_ballot") - set(id, SPIRExtension::SPV_AMD_shader_ballot); + spirv_ext = SPIRExtension::SPV_AMD_shader_ballot; else if (ext == "SPV_AMD_shader_explicit_vertex_parameter") - set(id, SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter); + spirv_ext = SPIRExtension::SPV_AMD_shader_explicit_vertex_parameter; else if (ext == "SPV_AMD_shader_trinary_minmax") - set(id, SPIRExtension::SPV_AMD_shader_trinary_minmax); + spirv_ext = SPIRExtension::SPV_AMD_shader_trinary_minmax; else if (ext == "SPV_AMD_gcn_shader") - set(id, SPIRExtension::SPV_AMD_gcn_shader); - else - set(id, SPIRExtension::Unsupported); + spirv_ext = SPIRExtension::SPV_AMD_gcn_shader; + else if (ext == "NonSemantic.DebugPrintf") + spirv_ext = SPIRExtension::NonSemanticDebugPrintf; + else if (ext == "NonSemantic.Shader.DebugInfo.100") + spirv_ext = SPIRExtension::NonSemanticShaderDebugInfo; + else if (ext.find("NonSemantic.") == 0) + spirv_ext = SPIRExtension::NonSemanticGeneric; + set(id, spirv_ext); // Other SPIR-V extensions which have ExtInstrs are currently not supported. break; @@ -290,7 +308,15 @@ void Parser::parse(const Instruction &instruction) { // The SPIR-V debug information extended instructions might come at global scope. if (current_block) + { current_block->ops.push_back(instruction); + if (length >= 2) + { + const auto *type = maybe_get(ops[0]); + if (type) + ir.load_type_width.insert({ ops[1], type->width }); + } + } break; } @@ -338,12 +364,32 @@ void Parser::parse(const Instruction &instruction) execution.output_vertices = ops[2]; break; + case ExecutionModeOutputPrimitivesEXT: + execution.output_primitives = ops[2]; + break; + default: break; } break; } + case OpExecutionModeId: + { + auto &execution = ir.entry_points[ops[0]]; + auto mode = static_cast(ops[1]); + execution.flags.set(mode); + + if (mode == ExecutionModeLocalSizeId) + { + execution.workgroup_size.id_x = ops[2]; + execution.workgroup_size.id_y = ops[3]; + execution.workgroup_size.id_z = ops[4]; + } + + break; + } + case OpName: { uint32_t id = ops[0]; @@ -471,7 +517,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeVoid: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::Void; break; } @@ -479,7 +525,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeBool: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::Boolean; type.width = 1; break; @@ -489,7 +535,7 @@ void Parser::parse(const Instruction &instruction) { uint32_t id = ops[0]; uint32_t width = ops[1]; - auto &type = set(id); + auto &type = set(id, op); if (width == 64) type.basetype = SPIRType::Double; else if (width == 32) @@ -507,7 +553,7 @@ void Parser::parse(const Instruction &instruction) uint32_t id = ops[0]; uint32_t width = ops[1]; bool signedness = ops[2] != 0; - auto &type = set(id); + auto &type = set(id, op); type.basetype = signedness ? to_signed_basetype(width) : to_unsigned_basetype(width); type.width = width; break; @@ -522,9 +568,9 @@ void Parser::parse(const Instruction &instruction) uint32_t vecsize = ops[2]; auto &base = get(ops[1]); - auto &vecbase = set(id); + auto &vecbase = set(id, base); - vecbase = base; + vecbase.op = op; vecbase.vecsize = vecsize; vecbase.self = id; vecbase.parent_type = ops[1]; @@ -537,9 +583,9 @@ void Parser::parse(const Instruction &instruction) uint32_t colcount = ops[2]; auto &base = get(ops[1]); - auto &matrixbase = set(id); + auto &matrixbase = set(id, base); - matrixbase = base; + matrixbase.op = op; matrixbase.columns = colcount; matrixbase.self = id; matrixbase.parent_type = ops[1]; @@ -549,12 +595,11 @@ void Parser::parse(const Instruction &instruction) case OpTypeArray: { uint32_t id = ops[0]; - auto &arraybase = set(id); - uint32_t tid = ops[1]; auto &base = get(tid); + auto &arraybase = set(id, base); - arraybase = base; + arraybase.op = op; arraybase.parent_type = tid; uint32_t cid = ops[2]; @@ -569,7 +614,9 @@ void Parser::parse(const Instruction &instruction) arraybase.array_size_literal.push_back(literal); arraybase.array.push_back(literal ? c->scalar() : cid); - // Do NOT set arraybase.self! + + // .self resolves down to non-array/non-pointer type. + arraybase.self = base.self; break; } @@ -578,25 +625,27 @@ void Parser::parse(const Instruction &instruction) uint32_t id = ops[0]; auto &base = get(ops[1]); - auto &arraybase = set(id); + auto &arraybase = set(id, base); // We're copying type information into Array types, so we'll need a fixup for any physical pointer // references. if (base.forward_pointer) forward_pointer_fixups.push_back({ id, ops[1] }); - arraybase = base; + arraybase.op = op; arraybase.array.push_back(0); arraybase.array_size_literal.push_back(true); arraybase.parent_type = ops[1]; - // Do NOT set arraybase.self! + + // .self resolves down to non-array/non-pointer type. + arraybase.self = base.self; break; } case OpTypeImage: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::Image; type.image.type = ops[1]; type.image.dim = static_cast(ops[2]); @@ -613,7 +662,7 @@ void Parser::parse(const Instruction &instruction) { uint32_t id = ops[0]; uint32_t imagetype = ops[1]; - auto &type = set(id); + auto &type = set(id, op); type = get(imagetype); type.basetype = SPIRType::SampledImage; type.self = id; @@ -623,7 +672,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeSampler: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::Sampler; break; } @@ -636,10 +685,13 @@ void Parser::parse(const Instruction &instruction) // We won't be able to compile it, but we shouldn't crash when parsing. // We should be able to reflect. auto *base = maybe_get(ops[2]); - auto &ptrbase = set(id); + auto &ptrbase = set(id, op); if (base) + { ptrbase = *base; + ptrbase.op = op; + } ptrbase.pointer = true; ptrbase.pointer_depth++; @@ -660,7 +712,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeForwardPointer: { uint32_t id = ops[0]; - auto &ptrbase = set(id); + auto &ptrbase = set(id, op); ptrbase.pointer = true; ptrbase.pointer_depth++; ptrbase.storage = static_cast(ops[1]); @@ -675,7 +727,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeStruct: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::Struct; for (uint32_t i = 1; i < length; i++) type.member_types.push_back(ops[i]); @@ -724,7 +776,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeAccelerationStructureKHR: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::AccelerationStructure; break; } @@ -732,7 +784,7 @@ void Parser::parse(const Instruction &instruction) case OpTypeRayQueryKHR: { uint32_t id = ops[0]; - auto &type = set(id); + auto &type = set(id, op); type.basetype = SPIRType::RayQuery; break; } @@ -979,10 +1031,9 @@ void Parser::parse(const Instruction &instruction) { uint32_t ids = ir.increase_bound_by(2); - SPIRType type; + auto &type = set(ids, OpTypeInt); type.basetype = SPIRType::Int; type.width = 32; - set(ids, type); auto &c = set(ids + 1, ids); current_block->condition = c.self; @@ -993,7 +1044,16 @@ void Parser::parse(const Instruction &instruction) } else { - ir.block_meta[current_block->next_block] &= ~ParsedIR::BLOCK_META_SELECTION_MERGE_BIT; + // Collapse loops if we have to. + bool collapsed_loop = current_block->true_block == current_block->merge_block && + current_block->merge == SPIRBlock::MergeLoop; + + if (collapsed_loop) + { + ir.block_meta[current_block->merge_block] &= ~ParsedIR::BLOCK_META_LOOP_MERGE_BIT; + ir.block_meta[current_block->continue_block] &= ~ParsedIR::BLOCK_META_CONTINUE_BIT; + } + current_block->next_block = current_block->true_block; current_block->condition = 0; current_block->true_block = 0; @@ -1042,6 +1102,7 @@ void Parser::parse(const Instruction &instruction) } case OpKill: + case OpTerminateInvocation: { if (!current_block) SPIRV_CROSS_THROW("Trying to end a non-existing block."); @@ -1066,6 +1127,18 @@ void Parser::parse(const Instruction &instruction) current_block = nullptr; break; + case OpEmitMeshTasksEXT: + if (!current_block) + SPIRV_CROSS_THROW("Trying to end a non-existing block."); + current_block->terminator = SPIRBlock::EmitMeshTasks; + for (uint32_t i = 0; i < 3; i++) + current_block->mesh.groups[i] = ops[i]; + current_block->mesh.payload = length >= 4 ? ops[3] : 0; + current_block = nullptr; + // Currently glslang is bugged and does not treat EmitMeshTasksEXT as a terminator. + ignore_trailing_block_opcodes = true; + break; + case OpReturn: { if (!current_block) @@ -1194,10 +1267,9 @@ void Parser::parse(const Instruction &instruction) { const auto *type = maybe_get(ops[0]); if (type) - { ir.load_type_width.insert({ ops[1], type->width }); - } } + if (!current_block) SPIRV_CROSS_THROW("Currently no block to insert opcode."); diff --git a/src/libraries/spirv_cross/spirv_parser.hpp b/src/libraries/spirv_cross/spirv_parser.hpp index d72fc71d8..dabc0e224 100644 --- a/src/libraries/spirv_cross/spirv_parser.hpp +++ b/src/libraries/spirv_cross/spirv_parser.hpp @@ -46,6 +46,8 @@ private: ParsedIR ir; SPIRFunction *current_function = nullptr; SPIRBlock *current_block = nullptr; + // For workarounds. + bool ignore_trailing_block_opcodes = false; void parse(const Instruction &instr); const uint32_t *stream(const Instruction &instr) const; diff --git a/src/libraries/spirv_cross/spirv_reflect.cpp b/src/libraries/spirv_cross/spirv_reflect.cpp index ee2fe930d..b02773722 100644 --- a/src/libraries/spirv_cross/spirv_reflect.cpp +++ b/src/libraries/spirv_cross/spirv_reflect.cpp @@ -291,8 +291,8 @@ static bool naturally_emit_type(const SPIRType &type) bool CompilerReflection::type_is_reference(const SPIRType &type) const { // Physical pointers and arrays of physical pointers need to refer to the pointee's type. - return type_is_top_level_physical_pointer(type) || - (!type.array.empty() && type_is_top_level_physical_pointer(get(type.parent_type))); + return is_physical_pointer(type) || + (type_is_array_of_pointers(type) && type.storage == StorageClassPhysicalStorageBuffer); } void CompilerReflection::emit_types() @@ -341,7 +341,7 @@ void CompilerReflection::emit_type(uint32_t type_id, bool &emitted_open_tag) json_stream->emit_json_key_object("_" + std::to_string(type_id)); json_stream->emit_json_key_value("name", name); - if (type_is_top_level_physical_pointer(type)) + if (is_physical_pointer(type)) { json_stream->emit_json_key_value("type", "_" + std::to_string(type.parent_type)); json_stream->emit_json_key_value("physical_pointer", true); @@ -404,7 +404,7 @@ void CompilerReflection::emit_type_member(const SPIRType &type, uint32_t index) void CompilerReflection::emit_type_array(const SPIRType &type) { - if (!type_is_top_level_physical_pointer(type) && !type.array.empty()) + if (!is_physical_pointer(type) && !type.array.empty()) { json_stream->emit_json_key_array("array"); // Note that we emit the zeros here as a means of identifying @@ -444,7 +444,7 @@ void CompilerReflection::emit_type_member_qualifiers(const SPIRType &type, uint3 if (dec.decoration_flags.get(DecorationRowMajor)) json_stream->emit_json_key_value("row_major", true); - if (type_is_top_level_physical_pointer(membertype)) + if (is_physical_pointer(membertype)) json_stream->emit_json_key_value("physical_pointer", true); } } @@ -587,18 +587,18 @@ void CompilerReflection::emit_resources(const char *tag, const SmallVectoremit_json_key_value("writeonly", true); - if (buffer_flags.get(DecorationNonWritable)) - json_stream->emit_json_key_value("readonly", true); - if (buffer_flags.get(DecorationRestrict)) - json_stream->emit_json_key_value("restrict", true); - if (buffer_flags.get(DecorationCoherent)) - json_stream->emit_json_key_value("coherent", true); - } + Bitset qualifier_mask = ssbo_block ? get_buffer_block_flags(res.id) : mask; + + if (qualifier_mask.get(DecorationNonReadable)) + json_stream->emit_json_key_value("writeonly", true); + if (qualifier_mask.get(DecorationNonWritable)) + json_stream->emit_json_key_value("readonly", true); + if (qualifier_mask.get(DecorationRestrict)) + json_stream->emit_json_key_value("restrict", true); + if (qualifier_mask.get(DecorationCoherent)) + json_stream->emit_json_key_value("coherent", true); + if (qualifier_mask.get(DecorationVolatile)) + json_stream->emit_json_key_value("volatile", true); } emit_type_array(type); diff --git a/src/love.cpp b/src/love.cpp index 10e0b5c3f..edd0e8eec 100644 --- a/src/love.cpp +++ b/src/love.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,6 +26,10 @@ #ifdef LOVE_BUILD_EXE +#if SDL_VERSION_ATLEAST(3, 0, 0) +#include +#endif + // Lua extern "C" { #include @@ -150,11 +154,11 @@ enum DoneAction static void print_usage() { // when editing this message, change it at boot.lua too - printf("LÖVE is an *awesome* framework you can use to make 2D games in Lua\n" + printf("LOVE is an *awesome* framework you can use to make 2D games in Lua\n" "https://love2d.org\n" "\n" "usage:\n" - " love --version prints LÖVE version and quits\n" + " love --version prints LOVE version and quits\n" " love --help prints this message and quits\n" " love path/to/gamedir runs the game from the given directory which contains a main.lua file\n" " love path/to/packagedgame.love runs the packaged game from the provided .love file\n" @@ -189,7 +193,7 @@ static DoneAction runlove(int argc, char **argv, int &retval, love::Variant &res // LuaJIT-specific setup needs to be done as early as possible - before // get_app_arguments because that loads external library code. This is also - // loaded inside require("love"). Note that it doesn't use the love table. + // loaded inside love's Lua threads. Note that it doesn't use the love table. love_preload(L, luaopen_love_jitsetup, "love.jitsetup"); lua_getglobal(L, "require"); lua_pushstring(L, "love.jitsetup"); diff --git a/src/modules/audio/Audio.cpp b/src/modules/audio/Audio.cpp index 6b357c9c2..336e9dff3 100644 --- a/src/modules/audio/Audio.cpp +++ b/src/modules/audio/Audio.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -68,6 +68,10 @@ void showRecordingPermissionMissingDialog() #endif } +Audio::Audio(const char *name) + : Module(M_AUDIO, name) +{} + bool Audio::setMixWithSystem(bool mix) { #ifdef LOVE_IOS diff --git a/src/modules/audio/Audio.h b/src/modules/audio/Audio.h index ef5a644a1..8b6eae670 100644 --- a/src/modules/audio/Audio.h +++ b/src/modules/audio/Audio.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -101,9 +101,6 @@ public: virtual ~Audio() {} - // Implements Module. - virtual ModuleType getModuleType() const { return M_AUDIO; } - virtual Source *newSource(love::sound::Decoder *decoder) = 0; virtual Source *newSource(love::sound::SoundData *soundData) = 0; virtual Source *newSource(int sampleRate, int bitDepth, int channels, int buffers) = 0; @@ -312,6 +309,10 @@ public: */ virtual void setPlaybackDevice(const char *name); +protected: + + Audio(const char *name); + private: static StringMap::Entry distanceModelEntries[]; diff --git a/src/modules/audio/Effect.cpp b/src/modules/audio/Effect.cpp index 0a3bd1243..aa2f18122 100644 --- a/src/modules/audio/Effect.cpp +++ b/src/modules/audio/Effect.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Effect.h b/src/modules/audio/Effect.h index 2d93d6a57..0eb4e307e 100644 --- a/src/modules/audio/Effect.h +++ b/src/modules/audio/Effect.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Filter.cpp b/src/modules/audio/Filter.cpp index beced0fe5..6ec622870 100644 --- a/src/modules/audio/Filter.cpp +++ b/src/modules/audio/Filter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Filter.h b/src/modules/audio/Filter.h index f2c1344c8..de1f64d11 100644 --- a/src/modules/audio/Filter.h +++ b/src/modules/audio/Filter.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/RecordingDevice.cpp b/src/modules/audio/RecordingDevice.cpp index 9ceefa6bc..f9123eb87 100644 --- a/src/modules/audio/RecordingDevice.cpp +++ b/src/modules/audio/RecordingDevice.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/RecordingDevice.h b/src/modules/audio/RecordingDevice.h index 4d85c2f14..7ee367863 100644 --- a/src/modules/audio/RecordingDevice.h +++ b/src/modules/audio/RecordingDevice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Source.cpp b/src/modules/audio/Source.cpp index 4877f9dcb..5e69457cb 100644 --- a/src/modules/audio/Source.cpp +++ b/src/modules/audio/Source.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/Source.h b/src/modules/audio/Source.h index a61ef043b..3f45ce06d 100644 --- a/src/modules/audio/Source.h +++ b/src/modules/audio/Source.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/null/Audio.cpp b/src/modules/audio/null/Audio.cpp index 1be9ed5d5..29f814be5 100644 --- a/src/modules/audio/null/Audio.cpp +++ b/src/modules/audio/null/Audio.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -28,7 +28,8 @@ namespace null { Audio::Audio() - : distanceModel(DISTANCE_NONE) + : love::audio::Audio("love.audio.null") + , distanceModel(DISTANCE_NONE) { } @@ -36,11 +37,6 @@ Audio::~Audio() { } -const char *Audio::getName() const -{ - return "love.audio.null"; -} - love::audio::Source *Audio::newSource(love::sound::Decoder *) { return new Source(); diff --git a/src/modules/audio/null/Audio.h b/src/modules/audio/null/Audio.h index 5559517d8..8d38d4523 100644 --- a/src/modules/audio/null/Audio.h +++ b/src/modules/audio/null/Audio.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -41,9 +41,6 @@ public: Audio(); virtual ~Audio(); - // Implements Module. - const char *getName() const; - // Implements Audio. love::audio::Source *newSource(love::sound::Decoder *decoder); love::audio::Source *newSource(love::sound::SoundData *soundData); diff --git a/src/modules/audio/null/RecordingDevice.cpp b/src/modules/audio/null/RecordingDevice.cpp index fbf80f86f..e206d87b6 100644 --- a/src/modules/audio/null/RecordingDevice.cpp +++ b/src/modules/audio/null/RecordingDevice.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/null/RecordingDevice.h b/src/modules/audio/null/RecordingDevice.h index 48d3fde7c..501007209 100644 --- a/src/modules/audio/null/RecordingDevice.h +++ b/src/modules/audio/null/RecordingDevice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/null/Source.cpp b/src/modules/audio/null/Source.cpp index d529b0ce9..b38e97a27 100644 --- a/src/modules/audio/null/Source.cpp +++ b/src/modules/audio/null/Source.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/null/Source.h b/src/modules/audio/null/Source.h index 2b4880c50..03071a9db 100644 --- a/src/modules/audio/null/Source.h +++ b/src/modules/audio/null/Source.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/Audio.cpp b/src/modules/audio/openal/Audio.cpp index 93dd08f12..1aa0783a0 100644 --- a/src/modules/audio/openal/Audio.cpp +++ b/src/modules/audio/openal/Audio.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -106,7 +106,8 @@ static const char *getDeviceSpecifier(ALCdevice *device) } Audio::Audio() - : device(nullptr) + : love::audio::Audio("love.audio.openal") + , device(nullptr) , context(nullptr) , pool(nullptr) , poolThread(nullptr) @@ -144,10 +145,10 @@ Audio::Audio() context = alcCreateContext(device, attribs.data()); if (context == nullptr) - throw love::Exception("Could not create context."); + throw love::Exception("Could not create context: %s", alcGetString(device, alcGetError(device))); - if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR) - throw love::Exception("Could not make context current."); + if (!alcMakeContextCurrent(context)) + throw love::Exception("Could not make context current: %s", alcGetString(device, alcGetError(device))); } #ifdef ALC_EXT_EFX @@ -256,11 +257,6 @@ Audio::~Audio() alcCloseDevice(device); } -const char *Audio::getName() const -{ - return "love.audio.openal"; -} - love::audio::Source *Audio::newSource(love::sound::Decoder *decoder) { return new Source(pool, decoder); diff --git a/src/modules/audio/openal/Audio.h b/src/modules/audio/openal/Audio.h index c6b7efa15..5dce39609 100644 --- a/src/modules/audio/openal/Audio.h +++ b/src/modules/audio/openal/Audio.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -50,9 +50,9 @@ #include #endif #else -#include -#include -#include +#include +#include +#include #endif namespace love @@ -78,9 +78,6 @@ public: **/ static ALenum getFormat(int bitDepth, int channels); - // Implements Module. - const char *getName() const; - // Implements Audio. love::audio::Source *newSource(love::sound::Decoder *decoder); love::audio::Source *newSource(love::sound::SoundData *soundData); diff --git a/src/modules/audio/openal/Effect.cpp b/src/modules/audio/openal/Effect.cpp index fa1b9026b..78c257584 100644 --- a/src/modules/audio/openal/Effect.cpp +++ b/src/modules/audio/openal/Effect.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/Effect.h b/src/modules/audio/openal/Effect.h index 9f67ce079..bff3ddfa0 100644 --- a/src/modules/audio/openal/Effect.h +++ b/src/modules/audio/openal/Effect.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,9 +34,9 @@ #include #endif #else -#include -#include -#include +#include +#include +#include #endif #include diff --git a/src/modules/audio/openal/Filter.cpp b/src/modules/audio/openal/Filter.cpp index 7b0528aed..7c890b6d8 100644 --- a/src/modules/audio/openal/Filter.cpp +++ b/src/modules/audio/openal/Filter.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/Filter.h b/src/modules/audio/openal/Filter.h index dc6532018..c8a4bf46f 100644 --- a/src/modules/audio/openal/Filter.h +++ b/src/modules/audio/openal/Filter.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,9 +34,9 @@ #include #endif #else -#include -#include -#include +#include +#include +#include #endif #include diff --git a/src/modules/audio/openal/Pool.cpp b/src/modules/audio/openal/Pool.cpp index cc01b77c1..7d08f6572 100644 --- a/src/modules/audio/openal/Pool.cpp +++ b/src/modules/audio/openal/Pool.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/Pool.h b/src/modules/audio/openal/Pool.h index fff1820b7..f44d7f460 100644 --- a/src/modules/audio/openal/Pool.h +++ b/src/modules/audio/openal/Pool.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,9 +46,9 @@ #include #endif #else -#include -#include -#include +#include +#include +#include #endif namespace love diff --git a/src/modules/audio/openal/RecordingDevice.cpp b/src/modules/audio/openal/RecordingDevice.cpp index 6b6c86326..56a74428b 100644 --- a/src/modules/audio/openal/RecordingDevice.cpp +++ b/src/modules/audio/openal/RecordingDevice.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/RecordingDevice.h b/src/modules/audio/openal/RecordingDevice.h index 09e8b41a1..0ec038f07 100644 --- a/src/modules/audio/openal/RecordingDevice.h +++ b/src/modules/audio/openal/RecordingDevice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -32,8 +32,8 @@ #include #endif #else -#include -#include +#include +#include #endif #include "audio/RecordingDevice.h" diff --git a/src/modules/audio/openal/Source.cpp b/src/modules/audio/openal/Source.cpp index bbec6827d..dcb5f3674 100644 --- a/src/modules/audio/openal/Source.cpp +++ b/src/modules/audio/openal/Source.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/openal/Source.h b/src/modules/audio/openal/Source.h index ecceaf151..46d7eee5f 100644 --- a/src/modules/audio/openal/Source.h +++ b/src/modules/audio/openal/Source.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,8 +48,8 @@ #include #endif #else -#include -#include +#include +#include #endif namespace love diff --git a/src/modules/audio/wrap_Audio.cpp b/src/modules/audio/wrap_Audio.cpp index c8253eef4..0541be892 100644 --- a/src/modules/audio/wrap_Audio.cpp +++ b/src/modules/audio/wrap_Audio.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/wrap_Audio.h b/src/modules/audio/wrap_Audio.h index 8ddc2e027..a24687deb 100644 --- a/src/modules/audio/wrap_Audio.h +++ b/src/modules/audio/wrap_Audio.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/wrap_RecordingDevice.cpp b/src/modules/audio/wrap_RecordingDevice.cpp index 6b3f37902..cd0b691e8 100644 --- a/src/modules/audio/wrap_RecordingDevice.cpp +++ b/src/modules/audio/wrap_RecordingDevice.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/wrap_RecordingDevice.h b/src/modules/audio/wrap_RecordingDevice.h index 51753ec8e..0a8f9547d 100644 --- a/src/modules/audio/wrap_RecordingDevice.h +++ b/src/modules/audio/wrap_RecordingDevice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/wrap_Source.cpp b/src/modules/audio/wrap_Source.cpp index 72204f663..8d4042d54 100644 --- a/src/modules/audio/wrap_Source.cpp +++ b/src/modules/audio/wrap_Source.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/audio/wrap_Source.h b/src/modules/audio/wrap_Source.h index 54f90aa88..d223dd0e3 100644 --- a/src/modules/audio/wrap_Source.h +++ b/src/modules/audio/wrap_Source.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/ByteData.cpp b/src/modules/data/ByteData.cpp index d99789611..2c4a18bd2 100644 --- a/src/modules/data/ByteData.cpp +++ b/src/modules/data/ByteData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/ByteData.h b/src/modules/data/ByteData.h index 0e1fdaa50..3606bc1e7 100644 --- a/src/modules/data/ByteData.h +++ b/src/modules/data/ByteData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/CompressedData.cpp b/src/modules/data/CompressedData.cpp index f94c67758..14b7b2426 100644 --- a/src/modules/data/CompressedData.cpp +++ b/src/modules/data/CompressedData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/CompressedData.h b/src/modules/data/CompressedData.h index 53ed19aa1..a7b33f49a 100644 --- a/src/modules/data/CompressedData.h +++ b/src/modules/data/CompressedData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/Compressor.cpp b/src/modules/data/Compressor.cpp index 2df1a1154..2a55e604b 100644 --- a/src/modules/data/Compressor.cpp +++ b/src/modules/data/Compressor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/Compressor.h b/src/modules/data/Compressor.h index fd4d49ad0..64570c29a 100644 --- a/src/modules/data/Compressor.h +++ b/src/modules/data/Compressor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/DataModule.cpp b/src/modules/data/DataModule.cpp index 9bda2cebb..a3b27ed89 100644 --- a/src/modules/data/DataModule.cpp +++ b/src/modules/data/DataModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -214,6 +214,7 @@ void hash(HashFunction::Function function, const char *input, uint64_t size, Has } DataModule::DataModule() + : Module(M_DATA, "love.data") { } diff --git a/src/modules/data/DataModule.h b/src/modules/data/DataModule.h index d7dd2f00d..f255cf07f 100644 --- a/src/modules/data/DataModule.h +++ b/src/modules/data/DataModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -117,10 +117,6 @@ public: DataModule(); virtual ~DataModule(); - // Implements Module. - ModuleType getModuleType() const override { return M_DATA; } - const char *getName() const override { return "love.data"; } - DataView *newDataView(Data *data, size_t offset, size_t size); ByteData *newByteData(size_t size); ByteData *newByteData(const void *d, size_t size); diff --git a/src/modules/data/DataStream.cpp b/src/modules/data/DataStream.cpp index ad7d7b275..bfa1873ee 100644 --- a/src/modules/data/DataStream.cpp +++ b/src/modules/data/DataStream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/DataStream.h b/src/modules/data/DataStream.h index da4d27977..05c032e5f 100644 --- a/src/modules/data/DataStream.h +++ b/src/modules/data/DataStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/DataView.cpp b/src/modules/data/DataView.cpp index 645638e7f..cb60f1e78 100644 --- a/src/modules/data/DataView.cpp +++ b/src/modules/data/DataView.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/DataView.h b/src/modules/data/DataView.h index 56ac4eff0..c253979a7 100644 --- a/src/modules/data/DataView.h +++ b/src/modules/data/DataView.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/HashFunction.cpp b/src/modules/data/HashFunction.cpp index 2ada4b19f..fdb1e9beb 100644 --- a/src/modules/data/HashFunction.cpp +++ b/src/modules/data/HashFunction.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/HashFunction.h b/src/modules/data/HashFunction.h index 372852678..e42d9c559 100644 --- a/src/modules/data/HashFunction.h +++ b/src/modules/data/HashFunction.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_ByteData.cpp b/src/modules/data/wrap_ByteData.cpp index e299cbae3..e15924d64 100644 --- a/src/modules/data/wrap_ByteData.cpp +++ b/src/modules/data/wrap_ByteData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -56,7 +56,7 @@ int w_ByteData_setString(lua_State *L) if (size == 0) return 0; - if (offset < 0 || offset + size > (int64) t->getSize()) + if (offset < 0 || offset + (int64) size > (int64) t->getSize()) return luaL_error(L, "The given string offset and size don't fit within the Data's size."); memcpy((char *) t->getData() + (size_t) offset, str, size); @@ -135,16 +135,6 @@ int w_ByteData_setUInt32(lua_State *L) return w_ByteData_setT(L); } -int w_ByteData_setInt64(lua_State *L) -{ - return w_ByteData_setT(L); -} - -int w_ByteData_setUInt64(lua_State *L) -{ - return w_ByteData_setT(L); -} - static const luaL_Reg w_ByteData_functions[] = { { "clone", w_ByteData_clone }, @@ -157,8 +147,6 @@ static const luaL_Reg w_ByteData_functions[] = { "setUInt16", w_ByteData_setUInt16 }, { "setInt32", w_ByteData_setInt32 }, { "setUInt32", w_ByteData_setUInt32 }, - { "setInt64", w_ByteData_setInt64 }, - { "setUInt64", w_ByteData_setUInt64 }, { 0, 0 } }; diff --git a/src/modules/data/wrap_ByteData.h b/src/modules/data/wrap_ByteData.h index 4e13de0a8..b8c340df3 100644 --- a/src/modules/data/wrap_ByteData.h +++ b/src/modules/data/wrap_ByteData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_CompressedData.cpp b/src/modules/data/wrap_CompressedData.cpp index 2d2d537cd..c01d69eee 100644 --- a/src/modules/data/wrap_CompressedData.cpp +++ b/src/modules/data/wrap_CompressedData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_CompressedData.h b/src/modules/data/wrap_CompressedData.h index a16d27501..661492938 100644 --- a/src/modules/data/wrap_CompressedData.h +++ b/src/modules/data/wrap_CompressedData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_Data.cpp b/src/modules/data/wrap_Data.cpp index ceab57242..97ff37469 100644 --- a/src/modules/data/wrap_Data.cpp +++ b/src/modules/data/wrap_Data.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -20,6 +20,7 @@ #include "wrap_Data.h" #include "common/int.h" +#include "thread/threads.h" // Put the Lua code directly into a raw string literal. static const char data_lua[] = @@ -78,6 +79,26 @@ int w_Data_getSize(lua_State *L) return 1; } +int w_Data_performAtomic(lua_State *L) +{ + Data *t = luax_checkdata(L, 1); + int err = 0; + + { + love::thread::Lock lock(t->getMutex()); + // call the function, passing any user-specified arguments. + err = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0); + } + + // Unfortunately, this eats the stack trace, too bad. + if (err != 0) + return lua_error(L); + + // The function and everything after it in the stack are eaten by the pcall, + // leaving only the Data object. Everything else is a return value. + return lua_gettop(L) - 1; +} + template static int w_Data_getT(lua_State* L) { @@ -139,16 +160,6 @@ int w_Data_getUInt32(lua_State* L) return w_Data_getT(L); } -int w_Data_getInt64(lua_State* L) -{ - return w_Data_getT(L); -} - -int w_Data_getUInt64(lua_State* L) -{ - return w_Data_getT(L); -} - // C functions in a struct, necessary for the FFI versions of Data methods. struct FFI_Data { @@ -170,6 +181,7 @@ const luaL_Reg w_Data_functions[] = { "getPointer", w_Data_getPointer }, { "getFFIPointer", w_Data_getFFIPointer }, { "getSize", w_Data_getSize }, + { "performAtomic", w_Data_performAtomic }, { "getFloat", w_Data_getFloat }, { "getDouble", w_Data_getDouble }, { "getInt8", w_Data_getInt8 }, @@ -178,8 +190,6 @@ const luaL_Reg w_Data_functions[] = { "getUInt16", w_Data_getUInt16 }, { "getInt32", w_Data_getInt32 }, { "getUInt32", w_Data_getUInt32 }, - { "getInt64", w_Data_getInt64 }, - { "getUInt64", w_Data_getUInt64 }, { 0, 0 } }; diff --git a/src/modules/data/wrap_Data.h b/src/modules/data/wrap_Data.h index c9447a0be..d66a3e645 100644 --- a/src/modules/data/wrap_Data.h +++ b/src/modules/data/wrap_Data.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_Data.lua b/src/modules/data/wrap_Data.lua index f15090a6e..eb18e66c8 100644 --- a/src/modules/data/wrap_Data.lua +++ b/src/modules/data/wrap_Data.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_DataModule.cpp b/src/modules/data/wrap_DataModule.cpp index 0b6ecff16..b9feda515 100644 --- a/src/modules/data/wrap_DataModule.cpp +++ b/src/modules/data/wrap_DataModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -302,25 +302,52 @@ int w_decode(lua_State *L) int w_hash(lua_State *L) { - const char *fstr = luaL_checkstring(L, 1); + int narg = 0; // used to change the arg position when using the deprecated function variant + + ContainerType ctype = CONTAINER_STRING; HashFunction::Function function; + + const char *str = luaL_checkstring(L, 1); + if (!getConstant(str, ctype)) + { + if (HashFunction::getConstant(str, function)) + { // check if the argument at 1 is a hash function; deprecated function variant + luax_markdeprecated(L, 1, "love.data.hash", API_FUNCTION_VARIANT, DEPRECATED_REPLACED, "variant with container return type parameter"); + narg = -1; + } + else + luax_enumerror(L, "container type", getConstants(ctype), str); + } + + const char *fstr = luaL_checkstring(L, 2 + narg); if (!HashFunction::getConstant(fstr, function)) return luax_enumerror(L, "hash function", HashFunction::getConstants(function), fstr); HashFunction::Value hashvalue; - if (lua_isstring(L, 2)) + if (lua_isstring(L, 3 + narg)) { size_t rawsize = 0; - const char *rawbytes = luaL_checklstring(L, 2, &rawsize); + const char *rawbytes = luaL_checklstring(L, 3 + narg, &rawsize); luax_catchexcept(L, [&](){ love::data::hash(function, rawbytes, rawsize, hashvalue); }); } else { - Data *rawdata = luax_checktype(L, 2); + Data *rawdata = luax_checktype(L, 3 + narg); luax_catchexcept(L, [&](){ love::data::hash(function, rawdata, hashvalue); }); } - lua_pushlstring(L, hashvalue.data, hashvalue.size); + if (ctype == CONTAINER_DATA) + { + Data* d = nullptr; + luax_catchexcept(L, [&]() { d = instance()->newByteData(hashvalue.size); }); + memcpy(d->getData(), hashvalue.data, hashvalue.size); + + luax_pushtype(L, Data::type, d); + d->release(); + } + else + lua_pushlstring(L, hashvalue.data, hashvalue.size); + return 1; } diff --git a/src/modules/data/wrap_DataModule.h b/src/modules/data/wrap_DataModule.h index c8614240e..046101d13 100644 --- a/src/modules/data/wrap_DataModule.h +++ b/src/modules/data/wrap_DataModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_DataView.cpp b/src/modules/data/wrap_DataView.cpp index 9c574bb67..b756eff0b 100644 --- a/src/modules/data/wrap_DataView.cpp +++ b/src/modules/data/wrap_DataView.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/data/wrap_DataView.h b/src/modules/data/wrap_DataView.h index a255fa255..fbcfc2efb 100644 --- a/src/modules/data/wrap_DataView.h +++ b/src/modules/data/wrap_DataView.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/event/Event.cpp b/src/modules/event/Event.cpp index 9f0df49d8..45b7c2c2b 100644 --- a/src/modules/event/Event.cpp +++ b/src/modules/event/Event.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,6 +38,11 @@ Message::~Message() { } +Event::Event(const char *name) + : Module(M_EVENT, name) +{ +} + Event::~Event() { } diff --git a/src/modules/event/Event.h b/src/modules/event/Event.h index 181c0b131..3b3c33d44 100644 --- a/src/modules/event/Event.h +++ b/src/modules/event/Event.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -54,10 +54,8 @@ public: class Event : public Module { public: - virtual ~Event(); - // Implements Module. - virtual ModuleType getModuleType() const { return M_EVENT; } + virtual ~Event(); void push(Message *msg); bool poll(Message *&msg); @@ -67,6 +65,9 @@ public: virtual Message *wait() = 0; protected: + + Event(const char *name); + love::thread::MutexRef mutex; std::queue queue; diff --git a/src/modules/event/sdl/Event.cpp b/src/modules/event/sdl/Event.cpp index 82972a069..e94619561 100644 --- a/src/modules/event/sdl/Event.cpp +++ b/src/modules/event/sdl/Event.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,7 +24,6 @@ #include "filesystem/Filesystem.h" #include "keyboard/sdl/Keyboard.h" #include "joystick/JoystickModule.h" -#include "joystick/sdl/Joystick.h" #include "touch/sdl/Touch.h" #include "graphics/Graphics.h" #include "window/Window.h" @@ -38,6 +37,58 @@ #include +#if SDL_VERSION_ATLEAST(3, 0, 0) +#include "joystick/sdl/JoystickSDL3.h" +#else +#include "joystick/sdl/Joystick.h" +#endif + +#if !SDL_VERSION_ATLEAST(3, 0, 0) +#define SDL_EVENT_DID_ENTER_BACKGROUND SDL_APP_DIDENTERBACKGROUND +#define SDL_EVENT_WILL_ENTER_FOREGROUND SDL_APP_WILLENTERFOREGROUND +#define SDL_EVENT_KEY_DOWN SDL_KEYDOWN +#define SDL_EVENT_KEY_UP SDL_KEYUP +#define SDL_EVENT_TEXT_INPUT SDL_TEXTINPUT +#define SDL_EVENT_TEXT_EDITING SDL_TEXTEDITING +#define SDL_EVENT_MOUSE_MOTION SDL_MOUSEMOTION +#define SDL_EVENT_MOUSE_BUTTON_DOWN SDL_MOUSEBUTTONDOWN +#define SDL_EVENT_MOUSE_BUTTON_UP SDL_MOUSEBUTTONUP +#define SDL_EVENT_MOUSE_WHEEL SDL_MOUSEWHEEL +#define SDL_EVENT_FINGER_DOWN SDL_FINGERDOWN +#define SDL_EVENT_FINGER_UP SDL_FINGERUP +#define SDL_EVENT_FINGER_MOTION SDL_FINGERMOTION + +#define SDL_EVENT_DROP_FILE SDL_DROPFILE +#define SDL_EVENT_QUIT SDL_QUIT +#define SDL_EVENT_TERMINATING SDL_APP_TERMINATING +#define SDL_EVENT_LOW_MEMORY SDL_APP_LOWMEMORY +#define SDL_EVENT_LOCALE_CHANGED SDL_LOCALECHANGED +#define SDL_EVENT_SENSOR_UPDATE SDL_SENSORUPDATE + +#define SDL_EVENT_JOYSTICK_BUTTON_DOWN SDL_JOYBUTTONDOWN +#define SDL_EVENT_JOYSTICK_BUTTON_UP SDL_JOYBUTTONUP +#define SDL_EVENT_JOYSTICK_AXIS_MOTION SDL_JOYAXISMOTION +#define SDL_EVENT_JOYSTICK_HAT_MOTION SDL_JOYHATMOTION +#define SDL_EVENT_JOYSTICK_ADDED SDL_JOYDEVICEADDED +#define SDL_EVENT_JOYSTICK_REMOVED SDL_JOYDEVICEREMOVED +#define SDL_EVENT_GAMEPAD_BUTTON_DOWN SDL_CONTROLLERBUTTONDOWN +#define SDL_EVENT_GAMEPAD_BUTTON_UP SDL_CONTROLLERBUTTONUP +#define SDL_EVENT_GAMEPAD_AXIS_MOTION SDL_CONTROLLERAXISMOTION +#define SDL_EVENT_GAMEPAD_SENSOR_UPDATE SDL_CONTROLLERSENSORUPDATE + +#define SDL_EVENT_WINDOW_FOCUS_GAINED SDL_WINDOWEVENT_FOCUS_GAINED +#define SDL_EVENT_WINDOW_FOCUS_LOST SDL_WINDOWEVENT_FOCUS_LOST +#define SDL_EVENT_WINDOW_MOUSE_ENTER SDL_WINDOWEVENT_ENTER +#define SDL_EVENT_WINDOW_MOUSE_LEAVE SDL_WINDOWEVENT_LEAVE +#define SDL_EVENT_WINDOW_SHOWN SDL_WINDOWEVENT_SHOWN +#define SDL_EVENT_WINDOW_HIDDEN SDL_WINDOWEVENT_HIDDEN +#define SDL_EVENT_WINDOW_RESIZED SDL_WINDOWEVENT_RESIZED +#define SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED SDL_WINDOWEVENT_SIZE_CHANGED +#define SDL_EVENT_WINDOW_MINIMIZED SDL_WINDOWEVENT_MINIMIZED +#define SDL_EVENT_WINDOW_RESTORED SDL_WINDOWEVENT_RESTORED + +#endif + namespace love { namespace event @@ -93,10 +144,10 @@ static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event) // On iOS, calling any OpenGL ES function after the function which triggers // SDL_APP_DIDENTERBACKGROUND is called will kill the app, so we handle it // with an event watch callback, which will be called inside that function. - case SDL_APP_DIDENTERBACKGROUND: - case SDL_APP_WILLENTERFOREGROUND: + case SDL_EVENT_DID_ENTER_BACKGROUND: + case SDL_EVENT_WILL_ENTER_FOREGROUND: if (gfx) - gfx->setActive(event->type == SDL_APP_WILLENTERFOREGROUND); + gfx->setActive(event->type == SDL_EVENT_WILL_ENTER_FOREGROUND); break; default: break; @@ -105,12 +156,8 @@ static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event) return 1; } -const char *Event::getName() const -{ - return "love.event.sdl"; -} - Event::Event() + : love::event::Event("love.event.sdl") { if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0) throw love::Exception("Could not initialize SDL events subsystem (%s)", SDL_GetError()); @@ -193,16 +240,15 @@ Message *Event::convert(const SDL_Event &e) const char *txt; const char *txt2; - std::map::const_iterator keyit; #ifndef LOVE_MACOS love::touch::sdl::Touch *touchmodule = nullptr; - love::touch::Touch::TouchInfo touchinfo; + love::touch::Touch::TouchInfo touchinfo = {}; #endif switch (e.type) { - case SDL_KEYDOWN: + case SDL_EVENT_KEY_DOWN: if (e.key.repeat) { auto kb = Module::getInstance(Module::M_KEYBOARD); @@ -210,10 +256,7 @@ Message *Event::convert(const SDL_Event &e) break; } - keyit = keys.find(e.key.keysym.sym); - if (keyit != keys.end()) - key = keyit->second; - + love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.sym, key); if (!love::keyboard::Keyboard::getConstant(key, txt)) txt = "unknown"; @@ -226,11 +269,8 @@ Message *Event::convert(const SDL_Event &e) vargs.emplace_back(e.key.repeat != 0); msg = new Message("keypressed", vargs); break; - case SDL_KEYUP: - keyit = keys.find(e.key.keysym.sym); - if (keyit != keys.end()) - key = keyit->second; - + case SDL_EVENT_KEY_UP: + love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.sym, key); if (!love::keyboard::Keyboard::getConstant(key, txt)) txt = "unknown"; @@ -242,19 +282,19 @@ Message *Event::convert(const SDL_Event &e) vargs.emplace_back(txt2, strlen(txt2)); msg = new Message("keyreleased", vargs); break; - case SDL_TEXTINPUT: + case SDL_EVENT_TEXT_INPUT: txt = e.text.text; vargs.emplace_back(txt, strlen(txt)); msg = new Message("textinput", vargs); break; - case SDL_TEXTEDITING: + case SDL_EVENT_TEXT_EDITING: txt = e.edit.text; vargs.emplace_back(txt, strlen(txt)); vargs.emplace_back((double) e.edit.start); vargs.emplace_back((double) e.edit.length); msg = new Message("textedited", vargs); break; - case SDL_MOUSEMOTION: + case SDL_EVENT_MOUSE_MOTION: { double x = (double) e.motion.x; double y = (double) e.motion.y; @@ -278,8 +318,8 @@ Message *Event::convert(const SDL_Event &e) msg = new Message("mousemoved", vargs); } break; - case SDL_MOUSEBUTTONDOWN: - case SDL_MOUSEBUTTONUP: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { // SDL uses button 3 for the right mouse button, but we use button 2 int button = e.button.button; @@ -305,14 +345,14 @@ Message *Event::convert(const SDL_Event &e) vargs.emplace_back(e.button.which == SDL_TOUCH_MOUSEID); vargs.emplace_back((double) e.button.clicks); - bool down = e.type == SDL_MOUSEBUTTONDOWN; + bool down = e.type == SDL_EVENT_MOUSE_BUTTON_DOWN; msg = new Message(down ? "mousepressed" : "mousereleased", vargs); } break; - case SDL_MOUSEWHEEL: + case SDL_EVENT_MOUSE_WHEEL: vargs.emplace_back((double) e.wheel.x); vargs.emplace_back((double) e.wheel.y); -#if SDL_VERSION_ATLEAST(2, 0, 18) +#if SDL_VERSION_ATLEAST(2, 0, 18) && !SDL_VERSION_ATLEAST(3, 0, 0) // These values will be garbage if 2.0.18+ headers are used but a lower // version of SDL is used at runtime, but other bits of code already // prevent running in that situation. @@ -328,15 +368,19 @@ Message *Event::convert(const SDL_Event &e) msg = new Message("wheelmoved", vargs); break; - case SDL_FINGERDOWN: - case SDL_FINGERUP: - case SDL_FINGERMOTION: + case SDL_EVENT_FINGER_DOWN: + case SDL_EVENT_FINGER_UP: + case SDL_EVENT_FINGER_MOTION: // Touch events are disabled in OS X because we only actually want touch // screen events, but most touch devices in OS X aren't touch screens // (and SDL doesn't differentiate.) Non-screen touch devices like Mac // trackpads won't give touch coords in the window's coordinate-space. #ifndef LOVE_MACOS - touchinfo.id = (int64) e.tfinger.fingerId; +#if SDL_VERSION_ATLEAST(3, 0, 0) + touchinfo.id = (int64) e.tfinger.fingerID; +#else + touchinfo.id = (int64)e.tfinger.fingerId; +#endif touchinfo.x = e.tfinger.x; touchinfo.y = e.tfinger.y; touchinfo.dx = e.tfinger.dx; @@ -364,35 +408,51 @@ Message *Event::convert(const SDL_Event &e) vargs.emplace_back(touchinfo.dy); vargs.emplace_back(touchinfo.pressure); - if (e.type == SDL_FINGERDOWN) + if (e.type == SDL_EVENT_FINGER_DOWN) txt = "touchpressed"; - else if (e.type == SDL_FINGERUP) + else if (e.type == SDL_EVENT_FINGER_UP) txt = "touchreleased"; else txt = "touchmoved"; msg = new Message(txt, vargs); #endif break; - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - case SDL_JOYAXISMOTION: - case SDL_JOYBALLMOTION: - case SDL_JOYHATMOTION: - case SDL_JOYDEVICEADDED: - case SDL_JOYDEVICEREMOVED: - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - case SDL_CONTROLLERAXISMOTION: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: + case SDL_EVENT_JOYSTICK_AXIS_MOTION: + case SDL_EVENT_JOYSTICK_HAT_MOTION: + case SDL_EVENT_JOYSTICK_ADDED: + case SDL_EVENT_JOYSTICK_REMOVED: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + case SDL_EVENT_GAMEPAD_AXIS_MOTION: #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR) - case SDL_CONTROLLERSENSORUPDATE: + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: #endif msg = convertJoystickEvent(e); break; +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_EVENT_WINDOW_FOCUS_GAINED: + case SDL_EVENT_WINDOW_FOCUS_LOST: + case SDL_EVENT_WINDOW_MOUSE_ENTER: + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + case SDL_EVENT_WINDOW_SHOWN: + case SDL_EVENT_WINDOW_HIDDEN: + case SDL_EVENT_WINDOW_RESIZED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: + case SDL_EVENT_WINDOW_MINIMIZED: + case SDL_EVENT_WINDOW_RESTORED: +#else case SDL_WINDOWEVENT: +#endif msg = convertWindowEvent(e); break; +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_EVENT_DISPLAY_ORIENTATION: +#else case SDL_DISPLAYEVENT: if (e.display.event == SDL_DISPLAYEVENT_ORIENTATION) +#endif { auto orientation = window::Window::ORIENTATION_UNKNOWN; switch ((SDL_DisplayOrientation) e.display.data1) @@ -418,47 +478,70 @@ Message *Event::convert(const SDL_Event &e) if (!window::Window::getConstant(orientation, txt)) txt = "unknown"; +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + int displayindex = 0; + SDL_DisplayID *displays = SDL_GetDisplays(&count); + for (int i = 0; i < count; i++) + { + if (displays[i] == e.display.displayID) + { + displayindex = i; + break; + } + } + SDL_free(displays); + vargs.emplace_back((double)(displayindex + 1)); +#else vargs.emplace_back((double)(e.display.display + 1)); +#endif vargs.emplace_back(txt, strlen(txt)); msg = new Message("displayrotated", vargs); } break; - case SDL_DROPFILE: + case SDL_EVENT_DROP_FILE: filesystem = Module::getInstance(Module::M_FILESYSTEM); if (filesystem != nullptr) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + const char *filepath = e.drop.data; +#else + const char *filepath = e.drop.file; +#endif // Allow mounting any dropped path, so zips or dirs can be mounted. - filesystem->allowMountingForPath(e.drop.file); + filesystem->allowMountingForPath(filepath); - if (filesystem->isRealDirectory(e.drop.file)) + if (filesystem->isRealDirectory(filepath)) { - vargs.emplace_back(e.drop.file, strlen(e.drop.file)); + vargs.emplace_back(filepath, strlen(filepath)); msg = new Message("directorydropped", vargs); } else { - auto *file = new love::filesystem::NativeFile(e.drop.file, love::filesystem::File::MODE_CLOSED); + auto *file = new love::filesystem::NativeFile(filepath, love::filesystem::File::MODE_CLOSED); vargs.emplace_back(&love::filesystem::NativeFile::type, file); msg = new Message("filedropped", vargs); file->release(); } } +#if !SDL_VERSION_ATLEAST(3, 0, 0) SDL_free(e.drop.file); +#endif break; - case SDL_QUIT: - case SDL_APP_TERMINATING: + case SDL_EVENT_QUIT: + case SDL_EVENT_TERMINATING: msg = new Message("quit"); break; - case SDL_APP_LOWMEMORY: + case SDL_EVENT_LOW_MEMORY: msg = new Message("lowmemory"); break; #if SDL_VERSION_ATLEAST(2, 0, 14) - case SDL_LOCALECHANGED: + case SDL_EVENT_LOCALE_CHANGED: msg = new Message("localechanged"); break; #endif - case SDL_SENSORUPDATE: + case SDL_EVENT_SENSOR_UPDATE: sensorInstance = Module::getInstance(M_SENSOR); if (sensorInstance) { @@ -467,13 +550,22 @@ Message *Event::convert(const SDL_Event &e) for (void *s: sensors) { SDL_Sensor *sensor = (SDL_Sensor *) s; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SensorID id = SDL_GetSensorInstanceID(sensor); +#else SDL_SensorID id = SDL_SensorGetInstanceID(sensor); +#endif if (e.sensor.which == id) { // Found sensor const char *sensorType; - if (!sensor::Sensor::getConstant(sensor::sdl::Sensor::convert(SDL_SensorGetType(sensor)), sensorType)) +#if SDL_VERSION_ATLEAST(3, 0, 0) + auto sdltype = SDL_GetSensorType(sensor); +#else + auto sdltype = SDL_SensorGetType(sensor); +#endif + if (!sensor::Sensor::getConstant(sensor::sdl::Sensor::convert(sdltype), sensorType)) sensorType = "unknown"; vargs.emplace_back(sensorType, strlen(sensorType)); @@ -516,19 +608,19 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const switch (e.type) { - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: stick = joymodule->getJoystickFromID(e.jbutton.which); if (!stick) break; vargs.emplace_back(joysticktype, stick); vargs.emplace_back((double)(e.jbutton.button+1)); - msg = new Message((e.type == SDL_JOYBUTTONDOWN) ? + msg = new Message((e.type == SDL_EVENT_JOYSTICK_BUTTON_DOWN) ? "joystickpressed" : "joystickreleased", vargs); break; - case SDL_JOYAXISMOTION: + case SDL_EVENT_JOYSTICK_AXIS_MOTION: { stick = joymodule->getJoystickFromID(e.jaxis.which); if (!stick) @@ -541,7 +633,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const msg = new Message("joystickaxis", vargs); } break; - case SDL_JOYHATMOTION: + case SDL_EVENT_JOYSTICK_HAT_MOTION: if (!joystick::sdl::Joystick::getConstant(e.jhat.value, hat) || !joystick::Joystick::getConstant(hat, txt)) break; @@ -554,41 +646,59 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const vargs.emplace_back(txt, strlen(txt)); msg = new Message("joystickhat", vargs); break; - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - if (!joystick::sdl::Joystick::getConstant((SDL_GameControllerButton) e.cbutton.button, padbutton)) - break; - - if (!joystick::Joystick::getConstant(padbutton, txt)) - break; - - stick = joymodule->getJoystickFromID(e.cbutton.which); - if (!stick) - break; - - vargs.emplace_back(joysticktype, stick); - vargs.emplace_back(txt, strlen(txt)); - msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ? - "gamepadpressed" : "gamepadreleased", vargs); - break; - case SDL_CONTROLLERAXISMOTION: - if (joystick::sdl::Joystick::getConstant((SDL_GameControllerAxis) e.caxis.axis, padaxis)) + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: { - if (!joystick::Joystick::getConstant(padaxis, txt)) +#if SDL_VERSION_ATLEAST(3, 0, 0) + const auto &b = e.gbutton; + if (!joystick::sdl::Joystick::getConstant((SDL_GamepadButton) b.button, padbutton)) +#else + const auto &b = e.cbutton; + if (!joystick::sdl::Joystick::getConstant((SDL_GameControllerButton) b.button, padbutton)) +#endif break; - stick = joymodule->getJoystickFromID(e.caxis.which); + if (!joystick::Joystick::getConstant(padbutton, txt)) + break; + + stick = joymodule->getJoystickFromID(b.which); if (!stick) break; vargs.emplace_back(joysticktype, stick); vargs.emplace_back(txt, strlen(txt)); - float value = joystick::Joystick::clampval(e.caxis.value / 32768.0f); + msg = new Message(e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ? + "gamepadpressed" : "gamepadreleased", vargs); + } + break; + case SDL_EVENT_GAMEPAD_AXIS_MOTION: +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (joystick::sdl::Joystick::getConstant((SDL_GamepadAxis) e.gaxis.axis, padaxis)) +#else + if (joystick::sdl::Joystick::getConstant((SDL_GameControllerAxis) e.caxis.axis, padaxis)) +#endif + { + if (!joystick::Joystick::getConstant(padaxis, txt)) + break; + +#if SDL_VERSION_ATLEAST(3, 0, 0) + const auto &a = e.gaxis; +#else + const auto &a = e.caxis; +#endif + + stick = joymodule->getJoystickFromID(a.which); + if (!stick) + break; + + vargs.emplace_back(joysticktype, stick); + vargs.emplace_back(txt, strlen(txt)); + float value = joystick::Joystick::clampval(a.value / 32768.0f); vargs.emplace_back((double) value); msg = new Message("gamepadaxis", vargs); } break; - case SDL_JOYDEVICEADDED: + case SDL_EVENT_JOYSTICK_ADDED: // jdevice.which is the joystick device index. stick = joymodule->addJoystick(e.jdevice.which); if (stick) @@ -597,7 +707,7 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const msg = new Message("joystickadded", vargs); } break; - case SDL_JOYDEVICEREMOVED: + case SDL_EVENT_JOYSTICK_REMOVED: // jdevice.which is the joystick instance ID now. stick = joymodule->getJoystickFromID(e.jdevice.which); if (stick) @@ -608,23 +718,30 @@ Message *Event::convertJoystickEvent(const SDL_Event &e) const } break; #if SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR) - case SDL_CONTROLLERSENSORUPDATE: - stick = joymodule->getJoystickFromID(e.csensor.which); - if (stick) + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: { - using Sensor = love::sensor::Sensor; +#if SDL_VERSION_ATLEAST(3, 0, 0) + const auto &sens = e.gsensor; +#else + const auto &sens = e.csensor; +#endif + stick = joymodule->getJoystickFromID(sens.which); + if (stick) + { + using Sensor = love::sensor::Sensor; - const char *sensorName; - Sensor::SensorType sensorType = love::sensor::sdl::Sensor::convert((SDL_SensorType) e.csensor.sensor); - if (!Sensor::getConstant(sensorType, sensorName)) - sensorName = "unknown"; + const char *sensorName; + Sensor::SensorType sensorType = love::sensor::sdl::Sensor::convert((SDL_SensorType) sens.sensor); + if (!Sensor::getConstant(sensorType, sensorName)) + sensorName = "unknown"; - vargs.emplace_back(joysticktype, stick); - vargs.emplace_back(sensorName, strlen(sensorName)); - vargs.emplace_back(e.csensor.data[0]); - vargs.emplace_back(e.csensor.data[1]); - vargs.emplace_back(e.csensor.data[2]); - msg = new Message("joysticksensorupdated", vargs); + vargs.emplace_back(joysticktype, stick); + vargs.emplace_back(sensorName, strlen(sensorName)); + vargs.emplace_back(sens.data[0]); + vargs.emplace_back(sens.data[1]); + vargs.emplace_back(sens.data[2]); + msg = new Message("joysticksensorupdated", vargs); + } } break; #endif // SDL_VERSION_ATLEAST(2, 0, 14) && defined(LOVE_ENABLE_SENSOR) @@ -645,27 +762,30 @@ Message *Event::convertWindowEvent(const SDL_Event &e) window::Window *win = nullptr; graphics::Graphics *gfx = nullptr; - if (e.type != SDL_WINDOWEVENT) - return nullptr; +#if SDL_VERSION_ATLEAST(3, 0, 0) + auto event = e.type; +#else + auto event = e.window.event; +#endif - switch (e.window.event) + switch (event) { - case SDL_WINDOWEVENT_FOCUS_GAINED: - case SDL_WINDOWEVENT_FOCUS_LOST: - vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED); + case SDL_EVENT_WINDOW_FOCUS_GAINED: + case SDL_EVENT_WINDOW_FOCUS_LOST: + vargs.emplace_back(event == SDL_EVENT_WINDOW_FOCUS_GAINED); msg = new Message("focus", vargs); break; - case SDL_WINDOWEVENT_ENTER: - case SDL_WINDOWEVENT_LEAVE: - vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_ENTER); + case SDL_EVENT_WINDOW_MOUSE_ENTER: + case SDL_EVENT_WINDOW_MOUSE_LEAVE: + vargs.emplace_back(event == SDL_EVENT_WINDOW_MOUSE_ENTER); msg = new Message("mousefocus", vargs); break; - case SDL_WINDOWEVENT_SHOWN: - case SDL_WINDOWEVENT_HIDDEN: - vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_SHOWN); + case SDL_EVENT_WINDOW_SHOWN: + case SDL_EVENT_WINDOW_HIDDEN: + vargs.emplace_back(event == SDL_EVENT_WINDOW_SHOWN); msg = new Message("visible", vargs); break; - case SDL_WINDOWEVENT_RESIZED: + case SDL_EVENT_WINDOW_RESIZED: { double width = e.window.data1; double height = e.window.data2; @@ -693,19 +813,19 @@ Message *Event::convertWindowEvent(const SDL_Event &e) msg = new Message("resize", vargs); } break; - case SDL_WINDOWEVENT_SIZE_CHANGED: + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: win = Module::getInstance(Module::M_WINDOW); if (win) win->onSizeChanged(e.window.data1, e.window.data2); break; - case SDL_WINDOWEVENT_MINIMIZED: - case SDL_WINDOWEVENT_RESTORED: + case SDL_EVENT_WINDOW_MINIMIZED: + case SDL_EVENT_WINDOW_RESTORED: #ifdef LOVE_ANDROID if (auto audio = Module::getInstance(Module::M_AUDIO)) { - if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) + if (event == SDL_EVENT_WINDOW_MINIMIZED) audio->pauseContext(); - else if (e.window.event == SDL_WINDOWEVENT_RESTORED) + else if (event == SDL_EVENT_WINDOW_RESTORED) audio->resumeContext(); } #endif @@ -715,226 +835,6 @@ Message *Event::convertWindowEvent(const SDL_Event &e) return msg; } -std::map Event::createKeyMap() -{ - using love::keyboard::Keyboard; - - std::map k; - - k[SDLK_UNKNOWN] = Keyboard::KEY_UNKNOWN; - - k[SDLK_RETURN] = Keyboard::KEY_RETURN; - k[SDLK_ESCAPE] = Keyboard::KEY_ESCAPE; - k[SDLK_BACKSPACE] = Keyboard::KEY_BACKSPACE; - k[SDLK_TAB] = Keyboard::KEY_TAB; - k[SDLK_SPACE] = Keyboard::KEY_SPACE; - k[SDLK_EXCLAIM] = Keyboard::KEY_EXCLAIM; - k[SDLK_QUOTEDBL] = Keyboard::KEY_QUOTEDBL; - k[SDLK_HASH] = Keyboard::KEY_HASH; - k[SDLK_PERCENT] = Keyboard::KEY_PERCENT; - k[SDLK_DOLLAR] = Keyboard::KEY_DOLLAR; - k[SDLK_AMPERSAND] = Keyboard::KEY_AMPERSAND; - k[SDLK_QUOTE] = Keyboard::KEY_QUOTE; - k[SDLK_LEFTPAREN] = Keyboard::KEY_LEFTPAREN; - k[SDLK_RIGHTPAREN] = Keyboard::KEY_RIGHTPAREN; - k[SDLK_ASTERISK] = Keyboard::KEY_ASTERISK; - k[SDLK_PLUS] = Keyboard::KEY_PLUS; - k[SDLK_COMMA] = Keyboard::KEY_COMMA; - k[SDLK_MINUS] = Keyboard::KEY_MINUS; - k[SDLK_PERIOD] = Keyboard::KEY_PERIOD; - k[SDLK_SLASH] = Keyboard::KEY_SLASH; - k[SDLK_0] = Keyboard::KEY_0; - k[SDLK_1] = Keyboard::KEY_1; - k[SDLK_2] = Keyboard::KEY_2; - k[SDLK_3] = Keyboard::KEY_3; - k[SDLK_4] = Keyboard::KEY_4; - k[SDLK_5] = Keyboard::KEY_5; - k[SDLK_6] = Keyboard::KEY_6; - k[SDLK_7] = Keyboard::KEY_7; - k[SDLK_8] = Keyboard::KEY_8; - k[SDLK_9] = Keyboard::KEY_9; - k[SDLK_COLON] = Keyboard::KEY_COLON; - k[SDLK_SEMICOLON] = Keyboard::KEY_SEMICOLON; - k[SDLK_LESS] = Keyboard::KEY_LESS; - k[SDLK_EQUALS] = Keyboard::KEY_EQUALS; - k[SDLK_GREATER] = Keyboard::KEY_GREATER; - k[SDLK_QUESTION] = Keyboard::KEY_QUESTION; - k[SDLK_AT] = Keyboard::KEY_AT; - - k[SDLK_LEFTBRACKET] = Keyboard::KEY_LEFTBRACKET; - k[SDLK_BACKSLASH] = Keyboard::KEY_BACKSLASH; - k[SDLK_RIGHTBRACKET] = Keyboard::KEY_RIGHTBRACKET; - k[SDLK_CARET] = Keyboard::KEY_CARET; - k[SDLK_UNDERSCORE] = Keyboard::KEY_UNDERSCORE; - k[SDLK_BACKQUOTE] = Keyboard::KEY_BACKQUOTE; - k[SDLK_a] = Keyboard::KEY_A; - k[SDLK_b] = Keyboard::KEY_B; - k[SDLK_c] = Keyboard::KEY_C; - k[SDLK_d] = Keyboard::KEY_D; - k[SDLK_e] = Keyboard::KEY_E; - k[SDLK_f] = Keyboard::KEY_F; - k[SDLK_g] = Keyboard::KEY_G; - k[SDLK_h] = Keyboard::KEY_H; - k[SDLK_i] = Keyboard::KEY_I; - k[SDLK_j] = Keyboard::KEY_J; - k[SDLK_k] = Keyboard::KEY_K; - k[SDLK_l] = Keyboard::KEY_L; - k[SDLK_m] = Keyboard::KEY_M; - k[SDLK_n] = Keyboard::KEY_N; - k[SDLK_o] = Keyboard::KEY_O; - k[SDLK_p] = Keyboard::KEY_P; - k[SDLK_q] = Keyboard::KEY_Q; - k[SDLK_r] = Keyboard::KEY_R; - k[SDLK_s] = Keyboard::KEY_S; - k[SDLK_t] = Keyboard::KEY_T; - k[SDLK_u] = Keyboard::KEY_U; - k[SDLK_v] = Keyboard::KEY_V; - k[SDLK_w] = Keyboard::KEY_W; - k[SDLK_x] = Keyboard::KEY_X; - k[SDLK_y] = Keyboard::KEY_Y; - k[SDLK_z] = Keyboard::KEY_Z; - - k[SDLK_CAPSLOCK] = Keyboard::KEY_CAPSLOCK; - - k[SDLK_F1] = Keyboard::KEY_F1; - k[SDLK_F2] = Keyboard::KEY_F2; - k[SDLK_F3] = Keyboard::KEY_F3; - k[SDLK_F4] = Keyboard::KEY_F4; - k[SDLK_F5] = Keyboard::KEY_F5; - k[SDLK_F6] = Keyboard::KEY_F6; - k[SDLK_F7] = Keyboard::KEY_F7; - k[SDLK_F8] = Keyboard::KEY_F8; - k[SDLK_F9] = Keyboard::KEY_F9; - k[SDLK_F10] = Keyboard::KEY_F10; - k[SDLK_F11] = Keyboard::KEY_F11; - k[SDLK_F12] = Keyboard::KEY_F12; - - k[SDLK_PRINTSCREEN] = Keyboard::KEY_PRINTSCREEN; - k[SDLK_SCROLLLOCK] = Keyboard::KEY_SCROLLLOCK; - k[SDLK_PAUSE] = Keyboard::KEY_PAUSE; - k[SDLK_INSERT] = Keyboard::KEY_INSERT; - k[SDLK_HOME] = Keyboard::KEY_HOME; - k[SDLK_PAGEUP] = Keyboard::KEY_PAGEUP; - k[SDLK_DELETE] = Keyboard::KEY_DELETE; - k[SDLK_END] = Keyboard::KEY_END; - k[SDLK_PAGEDOWN] = Keyboard::KEY_PAGEDOWN; - k[SDLK_RIGHT] = Keyboard::KEY_RIGHT; - k[SDLK_LEFT] = Keyboard::KEY_LEFT; - k[SDLK_DOWN] = Keyboard::KEY_DOWN; - k[SDLK_UP] = Keyboard::KEY_UP; - - k[SDLK_NUMLOCKCLEAR] = Keyboard::KEY_NUMLOCKCLEAR; - k[SDLK_KP_DIVIDE] = Keyboard::KEY_KP_DIVIDE; - k[SDLK_KP_MULTIPLY] = Keyboard::KEY_KP_MULTIPLY; - k[SDLK_KP_MINUS] = Keyboard::KEY_KP_MINUS; - k[SDLK_KP_PLUS] = Keyboard::KEY_KP_PLUS; - k[SDLK_KP_ENTER] = Keyboard::KEY_KP_ENTER; - k[SDLK_KP_0] = Keyboard::KEY_KP_0; - k[SDLK_KP_1] = Keyboard::KEY_KP_1; - k[SDLK_KP_2] = Keyboard::KEY_KP_2; - k[SDLK_KP_3] = Keyboard::KEY_KP_3; - k[SDLK_KP_4] = Keyboard::KEY_KP_4; - k[SDLK_KP_5] = Keyboard::KEY_KP_5; - k[SDLK_KP_6] = Keyboard::KEY_KP_6; - k[SDLK_KP_7] = Keyboard::KEY_KP_7; - k[SDLK_KP_8] = Keyboard::KEY_KP_8; - k[SDLK_KP_9] = Keyboard::KEY_KP_9; - k[SDLK_KP_PERIOD] = Keyboard::KEY_KP_PERIOD; - k[SDLK_KP_COMMA] = Keyboard::KEY_KP_COMMA; - k[SDLK_KP_EQUALS] = Keyboard::KEY_KP_EQUALS; - - k[SDLK_APPLICATION] = Keyboard::KEY_APPLICATION; - k[SDLK_POWER] = Keyboard::KEY_POWER; - k[SDLK_F13] = Keyboard::KEY_F13; - k[SDLK_F14] = Keyboard::KEY_F14; - k[SDLK_F15] = Keyboard::KEY_F15; - k[SDLK_F16] = Keyboard::KEY_F16; - k[SDLK_F17] = Keyboard::KEY_F17; - k[SDLK_F18] = Keyboard::KEY_F18; - k[SDLK_F19] = Keyboard::KEY_F19; - k[SDLK_F20] = Keyboard::KEY_F20; - k[SDLK_F21] = Keyboard::KEY_F21; - k[SDLK_F22] = Keyboard::KEY_F22; - k[SDLK_F23] = Keyboard::KEY_F23; - k[SDLK_F24] = Keyboard::KEY_F24; - k[SDLK_EXECUTE] = Keyboard::KEY_EXECUTE; - k[SDLK_HELP] = Keyboard::KEY_HELP; - k[SDLK_MENU] = Keyboard::KEY_MENU; - k[SDLK_SELECT] = Keyboard::KEY_SELECT; - k[SDLK_STOP] = Keyboard::KEY_STOP; - k[SDLK_AGAIN] = Keyboard::KEY_AGAIN; - k[SDLK_UNDO] = Keyboard::KEY_UNDO; - k[SDLK_CUT] = Keyboard::KEY_CUT; - k[SDLK_COPY] = Keyboard::KEY_COPY; - k[SDLK_PASTE] = Keyboard::KEY_PASTE; - k[SDLK_FIND] = Keyboard::KEY_FIND; - k[SDLK_MUTE] = Keyboard::KEY_MUTE; - k[SDLK_VOLUMEUP] = Keyboard::KEY_VOLUMEUP; - k[SDLK_VOLUMEDOWN] = Keyboard::KEY_VOLUMEDOWN; - - k[SDLK_ALTERASE] = Keyboard::KEY_ALTERASE; - k[SDLK_SYSREQ] = Keyboard::KEY_SYSREQ; - k[SDLK_CANCEL] = Keyboard::KEY_CANCEL; - k[SDLK_CLEAR] = Keyboard::KEY_CLEAR; - k[SDLK_PRIOR] = Keyboard::KEY_PRIOR; - k[SDLK_RETURN2] = Keyboard::KEY_RETURN2; - k[SDLK_SEPARATOR] = Keyboard::KEY_SEPARATOR; - k[SDLK_OUT] = Keyboard::KEY_OUT; - k[SDLK_OPER] = Keyboard::KEY_OPER; - k[SDLK_CLEARAGAIN] = Keyboard::KEY_CLEARAGAIN; - - k[SDLK_THOUSANDSSEPARATOR] = Keyboard::KEY_THOUSANDSSEPARATOR; - k[SDLK_DECIMALSEPARATOR] = Keyboard::KEY_DECIMALSEPARATOR; - k[SDLK_CURRENCYUNIT] = Keyboard::KEY_CURRENCYUNIT; - k[SDLK_CURRENCYSUBUNIT] = Keyboard::KEY_CURRENCYSUBUNIT; - - k[SDLK_LCTRL] = Keyboard::KEY_LCTRL; - k[SDLK_LSHIFT] = Keyboard::KEY_LSHIFT; - k[SDLK_LALT] = Keyboard::KEY_LALT; - k[SDLK_LGUI] = Keyboard::KEY_LGUI; - k[SDLK_RCTRL] = Keyboard::KEY_RCTRL; - k[SDLK_RSHIFT] = Keyboard::KEY_RSHIFT; - k[SDLK_RALT] = Keyboard::KEY_RALT; - k[SDLK_RGUI] = Keyboard::KEY_RGUI; - - k[SDLK_MODE] = Keyboard::KEY_MODE; - - k[SDLK_AUDIONEXT] = Keyboard::KEY_AUDIONEXT; - k[SDLK_AUDIOPREV] = Keyboard::KEY_AUDIOPREV; - k[SDLK_AUDIOSTOP] = Keyboard::KEY_AUDIOSTOP; - k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY; - k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE; - k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT; - k[SDLK_WWW] = Keyboard::KEY_WWW; - k[SDLK_MAIL] = Keyboard::KEY_MAIL; - k[SDLK_CALCULATOR] = Keyboard::KEY_CALCULATOR; - k[SDLK_COMPUTER] = Keyboard::KEY_COMPUTER; - k[SDLK_AC_SEARCH] = Keyboard::KEY_APP_SEARCH; - k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME; - k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK; - k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD; - k[SDLK_AC_STOP] = Keyboard::KEY_APP_STOP; - k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH; - k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS; - - k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN; - k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP; - k[SDLK_DISPLAYSWITCH] = Keyboard::KEY_DISPLAYSWITCH; - k[SDLK_KBDILLUMTOGGLE] = Keyboard::KEY_KBDILLUMTOGGLE; - k[SDLK_KBDILLUMDOWN] = Keyboard::KEY_KBDILLUMDOWN; - k[SDLK_KBDILLUMUP] = Keyboard::KEY_KBDILLUMUP; - k[SDLK_EJECT] = Keyboard::KEY_EJECT; - k[SDLK_SLEEP] = Keyboard::KEY_SLEEP; - -#ifdef LOVE_ANDROID - k[SDLK_AC_BACK] = Keyboard::KEY_ESCAPE; -#endif - - return k; -} - -std::map Event::keys = Event::createKeyMap(); - } // sdl } // event } // love diff --git a/src/modules/event/sdl/Event.h b/src/modules/event/sdl/Event.h index 3c1649b5c..b005e83bc 100644 --- a/src/modules/event/sdl/Event.h +++ b/src/modules/event/sdl/Event.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -28,9 +28,6 @@ // SDL #include -// STL -#include - namespace love { namespace event @@ -42,9 +39,6 @@ class Event : public love::event::Event { public: - // Implements Module. - const char *getName() const; - Event(); virtual ~Event(); @@ -75,9 +69,6 @@ private: Message *convertJoystickEvent(const SDL_Event &e) const; Message *convertWindowEvent(const SDL_Event &e); - static std::map createKeyMap(); - static std::map keys; - }; // Event } // sdl diff --git a/src/modules/event/wrap_Event.cpp b/src/modules/event/wrap_Event.cpp index ed293a1ca..e51ff9557 100644 --- a/src/modules/event/wrap_Event.cpp +++ b/src/modules/event/wrap_Event.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/event/wrap_Event.h b/src/modules/event/wrap_Event.h index ce7d9ed89..cc7cb7eb2 100644 --- a/src/modules/event/wrap_Event.h +++ b/src/modules/event/wrap_Event.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/event/wrap_Event.lua b/src/modules/event/wrap_Event.lua index a8f392d5c..52cf3bf11 100644 --- a/src/modules/event/wrap_Event.lua +++ b/src/modules/event/wrap_Event.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/File.cpp b/src/modules/filesystem/File.cpp index e1e2a726f..399a891f0 100644 --- a/src/modules/filesystem/File.cpp +++ b/src/modules/filesystem/File.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/File.h b/src/modules/filesystem/File.h index 57137e792..4ab3fe3d6 100644 --- a/src/modules/filesystem/File.h +++ b/src/modules/filesystem/File.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/FileData.cpp b/src/modules/filesystem/FileData.cpp index bc61cd5fd..806fcd7c6 100644 --- a/src/modules/filesystem/FileData.cpp +++ b/src/modules/filesystem/FileData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/FileData.h b/src/modules/filesystem/FileData.h index 0a64ca93c..c438b176f 100644 --- a/src/modules/filesystem/FileData.h +++ b/src/modules/filesystem/FileData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/Filesystem.cpp b/src/modules/filesystem/Filesystem.cpp index 542514dea..233e95a24 100644 --- a/src/modules/filesystem/Filesystem.cpp +++ b/src/modules/filesystem/Filesystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,7 +45,8 @@ namespace filesystem love::Type Filesystem::type("filesystem", &Module::type); -Filesystem::Filesystem() +Filesystem::Filesystem(const char *name) + : Module(M_FILESYSTEM, name) { } @@ -132,7 +133,21 @@ static bool createDirectoryRaw(const std::string &path) std::wstring wpath = to_widestr(path); return CreateDirectoryW(wpath.c_str(), nullptr) != 0; #else - return mkdir(path.c_str(), S_IRWXU) == 0; + int mode = S_IRWXU; + +#ifdef LOVE_ANDROID + // Need to create save directory with ugo+rwx and setgid bit if + // t.externalstorage is set and it's for save directory. + auto fs = Module::getInstance(Module::M_FILESYSTEM); + if (fs != nullptr && fs->isAndroidSaveExternal()) + { + const std::string &savedir = fs->getFullCommonPath(Filesystem::COMMONPATH_APP_SAVEDIR); + if (path.rfind(savedir, 0) == 0) + mode |= S_IRWXG | S_IRWXO | S_ISGID; + } +#endif + + return mkdir(path.c_str(), mode) == 0; #endif } diff --git a/src/modules/filesystem/Filesystem.h b/src/modules/filesystem/Filesystem.h index db1435e95..91359635d 100644 --- a/src/modules/filesystem/Filesystem.h +++ b/src/modules/filesystem/Filesystem.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -108,12 +108,8 @@ public: static love::Type type; - Filesystem(); virtual ~Filesystem(); - // Implements Module. - virtual ModuleType getModuleType() const { return M_FILESYSTEM; } - virtual void init(const char *arg0) = 0; virtual void setFused(bool fused) = 0; @@ -317,6 +313,10 @@ public: STRINGMAP_CLASS_DECLARE(MountPermissions); STRINGMAP_CLASS_DECLARE(LoadMode); +protected: + + Filesystem(const char *name); + private: bool getRealPathType(const std::string &path, FileType &ftype) const; diff --git a/src/modules/filesystem/NativeFile.cpp b/src/modules/filesystem/NativeFile.cpp index addf6ffd6..8760a594f 100644 --- a/src/modules/filesystem/NativeFile.cpp +++ b/src/modules/filesystem/NativeFile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/NativeFile.h b/src/modules/filesystem/NativeFile.h index 23d6e9667..7b46f5c01 100644 --- a/src/modules/filesystem/NativeFile.h +++ b/src/modules/filesystem/NativeFile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/physfs/File.cpp b/src/modules/filesystem/physfs/File.cpp index 421278753..a656287c3 100644 --- a/src/modules/filesystem/physfs/File.cpp +++ b/src/modules/filesystem/physfs/File.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -27,6 +27,10 @@ #include "Filesystem.h" #include "filesystem/FileData.h" +#ifdef LOVE_ANDROID +#include "common/android.h" +#endif + namespace love { namespace filesystem @@ -50,6 +54,21 @@ File::File(const std::string &filename, Mode mode) { if (!open(mode)) throw love::Exception("Could not open file at path %s", filename.c_str()); + +#ifdef LOVE_ANDROID + // In Android with t.externalstorage = true, make sure the file opened or + // created in the save directory has permissions of ugo+rw (0666) so that + // it's accessible through MTP. + auto fs = Module::getInstance(Module::M_FILESYSTEM); + if (fs != nullptr && fs->isAndroidSaveExternal()) + { + const char *realdir = PHYSFS_getRealDir(filename.c_str()); + const std::string &savedir = fs->getFullCommonPath(Filesystem::COMMONPATH_APP_SAVEDIR); + + if (realdir != nullptr && strcmp(realdir, savedir.c_str()) == 0) + love::android::fixupPermissionSingleFile(savedir, filename); + } +#endif } File::File(const File &other) diff --git a/src/modules/filesystem/physfs/File.h b/src/modules/filesystem/physfs/File.h index 8c485015e..bc0b04cb7 100644 --- a/src/modules/filesystem/physfs/File.h +++ b/src/modules/filesystem/physfs/File.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/physfs/Filesystem.cpp b/src/modules/filesystem/physfs/Filesystem.cpp index ef96149a9..99a1beb55 100644 --- a/src/modules/filesystem/physfs/Filesystem.cpp +++ b/src/modules/filesystem/physfs/Filesystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -107,7 +107,8 @@ static bool isAppCommonPath(Filesystem::CommonPath path) } Filesystem::Filesystem() - : appendIdentityToPath(false) + : love::filesystem::Filesystem("love.filesystem.physfs") + , appendIdentityToPath(false) , fused(false) , fusedSet(false) , fullPaths() @@ -128,11 +129,6 @@ Filesystem::~Filesystem() PHYSFS_deinit(); } -const char *Filesystem::getName() const -{ - return "love.filesystem.physfs"; -} - void Filesystem::init(const char *arg0) { #ifdef LOVE_ANDROID @@ -194,6 +190,11 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath) // These will be re-populated by getFullCommonPath. for (CommonPath p : appCommonPaths) fullPaths[p].clear(); +#ifdef LOVE_ANDROID + // Ensure COMMONPATH_USER_APPDATA is also cleared in Android to ensure + // `t.externalstorage` works as expected. + fullPaths[COMMONPATH_USER_APPDATA].clear(); +#endif // Store the save directory. getFullCommonPath(COMMONPATH_APP_*) uses this. saveIdentity = std::string(ident); @@ -249,8 +250,14 @@ bool Filesystem::setSource(const char *source) if (hasFusedGame) { if (gameLoveIO) - // Actually we should just be able to mount gameLoveIO, but that's experimental. + { + if (PHYSFS_mountIo(gameLoveIO, ".zip", nullptr, 0)) { + gameSource = new_search_path; + return true; + } + gameLoveIO->destroy(gameLoveIO); + } else { if (!love::android::initializeVirtualArchive()) @@ -278,6 +285,8 @@ bool Filesystem::setSource(const char *source) gameSource = new_search_path; return true; } + + io->destroy(io); } } #endif @@ -792,6 +801,16 @@ bool Filesystem::createDirectory(const char *dir) if (!PHYSFS_mkdir(dir)) return false; +#ifdef LOVE_ANDROID + // In Android with t.externalstorage = true, make sure the directory + // created in the save directory has permissions of ugo+rwx (0777) so that + // it's accessible through MTP. + if (isAndroidSaveExternal()) + love::android::fixupExternalStoragePermission( + getFullCommonPath(CommonPath::COMMONPATH_APP_SAVEDIR), + dir + ); +#endif return true; } diff --git a/src/modules/filesystem/physfs/Filesystem.h b/src/modules/filesystem/physfs/Filesystem.h index be12d2cc0..beffe3bab 100644 --- a/src/modules/filesystem/physfs/Filesystem.h +++ b/src/modules/filesystem/physfs/Filesystem.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,9 +43,6 @@ public: Filesystem(); virtual ~Filesystem(); - // Implements Module. - const char *getName() const override; - void init(const char *arg0) override; void setFused(bool fused) override; diff --git a/src/modules/filesystem/physfs/PhysfsIo.cpp b/src/modules/filesystem/physfs/PhysfsIo.cpp index cdcea8dd2..ec48f5d73 100644 --- a/src/modules/filesystem/physfs/PhysfsIo.cpp +++ b/src/modules/filesystem/physfs/PhysfsIo.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -18,7 +18,6 @@ * 3. This notice may not be removed or altered from any source distribution. **/ -#include #include #include "PhysfsIo.h" @@ -32,14 +31,15 @@ namespace physfs bool StripSuffixIo::determineStrippedLength() { - if (!file) { + if (!file) return false; - } - const int64_t fullSize = fullLength(); - int64_t chunkSize = std::min(fullSize, (int64_t)8192); + + const int64 fullSize = file->getSize(); + + int64 chunkSize = std::min(fullSize, (int64) 8192); std::string buffer; buffer.reserve(chunkSize); - int64_t i = fullSize - chunkSize; + int64 i = fullSize - chunkSize; // I don't think we really need to go through the whole file. The main known use // case for this functionality is to skip windows codesign signatures, which are // from what I have seen ~12KB or so, but trying is better than just failing. @@ -64,7 +64,7 @@ bool StripSuffixIo::determineStrippedLength() } if (i == 0) break; - i = std::max((int64_t)0, i - chunkSize); + i = std::max((int64)0, i - chunkSize); } if (i > 0) @@ -75,7 +75,7 @@ bool StripSuffixIo::determineStrippedLength() // The comment length (u16) is located 20 bytes from the start of the EOCD record if (seek(i + 20) == 0) return false; - uint8_t buffer[2]; + uint8 buffer[2]; const auto n = read(buffer, 2); if (n <= 0) return false; @@ -96,17 +96,17 @@ bool StripSuffixIo::determineStrippedLength() return true; } -int64_t StripSuffixIo::read(void* buf, uint64_t len) +int64 StripSuffixIo::read(void *buf, uint64 len) { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return -1; } - const auto ret = std::fread(buf, 1, len, file); - if (ret == 0) + int64 r = file->read(buf, (int64) len); + if (r == 0) { - if (std::feof(file)) + if (file->isEOF()) { PHYSFS_setErrorCode(PHYSFS_ERR_OK); return 0; @@ -117,85 +117,59 @@ int64_t StripSuffixIo::read(void* buf, uint64_t len) return -1; } } - else if (ret < len && std::ferror(file)) - { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } PHYSFS_setErrorCode(PHYSFS_ERR_OK); - return ret; + return r; } -int64_t StripSuffixIo::write(const void* /*buf*/, uint64_t /*len*/) +int64 StripSuffixIo::write(const void */*buf*/, uint64 /*len*/) { PHYSFS_setErrorCode(PHYSFS_ERR_READ_ONLY); return -1; } -int64_t StripSuffixIo::seek(uint64_t offset) +int64 StripSuffixIo::seek(uint64 offset) { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return 0; } - const auto ret = std::fseek(file, offset, SEEK_SET); - PHYSFS_setErrorCode(ret != 0 ? PHYSFS_ERR_OS_ERROR : PHYSFS_ERR_OK); - return ret == 0 ? 1 : 0; + bool success = file->seek(offset, Stream::SEEKORIGIN_BEGIN); + PHYSFS_setErrorCode(success ? PHYSFS_ERR_OK : PHYSFS_ERR_OS_ERROR); + return success ? 1 : 0; } -int64_t StripSuffixIo::tell() +int64 StripSuffixIo::tell() { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return -1; } - return std::ftell(file); + return file->tell(); } -int64_t StripSuffixIo::length() +int64 StripSuffixIo::length() { return strippedLength_; } -int64_t StripSuffixIo::flush() +int64 StripSuffixIo::flush() { if (!file) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); return 0; } - return std::fflush(file) == 0 ? 1 : 0; -} - -int64_t StripSuffixIo::fullLength() -{ - assert(file); - const auto cur = std::ftell(file); - if (cur == -1) + try + { + return file->flush() ? 1 : 0; + } + catch (love::Exception &) { PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; + return 0; } - if (std::fseek(file, 0, SEEK_END) != 0) - { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } - const auto len = std::ftell(file); - if (len == -1) - { - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } - if (std::fseek(file, cur, SEEK_SET) != 0) - { - // We do have the length now, but something is wrong, so we return an error anyways - PHYSFS_setErrorCode(PHYSFS_ERR_OS_ERROR); - return -1; - } - return len; } } // physfs diff --git a/src/modules/filesystem/physfs/PhysfsIo.h b/src/modules/filesystem/physfs/PhysfsIo.h index 35b92cc6c..764df9390 100644 --- a/src/modules/filesystem/physfs/PhysfsIo.h +++ b/src/modules/filesystem/physfs/PhysfsIo.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,11 +21,11 @@ #ifndef LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H #define LOVE_FILESYSTEM_PHYSFS_PHYSFSIO_H -#include -#include -#include - #include "libraries/physfs/physfs.h" +#include "common/int.h" +#include "filesystem/NativeFile.h" + +#include namespace love { @@ -61,54 +61,54 @@ protected: private: // Returns: number of bytes read, 0 on EOF, -1 on failure - static PHYSFS_sint64 staticRead(struct PHYSFS_Io* io, void* buf, PHYSFS_uint64 len) + static PHYSFS_sint64 staticRead(struct PHYSFS_Io *io, void *buf, PHYSFS_uint64 len) { return derived(io)->read(buf, len); } // Returns: number of bytes written, -1 on failure - static PHYSFS_sint64 staticWrite(struct PHYSFS_Io* io, const void* buf, PHYSFS_uint64 len) + static PHYSFS_sint64 staticWrite(struct PHYSFS_Io *io, const void *buf, PHYSFS_uint64 len) { return derived(io)->write(buf, len); } // Returns: non-zero on success, zero on error - static int staticSeek(struct PHYSFS_Io* io, PHYSFS_uint64 offset) + static int staticSeek(struct PHYSFS_Io *io, PHYSFS_uint64 offset) { return derived(io)->seek(offset); } // Returns: current offset from start, -1 on error - static PHYSFS_sint64 staticTell(struct PHYSFS_Io* io) + static PHYSFS_sint64 staticTell(struct PHYSFS_Io *io) { return derived(io)->tell(); } // Returns: total size in bytes, -1 on error - static PHYSFS_sint64 staticLength(struct PHYSFS_Io* io) + static PHYSFS_sint64 staticLength(struct PHYSFS_Io *io) { return derived(io)->length(); } - static struct PHYSFS_Io* staticDuplicate(struct PHYSFS_Io* io) + static struct PHYSFS_Io *staticDuplicate(struct PHYSFS_Io *io) { // Just use copy constructor return new Derived(*derived(io)); } // Returns: non-zero on success, zero on error - static int staticFlush(struct PHYSFS_Io* io) + static int staticFlush(struct PHYSFS_Io *io) { return derived(io)->flush(); } - static void staticDestroy(struct PHYSFS_Io* io) + static void staticDestroy(struct PHYSFS_Io *io) { // Just use destructor delete derived(io); } - static Derived* derived(PHYSFS_Io* io) + static Derived* derived(PHYSFS_Io *io) { return static_cast(reinterpret_cast(io->opaque)); } @@ -116,47 +116,52 @@ private: struct StripSuffixIo : public PhysfsIo { - static const uint32_t version = 0; + static const uint32 version = 0; std::string filename; - FILE* file = nullptr; + NativeFile *file = nullptr; // The constructor is private in favor of this function to prevent stack allocation // because Physfs will take ownership of this object and call destroy on it later. - static StripSuffixIo* create(std::string f) { return new StripSuffixIo(f); } + static StripSuffixIo *create(const std::string &f) { return new StripSuffixIo(f); } virtual ~StripSuffixIo() { if (file) { - std::fclose(file); + file->release(); } } - StripSuffixIo(const StripSuffixIo& other) + StripSuffixIo(const StripSuffixIo &other) : StripSuffixIo(other.filename) { } bool determineStrippedLength(); - int64_t read(void* buf, uint64_t len); - int64_t write(const void* buf, uint64_t len); - int64_t seek(uint64_t offset); - int64_t tell(); - int64_t length(); - int64_t flush(); + int64 read(void *buf, uint64 len); + int64 write(const void *buf, uint64 len); + int64 seek(uint64 offset); + int64 tell(); + int64 length(); + int64 flush(); private: - StripSuffixIo(std::string f) - : filename(std::move(f)) - , file(std::fopen(filename.c_str(), "rb")) + StripSuffixIo(const std::string &f) + : filename(f) + , file(nullptr) { + try + { + file = new NativeFile(f, File::MODE_READ); + } + catch (love::Exception &) + { + } } - int64_t fullLength(); - int64_t strippedLength_ = -1; }; diff --git a/src/modules/filesystem/wrap_File.cpp b/src/modules/filesystem/wrap_File.cpp index 998133047..4fa851a76 100644 --- a/src/modules/filesystem/wrap_File.cpp +++ b/src/modules/filesystem/wrap_File.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_File.h b/src/modules/filesystem/wrap_File.h index e935436bc..10277996f 100644 --- a/src/modules/filesystem/wrap_File.h +++ b/src/modules/filesystem/wrap_File.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_FileData.cpp b/src/modules/filesystem/wrap_FileData.cpp index 1135a5c1a..00e288fe4 100644 --- a/src/modules/filesystem/wrap_FileData.cpp +++ b/src/modules/filesystem/wrap_FileData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_FileData.h b/src/modules/filesystem/wrap_FileData.h index 0f036f365..58b870df0 100644 --- a/src/modules/filesystem/wrap_FileData.h +++ b/src/modules/filesystem/wrap_FileData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_Filesystem.cpp b/src/modules/filesystem/wrap_Filesystem.cpp index 13d5e48f9..65ed25eec 100644 --- a/src/modules/filesystem/wrap_Filesystem.cpp +++ b/src/modules/filesystem/wrap_Filesystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,6 +35,7 @@ // SDL #include +#include // STL #include @@ -987,7 +988,12 @@ int extloader(lua_State *L) // We look for both loveopen_ and luaopen_, so libraries with specific love support // can tell when they've been loaded by love. - void *func = SDL_LoadFunction(handle, ("loveopen_" + tokenized_function).c_str()); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_FunctionPointer func = nullptr; +#else + void *func = nullptr; +#endif + func = SDL_LoadFunction(handle, ("loveopen_" + tokenized_function).c_str()); if (!func) func = SDL_LoadFunction(handle, ("luaopen_" + tokenized_function).c_str()); diff --git a/src/modules/filesystem/wrap_Filesystem.h b/src/modules/filesystem/wrap_Filesystem.h index c32f794d9..d092ffac0 100644 --- a/src/modules/filesystem/wrap_Filesystem.h +++ b/src/modules/filesystem/wrap_Filesystem.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_NativeFile.cpp b/src/modules/filesystem/wrap_NativeFile.cpp index 7dacb76c9..ca5a39130 100644 --- a/src/modules/filesystem/wrap_NativeFile.cpp +++ b/src/modules/filesystem/wrap_NativeFile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/filesystem/wrap_NativeFile.h b/src/modules/filesystem/wrap_NativeFile.h index 8121f598a..aaa62569c 100644 --- a/src/modules/filesystem/wrap_NativeFile.h +++ b/src/modules/filesystem/wrap_NativeFile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/BMFontRasterizer.cpp b/src/modules/font/BMFontRasterizer.cpp index 660c4ce35..b08c2a621 100644 --- a/src/modules/font/BMFontRasterizer.cpp +++ b/src/modules/font/BMFontRasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -343,6 +343,7 @@ GlyphData *BMFontRasterizer::getGlyphDataForIndex(int index) const uint8 *pixels = (uint8 *) g->getData(); const uint8 *ipixels = (const uint8 *) imagedata->getData(); + // Always lock the mutex since the user can't know when to do it. love::thread::Lock lock(imagedata->getMutex()); // Copy the subsection of the texture from the ImageData to the GlyphData. diff --git a/src/modules/font/BMFontRasterizer.h b/src/modules/font/BMFontRasterizer.h index 3d4a452f8..43b5a84c4 100644 --- a/src/modules/font/BMFontRasterizer.h +++ b/src/modules/font/BMFontRasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/Font.cpp b/src/modules/font/Font.cpp index 818e3facf..e81b06a75 100644 --- a/src/modules/font/Font.cpp +++ b/src/modules/font/Font.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,7 +34,8 @@ namespace font // Default TrueType font, gzip-compressed. #include "NotoSans-Regular.ttf.gzip.h" -Font::Font() +Font::Font(const char *name) + : Module(M_FONT, name) { auto compressedbytes = (const char *) NotoSans_Regular_ttf_gzip; size_t compressedsize = NotoSans_Regular_ttf_gzip_len; @@ -45,14 +46,9 @@ Font::Font() defaultFontData.set(new data::ByteData(fontdata, rawsize, true), Acquire::NORETAIN); } -Rasterizer *Font::newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting) +Rasterizer *Font::newTrueTypeRasterizer(int size, const TrueTypeRasterizer::Settings &settings) { - return newTrueTypeRasterizer(defaultFontData.get(), size, hinting); -} - -Rasterizer *Font::newTrueTypeRasterizer(int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) -{ - return newTrueTypeRasterizer(defaultFontData.get(), size, dpiscale, hinting); + return newTrueTypeRasterizer(defaultFontData.get(), size, settings); } Rasterizer *Font::newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector &images, float dpiscale) @@ -78,12 +74,7 @@ Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, const std::st throw love::Exception("UTF-8 decoding error: %s", e.what()); } - return newImageRasterizer(data, &glyphs[0], (int) glyphs.size(), extraspacing, dpiscale); -} - -Rasterizer *Font::newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int numglyphs, int extraspacing, float dpiscale) -{ - return new ImageRasterizer(data, glyphs, numglyphs, extraspacing, dpiscale); + return new ImageRasterizer(data, glyphs.data(), (int) glyphs.size(), extraspacing, dpiscale); } GlyphData *Font::newGlyphData(Rasterizer *r, const std::string &text) diff --git a/src/modules/font/Font.h b/src/modules/font/Font.h index ed01557df..2fb1a69ea 100644 --- a/src/modules/font/Font.h +++ b/src/modules/font/Font.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,27 +43,23 @@ class Font : public Module public: - Font(); virtual ~Font() {} virtual Rasterizer *newRasterizer(love::filesystem::FileData *data) = 0; - virtual Rasterizer *newTrueTypeRasterizer(int size, TrueTypeRasterizer::Hinting hinting); - virtual Rasterizer *newTrueTypeRasterizer(int size, float dpiscale, TrueTypeRasterizer::Hinting hinting); - virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) = 0; - virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) = 0; + Rasterizer *newTrueTypeRasterizer(int size, const TrueTypeRasterizer::Settings &settings); + virtual Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, const TrueTypeRasterizer::Settings &settings) = 0; virtual Rasterizer *newBMFontRasterizer(love::filesystem::FileData *fontdef, const std::vector &images, float dpiscale); virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, const std::string &glyphs, int extraspacing, float dpiscale); - virtual Rasterizer *newImageRasterizer(love::image::ImageData *data, uint32 *glyphs, int length, int extraspacing, float dpiscale); virtual GlyphData *newGlyphData(Rasterizer *r, const std::string &glyph); virtual GlyphData *newGlyphData(Rasterizer *r, uint32 glyph); - // Implement Module. - virtual ModuleType getModuleType() const { return M_FONT; } - virtual const char *getName() const = 0; +protected: + + Font(const char *name); private: diff --git a/src/modules/font/GenericShaper.cpp b/src/modules/font/GenericShaper.cpp index ef5854602..813f31a0a 100644 --- a/src/modules/font/GenericShaper.cpp +++ b/src/modules/font/GenericShaper.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -151,8 +151,7 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran float w = 0.0f; float outwidth = 0.0f; float widthbeforelastspace = 0.0f; - int wrapindex = -1; - int lastspaceindex = -1; + int firstindexafterspace = -1; for (int i = (int)range.getMin(); i <= (int)range.getMax(); i++) { @@ -166,37 +165,48 @@ int GenericShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ran float newwidth = w + getKerning(prevglyph, g) + getGlyphAdvance(g); - // Only wrap when there's a non-space character. - if (newwidth > wraplimit && !isWhitespace(g)) - { - // Rewind to the last seen space when wrapping. - if (lastspaceindex != -1) - { - wrapindex = lastspaceindex; - outwidth = widthbeforelastspace; - } - break; - } - // Don't count trailing spaces in the output width. if (isWhitespace(g)) { - lastspaceindex = i; if (!isWhitespace(prevglyph)) widthbeforelastspace = w; } else + { + if (isWhitespace(prevglyph)) + firstindexafterspace = i; + + // Only wrap when there's a non-space character. + if (newwidth > wraplimit) + { + // If this is the first character, wrap from the next one instead of this one. + int wrapindex = i > (int)range.first ? i : (int)range.first + 1; + + // Rewind to after the last seen space when wrapping. + if (firstindexafterspace != -1) + { + wrapindex = firstindexafterspace; + outwidth = widthbeforelastspace; + } + + if (width) + *width = outwidth; + + return wrapindex; + } + outwidth = newwidth; + } w = newwidth; prevglyph = g; - wrapindex = i; } if (width) *width = outwidth; - return wrapindex; + // There wasn't any wrap in the middle of the range. + return range.last + 1; } } // font diff --git a/src/modules/font/GenericShaper.h b/src/modules/font/GenericShaper.h index c77b5b309..49763d789 100644 --- a/src/modules/font/GenericShaper.h +++ b/src/modules/font/GenericShaper.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/GlyphData.cpp b/src/modules/font/GlyphData.cpp index 8b1d4c285..8db2e9ea2 100644 --- a/src/modules/font/GlyphData.cpp +++ b/src/modules/font/GlyphData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/GlyphData.h b/src/modules/font/GlyphData.h index 0f214cb4f..4e4791538 100644 --- a/src/modules/font/GlyphData.h +++ b/src/modules/font/GlyphData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/ImageRasterizer.cpp b/src/modules/font/ImageRasterizer.cpp index 93b71b894..00adc5f96 100644 --- a/src/modules/font/ImageRasterizer.cpp +++ b/src/modules/font/ImageRasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -90,7 +90,7 @@ GlyphData *ImageRasterizer::getGlyphDataForIndex(int index) const if (gm.width == 0) return g; - // We don't want another thread modifying our ImageData mid-copy. + // Always lock the mutex since the user can't know when to do it. love::thread::Lock lock(imageData->getMutex()); Color32 *gdpixels = (Color32 *) g->getData(); @@ -118,9 +118,6 @@ void ImageRasterizer::load(const uint32 *glyphs, int glyphcount) int imgw = imageData->getWidth(); int imgh = imageData->getHeight(); - // We don't want another thread modifying our ImageData mid-parse. - love::thread::Lock lock(imageData->getMutex()); - // Set the only metric that matters metrics.height = imgh; diff --git a/src/modules/font/ImageRasterizer.h b/src/modules/font/ImageRasterizer.h index 538b6dbd5..266a61a24 100644 --- a/src/modules/font/ImageRasterizer.h +++ b/src/modules/font/ImageRasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/Rasterizer.cpp b/src/modules/font/Rasterizer.cpp index 53fa2d7f3..c5ff73f84 100644 --- a/src/modules/font/Rasterizer.cpp +++ b/src/modules/font/Rasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/Rasterizer.h b/src/modules/font/Rasterizer.h index 67575edd6..20174e498 100644 --- a/src/modules/font/Rasterizer.h +++ b/src/modules/font/Rasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/TextShaper.cpp b/src/modules/font/TextShaper.cpp index 43854e719..555ef598e 100644 --- a/src/modules/font/TextShaper.cpp +++ b/src/modules/font/TextShaper.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -303,10 +303,10 @@ void TextShaper::getWrap(const ColoredCodepoints &codepoints, float wraplimit, s float width = 0.0f; int wrapindex = computeWordWrapIndex(codepoints, r, wraplimit, &width); - if (wrapindex >= (int) i) + if (wrapindex > (int) i) { - r = Range(i, (size_t) wrapindex + 1 - i); - i = (size_t)wrapindex + 1; + r = Range(i, (size_t) wrapindex - i); + i = (size_t)wrapindex; } else { diff --git a/src/modules/font/TextShaper.h b/src/modules/font/TextShaper.h index b5417514c..9ddf7f9e1 100644 --- a/src/modules/font/TextShaper.h +++ b/src/modules/font/TextShaper.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/TrueTypeRasterizer.cpp b/src/modules/font/TrueTypeRasterizer.cpp index cd4b6f087..6404fd4fd 100644 --- a/src/modules/font/TrueTypeRasterizer.cpp +++ b/src/modules/font/TrueTypeRasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/TrueTypeRasterizer.h b/src/modules/font/TrueTypeRasterizer.h index 51ea65c8a..1a158a39a 100644 --- a/src/modules/font/TrueTypeRasterizer.h +++ b/src/modules/font/TrueTypeRasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ // LOVE #include "Rasterizer.h" #include "common/StringMap.h" +#include "common/Optional.h" namespace love { @@ -45,6 +46,12 @@ public: HINTING_MAX_ENUM }; + struct Settings + { + Hinting hinting = HINTING_NORMAL; + OptionalFloat dpiScale; + }; + virtual ~TrueTypeRasterizer() {} static bool getConstant(const char *in, Hinting &out); diff --git a/src/modules/font/freetype/Font.cpp b/src/modules/font/freetype/Font.cpp index ec7fe9c27..1e8f61b46 100644 --- a/src/modules/font/freetype/Font.cpp +++ b/src/modules/font/freetype/Font.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -36,6 +36,7 @@ namespace freetype { Font::Font() + : love::font::Font("love.font.freetype") { if (FT_Init_FreeType(&library)) throw love::Exception("TrueTypeFont Loading error: FT_Init_FreeType failed"); @@ -49,31 +50,21 @@ Font::~Font() Rasterizer *Font::newRasterizer(love::filesystem::FileData *data) { if (TrueTypeRasterizer::accepts(library, data)) - return newTrueTypeRasterizer(data, 12, TrueTypeRasterizer::HINTING_NORMAL); + return newTrueTypeRasterizer(data, 12, font::TrueTypeRasterizer::Settings()); else if (BMFontRasterizer::accepts(data)) return newBMFontRasterizer(data, {}, 1.0f); throw love::Exception("Invalid font file: %s", data->getFilename().c_str()); } -Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) +Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, const font::TrueTypeRasterizer::Settings &settings) { - float dpiscale = 1.0f; + float defaultdpiscale = 1.0f; auto window = Module::getInstance(Module::M_WINDOW); if (window != nullptr) - dpiscale = window->getDPIScale(); + defaultdpiscale = window->getDPIScale(); - return newTrueTypeRasterizer(data, size, dpiscale, hinting); -} - -Rasterizer *Font::newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) -{ - return new TrueTypeRasterizer(library, data, size, dpiscale, hinting); -} - -const char *Font::getName() const -{ - return "love.font.freetype"; + return new TrueTypeRasterizer(library, data, size, settings, defaultdpiscale); } } // freetype diff --git a/src/modules/font/freetype/Font.h b/src/modules/font/freetype/Font.h index 8d023cf48..c946925ad 100644 --- a/src/modules/font/freetype/Font.h +++ b/src/modules/font/freetype/Font.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,11 +45,7 @@ public: // Implements Font Rasterizer *newRasterizer(love::filesystem::FileData *data) override; - Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, TrueTypeRasterizer::Hinting hinting) override; - Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, float dpiscale, TrueTypeRasterizer::Hinting hinting) override; - - // Implement Module - const char *getName() const override; + Rasterizer *newTrueTypeRasterizer(love::Data *data, int size, const font::TrueTypeRasterizer::Settings &settings) override; private: diff --git a/src/modules/font/freetype/HarfbuzzShaper.cpp b/src/modules/font/freetype/HarfbuzzShaper.cpp index b38859741..cd595c888 100644 --- a/src/modules/font/freetype/HarfbuzzShaper.cpp +++ b/src/modules/font/freetype/HarfbuzzShaper.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -153,18 +153,18 @@ void HarfbuzzShaper::computeBufferRanges(const ColoredCodepoints &codepoints, Ra hb_shape(hbFonts[rasti], hbb, nullptr, 0); - int glyphcount = (int)hb_buffer_get_length(hbb); + size_t glyphcount = (size_t)hb_buffer_get_length(hbb); const hb_glyph_info_t *glyphinfos = hb_buffer_get_glyph_infos(hbb, nullptr); hb_direction_t direction = hb_buffer_get_direction(hbb); fallbackranges.clear(); - for (int i = 0; i < glyphcount; i++) + for (size_t i = 0; i < glyphcount; i++) { if (isValidGlyph(glyphinfos[i].codepoint, codepoints.cps, glyphinfos[i].cluster)) { if (bufferranges.empty() || bufferranges.back().index != rasti || bufferranges.back().range.getMax() + 1 != i) - bufferranges.push_back({(int)rasti, (int)glyphinfos[i].cluster, Range(i, 1)}); + bufferranges.push_back({rasti, (int)glyphinfos[i].cluster, Range(i, 1)}); else bufferranges.back().range.last++; } @@ -247,7 +247,7 @@ void HarfbuzzShaper::computeGlyphPositions(const ColoredCodepoints &codepoints, // TODO: this doesn't handle situations where the user inserted a color // change in the middle of some characters that get combined into a single // cluster. - if (colors && colorindex < ncolors && codepoints.colors[colorindex].index == info.cluster) + if (colors && colorindex < ncolors && codepoints.colors[colorindex].index == (int)info.cluster) { colorToAdd.set(codepoints.colors[colorindex].color); colorindex++; @@ -273,7 +273,7 @@ void HarfbuzzShaper::computeGlyphPositions(const ColoredCodepoints &codepoints, continue; // This is a glyph index at this point, despite the name. - GlyphIndex gindex = { (int) info.codepoint, bufferrange.index }; + GlyphIndex gindex = { (int) info.codepoint, (int)bufferrange.index }; if (clustercodepoint == '\t' && isUsingSpacesForTab()) { @@ -335,8 +335,7 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra float w = 0.0f; float outwidth = 0.0f; float widthbeforelastspace = 0.0f; - int wrapindex = -1; - int lastspaceindex = -1; + int firstindexafterspace = -1; uint32 prevcodepoint = 0; @@ -376,38 +375,49 @@ int HarfbuzzShaper::computeWordWrapIndex(const ColoredCodepoints &codepoints, Ra float newwidth = w + floorf((glyphpos.x_advance >> 6) / dpiScales[0] + 0.5f); - // Only wrap when there's a non-space character. - if (newwidth > wraplimit && !isWhitespace(clustercodepoint)) - { - // Rewind to the last seen space when wrapping. - if (lastspaceindex != -1) - { - wrapindex = lastspaceindex; - outwidth = widthbeforelastspace; - } - break; - } - // Don't count trailing spaces in the output width. if (isWhitespace(clustercodepoint)) { - lastspaceindex = info.cluster; if (!isWhitespace(prevcodepoint)) widthbeforelastspace = w; } else + { + if (isWhitespace(prevcodepoint)) + firstindexafterspace = info.cluster; + + // Only wrap when there's a non-space character. + if (newwidth > wraplimit) + { + // If this is the first character, wrap from the next one instead of this one. + int wrapindex = (int)info.cluster > (int)range.first ? (int)info.cluster : (int)range.first + 1; + + // Rewind to after the last seen space when wrapping. + if (firstindexafterspace != -1) + { + wrapindex = firstindexafterspace; + outwidth = widthbeforelastspace; + } + + if (width) + *width = outwidth; + + return wrapindex; + } + outwidth = newwidth; + } w = newwidth; prevcodepoint = clustercodepoint; - wrapindex = info.cluster; } } if (width) *width = outwidth; - return wrapindex; + // There wasn't any wrap in the middle of the range. + return (int) range.last + 1; } } // freetype diff --git a/src/modules/font/freetype/HarfbuzzShaper.h b/src/modules/font/freetype/HarfbuzzShaper.h index 3a71a5b8b..81e4f3c65 100644 --- a/src/modules/font/freetype/HarfbuzzShaper.h +++ b/src/modules/font/freetype/HarfbuzzShaper.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -53,7 +53,7 @@ private: struct BufferRange { - int index; + size_t index; int codepointStart; Range range; }; diff --git a/src/modules/font/freetype/TrueTypeRasterizer.cpp b/src/modules/font/freetype/TrueTypeRasterizer.cpp index a98ce5a35..c88deedb3 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.cpp +++ b/src/modules/font/freetype/TrueTypeRasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -33,12 +33,12 @@ namespace font namespace freetype { -TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, love::Data *data, int size, float dpiscale, Hinting hinting) +TrueTypeRasterizer::TrueTypeRasterizer(FT_Library library, love::Data *data, int size, const Settings &settings, float defaultdpiscale) : data(data) - , hinting(hinting) + , hinting(settings.hinting) { - this->dpiScale = dpiscale; - size = floorf(size * dpiscale + 0.5f); + dpiScale = settings.dpiScale.get(defaultdpiscale); + size = floorf(size * dpiScale + 0.5f); if (size <= 0) throw love::Exception("Invalid TrueType font size: %d", size); diff --git a/src/modules/font/freetype/TrueTypeRasterizer.h b/src/modules/font/freetype/TrueTypeRasterizer.h index e97e91967..534034ab3 100644 --- a/src/modules/font/freetype/TrueTypeRasterizer.h +++ b/src/modules/font/freetype/TrueTypeRasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -44,7 +44,7 @@ class TrueTypeRasterizer : public love::font::TrueTypeRasterizer { public: - TrueTypeRasterizer(FT_Library library, love::Data *data, int size, float dpiscale, Hinting hinting); + TrueTypeRasterizer(FT_Library library, love::Data *data, int size, const Settings &settings, float defaultdpiscale); virtual ~TrueTypeRasterizer(); // Implement Rasterizer diff --git a/src/modules/font/wrap_Font.cpp b/src/modules/font/wrap_Font.cpp index b10e1d376..a43377bb0 100644 --- a/src/modules/font/wrap_Font.cpp +++ b/src/modules/font/wrap_Font.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -64,30 +64,65 @@ int w_newRasterizer(lua_State *L) } } +static TrueTypeRasterizer::Settings luax_checktruetypesettings(lua_State* L, int startidx) +{ + TrueTypeRasterizer::Settings s; + + if (lua_type(L, startidx) == LUA_TSTRING) + { + // Legacy parameters. + const char *hintstr = lua_isnoneornil(L, startidx) ? nullptr : luaL_checkstring(L, startidx); + if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, s.hinting)) + luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(s.hinting), hintstr); + + if (!lua_isnoneornil(L, startidx + 1)) + s.dpiScale.set((float)luaL_checknumber(L, startidx + 1)); + } + else + { + luaL_checktype(L, startidx, LUA_TTABLE); + + lua_getfield(L, startidx, "hinting"); + if (!lua_isnoneornil(L, -1)) + { + const char *hintstr = luaL_checkstring(L, -1); + if (!TrueTypeRasterizer::getConstant(hintstr, s.hinting)) + luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(s.hinting), hintstr); + } + lua_pop(L, 1); + + lua_getfield(L, startidx, "dpiscale"); + if (!lua_isnoneornil(L, -1)) + s.dpiScale.set((float)luaL_checknumber(L, -1)); + lua_pop(L, 1); + } + + return s; +} + int w_newTrueTypeRasterizer(lua_State *L) { Rasterizer *t = nullptr; - TrueTypeRasterizer::Hinting hinting = TrueTypeRasterizer::HINTING_NORMAL; if (lua_type(L, 1) == LUA_TNUMBER || lua_isnone(L, 1)) { // First argument is a number: use the default TrueType font. int size = (int) luaL_optinteger(L, 1, 13); - const char *hintstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2); - if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) - return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr); + TrueTypeRasterizer::Settings settings; + if (!lua_isnoneornil(L, 2)) + settings = luax_checktruetypesettings(L, 2); - if (lua_isnoneornil(L, 3)) - luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, hinting); }); - else - { - float dpiscale = (float) luaL_checknumber(L, 3); - luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, dpiscale, hinting); }); - } + luax_catchexcept(L, [&](){ t = instance()->newTrueTypeRasterizer(size, settings); }); } else { + int size = (int) luaL_optinteger(L, 2, 12); + + TrueTypeRasterizer::Settings settings; + if (!lua_isnoneornil(L, 3)) + settings = luax_checktruetypesettings(L, 3); + love::Data *d = nullptr; if (luax_istype(L, 1, love::Data::type)) @@ -98,27 +133,10 @@ int w_newTrueTypeRasterizer(lua_State *L) else d = filesystem::luax_getfiledata(L, 1); - int size = (int) luaL_optinteger(L, 2, 12); - - const char *hintstr = lua_isnoneornil(L, 3) ? nullptr : luaL_checkstring(L, 3); - if (hintstr && !TrueTypeRasterizer::getConstant(hintstr, hinting)) - return luax_enumerror(L, "TrueType font hinting mode", TrueTypeRasterizer::getConstants(hinting), hintstr); - - if (lua_isnoneornil(L, 4)) - { - luax_catchexcept(L, - [&]() { t = instance()->newTrueTypeRasterizer(d, size, hinting); }, - [&](bool) { d->release(); } - ); - } - else - { - float dpiscale = (float) luaL_checknumber(L, 4); - luax_catchexcept(L, - [&]() { t = instance()->newTrueTypeRasterizer(d, size, dpiscale, hinting); }, - [&](bool) { d->release(); } - ); - } + luax_catchexcept(L, + [&]() { t = instance()->newTrueTypeRasterizer(d, size, settings); }, + [&](bool) { d->release(); } + ); } luax_pushtype(L, t); @@ -154,7 +172,7 @@ int w_newBMFontRasterizer(lua_State *L) lua_pop(L, 1); } } - else + else if (!lua_isnoneornil(L, 2)) { convimagedata(L, 2); image::ImageData *id = luax_checktype(L, 2); diff --git a/src/modules/font/wrap_Font.h b/src/modules/font/wrap_Font.h index ddbe327eb..a52de0ed0 100644 --- a/src/modules/font/wrap_Font.h +++ b/src/modules/font/wrap_Font.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/wrap_GlyphData.cpp b/src/modules/font/wrap_GlyphData.cpp index 68a232531..a411957dd 100644 --- a/src/modules/font/wrap_GlyphData.cpp +++ b/src/modules/font/wrap_GlyphData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/wrap_GlyphData.h b/src/modules/font/wrap_GlyphData.h index e71062fe3..59a6d257e 100644 --- a/src/modules/font/wrap_GlyphData.h +++ b/src/modules/font/wrap_GlyphData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/wrap_Rasterizer.cpp b/src/modules/font/wrap_Rasterizer.cpp index 2340b6abe..88a063c15 100644 --- a/src/modules/font/wrap_Rasterizer.cpp +++ b/src/modules/font/wrap_Rasterizer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/font/wrap_Rasterizer.h b/src/modules/font/wrap_Rasterizer.h index 0359656a9..83c8a6009 100644 --- a/src/modules/font/wrap_Rasterizer.h +++ b/src/modules/font/wrap_Rasterizer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Buffer.cpp b/src/modules/graphics/Buffer.cpp index 3ebbc61d1..d1b6e49fe 100644 --- a/src/modules/graphics/Buffer.cpp +++ b/src/modules/graphics/Buffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -29,12 +29,16 @@ namespace graphics love::Type Buffer::type("GraphicsBuffer", &Object::type); +int Buffer::bufferCount = 0; +int64 Buffer::totalGraphicsMemory = 0; + Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector &bufferformat, size_t size, size_t arraylength) : arrayLength(0) , arrayStride(0) , size(size) , usageFlags(settings.usageFlags) , dataUsage(settings.dataUsage) + , debugName(settings.debugName) , mapped(false) , mappedType(MAP_WRITE_INVALIDATE) , immutable(false) @@ -46,7 +50,6 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vectorgetCapabilities(); - bool supportsGLSL3 = caps.features[Graphics::FEATURE_GLSL3]; bool indexbuffer = usageFlags & BUFFERUSAGEFLAG_INDEX; bool vertexbuffer = usageFlags & BUFFERUSAGEFLAG_VERTEX; @@ -82,9 +85,6 @@ Buffer::Buffer(Graphics *gfx, const Settings &settings, const std::vector caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE]) throw love::Exception("Cannot create texel buffer: total number of values in the buffer (%d * %d) is too large for this system (maximum %d).", (int) dataMembers.size(), (int) arraylength, caps.limits[Graphics::LIMIT_TEXEL_BUFFER_SIZE]); + + ++bufferCount; + totalGraphicsMemory += size; } Buffer::~Buffer() { + totalGraphicsMemory -= size; + --bufferCount; } int Buffer::getDataMemberIndex(const std::string &name) const @@ -256,6 +258,20 @@ int Buffer::getDataMemberIndex(const std::string &name) const return -1; } +void Buffer::clear(size_t offset, size_t size) +{ + if (isImmutable()) + throw love::Exception("Cannot clear an immutable Buffer."); + else if (isMapped()) + throw love::Exception("Cannot clear a mapped Buffer."); + else if (offset + size > getSize()) + throw love::Exception("The given offset and size parameters to clear() are not within the Buffer's size."); + else if (offset % 4 != 0 || size % 4 != 0) + throw love::Exception("clear() must be used with offset and size parameters that are multiples of 4 bytes."); + + clearInternal(offset, size); +} + std::vector Buffer::getCommonFormatDeclaration(CommonFormat format) { switch (format) diff --git a/src/modules/graphics/Buffer.h b/src/modules/graphics/Buffer.h index 5ca409413..67fc6757e 100644 --- a/src/modules/graphics/Buffer.h +++ b/src/modules/graphics/Buffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ #include "common/config.h" #include "common/int.h" #include "common/Object.h" +#include "common/Optional.h" #include "vertex.h" #include "Resource.h" @@ -48,6 +49,9 @@ public: static love::Type type; + static int bufferCount; + static int64 totalGraphicsMemory; + static const size_t SHADER_STORAGE_BUFFER_MAX_STRIDE = 2048; enum MapType @@ -89,11 +93,13 @@ public: BufferUsageFlags usageFlags; BufferDataUsage dataUsage; bool zeroInitialize; + std::string debugName; Settings(uint32 usageflags, BufferDataUsage dataUsage) : usageFlags((BufferUsageFlags)usageflags) , dataUsage(dataUsage) , zeroInitialize(false) + , debugName() {} }; @@ -111,6 +117,7 @@ public: const DataMember &getDataMember(int index) const { return dataMembers[index]; } size_t getMemberOffset(int index) const { return dataMembers[index].offset; } int getDataMemberIndex(const std::string &name) const; + const std::string &getDebugName() const { return debugName; } void setImmutable(bool immutable) { this->immutable = immutable; }; bool isImmutable() const { return immutable; } @@ -134,7 +141,7 @@ public: /** * Reset the given portion of this buffer's data to 0. */ - virtual void clear(size_t offset, size_t size) = 0; + void clear(size_t offset, size_t size); /** * Copy a portion of this Buffer's data to another buffer, using the GPU. @@ -171,6 +178,8 @@ public: protected: + virtual void clearInternal(size_t offset, size_t size) = 0; + std::vector dataMembers; size_t arrayLength; size_t arrayStride; @@ -184,6 +193,8 @@ protected: // Usage hint. GL_[DYNAMIC, STATIC, STREAM]_DRAW. BufferDataUsage dataUsage; + std::string debugName; + bool mapped; MapType mappedType; bool immutable; diff --git a/src/modules/graphics/Deprecations.cpp b/src/modules/graphics/Deprecations.cpp index 92a5d51c5..7200dd32a 100644 --- a/src/modules/graphics/Deprecations.cpp +++ b/src/modules/graphics/Deprecations.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -74,12 +74,12 @@ void Deprecations::draw(Graphics *gfx) if (font.get() == nullptr) { - auto hinting = font::TrueTypeRasterizer::HINTING_NORMAL; + font::TrueTypeRasterizer::Settings settings; if (!isGammaCorrect() && gfx->getScreenDPIScale() <= 1.0) - hinting = font::TrueTypeRasterizer::HINTING_LIGHT; + settings.hinting = font::TrueTypeRasterizer::HINTING_LIGHT; - font.set(gfx->newDefaultFont(9, hinting), Acquire::NORETAIN); + font.set(gfx->newDefaultFont(9, settings), Acquire::NORETAIN); } gfx->flushBatchedDraws(); diff --git a/src/modules/graphics/Deprecations.h b/src/modules/graphics/Deprecations.h index 6014d1fe1..e2aeae419 100644 --- a/src/modules/graphics/Deprecations.h +++ b/src/modules/graphics/Deprecations.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Drawable.cpp b/src/modules/graphics/Drawable.cpp index 44762c9c1..5e4880913 100644 --- a/src/modules/graphics/Drawable.cpp +++ b/src/modules/graphics/Drawable.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Drawable.h b/src/modules/graphics/Drawable.h index 0703d3c62..6eb573aa8 100644 --- a/src/modules/graphics/Drawable.h +++ b/src/modules/graphics/Drawable.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index a4e3485b0..c5303b6ad 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Font.h b/src/modules/graphics/Font.h index 873fcc696..215c809e0 100644 --- a/src/modules/graphics/Font.h +++ b/src/modules/graphics/Font.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 098c886cc..7fc301682 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -180,11 +180,14 @@ Graphics::DisplayState::DisplayState() defaultSamplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_LINEAR; } -Graphics::Graphics() - : width(0) +Graphics::Graphics(const char *name) + : Module(M_GRAPHICS, name) + , width(0) , height(0) , pixelWidth(0) , pixelHeight(0) + , backbufferHasStencil(false) + , backbufferHasDepth(false) , created(false) , active(true) , batchedDrawState() @@ -195,6 +198,9 @@ Graphics::Graphics() , quadIndexBuffer(nullptr) , fanIndexBuffer(nullptr) , capabilities() + , defaultTextures() + , defaultTexelBuffers() + , defaultStorageBuffer(nullptr) , cachedShaderStages() { transformStack.reserve(16); @@ -217,6 +223,8 @@ Graphics::~Graphics() if (fanIndexBuffer != nullptr) fanIndexBuffer->release(); + releaseDefaultResources(); + // Clean up standard shaders before the active shader. If we do it after, // the active shader may try to activate a standard shader when deactivating // itself, which will cause problems since it calls Graphics methods in the @@ -294,13 +302,13 @@ Font *Graphics::newFont(love::font::Rasterizer *data) return new Font(data, states.back().defaultSamplerState); } -Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting) +Font *Graphics::newDefaultFont(int size, const font::TrueTypeRasterizer::Settings &settings) { auto fontmodule = Module::getInstance(M_FONT); if (!fontmodule) throw love::Exception("Font module has not been loaded."); - StrongRef r(fontmodule->newTrueTypeRasterizer(size, hinting), Acquire::NORETAIN); + StrongRef r(fontmodule->newTrueTypeRasterizer(size, settings), Acquire::NORETAIN); return newFont(r.get()); } @@ -399,7 +407,7 @@ Shader *Graphics::newShader(const std::vector &stagessource, const } - return newShaderInternal(stages); + return newShaderInternal(stages, options); } Shader *Graphics::newComputeShader(const std::string &source, const Shader::CompileOptions &options) @@ -415,7 +423,7 @@ Shader *Graphics::newComputeShader(const std::string &source, const Shader::Comp // shouldn't be much reuse. stages[SHADERSTAGE_COMPUTE].set(newShaderStage(SHADERSTAGE_COMPUTE, source, options, info, false)); - return newShaderInternal(stages); + return newShaderInternal(stages, options); } Buffer *Graphics::newBuffer(const Buffer::Settings &settings, DataFormat format, const void *data, size_t size, size_t arraylength) @@ -530,6 +538,198 @@ bool Graphics::validateShader(bool gles, const std::vector &stagess return Shader::validate(stages, err); } +Texture *Graphics::getDefaultTexture(TextureType type, DataBaseType dataType, bool depthSample) +{ + uint32 depthsampleindex = depthSample ? 1 : 0; + Texture *tex = defaultTextures[type][dataType][depthsampleindex]; + if (tex != nullptr) + return tex; + + Texture::Settings settings; + settings.type = type; + + switch (dataType) + { + case DATA_BASETYPE_INT: + settings.format = PIXELFORMAT_RGBA8_INT; + break; + case DATA_BASETYPE_UINT: + settings.format = PIXELFORMAT_RGBA8_UINT; + break; + case DATA_BASETYPE_FLOAT: + default: + settings.format = PIXELFORMAT_RGBA8_UNORM; + break; + } + + if (depthSample) + { + if (isPixelFormatSupported(PIXELFORMAT_DEPTH16_UNORM, PIXELFORMATUSAGE_SAMPLE)) + settings.format = PIXELFORMAT_DEPTH16_UNORM; + else if (isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGE_SAMPLE)) + settings.format = PIXELFORMAT_DEPTH24_UNORM; + else if (isPixelFormatSupported(PIXELFORMAT_DEPTH32_FLOAT, PIXELFORMATUSAGE_SAMPLE)) + settings.format = PIXELFORMAT_DEPTH32_FLOAT; + else // TODO? + settings.format = PIXELFORMAT_DEPTH24_UNORM; + } + + std::string name = "default_"; + + const char *tname = "unknown"; + Texture::getConstant(type, tname); + name += tname; + + const char *formatname = "unknown"; + love::getConstant(settings.format, formatname); + name += std::string("_") + formatname; + + settings.debugName = name; + + tex = newTexture(settings); + + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; + + if (depthSample) + s.depthSampleMode.set(COMPARE_ALWAYS); + + tex->setSamplerState(s); + + uint8 pixel[] = {255, 255, 255, 255}; + if (isPixelFormatInteger(settings.format)) + pixel[0] = pixel[1] = pixel[2] = pixel[3] = 1; + + for (int slice = 0; slice < (type == TEXTURE_CUBE ? 6 : 1); slice++) + tex->replacePixels(pixel, sizeof(pixel), slice, 0, {0, 0, 1, 1}, false); + + defaultTextures[type][dataType][depthsampleindex] = tex; + + return tex; +} + +Buffer *Graphics::getDefaultTexelBuffer(DataBaseType dataType) +{ + Buffer *buffer = defaultTexelBuffers[dataType]; + if (buffer != nullptr) + return buffer; + + Buffer::Settings settings(BUFFERUSAGEFLAG_TEXEL, BUFFERDATAUSAGE_STATIC); + settings.zeroInitialize = true; + settings.debugName = "default_texelbuffer_"; + + DataFormat format = DATAFORMAT_FLOAT; + switch (dataType) + { + case DATA_BASETYPE_FLOAT: + default: + format = DATAFORMAT_FLOAT; + settings.debugName += "float"; + break; + case DATA_BASETYPE_INT: + format = DATAFORMAT_INT32; + settings.debugName += "int"; + break; + case DATA_BASETYPE_UINT: + format = DATAFORMAT_UINT32; + settings.debugName += "uint"; + break; + } + + buffer = newBuffer(settings, format, nullptr, sizeof(float), 1); + + defaultTexelBuffers[dataType] = buffer; + + return buffer; +} + +Buffer *Graphics::getDefaultStorageBuffer() +{ + if (defaultStorageBuffer != nullptr) + return defaultStorageBuffer; + + Buffer::Settings settings(BUFFERUSAGEFLAG_SHADER_STORAGE, BUFFERDATAUSAGE_STATIC); + settings.zeroInitialize = true; + settings.debugName = "default_storagebuffer"; + + defaultStorageBuffer = newBuffer(settings, DATAFORMAT_FLOAT, nullptr, Buffer::SHADER_STORAGE_BUFFER_MAX_STRIDE, 0); + + return defaultStorageBuffer; +} + +void Graphics::releaseDefaultResources() +{ + for (int type = 0; type < TEXTURE_MAX_ENUM; type++) + { + for (int dataType = 0; dataType < DATA_BASETYPE_MAX_ENUM; dataType++) + { + for (int depthsample = 0; depthsample < 2; depthsample++) + { + if (defaultTextures[type][dataType][depthsample]) + defaultTextures[type][dataType][depthsample]->release(); + defaultTextures[type][dataType][depthsample] = nullptr; + } + } + } + + for (int dataType = 0; dataType < DATA_BASETYPE_MAX_ENUM; dataType++) + { + if (defaultTexelBuffers[dataType]) + defaultTexelBuffers[dataType]->release(); + defaultTexelBuffers[dataType] = nullptr; + } + + if (defaultStorageBuffer) + defaultStorageBuffer->release(); + defaultStorageBuffer = nullptr; +} + +Texture *Graphics::getTextureOrDefaultForActiveShader(Texture *tex) +{ + if (tex != nullptr) + return tex; + + Shader *shader = Shader::current; + + if (shader != nullptr) + { + auto texinfo = shader->getMainTextureInfo(); + if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM) + return getDefaultTexture(texinfo->textureType, texinfo->dataBaseType, texinfo->isDepthSampler); + } + + return getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT, false); +} + +void Graphics::validateStencilState(const StencilState &s) const +{ + if (s.action != STENCIL_KEEP) + { + const auto &rts = states.back().renderTargets; + love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); + + if (!isRenderTargetActive() && !backbufferHasStencil) + throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); + else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) + throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); + } +} + +void Graphics::validateDepthState(bool depthwrite) const +{ + if (depthwrite) + { + const auto &rts = states.back().renderTargets; + love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); + + if (!isRenderTargetActive() && !backbufferHasDepth) + throw love::Exception("The window must have depth enabled to draw to the main screen's depth buffer."); + else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) == 0 && (dstexture == nullptr || !isPixelFormatDepth(dstexture->getPixelFormat()))) + throw love::Exception("Drawing to the depth buffer with a Canvas active requires either depth=true or a custom depth-type Canvas to be used, in setCanvas."); + } +} + int Graphics::getWidth() const { return width; @@ -584,6 +784,11 @@ void Graphics::reset() origin(); } +void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight) +{ + backbufferChanged(width, height, pixelwidth, pixelheight, backbufferHasStencil, backbufferHasDepth, getRequestedBackbufferMSAA()); +} + /** * State functions. **/ @@ -613,7 +818,7 @@ void Graphics::restoreState(const DisplayState &s) setShader(s.shader.get()); setRenderTargets(s.renderTargets); - setStencilMode(s.stencil.action, s.stencil.compare, s.stencil.value, s.stencil.readMask, s.stencil.writeMask); + setStencilState(s.stencil); setDepthMode(s.depthTest, s.depthWrite); setColorMask(s.colorMask); @@ -689,7 +894,7 @@ void Graphics::restoreStateChecked(const DisplayState &s) setRenderTargets(s.renderTargets); if (!(s.stencil == cur.stencil)) - setStencilMode(s.stencil.action, s.stencil.compare, s.stencil.value, s.stencil.readMask, s.stencil.writeMask); + setStencilState(s.stencil); if (s.depthTest != cur.depthTest || s.depthWrite != cur.depthWrite) setDepthMode(s.depthTest, s.depthWrite); @@ -703,7 +908,7 @@ void Graphics::restoreStateChecked(const DisplayState &s) setDefaultSamplerState(s.defaultSamplerState); if (s.useCustomProjection) - setCustomProjection(s.customProjection); + setProjection(s.customProjection); else if (cur.useCustomProjection) resetProjection(); } @@ -731,7 +936,10 @@ void Graphics::checkSetDefaultFont() // Create a new default font if we don't have one yet. if (!defaultFont.get()) - defaultFont.set(newDefaultFont(13, font::TrueTypeRasterizer::HINTING_NORMAL), Acquire::NORETAIN); + { + font::TrueTypeRasterizer::Settings settings; + defaultFont.set(newDefaultFont(13, settings), Acquire::NORETAIN); + } states.back().font.set(defaultFont.get()); } @@ -807,36 +1015,36 @@ void Graphics::setRenderTargets(const RenderTargets &rts) if (firsttex == nullptr) return setRenderTarget(); - const auto &prevRTs = state.renderTargets; + const auto &prevRTsRef = state.renderTargets; - if (rtcount == (int) prevRTs.colors.size()) + if (rtcount == (int) prevRTsRef.colors.size()) { bool modified = false; for (int i = 0; i < rtcount; i++) { - if (rts.colors[i] != prevRTs.colors[i]) + if (rts.colors[i] != prevRTsRef.colors[i]) { modified = true; break; } } - if (!modified && rts.depthStencil != prevRTs.depthStencil) + if (!modified && rts.depthStencil != prevRTsRef.depthStencil) modified = true; - if (rts.temporaryRTFlags != prevRTs.temporaryRTFlags) + if (rts.temporaryRTFlags != prevRTsRef.temporaryRTFlags) modified = true; if (!modified) return; } + const RenderTargetsStrongRef prevRTs = prevRTsRef; + if (rtcount > capabilities.limits[LIMIT_RENDER_TARGETS]) throw love::Exception("This system can't simultaneously render to %d textures.", rtcount); - bool multiformatsupported = capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS]; - PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN; if (!rts.colors.empty()) firstcolorformat = rts.colors[0].texture->getPixelFormat(); @@ -877,9 +1085,6 @@ void Graphics::setRenderTargets(const RenderTargets &rts) if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh) throw love::Exception("All textures must have the same pixel dimensions."); - if (!multiformatsupported && format != firstcolorformat) - throw love::Exception("This system doesn't support multi-render-target rendering with different texture formats."); - if (c->getRequestedMSAA() != reqmsaa) throw love::Exception("All textures must have the same MSAA value."); @@ -925,7 +1130,7 @@ void Graphics::setRenderTargets(const RenderTargets &rts) PixelFormat dsformat = PIXELFORMAT_STENCIL8; if (wantsdepth && wantsstencil) dsformat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; - else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGEFLAGS_RENDERTARGET, false)) + else if (wantsdepth && isPixelFormatSupported(PIXELFORMAT_DEPTH24_UNORM, PIXELFORMATUSAGEFLAGS_RENDERTARGET)) dsformat = PIXELFORMAT_DEPTH24_UNORM; else if (wantsdepth) dsformat = PIXELFORMAT_DEPTH16_UNORM; @@ -963,6 +1168,13 @@ void Graphics::setRenderTargets(const RenderTargets &rts) resetProjection(); + // generateMipmaps can't be used for depth/stencil textures. + for (const auto &rt : prevRTs.colors) + { + if (rt.texture && rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) + rt.texture->generateMipmaps(); + } + // Clear/reset the temporary depth/stencil buffers. // TODO: make this deferred somehow to avoid double clearing if the user // also calls love.graphics.clear after setCanvas. @@ -982,6 +1194,8 @@ void Graphics::setRenderTarget() if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.texture == nullptr) return; + const RenderTargetsStrongRef prevRTs = state.renderTargets; + flushBatchedDraws(); setRenderTargetsInternal(RenderTargets(), pixelWidth, pixelHeight, isGammaCorrect()); @@ -989,6 +1203,13 @@ void Graphics::setRenderTarget() renderTargetSwitchCount++; resetProjection(); + + // generateMipmaps can't be used for depth/stencil textures. + for (const auto& rt : prevRTs.colors) + { + if (rt.texture && rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) + rt.texture->generateMipmaps(); + } } Graphics::RenderTargets Graphics::getRenderTargets() const @@ -1015,15 +1236,16 @@ bool Graphics::isRenderTargetActive() const bool Graphics::isRenderTargetActive(Texture *texture) const { + Texture *roottexture = texture->getRootViewInfo().texture; const auto &rts = states.back().renderTargets; for (const auto &rt : rts.colors) { - if (rt.texture.get() == texture) + if (rt.texture.get() && rt.texture->getRootViewInfo().texture == roottexture) return true; } - if (rts.depthStencil.texture.get() == texture) + if (rts.depthStencil.texture.get() && rts.depthStencil.texture->getRootViewInfo().texture == roottexture) return true; return false; @@ -1031,16 +1253,27 @@ bool Graphics::isRenderTargetActive(Texture *texture) const bool Graphics::isRenderTargetActive(Texture *texture, int slice) const { + const auto &rootinfo = texture->getRootViewInfo(); + slice += rootinfo.startLayer; + const auto &rts = states.back().renderTargets; for (const auto &rt : rts.colors) { - if (rt.texture.get() == texture && rt.slice == slice) - return true; + if (rt.texture.get()) + { + const auto &info = rt.texture->getRootViewInfo(); + if (rootinfo.texture == info.texture && rt.slice + info.startLayer == slice) + return true; + } } - if (rts.depthStencil.texture.get() == texture && rts.depthStencil.slice == slice) - return true; + if (rts.depthStencil.texture.get()) + { + const auto &info = rts.depthStencil.texture->getRootViewInfo(); + if (rootinfo.texture == info.texture && rts.depthStencil.slice + info.startLayer == slice) + return true; + } return false; } @@ -1219,19 +1452,39 @@ bool Graphics::getScissor(Rect &rect) const return state.scissor; } -void Graphics::setStencilMode() +void Graphics::setStencilMode(StencilMode mode, int value) { - setStencilMode(STENCIL_KEEP, COMPARE_ALWAYS, 0, LOVE_UINT32_MAX, LOVE_UINT32_MAX); + setStencilState(computeStencilState(mode, value)); + if (mode == STENCIL_MODE_DRAW) + setColorMask({ false, false, false, false }); + else + setColorMask({ true, true, true, true }); } -void Graphics::getStencilMode(StencilAction &action, CompareMode &compare, int &value, uint32 &readmask, uint32 &writemask) const +void Graphics::setStencilMode() +{ + setStencilState(computeStencilState(STENCIL_MODE_OFF, 0)); + setColorMask({ true, true, true, true }); +} + +StencilMode Graphics::getStencilMode(int &value) const +{ + const DisplayState& state = states.back(); + StencilMode mode = computeStencilMode(state.stencil); + value = state.stencil.value; + return mode; +} + +void Graphics::setStencilState() +{ + StencilState s; + setStencilState(s); +} + +const StencilState &Graphics::getStencilState() const { const DisplayState &state = states.back(); - action = state.stencil.action; - compare = state.stencil.compare; - value = state.stencil.value; - readmask = state.stencil.readMask; - writemask = state.stencil.writeMask; + return state.stencil; } void Graphics::setDepthMode() @@ -1346,9 +1599,6 @@ void Graphics::captureScreenshot(const ScreenshotInfo &info) void Graphics::copyBuffer(Buffer *source, Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) { - if (!capabilities.features[FEATURE_COPY_BUFFER]) - throw love::Exception("Buffer copying is not supported on this system."); - Range sourcerange(sourceoffset, size); Range destrange(destoffset, size); @@ -1382,9 +1632,6 @@ void Graphics::copyTextureToBuffer(Texture *source, Buffer *dest, int slice, int { if (!source->isRenderTarget()) throw love::Exception("Copying a non-render target Texture to a Buffer is not supported on this system."); - - if (!capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER]) - throw love::Exception("Copying a render target Texture to a Buffer is not supported on this system."); } PixelFormat format = source->getPixelFormat(); @@ -1470,9 +1717,6 @@ void Graphics::copyTextureToBuffer(Texture *source, Buffer *dest, int slice, int void Graphics::copyBufferToTexture(Buffer *source, Texture *dest, size_t sourceoffset, int sourcewidth, int slice, int mipmap, const Rect &rect) { - if (!capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE]) - throw love::Exception("Copying a Buffer to a Texture is not supported on this system."); - if (source->getDataUsage() == BUFFERDATAUSAGE_READBACK) throw love::Exception("Buffers created with 'readback' data usage cannot be used as a copy source."); @@ -1782,7 +2026,7 @@ void Graphics::flushBatchedDraws() { auto &sbstate = batchedDrawState; - if (sbstate.vertexCount == 0 && sbstate.indexCount == 0) + if ((sbstate.vertexCount == 0 && sbstate.indexCount == 0) || sbstate.flushing) return; VertexAttributes attributes; @@ -1807,6 +2051,8 @@ void Graphics::flushBatchedDraws() if (attributes.enableBits == 0) return; + sbstate.flushing = true; + Colorf nc = getColor(); if (attributes.isEnabled(ATTRIB_COLOR)) setColor(Colorf(1.0f, 1.0f, 1.0f, 1.0f)); @@ -1822,7 +2068,7 @@ void Graphics::flushBatchedDraws() cmd.indexCount = sbstate.indexCount; cmd.indexType = INDEX_UINT16; cmd.indexBufferOffset = sbstate.indexBuffer->unmap(usedsizes[2]); - cmd.texture = sbstate.texture; + cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture); draw(cmd); sbstate.indexBufferMap = StreamBuffer::MapInfo(); @@ -1833,7 +2079,7 @@ void Graphics::flushBatchedDraws() cmd.primitiveType = sbstate.primitiveMode; cmd.vertexStart = 0; cmd.vertexCount = sbstate.vertexCount; - cmd.texture = sbstate.texture; + cmd.texture = getTextureOrDefaultForActiveShader(sbstate.texture); draw(cmd); } @@ -1851,8 +2097,9 @@ void Graphics::flushBatchedDraws() if (attributes.isEnabled(ATTRIB_COLOR)) setColor(nc); - batchedDrawState.vertexCount = 0; - batchedDrawState.indexCount = 0; + sbstate.vertexCount = 0; + sbstate.indexCount = 0; + sbstate.flushing = false; } void Graphics::flushBatchedDrawsGlobal() @@ -1911,9 +2158,6 @@ void Graphics::drawFromShader(PrimitiveType primtype, int vertexcount, int insta flushBatchedDraws(); - if (!capabilities.features[FEATURE_GLSL3]) - throw love::Exception("drawFromShader is not supported on this system (GLSL3 support is required.)"); - if (Shader::isDefaultActive() || !Shader::current) throw love::Exception("drawFromShader can only be used with a custom shader."); @@ -1930,7 +2174,7 @@ void Graphics::drawFromShader(PrimitiveType primtype, int vertexcount, int insta cmd.primitiveType = primtype; cmd.vertexCount = vertexcount; cmd.instanceCount = std::max(1, instancecount); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -1939,9 +2183,6 @@ void Graphics::drawFromShader(Buffer *indexbuffer, int indexcount, int instancec { flushBatchedDraws(); - if (!capabilities.features[FEATURE_GLSL3]) - throw love::Exception("drawFromShader is not supported on this system (GLSL3 support is required.)"); - if (!(indexbuffer->getUsageFlags() & BUFFERUSAGEFLAG_INDEX)) throw love::Exception("The buffer passed to drawFromShader must be an index buffer."); @@ -1971,7 +2212,7 @@ void Graphics::drawFromShader(Buffer *indexbuffer, int indexcount, int instancec cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format); cmd.indexBufferOffset = startindex * getIndexDataSize(cmd.indexType); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -1998,7 +2239,7 @@ void Graphics::drawFromShaderIndirect(PrimitiveType primtype, Buffer *indirectar cmd.primitiveType = primtype; cmd.indirectBuffer = indirectargs; cmd.indirectBufferOffset = argsindex * indirectargs->getArrayStride(); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -2026,7 +2267,7 @@ void Graphics::drawFromShaderIndirect(Buffer *indexbuffer, Buffer *indirectargs, cmd.indexType = getIndexDataType(indexbuffer->getDataMember(0).decl.format); cmd.indirectBuffer = indirectargs; cmd.indexBufferOffset = argsindex * indirectargs->getArrayStride(); - cmd.texture = maintexture; + cmd.texture = getTextureOrDefaultForActiveShader(maintexture); draw(cmd); } @@ -2366,21 +2607,42 @@ void Graphics::polygon(DrawMode mode, const Vector2 *coords, size_t count, bool BatchedDrawCommand cmd; cmd.formats[0] = getSinglePositionFormat(is2D); - cmd.formats[1] = CommonFormat::RGBAub; + cmd.formats[1] = CommonFormat::STf_RGBAub; cmd.indexMode = TRIANGLEINDEX_FAN; cmd.vertexCount = (int)count - (skipLastFilledVertex ? 1 : 0); BatchedVertexData data = requestBatchedDraw(cmd); - if (is2D) - t.transformXY((Vector2 *) data.stream[0], coords, cmd.vertexCount); - else - t.transformXY0((Vector3 *) data.stream[0], coords, cmd.vertexCount); + // Compute texture coordinates. + constexpr float inf = std::numeric_limits::infinity(); + Vector2 mincoord(inf, inf); + Vector2 maxcoord(-inf, -inf); + + for (int i = 0; i < cmd.vertexCount; i++) + { + Vector2 v = coords[i]; + mincoord.x = std::min(mincoord.x, v.x); + mincoord.y = std::min(mincoord.y, v.y); + maxcoord.x = std::max(maxcoord.x, v.x); + maxcoord.y = std::max(maxcoord.y, v.y); + } + + Vector2 invsize(1.0f / (maxcoord.x - mincoord.x), 1.0f / (maxcoord.y - mincoord.y)); + Vector2 start(mincoord.x * invsize.x, mincoord.y * invsize.y); Color32 c = toColor32(getColor()); - Color32 *colordata = (Color32 *) data.stream[1]; + STf_RGBAub *attributes = (STf_RGBAub *) data.stream[1]; for (int i = 0; i < cmd.vertexCount; i++) - colordata[i] = c; + { + attributes[i].s = coords[i].x * invsize.x - start.x; + attributes[i].t = coords[i].y * invsize.y - start.y; + attributes[i].color = c; + } + + if (is2D) + t.transformXY((Vector2*)data.stream[0], coords, cmd.vertexCount); + else + t.transformXY0((Vector3*)data.stream[0], coords, cmd.vertexCount); } } @@ -2389,6 +2651,22 @@ const Graphics::Capabilities &Graphics::getCapabilities() const return capabilities; } +PixelFormat Graphics::getSizedFormat(PixelFormat format) const +{ + switch (format) + { + case PIXELFORMAT_NORMAL: + if (isGammaCorrect()) + return PIXELFORMAT_RGBA8_sRGB; + else + return PIXELFORMAT_RGBA8_UNORM; + case PIXELFORMAT_HDR: + return PIXELFORMAT_RGBA16_FLOAT; + default: + return format; + } +} + Graphics::Stats Graphics::getStats() const { Stats stats; @@ -2403,8 +2681,10 @@ Graphics::Stats Graphics::getStats() const stats.drawCallsBatched = drawCallsBatched; stats.textures = Texture::textureCount; stats.fonts = Font::fontCount; + stats.buffers = Buffer::bufferCount; stats.textureMemory = Texture::totalGraphicsMemory; - + stats.bufferMemory = Buffer::totalGraphicsMemory; + return stats; } @@ -2540,28 +2820,7 @@ Vector2 Graphics::inverseTransformPoint(Vector2 point) return p; } -void Graphics::setOrthoProjection(float w, float h, float near, float far) -{ - if (near >= far) - throw love::Exception("Orthographic projection Z far value must be greater than the Z near value."); - - Matrix4 m = Matrix4::ortho(0.0f, w, 0.0f, h, near, far); - setCustomProjection(m); -} - -void Graphics::setPerspectiveProjection(float verticalfov, float aspect, float near, float far) -{ - if (near <= 0.0f) - throw love::Exception("Perspective projection Z near value must be greater than 0."); - - if (near >= far) - throw love::Exception("Perspective projection Z far value must be greater than the Z near value."); - - Matrix4 m = Matrix4::perspective(verticalfov, aspect, near, far); - setCustomProjection(m); -} - -void Graphics::setCustomProjection(const Matrix4 &m) +void Graphics::setProjection(const Matrix4 &m) { flushBatchedDraws(); @@ -2590,29 +2849,14 @@ void Graphics::resetProjection() state.useCustomProjection = false; - updateDeviceProjection(Matrix4::ortho(0.0f, w, 0.0f, h, -10.0f, 10.0f)); + // NDC is y-up. The ortho() parameter names assume that as well. We want + // a y-down projection, so we set bottom to h and top to 0. + updateDeviceProjection(Matrix4::ortho(0.0f, w, h, 0.0f, -10.0f, 10.0f)); } void Graphics::updateDeviceProjection(const Matrix4 &projection) { - // Note: graphics implementations define computeDeviceProjection. - deviceProjectionMatrix = computeDeviceProjection(projection, isRenderTargetActive()); -} - -Matrix4 Graphics::calculateDeviceProjection(const Matrix4 &projection, uint32 flags) const -{ - Matrix4 m = projection; - bool reverseZ = (flags & DEVICE_PROJECTION_REVERSE_Z) != 0; - - if (flags & DEVICE_PROJECTION_FLIP_Y) - m.setRow(1, -m.getRow(1)); - - if (flags & DEVICE_PROJECTION_Z_01) // Go from Z [-1, 1] to Z [0, 1]. - m.setRow(2, m.getRow(2) * (reverseZ ? -0.5f : 0.5f) + m.getRow(3)); - else if (reverseZ) - m.setRow(2, -m.getRow(2)); - - return m; + deviceProjectionMatrix = projection; } STRINGMAP_CLASS_BEGIN(Graphics, Graphics::DrawMode, Graphics::DRAW_MAX_ENUM, drawMode) @@ -2650,7 +2894,6 @@ STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, f { "multirendertargetformats", Graphics::FEATURE_MULTI_RENDER_TARGET_FORMATS }, { "clampzero", Graphics::FEATURE_CLAMP_ZERO }, { "clampone", Graphics::FEATURE_CLAMP_ONE }, - { "blendminmax", Graphics::FEATURE_BLEND_MINMAX }, { "lighten", Graphics::FEATURE_LIGHTEN }, { "fullnpot", Graphics::FEATURE_FULL_NPOT }, { "pixelshaderhighp", Graphics::FEATURE_PIXEL_SHADER_HIGHP }, @@ -2659,12 +2902,7 @@ STRINGMAP_CLASS_BEGIN(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, f { "glsl4", Graphics::FEATURE_GLSL4 }, { "instancing", Graphics::FEATURE_INSTANCING }, { "texelbuffer", Graphics::FEATURE_TEXEL_BUFFER }, - { "indexbuffer32bit", Graphics::FEATURE_INDEX_BUFFER_32BIT }, - { "copybuffer", Graphics::FEATURE_COPY_BUFFER }, - { "copybuffertotexture", Graphics::FEATURE_COPY_BUFFER_TO_TEXTURE }, { "copytexturetobuffer", Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER }, - { "copyrendertargettobuffer", Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER }, - { "mipmaprange", Graphics::FEATURE_MIPMAP_RANGE }, { "indirectdraw", Graphics::FEATURE_INDIRECT_DRAW }, } STRINGMAP_CLASS_END(Graphics, Graphics::Feature, Graphics::FEATURE_MAX_ENUM, feature) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 456e5d28f..3c1381019 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -147,24 +147,18 @@ public: enum Feature { - FEATURE_MULTI_RENDER_TARGET_FORMATS, + FEATURE_MULTI_RENDER_TARGET_FORMATS, // Deprecated FEATURE_CLAMP_ZERO, FEATURE_CLAMP_ONE, - FEATURE_BLEND_MINMAX, FEATURE_LIGHTEN, // Deprecated - FEATURE_FULL_NPOT, - FEATURE_PIXEL_SHADER_HIGHP, - FEATURE_SHADER_DERIVATIVES, - FEATURE_GLSL3, + FEATURE_FULL_NPOT, // Deprecated + FEATURE_PIXEL_SHADER_HIGHP, // Deprecated + FEATURE_SHADER_DERIVATIVES, // Deprecated + FEATURE_GLSL3, // Deprecated FEATURE_GLSL4, - FEATURE_INSTANCING, + FEATURE_INSTANCING, // Deprecated FEATURE_TEXEL_BUFFER, - FEATURE_INDEX_BUFFER_32BIT, - FEATURE_COPY_BUFFER, - FEATURE_COPY_BUFFER_TO_TEXTURE, FEATURE_COPY_TEXTURE_TO_BUFFER, - FEATURE_COPY_RENDER_TARGET_TO_BUFFER, - FEATURE_MIPMAP_RANGE, FEATURE_INDIRECT_DRAW, FEATURE_MAX_ENUM }; @@ -230,7 +224,9 @@ public: int shaderSwitches; int textures; int fonts; + int buffers; int64 textureMemory; + int64 bufferMemory; }; struct DrawCommand @@ -449,17 +445,15 @@ public: } }; - Graphics(); + Graphics(const char *name); virtual ~Graphics(); - // Implements Module. - virtual ModuleType getModuleType() const { return M_GRAPHICS; } - virtual Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) = 0; + virtual Texture *newTextureView(Texture *base, const Texture::ViewSettings &viewsettings) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); Font *newFont(love::font::Rasterizer *data); - Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting); + Font *newDefaultFont(int size, const font::TrueTypeRasterizer::Settings &settings); Video *newVideo(love::video::VideoStream *stream, float dpiscale); SpriteBatch *newSpriteBatch(Texture *texture, int size, BufferDataUsage usage); @@ -485,6 +479,11 @@ public: bool validateShader(bool gles, const std::vector &stages, const Shader::CompileOptions &options, std::string &err); + Texture *getDefaultTexture(TextureType type, DataBaseType dataType, bool depthSample); + Buffer *getDefaultTexelBuffer(DataBaseType dataType); + Buffer *getDefaultStorageBuffer(); + Texture *getTextureOrDefaultForActiveShader(Texture *tex); + /** * Resets the current color, background color, line style, and so forth. **/ @@ -501,16 +500,15 @@ public: virtual void present(void *screenshotCallbackData) = 0; /** - * Sets the current graphics display viewport dimensions. + * Called when the backbuffer changes. **/ - virtual void setViewportSize(int width, int height, int pixelwidth, int pixelheight) = 0; + virtual void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) = 0; + void backbufferChanged(int width, int height, int pixelwidth, int pixelheight); /** * Sets the current graphics display viewport and initializes the renderer. - * @param width The viewport width. - * @param height The viewport height. **/ - virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) = 0; + virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) = 0; /** * Un-sets the current graphics display mode (uninitializing objects if @@ -608,9 +606,13 @@ public: */ bool getScissor(Rect &rect) const; - virtual void setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) = 0; + void setStencilMode(StencilMode mode, int value); void setStencilMode(); - void getStencilMode(StencilAction &action, CompareMode &compare, int &value, uint32 &readmask, uint32 &writemask) const; + StencilMode getStencilMode(int &value) const; + + virtual void setStencilState(const StencilState &state) = 0; + void setStencilState(); + const StencilState &getStencilState() const; virtual void setDepthMode(CompareMode compare, bool write) = 0; void setDepthMode(); @@ -619,6 +621,9 @@ public: void setMeshCullMode(CullMode cull); CullMode getMeshCullMode() const; + // Note: These are meant to be relative to the y-down default projection, + // which may be flipped compared to device NDC. Implementations may have + // to flip the winding internally. virtual void setFrontFaceWinding(Winding winding) = 0; Winding getFrontFaceWinding() const; @@ -819,12 +824,12 @@ public: /** * Converts PIXELFORMAT_NORMAL and PIXELFORMAT_HDR into a real format. **/ - virtual PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const = 0; + PixelFormat getSizedFormat(PixelFormat format) const; /** * Gets whether the specified pixel format usage is supported. **/ - virtual bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) = 0; + virtual bool isPixelFormatSupported(PixelFormat format, uint32 usage) = 0; /** * Gets the renderer used by love.graphics. @@ -867,13 +872,9 @@ public: Vector2 transformPoint(Vector2 point); Vector2 inverseTransformPoint(Vector2 point); - void setOrthoProjection(float w, float h, float near, float far); - void setPerspectiveProjection(float verticalfov, float aspect, float near, float far); - void setCustomProjection(const Matrix4 &m); + void setProjection(const Matrix4 &m); void resetProjection(); - virtual Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const = 0; - virtual void draw(const DrawCommand &cmd) = 0; virtual void draw(const DrawIndexedCommand &cmd) = 0; virtual void drawQuads(int start, int count, const VertexAttributes &attributes, const BufferBindings &buffers, Texture *texture) = 0; @@ -916,14 +917,6 @@ public: protected: - enum DeviceProjectionFlags - { - DEVICE_PROJECTION_DEFAULT = 0, - DEVICE_PROJECTION_FLIP_Y = (1 << 0), - DEVICE_PROJECTION_Z_01 = (1 << 1), - DEVICE_PROJECTION_REVERSE_Z = (1 << 2), - }; - struct DisplayState { DisplayState(); @@ -981,6 +974,8 @@ protected: StreamBuffer::MapInfo vbMap[2]; StreamBuffer::MapInfo indexBufferMap = StreamBuffer::MapInfo(); + bool flushing = false; + BatchedDrawState() { vb[0] = vb[1] = nullptr; @@ -1015,7 +1010,7 @@ protected: ShaderStage *newShaderStage(ShaderStageType stage, const std::string &source, const Shader::CompileOptions &options, const Shader::SourceInfo &info, bool cache); virtual ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) = 0; - virtual Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) = 0; + virtual Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) = 0; virtual StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) = 0; virtual GraphicsReadback *newReadbackInternal(ReadbackMethod method, Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) = 0; @@ -1037,6 +1032,11 @@ protected: void updatePendingReadbacks(); + void releaseDefaultResources(); + + void validateStencilState(const StencilState &s) const; + void validateDepthState(bool depthwrite) const; + void restoreState(const DisplayState &s); void restoreStateChecked(const DisplayState &s); @@ -1045,13 +1045,15 @@ protected: void popTransform(); void updateDeviceProjection(const Matrix4 &projection); - Matrix4 calculateDeviceProjection(const Matrix4 &projection, uint32 flags) const; int width; int height; int pixelWidth; int pixelHeight; + bool backbufferHasStencil; + bool backbufferHasDepth; + bool created; bool active; @@ -1092,6 +1094,10 @@ private: void checkSetDefaultFont(); int calculateEllipsePoints(float rx, float ry) const; + Texture *defaultTextures[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM][2]; + Buffer *defaultTexelBuffers[DATA_BASETYPE_MAX_ENUM]; + Buffer *defaultStorageBuffer; + std::vector scratchBuffer; std::unordered_map cachedShaderStages[SHADERSTAGE_MAX_ENUM]; diff --git a/src/modules/graphics/GraphicsReadback.cpp b/src/modules/graphics/GraphicsReadback.cpp index 935499ab5..d99a05567 100644 --- a/src/modules/graphics/GraphicsReadback.cpp +++ b/src/modules/graphics/GraphicsReadback.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -40,9 +40,6 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Buffer { const auto &caps = gfx->getCapabilities(); - if (!caps.features[Graphics::FEATURE_COPY_BUFFER]) - throw love::Exception("readbackBuffer is not supported on this system (buffer copy support is required)."); - if (offset + size > buffer->getSize()) throw love::Exception("Invalid offset or size for the given Buffer."); @@ -81,6 +78,7 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture } textureFormat = getLinearPixelFormat(texture->getPixelFormat()); + isFormatLinear = isGammaCorrect() && !isPixelFormatSRGB(texture->getPixelFormat()); if (!image::ImageData::validPixelFormat(textureFormat)) { @@ -93,10 +91,8 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture if (method == READBACK_ASYNC) { - if (isRT && !caps.features[Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER]) - throw love::Exception("readbackTextureAsync is not supported on this system."); - else if (!isRT && !caps.features[Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER]) - throw love::Exception("readbackTextureAsync a with non-render-target textures is not supported on this system."); + if (!isRT && !caps.features[Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER]) + throw love::Exception("readbackTextureAsync with a non-render-target texture is not supported on this system."); } else { @@ -158,6 +154,7 @@ void *GraphicsReadback::prepareReadbackDest(size_t size) throw love::Exception("The love.image module must be loaded for readbackTexture."); imageData.set(module->newImageData(rect.w, rect.h, textureFormat, nullptr), Acquire::NORETAIN); + imageData->setLinear(isFormatLinear); return imageData->getData(); } } @@ -190,6 +187,7 @@ GraphicsReadback::Status GraphicsReadback::readbackBuffer(Buffer *buffer, size_t if (imageData.get()) { + // Always lock the mutex since the user can't know when to do it. love::thread::Lock lock(imageData->getMutex()); if (imageData->getWidth() != rect.w) diff --git a/src/modules/graphics/GraphicsReadback.h b/src/modules/graphics/GraphicsReadback.h index 0524d4c2b..3e8a42e91 100644 --- a/src/modules/graphics/GraphicsReadback.h +++ b/src/modules/graphics/GraphicsReadback.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -103,6 +103,7 @@ protected: StrongRef imageData; Rect rect = {}; PixelFormat textureFormat = PIXELFORMAT_UNKNOWN; + bool isFormatLinear = false; int imageDataX = 0; int imageDataY = 0; diff --git a/src/modules/graphics/Mesh.cpp b/src/modules/graphics/Mesh.cpp index 78abd2d96..b8565b9b0 100644 --- a/src/modules/graphics/Mesh.cpp +++ b/src/modules/graphics/Mesh.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -107,15 +107,18 @@ Mesh::Mesh(const std::vector &attributes, PrimitiveType d throw love::Exception("At least one buffer attribute must be specified in this constructor."); attachedAttributes = attributes; - vertexCount = attachedAttributes.size() > 0 ? LOVE_UINT32_MAX : 0; - for (const auto &attrib : attachedAttributes) - { - if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0) - throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute."); + auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (getAttachedAttributeIndex(attrib.name) != -1) + for (int i = 0; i < (int) attachedAttributes.size(); i++) + { + auto &attrib = attachedAttributes[i]; + + finalizeAttribute(gfx, attrib); + + int attributeIndex = getAttachedAttributeIndex(attrib.name); + if (attributeIndex != i && attributeIndex != -1) throw love::Exception("Duplicate vertex attribute name: %s", attrib.name.c_str()); vertexCount = std::min(vertexCount, attrib.buffer->getArrayLength()); @@ -140,7 +143,7 @@ void Mesh::setupAttachedAttributes() if (getAttachedAttributeIndex(name) != -1) throw love::Exception("Duplicate vertex attribute name: %s", name.c_str()); - attachedAttributes.push_back({name, vertexBuffer, nullptr, (int) i, 0, STEP_PER_VERTEX, true}); + attachedAttributes.push_back({name, vertexBuffer, nullptr, name, (int) i, 0, STEP_PER_VERTEX, true}); } } @@ -155,6 +158,21 @@ int Mesh::getAttachedAttributeIndex(const std::string &name) const return -1; } +void Mesh::finalizeAttribute(Graphics *gfx, BufferAttribute &attrib) const +{ + if ((attrib.buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0) + throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute."); + + if (attrib.startArrayIndex < 0 || attrib.startArrayIndex >= (int)attrib.buffer->getArrayLength()) + throw love::Exception("Invalid start array index %d.", attrib.startArrayIndex + 1); + + int indexInBuffer = attrib.buffer->getDataMemberIndex(attrib.nameInBuffer); + if (indexInBuffer < 0) + throw love::Exception("Buffer does not have a vertex attribute with name '%s'.", attrib.nameInBuffer.c_str()); + + attrib.indexInBuffer = indexInBuffer; +} + void *Mesh::checkVertexDataOffset(size_t vertindex, size_t *byteoffset) { if (vertindex >= vertexCount) @@ -210,15 +228,7 @@ bool Mesh::isAttributeEnabled(const std::string &name) const void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, const std::string &attachname, int startindex, AttributeStep step) { - if ((buffer->getUsageFlags() & BUFFERUSAGEFLAG_VERTEX) == 0) - throw love::Exception("Buffer must be created with vertex buffer support to be used as a Mesh vertex attribute."); - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (step == STEP_PER_INSTANCE && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) - throw love::Exception("Vertex attribute instancing is not supported on this system."); - - if (startindex < 0 || startindex >= (int) buffer->getArrayLength()) - throw love::Exception("Invalid start array index %d.", startindex + 1); BufferAttribute oldattrib = {}; BufferAttribute newattrib = {}; @@ -233,10 +243,13 @@ void Mesh::attachAttribute(const std::string &name, Buffer *buffer, Mesh *mesh, newattrib.buffer = buffer; newattrib.mesh = mesh; newattrib.enabled = oldattrib.buffer.get() ? oldattrib.enabled : true; - newattrib.indexInBuffer = buffer->getDataMemberIndex(attachname); + newattrib.nameInBuffer = attachname; + newattrib.indexInBuffer = -1; newattrib.startArrayIndex = startindex; newattrib.step = step; + finalizeAttribute(gfx, newattrib); + if (newattrib.indexInBuffer < 0) throw love::Exception("The specified vertex buffer does not have a vertex attribute named '%s'", attachname.c_str()); @@ -320,6 +333,9 @@ static void copyToIndexBuffer(const std::vector &indices, void *data, si void Mesh::setVertexMap(const std::vector &map) { + if (map.empty()) + throw love::Exception("Vertex map array must not be empty."); + size_t maxval = getVertexCount(); IndexDataType datatype = getIndexDataTypeFromMax(maxval); @@ -543,9 +559,6 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff if (vertexCount <= 0 || (instancecount <= 0 && indirectargs == nullptr)) return; - if (instancecount > 1 && !gfx->getCapabilities().features[Graphics::FEATURE_INSTANCING]) - throw love::Exception("Instancing is not supported on this system."); - if (indirectargs != nullptr) { if (primitiveType == PRIMITIVE_TRIANGLE_FAN) @@ -615,8 +628,8 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff } // Not supported on all platforms or GL versions, I believe. - if (!attributes.isEnabled(ATTRIB_POS)) - throw love::Exception("Mesh must have an enabled VertexPosition attribute to be drawn."); + if ((attributes.enableBits & ~(ATTRIBFLAG_TEXCOORD | ATTRIBFLAG_COLOR)) == 0) + throw love::Exception("Mesh must have an enabled VertexPosition or custom attribute to be drawn."); Graphics::TempTransform transform(gfx, m); @@ -648,7 +661,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff cmd.primitiveType = primitiveType; cmd.indexType = indexDataType; cmd.instanceCount = instancecount; - cmd.texture = texture; + cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture); cmd.cullMode = gfx->getMeshCullMode(); cmd.indexBufferOffset = r.getOffset() * indexbuffer->getArrayStride(); @@ -672,7 +685,7 @@ void Mesh::drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buff cmd.vertexStart = (int) r.getOffset(); cmd.vertexCount = (int) r.getSize(); cmd.instanceCount = instancecount; - cmd.texture = texture; + cmd.texture = gfx->getTextureOrDefaultForActiveShader(texture); cmd.cullMode = gfx->getMeshCullMode(); cmd.indirectBuffer = indirectargs; diff --git a/src/modules/graphics/Mesh.h b/src/modules/graphics/Mesh.h index b164b7cfb..f48df211d 100644 --- a/src/modules/graphics/Mesh.h +++ b/src/modules/graphics/Mesh.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -56,6 +56,7 @@ public: std::string name; StrongRef buffer; StrongRef mesh; + std::string nameInBuffer; int indexInBuffer; int startArrayIndex; AttributeStep step; @@ -186,6 +187,7 @@ private: void setupAttachedAttributes(); int getAttachedAttributeIndex(const std::string &name) const; + void finalizeAttribute(Graphics *gfx, BufferAttribute &attrib) const; void drawInternal(Graphics *gfx, const Matrix4 &m, int instancecount, Buffer *indirectargs, int argsindex); diff --git a/src/modules/graphics/ParticleSystem.cpp b/src/modules/graphics/ParticleSystem.cpp index ef077c0b9..64db60f70 100644 --- a/src/modules/graphics/ParticleSystem.cpp +++ b/src/modules/graphics/ParticleSystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -1086,7 +1086,8 @@ void ParticleSystem::draw(Graphics *gfx, const Matrix4 &m) BufferBindings vertexbuffers; vertexbuffers.set(0, buffer, 0); - gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, texture); + Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture); + gfx->drawQuads(0, pCount, vertexAttributes, vertexbuffers, tex); } bool ParticleSystem::getConstant(const char *in, AreaSpreadDistribution &out) diff --git a/src/modules/graphics/ParticleSystem.h b/src/modules/graphics/ParticleSystem.h index 9343ad24f..05727d838 100644 --- a/src/modules/graphics/ParticleSystem.h +++ b/src/modules/graphics/ParticleSystem.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Polyline.cpp b/src/modules/graphics/Polyline.cpp index 5e58d5b68..e768687c4 100644 --- a/src/modules/graphics/Polyline.cpp +++ b/src/modules/graphics/Polyline.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -424,7 +424,7 @@ void Polyline::draw(love::graphics::Graphics *gfx) Graphics::BatchedDrawCommand cmd; cmd.formats[0] = getSinglePositionFormat(is2D); - cmd.formats[1] = CommonFormat::RGBAub; + cmd.formats[1] = CommonFormat::STf_RGBAub; cmd.indexMode = triangle_mode; cmd.vertexCount = std::min(maxvertices, total_vertex_count - vertex_start); @@ -435,13 +435,19 @@ void Polyline::draw(love::graphics::Graphics *gfx) else t.transformXY0((Vector3 *) data.stream[0], verts, cmd.vertexCount); - Color32 *colordata = (Color32 *) data.stream[1]; + STf_RGBAub *attributes = (STf_RGBAub *) data.stream[1]; int draw_rough_count = std::min(cmd.vertexCount, (int) vertex_count - vertex_start); // Constant vertex color up to the overdraw vertices. + // Texture coordinates are a constant value, we only have them to keep auto-batching + // when drawing filled and line polygons together. for (int i = 0; i < draw_rough_count; i++) - colordata[i] = curcolor; + { + attributes[i].s = 0.0f; + attributes[i].t = 0.0f; + attributes[i].color = curcolor; + } if (overdraw) { @@ -456,30 +462,41 @@ void Polyline::draw(love::graphics::Graphics *gfx) if (draw_overdraw_count > 0) { - Color32 *colors = colordata + draw_overdraw_begin; - fill_color_array(curcolor, colors, draw_overdraw_count); + STf_RGBAub *c = attributes + draw_overdraw_begin; + fill_color_array(curcolor, c, draw_overdraw_count); } } } } -void Polyline::fill_color_array(Color32 constant_color, Color32 *colors, int count) +void Polyline::fill_color_array(Color32 constant_color, STf_RGBAub *attributes, int count) { + // Note: assigning each element individually seems to be needed to avoid + // performance issues in OpenGL + Windows. VS' compiler is likely doing + // something that doesn't play nice with write-combined memory from the + // graphics driver, when assigning a whole struct after modifying it, or + // when using memcpy. for (int i = 0; i < count; ++i) { - Color32 c = constant_color; - c.a *= (i+1) % 2; // avoids branching. equiv to if (i%2 == 1) c.a = 0; - colors[i] = c; + attributes[i].s = 0.0f; + attributes[i].t = 0.0f; + attributes[i].color.r = constant_color.r; + attributes[i].color.g = constant_color.g; + attributes[i].color.b = constant_color.b; + attributes[i].color.a = constant_color.a * ((i + 1) % 2); // avoids branching. equiv to if (i%2 == 1) c.a = 0; } } -void NoneJoinPolyline::fill_color_array(Color32 constant_color, Color32 *colors, int count) +void NoneJoinPolyline::fill_color_array(Color32 constant_color, STf_RGBAub *attributes, int count) { for (int i = 0; i < count; ++i) { - Color32 c = constant_color; - c.a *= (i & 3) < 2; // if (i % 4 == 2 || i % 4 == 3) c.a = 0 - colors[i] = c; + attributes[i].s = 0.0f; + attributes[i].t = 0.0f; + attributes[i].color.r = constant_color.r; + attributes[i].color.g = constant_color.g; + attributes[i].color.b = constant_color.b; + attributes[i].color.a = constant_color.a * ((i & 3) < 2); // if (i % 4 == 2 || i % 4 == 3) c.a = 0 } } diff --git a/src/modules/graphics/Polyline.h b/src/modules/graphics/Polyline.h index 7685efd12..2acf88382 100644 --- a/src/modules/graphics/Polyline.h +++ b/src/modules/graphics/Polyline.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -73,7 +73,7 @@ protected: virtual void calc_overdraw_vertex_count(bool is_looping); virtual void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping); - virtual void fill_color_array(Color32 constant_color, Color32 *colors, int count); + virtual void fill_color_array(Color32 constant_color, STf_RGBAub *attributes, int count); /** Calculate line boundary points. * @@ -133,7 +133,7 @@ protected: void calc_overdraw_vertex_count(bool is_looping) override; void render_overdraw(const std::vector &normals, float pixel_size, bool is_looping) override; - void fill_color_array(Color32 constant_color, Color32 *colors, int count) override; + void fill_color_array(Color32 constant_color, STf_RGBAub *attributes, int count) override; void renderEdge(std::vector &anchors, std::vector &normals, Vector2 &s, float &len_s, Vector2 &ns, const Vector2 &q, const Vector2 &r, float hw) override; diff --git a/src/modules/graphics/Quad.cpp b/src/modules/graphics/Quad.cpp index 0d218dc38..40c7a9737 100644 --- a/src/modules/graphics/Quad.cpp +++ b/src/modules/graphics/Quad.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Quad.h b/src/modules/graphics/Quad.h index eba404432..8e7d08c53 100644 --- a/src/modules/graphics/Quad.h +++ b/src/modules/graphics/Quad.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Resource.h b/src/modules/graphics/Resource.h index 17d23e893..b277e22f5 100644 --- a/src/modules/graphics/Resource.h +++ b/src/modules/graphics/Resource.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index f6c314420..14fb6f63d 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,6 +26,7 @@ // glslang #include "libraries/glslang/glslang/Public/ShaderLang.h" +#include "libraries/glslang/glslang/Public/ResourceLimits.h" // Needed for reflection information. #include "libraries/glslang/glslang/Include/Types.h" @@ -45,140 +46,119 @@ namespace glsl { static const char global_syntax[] = R"( -#if !defined(GL_ES) && __VERSION__ < 140 - #define lowp - #define mediump - #define highp -#endif -#if defined(VERTEX) || __VERSION__ > 100 || defined(GL_FRAGMENT_PRECISION_HIGH) - #define LOVE_HIGHP_OR_MEDIUMP highp -#else - #define LOVE_HIGHP_OR_MEDIUMP mediump -#endif -#if __VERSION__ >= 300 -#define LOVE_IO_LOCATION(x) layout (location = x) -#else -#define LOVE_IO_LOCATION(x) -#endif +#define LOVE_HIGHP_OR_MEDIUMP highp #define number float #define Image sampler2D #define ArrayImage sampler2DArray #define CubeImage samplerCube #define VolumeImage sampler3D -#if __VERSION__ >= 300 && !defined(LOVE_GLSL1_ON_GLSL3) - #define DepthImage sampler2DShadow - #define DepthArrayImage sampler2DArrayShadow - #define DepthCubeImage samplerCubeShadow -#endif +#define DepthImage sampler2DShadow +#define DepthArrayImage sampler2DArrayShadow +#define DepthCubeImage samplerCubeShadow #define extern uniform -#if defined(GL_EXT_texture_array) && (!defined(GL_ES) || __VERSION__ > 100 || defined(GL_OES_gpu_shader5)) -// Only used when !GLSLES1 to work around Ouya driver bug. But we still want it -// enabled for glslang validation when glsl 1-on-3 is used, so also enable it if -// OES_gpu_shader5 exists. -#define LOVE_EXT_TEXTURE_ARRAY_ENABLED -#extension GL_EXT_texture_array : enable -#endif -#ifdef GL_OES_texture_3D -#extension GL_OES_texture_3D : enable -#endif -#ifdef GL_OES_standard_derivatives -#extension GL_OES_standard_derivatives : enable + +#if __VERSION__ >= 430 || (defined(GL_ES) && __VERSION__ >= 310) + layout (std430) buffer; #endif )"; static const char render_uniforms[] = R"( -// According to the GLSL ES 1.0 spec, uniform precision must match between stages, -// but we can't guarantee that highp is always supported in fragment shaders... -// We *really* don't want to use mediump for these in vertex shaders though. -#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW -uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[12]; -uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw2[1]; -#else -uniform LOVE_HIGHP_OR_MEDIUMP vec4 love_UniformsPerDraw[13]; -#endif +uniform highp vec4 love_UniformsPerDraw[12]; // Older GLSL doesn't support preprocessor line continuations... #define TransformMatrix mat4(love_UniformsPerDraw[0], love_UniformsPerDraw[1], love_UniformsPerDraw[2], love_UniformsPerDraw[3]) #define ProjectionMatrix mat4(love_UniformsPerDraw[4], love_UniformsPerDraw[5], love_UniformsPerDraw[6], love_UniformsPerDraw[7]) #define TransformProjectionMatrix (ProjectionMatrix * TransformMatrix) -#define NormalMatrix mat3(love_UniformsPerDraw[8].xyz, love_UniformsPerDraw[9].xyz, love_UniformsPerDraw[10].xyz) - -#define CurrentDPIScale (love_UniformsPerDraw[8].w) -#define ConstantPointSize (love_UniformsPerDraw[9].w) -#define ConstantColor (love_UniformsPerDraw[11]) - -#ifdef LOVE_SPLIT_UNIFORMS_PER_DRAW -#define love_ScreenSize (love_UniformsPerDraw2[0]) -#else -#define love_ScreenSize (love_UniformsPerDraw[12]) -#endif +#define CurrentDPIScale (love_UniformsPerDraw[8].x) +#define ConstantPointSize (love_UniformsPerDraw[8].y) +#define love_ClipSpaceParams (love_UniformsPerDraw[9]) +#define ConstantColor (love_UniformsPerDraw[10]) +#define love_ScreenSize (love_UniformsPerDraw[11]) // Alternate names #define ViewSpaceFromLocal TransformMatrix #define ClipSpaceFromView ProjectionMatrix #define ClipSpaceFromLocal TransformProjectionMatrix -#define ViewNormalFromLocal NormalMatrix )"; static const char global_functions[] = R"( #ifdef GL_ES - #if __VERSION__ >= 300 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED) - precision lowp sampler2DArray; - #endif - #if __VERSION__ >= 300 || defined(GL_OES_texture_3D) - precision lowp sampler3D; - #endif - #if __VERSION__ >= 300 && !defined(LOVE_GLSL1_ON_GLSL3) - precision lowp sampler2DShadow; - precision lowp samplerCubeShadow; - precision lowp sampler2DArrayShadow; - #endif + precision mediump sampler2D; + precision mediump sampler2DArray; + precision mediump sampler3D; + precision mediump samplerCube; + precision mediump sampler2DShadow; + precision mediump samplerCubeShadow; + precision mediump sampler2DArrayShadow; + + precision highp isampler2D; + precision highp isampler2DArray; + precision highp isampler3D; + precision highp isamplerCube; + + precision highp usampler2D; + precision highp usampler2DArray; + precision highp usampler3D; + precision highp usamplerCube; #endif -#if __VERSION__ >= 430 || (defined(GL_ES) && __VERSION__ >= 310) - layout (std430) buffer; +// Avoid #define so legacy code that uses 'texture' as a variable can work... +// Unfortunately it means these can't have variable precision. +vec4 Texel(sampler2D s, highp vec2 c) { return texture(s, c); } +ivec4 Texel(isampler2D s, highp vec2 c) { return texture(s, c); } +uvec4 Texel(usampler2D s, highp vec2 c) { return texture(s, c); } + +vec4 Texel(sampler3D s, highp vec3 c) { return texture(s, c); } +ivec4 Texel(isampler3D s, highp vec3 c) { return texture(s, c); } +uvec4 Texel(usampler3D s, highp vec3 c) { return texture(s, c); } + +vec4 Texel(samplerCube s, highp vec3 c) { return texture(s, c); } +ivec4 Texel(isamplerCube s, highp vec3 c) { return texture(s, c); } +uvec4 Texel(usamplerCube s, highp vec3 c) { return texture(s, c); } + +vec4 Texel(sampler2DArray s, highp vec3 c) { return texture(s, c); } +ivec4 Texel(isampler2DArray s, highp vec3 c) { return texture(s, c); } +uvec4 Texel(usampler2DArray s, highp vec3 c) { return texture(s, c); } + +float Texel(sampler2DShadow s, highp vec3 c) { return texture(s, c); } +float Texel(samplerCubeShadow s, highp vec4 c) { return texture(s, c); } +float Texel(sampler2DArrayShadow s, highp vec4 c) { return texture(s, c); } + +#ifdef PIXEL + vec4 Texel(sampler2D s, highp vec2 c, float b) { return texture(s, c, b); } + ivec4 Texel(isampler2D s, highp vec2 c, float b) { return texture(s, c, b); } + uvec4 Texel(usampler2D s, highp vec2 c, float b) { return texture(s, c, b); } + + vec4 Texel(sampler3D s, highp vec3 c, float b) { return texture(s, c, b); } + ivec4 Texel(isampler3D s, highp vec3 c, float b) { return texture(s, c, b); } + uvec4 Texel(usampler3D s, highp vec3 c, float b) { return texture(s, c, b); } + + vec4 Texel(samplerCube s, highp vec3 c, float b) { return texture(s, c, b); } + ivec4 Texel(isamplerCube s, highp vec3 c, float b) { return texture(s, c, b); } + uvec4 Texel(usamplerCube s, highp vec3 c, float b) { return texture(s, c, b); } + + vec4 Texel(sampler2DArray s, highp vec3 c, float b) { return texture(s, c, b); } + ivec4 Texel(isampler2DArray s, highp vec3 c, float b) { return texture(s, c, b); } + uvec4 Texel(usampler2DArray s, highp vec3 c, float b) { return texture(s, c, b); } + + float Texel(sampler2DShadow s, highp vec3 c, float b) { return texture(s, c, b); } + float Texel(samplerCubeShadow s, highp vec4 c, float b) { return texture(s, c, b); } #endif -#if __VERSION__ >= 130 && !defined(LOVE_GLSL1_ON_GLSL3) - #define Texel texture -#else - #if __VERSION__ >= 130 - #define texture2D Texel - #define texture3D Texel - #define textureCube Texel - #define texture2DArray Texel - #define love_texture2D texture - #define love_texture3D texture - #define love_textureCube texture - #define love_texture2DArray texture - #else - #define love_texture2D texture2D - #define love_texture3D texture3D - #define love_textureCube textureCube - #define love_texture2DArray texture2DArray - #endif - vec4 Texel(sampler2D s, vec2 c) { return love_texture2D(s, c); } - vec4 Texel(samplerCube s, vec3 c) { return love_textureCube(s, c); } - #if __VERSION__ > 100 || defined(GL_OES_texture_3D) - vec4 Texel(sampler3D s, vec3 c) { return love_texture3D(s, c); } - #endif - #if __VERSION__ >= 130 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED) - vec4 Texel(sampler2DArray s, vec3 c) { return love_texture2DArray(s, c); } - #endif - #ifdef PIXEL - vec4 Texel(sampler2D s, vec2 c, float b) { return love_texture2D(s, c, b); } - vec4 Texel(samplerCube s, vec3 c, float b) { return love_textureCube(s, c, b); } - #if __VERSION__ > 100 || defined(GL_OES_texture_3D) - vec4 Texel(sampler3D s, vec3 c, float b) { return love_texture3D(s, c, b); } - #endif - #if __VERSION__ >= 130 || defined(LOVE_EXT_TEXTURE_ARRAY_ENABLED) - vec4 Texel(sampler2DArray s, vec3 c, float b) { return love_texture2DArray(s, c, b); } - #endif - #endif - #define texture love_texture +uniform mediump float deprecatedTextureCall; + +vec4 texture2DDeprecated(sampler2D s, vec2 c) { return texture(s, c) + deprecatedTextureCall; } +vec4 textureCubeDeprecated(samplerCube s, vec3 c) { return texture(s, c) + deprecatedTextureCall; } + +#ifdef PIXEL +vec4 texture2DDeprecated(sampler2D s, vec2 c, float b) { return texture(s, c, b) + deprecatedTextureCall; } +vec4 textureCubeDeprecated(samplerCube s, vec3 c, float b) { return texture(s, c, b) + deprecatedTextureCall; } #endif +#define texture2D texture2DDeprecated +#define textureCube textureCubeDeprecated + float gammaToLinearPrecise(float c) { return c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4); } @@ -236,25 +216,27 @@ static const char vertex_header[] = R"( #define love_Position gl_Position #define love_PointSize gl_PointSize -#if __VERSION__ >= 130 - #define attribute in - #define varying out - #ifndef LOVE_GLSL1_ON_GLSL3 - #define love_VertexID gl_VertexID - #define love_InstanceID gl_InstanceID - #endif -#endif +#define attribute in +#define varying out +#define love_VertexID gl_VertexID +#define love_InstanceID gl_InstanceID )"; -static const char vertex_functions[] = R"()"; +static const char vertex_functions[] = R"( +vec4 love_clipSpaceTransform(vec4 clipPosition) { + clipPosition.y *= love_ClipSpaceParams.x; + clipPosition.z = (love_ClipSpaceParams.y * clipPosition.z + love_ClipSpaceParams.z * clipPosition.w) * love_ClipSpaceParams.w; + return clipPosition; +} +)"; static const char vertex_main[] = R"( -LOVE_IO_LOCATION(0) attribute vec4 VertexPosition; -LOVE_IO_LOCATION(1) attribute vec4 VertexTexCoord; -LOVE_IO_LOCATION(2) attribute vec4 VertexColor; +layout (location = 0) in vec4 VertexPosition; +layout (location = 1) in vec4 VertexTexCoord; +layout (location = 2) in vec4 VertexColor; -varying vec4 VaryingTexCoord; -varying vec4 VaryingColor; +out vec4 VaryingTexCoord; +out vec4 VaryingColor; vec4 position(mat4 clipSpaceFromLocal, vec4 localPosition); @@ -262,6 +244,7 @@ void main() { VaryingTexCoord = VertexTexCoord; VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor; love_Position = position(ClipSpaceFromLocal, VertexPosition); + love_Position = love_clipSpaceTransform(love_Position); } )"; @@ -270,6 +253,7 @@ void vertexmain(); void main() { vertexmain(); + love_Position = love_clipSpaceTransform(love_Position); } )"; @@ -280,9 +264,7 @@ static const char pixel_header[] = R"( #define love_MaxRenderTargets gl_MaxDrawBuffers -#if __VERSION__ >= 130 - #define varying in -#endif +#define varying in // Legacy #define love_MaxCanvases love_MaxRenderTargets @@ -314,15 +296,11 @@ vec4 VideoTexel(vec2 texcoords) { )"; static const char pixel_main[] = R"( -#if __VERSION__ >= 130 - LOVE_IO_LOCATION(0) out vec4 love_PixelColor; -#else - #define love_PixelColor gl_FragColor -#endif +layout (location = 0) out vec4 love_PixelColor; uniform sampler2D MainTex; -varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -varying mediump vec4 VaryingColor; +in highp vec4 VaryingTexCoord; +in mediump vec4 VaryingColor; vec4 effect(vec4 vcolor, Image tex, vec2 texcoord, vec2 pixcoord); @@ -332,22 +310,15 @@ void main() { )"; static const char pixel_main_custom[] = R"( -#if __VERSION__ >= 130 - // Some drivers seem to make the pixel shader do more work when multiple - // pixel shader outputs are defined, even when only one is actually used. - // TODO: We should use reflection or something instead of this, to determine - // how many outputs are actually used in the shader code. - #ifdef LOVE_MULTI_RENDER_TARGETS - LOVE_IO_LOCATION(0) out vec4 love_RenderTargets[love_MaxRenderTargets]; - #define love_PixelColor love_RenderTargets[0] - #else - LOVE_IO_LOCATION(0) out vec4 love_PixelColor; - #endif +// Some drivers seem to make the pixel shader do more work when multiple +// pixel shader outputs are defined, even when only one is actually used. +// TODO: We should use reflection or something instead of this, to determine +// how many outputs are actually used in the shader code. +#ifdef LOVE_MULTI_RENDER_TARGETS + layout (location = 0) out vec4 love_RenderTargets[love_MaxRenderTargets]; + #define love_PixelColor love_RenderTargets[0] #else - #ifdef LOVE_MULTI_RENDER_TARGETS - #define love_RenderTargets gl_FragData - #endif - #define love_PixelColor gl_FragColor + layout (location = 0) out vec4 love_PixelColor; #endif // Legacy @@ -356,8 +327,8 @@ static const char pixel_main_custom[] = R"( #define LOVE_MULTI_CANVASES 1 #endif -varying LOVE_HIGHP_OR_MEDIUMP vec4 VaryingTexCoord; -varying mediump vec4 VaryingColor; +in highp vec4 VaryingTexCoord; +in mediump vec4 VaryingColor; void effect(); @@ -425,7 +396,6 @@ struct Version // Indexed by Shader::Version static const Version versions[] = { - { "#version 120", "#version 100" }, { "#version 330 core", "#version 300 es" }, { "#version 430 core", "#version 320 es" }, }; @@ -539,7 +509,7 @@ static Shader::Language getTargetLanguage(const std::string &src) { std::regex r("^\\s*#pragma language (\\w+)"); std::smatch m; - std::string langstr = std::regex_search(src, m, r) && m.size() > 1 ? m[1] : std::string("glsl1"); + std::string langstr = std::regex_search(src, m, r) && m.size() > 1 ? m[1] : std::string("glsl3"); Shader::Language lang = Shader::LANGUAGE_MAX_ENUM; Shader::getConstant(langstr.c_str(), lang); return lang; @@ -586,7 +556,7 @@ static Shader::EntryPoint getComputeEntryPoint(const std::string &src, const std } // glsl -static_assert(sizeof(Shader::BuiltinUniformData) == sizeof(float) * 4 * 13, "Update the array in wrap_GraphicsShader.lua if this changes."); +static_assert(sizeof(Shader::BuiltinUniformData) == sizeof(float) * 4 * 12, "Update the array in wrap_GraphicsShader.lua if this changes."); love::Type Shader::type("Shader", &Object::type); @@ -616,14 +586,9 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (info.stages[stage] == ENTRYPOINT_NONE) throw love::Exception("Cannot find entry point for shader stage."); - if (info.stages[stage] == ENTRYPOINT_RAW && info.language == LANGUAGE_GLSL1) - throw love::Exception("Shaders using a raw entry point (vertexmain or pixelmain) must use GLSL 3 or greater."); - if (stage == SHADERSTAGE_COMPUTE && info.language != LANGUAGE_GLSL4) throw love::Exception("Compute shaders must use GLSL 4."); - bool glsl1on3 = info.language == LANGUAGE_GLSL1; - if (checksystemfeatures) { const auto &features = gfx->getCapabilities().features; @@ -631,37 +596,23 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, if (stage == SHADERSTAGE_COMPUTE && !features[Graphics::FEATURE_GLSL4]) throw love::Exception("Compute shaders require GLSL 4 which is not supported on this system."); - if (info.language == LANGUAGE_GLSL3 && !features[Graphics::FEATURE_GLSL3]) - throw love::Exception("GLSL 3 shaders are not supported on this system."); - if (info.language == LANGUAGE_GLSL4 && !features[Graphics::FEATURE_GLSL4]) throw love::Exception("GLSL 4 shaders are not supported on this system."); - - glsl1on3 = info.language == LANGUAGE_GLSL1 && features[Graphics::FEATURE_GLSL3]; } Language lang = info.language; - if (glsl1on3) - lang = LANGUAGE_GLSL3; glsl::StageInfo stageinfo = glsl::stageInfo[stage]; std::stringstream ss; ss << (gles ? glsl::versions[lang].glsles : glsl::versions[lang].glsl) << "\n"; - if (glsl1on3) - ss << "#define LOVE_GLSL1_ON_GLSL3 1\n"; if (isGammaCorrect()) ss << "#define LOVE_GAMMA_CORRECT 1\n"; if (info.usesMRT) ss << "#define LOVE_MULTI_RENDER_TARGETS 1\n"; - // Note: backends are expected to handle this situation if highp is ever - // conditional in that backend. - if (!gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]) - ss << "#define LOVE_SPLIT_UNIFORMS_PER_DRAW 1\n"; - for (const auto &def : options.defines) ss << "#define " + def.first + " " + def.second + "\n"; @@ -680,19 +631,59 @@ std::string Shader::createShaderStageCode(Graphics *gfx, ShaderStageType stage, ss << stageinfo.main_raw; else throw love::Exception("Unknown shader entry point %d", info.stages[stage]); - ss << ((!gles && (lang == Shader::LANGUAGE_GLSL1 || glsl1on3)) ? "#line 0\n" : "#line 1\n"); + ss << "#line 1\n"; ss << code; return ss.str(); } -Shader::Shader(StrongRef _stages[]) +Shader::Shader(StrongRef _stages[], const CompileOptions &options) : stages() + , debugName(options.debugName) { std::string err; - if (!validateInternal(_stages, err, validationReflection)) + if (!validateInternal(_stages, err, reflection)) throw love::Exception("%s", err.c_str()); + activeTextures.resize(reflection.textureCount); + activeBuffers.resize(reflection.bufferCount); + + auto gfx = Module::getInstance(Module::M_GRAPHICS); + + // Default bindings for read-only resources. + for (const auto &kvp : reflection.allUniforms) + { + const auto &u = *kvp.second; + + if (u.resourceIndex < 0) + continue; + + if ((u.access & ACCESS_WRITE) != 0) + continue; + + if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_STORAGETEXTURE) + { + auto tex = gfx->getDefaultTexture(u.textureType, u.dataBaseType, u.isDepthSampler); + for (int i = 0; i < u.count; i++) + { + tex->retain(); + activeTextures[u.resourceIndex + i] = tex; + } + } + else if (u.baseType == UNIFORM_TEXELBUFFER || u.baseType == UNIFORM_STORAGEBUFFER) + { + auto buffer = u.baseType == UNIFORM_TEXELBUFFER + ? gfx->getDefaultTexelBuffer(u.dataBaseType) + : gfx->getDefaultStorageBuffer(); + + for (int i = 0; i < u.count; i++) + { + buffer->retain(); + activeBuffers[u.resourceIndex + i] = buffer; + } + } + } + for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) stages[i] = _stages[i]; } @@ -707,6 +698,18 @@ Shader::~Shader() if (current == this) attachDefault(STANDARD_DEFAULT); + + for (Texture *tex : activeTextures) + { + if (tex) + tex->release(); + } + + for (Buffer *buffer : activeBuffers) + { + if (buffer) + buffer->release(); + } } bool Shader::hasStage(ShaderStageType stage) @@ -739,6 +742,40 @@ bool Shader::isDefaultActive() return false; } +Vector4 Shader::computeClipSpaceParams(uint32 clipSpaceTransformFlags) +{ + // See the love_clipSpaceTransform vertex shader function. + Vector4 params(1.0f, 1.0f, 0.0f, 1.0f); + + if (clipSpaceTransformFlags & CLIP_TRANSFORM_FLIP_Y) + params.x = -1.0f; + + if (clipSpaceTransformFlags & CLIP_TRANSFORM_Z_NEG1_1_TO_0_1) + { + params.z = 1.0f; + params.w = 0.5f; + } + else if (clipSpaceTransformFlags & CLIP_TRANSFORM_Z_0_1_TO_NEG1_1) + { + params.y = 2.0f; + params.z = -1.0f; + } + + return params; +} + +const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const +{ + const auto it = reflection.allUniforms.find(name); + return it != reflection.allUniforms.end() ? it->second : nullptr; +} + +bool Shader::hasUniform(const std::string &name) const +{ + const auto it = reflection.allUniforms.find(name); + return it != reflection.allUniforms.end() && it->second->active; +} + const Shader::UniformInfo *Shader::getMainTextureInfo() const { return getUniformInfo(BUILTIN_TEXTURE_MAIN); @@ -780,9 +817,9 @@ bool Shader::isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b) void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const { - if ((primtype == PRIMITIVE_POINTS) != validationReflection.usesPointSize) + if ((primtype == PRIMITIVE_POINTS) != reflection.usesPointSize) { - if (validationReflection.usesPointSize) + if (reflection.usesPointSize) throw love::Exception("The active shader can only be used to draw points."); else throw love::Exception("The gl_PointSize variable must be set in a vertex shader when drawing points."); @@ -824,17 +861,114 @@ void Shader::validateDrawState(PrimitiveType primtype, Texture *maintex) const void Shader::getLocalThreadgroupSize(int *x, int *y, int *z) { - *x = validationReflection.localThreadgroupSize[0]; - *y = validationReflection.localThreadgroupSize[1]; - *z = validationReflection.localThreadgroupSize[2]; + *x = reflection.localThreadgroupSize[0]; + *y = reflection.localThreadgroupSize[1]; + *z = reflection.localThreadgroupSize[2]; +} + +const std::vector *Shader::getBufferFormat(const std::string &name) const +{ + auto it = reflection.bufferFormats.find(name); + if (it != reflection.bufferFormats.end()) + return &it->second; + return nullptr; +} + +bool Shader::isUsingDeprecatedTextureFunctions() const +{ + auto it = reflection.localUniforms.find("deprecatedTextureCall"); + return it != reflection.localUniforms.end() && it->second.stageMask != 0; +} + +bool Shader::isUsingDeprecatedTextureUniform() const +{ + auto it = reflection.allUniforms.find("texture"); + return it != reflection.allUniforms.end() && it->second->stageMask != 0; } bool Shader::validate(StrongRef stages[], std::string& err) { - ValidationReflection reflection; + Reflection reflection; return validateInternal(stages, err, reflection); } +static DataBaseType getBaseType(glslang::TBasicType basictype) +{ + switch (basictype) + { + case glslang::EbtInt: return DATA_BASETYPE_INT; + case glslang::EbtUint: return DATA_BASETYPE_UINT; + case glslang::EbtFloat: return DATA_BASETYPE_FLOAT; + case glslang::EbtBool: return DATA_BASETYPE_BOOL; + default: return DATA_BASETYPE_FLOAT; + } +} + +static DataFormat getDataFormat(glslang::TBasicType basictype, int components, int rows, int columns, bool matrix) +{ + if (matrix) + { + if (basictype != glslang::EbtFloat) + return DATAFORMAT_MAX_ENUM; + + if (rows == 2 && columns == 2) + return DATAFORMAT_FLOAT_MAT2X2; + else if (rows == 2 && columns == 3) + return DATAFORMAT_FLOAT_MAT2X3; + else if (rows == 2 && columns == 4) + return DATAFORMAT_FLOAT_MAT2X4; + else if (rows == 3 && columns == 2) + return DATAFORMAT_FLOAT_MAT3X2; + else if (rows == 3 && columns == 3) + return DATAFORMAT_FLOAT_MAT3X3; + else if (rows == 3 && columns == 4) + return DATAFORMAT_FLOAT_MAT3X4; + else if (rows == 4 && columns == 2) + return DATAFORMAT_FLOAT_MAT4X2; + else if (rows == 4 && columns == 3) + return DATAFORMAT_FLOAT_MAT4X3; + else if (rows == 4 && columns == 4) + return DATAFORMAT_FLOAT_MAT4X4; + else + return DATAFORMAT_MAX_ENUM; + } + else if (basictype == glslang::EbtFloat) + { + if (components == 1) + return DATAFORMAT_FLOAT; + else if (components == 2) + return DATAFORMAT_FLOAT_VEC2; + else if (components == 3) + return DATAFORMAT_FLOAT_VEC2; + else if (components == 4) + return DATAFORMAT_FLOAT_VEC2; + } + else if (basictype == glslang::EbtInt) + { + if (components == 1) + return DATAFORMAT_INT32; + else if (components == 2) + return DATAFORMAT_INT32_VEC2; + else if (components == 3) + return DATAFORMAT_INT32_VEC2; + else if (components == 4) + return DATAFORMAT_INT32_VEC2; + } + else if (basictype == glslang::EbtUint) + { + if (components == 1) + return DATAFORMAT_UINT32; + else if (components == 2) + return DATAFORMAT_UINT32_VEC2; + else if (components == 3) + return DATAFORMAT_UINT32_VEC2; + else if (components == 4) + return DATAFORMAT_UINT32_VEC2; + } + + return DATAFORMAT_MAX_ENUM; +} + static PixelFormat getPixelFormat(glslang::TLayoutFormat format) { using namespace glslang; @@ -884,6 +1018,30 @@ static PixelFormat getPixelFormat(glslang::TLayoutFormat format) } } +static TextureType getTextureType(const glslang::TSampler &sampler) +{ + if (sampler.is2D()) + return sampler.isArrayed() ? TEXTURE_2D_ARRAY : TEXTURE_2D; + else if (sampler.dim == glslang::EsdCube) + return sampler.isArrayed() ? TEXTURE_MAX_ENUM : TEXTURE_CUBE; + else if (sampler.dim == glslang::Esd3D) + return TEXTURE_VOLUME; + else + return TEXTURE_MAX_ENUM; +} + +static uint32 getStageMask(EShLanguageMask mask) +{ + uint32 m = 0; + if (mask & EShLangVertexMask) + m |= SHADERSTAGEMASK_VERTEX; + if (mask & EShLangFragmentMask) + m |= SHADERSTAGEMASK_PIXEL; + if (mask & EShLangComputeMask) + m |= SHADERSTAGEMASK_COMPUTE; + return m; +} + template static T convertData(const glslang::TConstUnion &data) { @@ -902,7 +1060,49 @@ static T convertData(const glslang::TConstUnion &data) } } -bool Shader::validateInternal(StrongRef stages[], std::string &err, ValidationReflection &reflection) +static bool AddFieldsToFormat(std::vector &format, int level, const glslang::TType *type, int arraylength, const std::string &basename, std::string &err) +{ + if (type->isStruct()) + { + auto fields = type->getStruct(); + + for (int i = 0; i < std::max(arraylength, 1); i++) + { + std::string name = basename; + if (level > 0) + { + name += type->getFieldName().c_str(); + if (arraylength > 0) + name += "[" + std::to_string(i) + "]"; + name += "."; + } + for (size_t fieldi = 0; fieldi < fields->size(); fieldi++) + { + const glslang::TType *fieldtype = (*fields)[fieldi].type; + int fieldlength = fieldtype->isSizedArray() ? fieldtype->getCumulativeArraySize() : 0; + + if (!AddFieldsToFormat(format, level + 1, fieldtype, fieldlength, name, err)) + return false; + } + } + } + else + { + DataFormat dataformat = getDataFormat(type->getBasicType(), type->getVectorSize(), type->getMatrixRows(), type->getMatrixCols(), type->isMatrix()); + if (dataformat == DATAFORMAT_MAX_ENUM) + { + err = "Shader validation error:\n"; + return false; + } + + std::string name = basename.empty() ? type->getFieldName().c_str() : basename + type->getFieldName().c_str(); + format.emplace_back(name.c_str(), dataformat, arraylength); + } + + return true; +} + +bool Shader::validateInternal(StrongRef stages[], std::string &err, Reflection &reflection) { glslang::TProgram program; @@ -945,6 +1145,9 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, } } + reflection.textureCount = 0; + reflection.bufferCount = 0; + for (int i = 0; i < program.getNumUniformVariables(); i++) { const glslang::TObjectReflection &info = program.getUniform(i); @@ -954,9 +1157,40 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, const glslang::TQualifier &qualifiers = type->getQualifier(); - if (type->isImage()) + UniformInfo u = {}; + + u.name = canonicaliizeUniformName(info.name); + u.location = -1; + u.access = ACCESS_READ; + u.stageMask = getStageMask(info.stages); + u.components = 1; + u.resourceIndex = -1; + + if (type->isSizedArray()) + u.count = type->getArraySizes()->getCumulativeSize(); + else + u.count = 1; + + const auto &sampler = type->getSampler(); + + if (type->isTexture() && type->getSampler().isCombined() && !sampler.isBuffer()) { - if ((info.stages & EShLangComputeMask) == 0) + u.baseType = UNIFORM_SAMPLER; + u.dataBaseType = getBaseType(sampler.getBasicType()); + u.isDepthSampler = sampler.isShadow(); + u.textureType = getTextureType(sampler); + + if (u.textureType == TEXTURE_MAX_ENUM) + continue; + + u.resourceIndex = reflection.textureCount; + reflection.textureCount += u.count; + + reflection.sampledTextures[u.name] = u; + } + else if (type->isImage()) + { + if ((info.stages & (~EShLangComputeMask)) != 0) { err = "Shader validation error:\nStorage Texture uniform variables (image2D, etc) are only allowed in compute shaders."; return false; @@ -964,36 +1198,63 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, if (!qualifiers.hasFormat()) { - err = "Shader validation error:\nStorage Texture '" + info.name + "' must have an explicit format set in its layout declaration."; + err = "Shader validation error:\nStorage Texture '" + u.name + "' must have an explicit format set in its layout declaration."; return false; } - StorageTextureReflection texreflection = {}; + u.baseType = UNIFORM_STORAGETEXTURE; + u.storageTextureFormat = getPixelFormat(qualifiers.getFormat()); + u.dataBaseType = getDataBaseType(u.storageTextureFormat); + u.textureType = getTextureType(sampler); - texreflection.format = getPixelFormat(qualifiers.getFormat()); + if (u.textureType == TEXTURE_MAX_ENUM) + continue; + + u.resourceIndex = reflection.textureCount; + reflection.textureCount += u.count; if (qualifiers.isReadOnly()) - texreflection.access = ACCESS_READ; + u.access = ACCESS_READ; else if (qualifiers.isWriteOnly()) - texreflection.access = ACCESS_WRITE; + u.access = ACCESS_WRITE; else - texreflection.access = (Access)(ACCESS_READ | ACCESS_WRITE); + u.access = (Access)(ACCESS_READ | ACCESS_WRITE); - reflection.storageTextures[info.name] = texreflection; + reflection.storageTextures[u.name] = u; + } + else if (type->getBasicType() == glslang::EbtSampler && sampler.isBuffer()) + { + u.baseType = UNIFORM_TEXELBUFFER; + u.dataBaseType = getBaseType(sampler.getBasicType()); + + u.resourceIndex = reflection.bufferCount; + reflection.bufferCount += u.count; + + reflection.texelBuffers[u.name] = u; } else if (!type->isOpaque()) { - LocalUniform u = {}; - auto &values = u.initializerValues; + std::vector values; const glslang::TConstUnionArray *constarray = info.getConstArray(); + if (type->isMatrix()) + { + u.matrix.rows = type->getMatrixRows(); + u.matrix.columns = type->getMatrixCols(); + } + else + { + u.components = type->getVectorSize(); + } + // Store initializer values for local uniforms. Some love graphics // backends strip these out of the shader so we need to be able to // access them (to re-send them) by getting them here. switch (type->getBasicType()) { case glslang::EbtFloat: - u.dataType = DATA_BASETYPE_FLOAT; + u.baseType = type->isMatrix() ? UNIFORM_MATRIX : UNIFORM_FLOAT; + u.dataBaseType = DATA_BASETYPE_FLOAT; if (constarray != nullptr) { values.resize(constarray->size()); @@ -1002,7 +1263,18 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, } break; case glslang::EbtUint: - u.dataType = DATA_BASETYPE_UINT; + u.baseType = UNIFORM_UINT; + u.dataBaseType = DATA_BASETYPE_UINT; + if (constarray != nullptr) + { + values.resize(constarray->size()); + for (int i = 0; i < constarray->size(); i++) + values[i].u = convertData((*constarray)[i]); + } + break; + case glslang::EbtBool: + u.baseType = UNIFORM_BOOL; + u.dataBaseType = DATA_BASETYPE_BOOL; if (constarray != nullptr) { values.resize(constarray->size()); @@ -1011,9 +1283,9 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, } break; case glslang::EbtInt: - case glslang::EbtBool: default: - u.dataType = DATA_BASETYPE_INT; + u.baseType = UNIFORM_INT; + u.dataBaseType = DATA_BASETYPE_INT; if (constarray != nullptr) { values.resize(constarray->size()); @@ -1023,7 +1295,8 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, break; } - reflection.localUniforms[info.name] = u; + reflection.localUniforms[u.name] = u; + reflection.localUniformInitializerValues[u.name] = values; } } @@ -1035,7 +1308,7 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, { const glslang::TQualifier &qualifiers = type->getQualifier(); - if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && (info.stages & EShLangComputeMask) == 0) + if ((!qualifiers.isReadOnly() || qualifiers.isWriteOnly()) && ((info.stages & (~EShLangComputeMask)) != 0)) { err = "Shader validation error:\nStorage Buffer block '" + info.name + "' must be marked as readonly in vertex and pixel shaders."; return false; @@ -1061,18 +1334,38 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, return false; } - BufferReflection bufferReflection = {}; - bufferReflection.stride = (size_t) info.size; - bufferReflection.memberCount = (size_t) info.numMembers; + UniformInfo u = {}; + u.name = canonicaliizeUniformName(info.name); + u.location = -1; + u.stageMask = getStageMask(info.stages); + u.components = 1; + u.baseType = UNIFORM_STORAGEBUFFER; + + if (type->isSizedArray()) + u.count = type->getArraySizes()->getCumulativeSize(); + else + u.count = 1; + + u.bufferStride = (size_t) info.size; + u.bufferMemberCount = (size_t) info.numMembers; + + u.resourceIndex = reflection.bufferCount; + reflection.bufferCount += u.count; if (qualifiers.isReadOnly()) - bufferReflection.access = ACCESS_READ; + u.access = ACCESS_READ; else if (qualifiers.isWriteOnly()) - bufferReflection.access = ACCESS_WRITE; + u.access = ACCESS_WRITE; else - bufferReflection.access = (Access)(ACCESS_READ | ACCESS_WRITE); + u.access = (Access)(ACCESS_READ | ACCESS_WRITE); - reflection.storageBuffers[info.name] = bufferReflection; + reflection.storageBuffers[u.name] = u; + + std::vector format; + if (!AddFieldsToFormat(format, 0, elementtype, 0, "", err)) + return false; + + reflection.bufferFormats[u.name] = format; } else { @@ -1081,6 +1374,21 @@ bool Shader::validateInternal(StrongRef stages[], std::string &err, } } + for (auto &kvp : reflection.texelBuffers) + reflection.allUniforms[kvp.first] = &kvp.second; + + for (auto &kvp : reflection.storageBuffers) + reflection.allUniforms[kvp.first] = &kvp.second; + + for (auto &kvp : reflection.sampledTextures) + reflection.allUniforms[kvp.first] = &kvp.second; + + for (auto &kvp : reflection.storageTextures) + reflection.allUniforms[kvp.first] = &kvp.second; + + for (auto &kvp : reflection.localUniforms) + reflection.allUniforms[kvp.first] = &kvp.second; + return true; } @@ -1132,7 +1440,7 @@ bool Shader::validateTexture(const UniformInfo *info, Texture *tex, bool interna else throw love::Exception("Texture must be created with the computewrite flag set to true in order to be used with a storage texture (image2D etc) shader uniform variable."); } - else if (isstoragetex && info->storageTextureFormat != getLinearPixelFormat(tex->getPixelFormat())) + else if (isstoragetex && info->storageTextureFormat != tex->getPixelFormat()) { if (internalUpdate) return false; @@ -1207,44 +1515,91 @@ bool Shader::validateBuffer(const UniformInfo *info, Buffer *buffer, bool intern return true; } -bool Shader::fillUniformReflectionData(UniformInfo &u) +std::string Shader::getShaderStageDebugName(ShaderStageType stage) const { - const auto &r = validationReflection; + std::string name = debugName; - if (u.baseType == UNIFORM_STORAGETEXTURE) + if (!name.empty()) { - const auto reflectionit = r.storageTextures.find(u.name); - if (reflectionit != r.storageTextures.end()) - { - u.storageTextureFormat = reflectionit->second.format; - u.access = reflectionit->second.access; - return true; - } - - // No reflection info - maybe glslang was better at detecting dead code - // than the driver's compiler? - return false; - } - else if (u.baseType == UNIFORM_STORAGEBUFFER) - { - const auto reflectionit = r.storageBuffers.find(u.name); - if (reflectionit != r.storageBuffers.end()) - { - u.bufferStride = reflectionit->second.stride; - u.bufferMemberCount = reflectionit->second.memberCount; - u.access = reflectionit->second.access; - return true; - } - - return false; + const char *stagename = "unknown"; + ShaderStage::getConstant(stage, stagename); + name += " (" + std::string(stagename) + ")"; } - return true; + return name; +} + +std::string Shader::canonicaliizeUniformName(const std::string &n) +{ + std::string name(n); + + // Some drivers/compilers append "[0]" to the end of array uniform names. + if (name.length() > 3) + { + size_t findpos = name.rfind("[0]"); + if (findpos != std::string::npos && findpos == name.length() - 3) + name.erase(name.length() - 3); + } + + return name; +} + +void Shader::handleUnknownUniformName(const char */*name*/) +{ + // TODO: do something here? +} + +void Shader::copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const +{ + count = std::min(count, info->count); + + size_t elementsize = info->components * 4; + if (info->baseType == UNIFORM_MATRIX) + elementsize = info->matrix.columns * info->matrix.rows * 4; + + // Assuming std140 packing rules, the source data can only be direct-copied + // to the uniform buffer in certain cases because it's tightly packed whereas + // the buffer's data isn't. + if (elementsize * info->count == info->dataSize || (count == 1 && info->baseType != UNIFORM_MATRIX)) + { + memcpy(dst, src, elementsize * count); + } + else + { + int veccount = count; + int comp = info->components; + + if (info->baseType == UNIFORM_MATRIX) + { + veccount *= info->matrix.rows; + comp = info->matrix.columns; + } + + const int *isrc = (const int *) src; + int *idst = (int *) dst; + + for (int i = 0; i < veccount; i++) + { + for (int c = 0; c < comp; c++) + idst[i * 4 + c] = isrc[i * comp + c]; + } + } } bool Shader::initialize() { - return glslang::InitializeProcess(); + bool success = glslang::InitializeProcess(); + if (!success) + return false; + + TBuiltInResource *resources = GetResources(); + *resources = *GetDefaultResources(); + + // This is 32 in the default resource struct, which is too high for Metal. + // TODO: Set this based on what the system actually supports? + resources->maxDrawBuffers = 8; + + return true; } void Shader::deinitialize() @@ -1315,7 +1670,6 @@ const std::string &Shader::getDefaultCode(StandardShader shader, ShaderStageType static StringMap::Entry languageEntries[] = { - { "glsl1", Shader::LANGUAGE_GLSL1 }, { "glsl3", Shader::LANGUAGE_GLSL3 }, { "glsl4", Shader::LANGUAGE_GLSL4 }, }; diff --git a/src/modules/graphics/Shader.h b/src/modules/graphics/Shader.h index 64e824cb8..7eaff628c 100644 --- a/src/modules/graphics/Shader.h +++ b/src/modules/graphics/Shader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,6 +26,7 @@ #include "Texture.h" #include "ShaderStage.h" #include "Resource.h" +#include "Buffer.h" // STL #include @@ -50,7 +51,6 @@ public: enum Language { - LANGUAGE_GLSL1, LANGUAGE_GLSL3, LANGUAGE_GLSL4, LANGUAGE_MAX_ENUM @@ -108,9 +108,18 @@ public: ACCESS_WRITE = (1 << 1), }; + enum ClipSpaceTransformFlags + { + CLIP_TRANSFORM_NONE = 0, + CLIP_TRANSFORM_FLIP_Y = 1 << 0, + CLIP_TRANSFORM_Z_NEG1_1_TO_0_1 = 1 << 1, + CLIP_TRANSFORM_Z_0_1_TO_NEG1_1 = 1 << 2, + }; + struct CompileOptions { std::map defines; + std::string debugName; }; struct SourceInfo @@ -128,6 +137,10 @@ public: struct UniformInfo { + UniformType baseType; + uint32 stageMask; + bool active; + int location; int count; @@ -137,7 +150,6 @@ public: MatrixSize matrix; }; - UniformType baseType; DataBaseType dataBaseType; TextureType textureType; Access access; @@ -147,6 +159,9 @@ public: size_t bufferMemberCount; std::string name; + int resourceIndex; + int bindingStartIndex; + union { void *data; @@ -156,12 +171,6 @@ public: }; size_t dataSize; - - union - { - Texture **textures; - Buffer **buffers; - }; }; union LocalUniformValue @@ -176,7 +185,8 @@ public: { Matrix4 transformMatrix; Matrix4 projectionMatrix; - Vector4 normalMatrix[3]; // 3x3 matrix padded to an array of 3 vector4s. + Vector4 scaleParams; + Vector4 clipSpaceParams; Colorf constantColor; // Pixel shader-centric variables past this point. @@ -189,7 +199,7 @@ public: // Pointer to the default Shader. static Shader *standardShaders[STANDARD_MAX_ENUM]; - Shader(StrongRef stages[]); + Shader(StrongRef stages[], const CompileOptions &options); virtual ~Shader(); /** @@ -212,14 +222,28 @@ public: **/ static bool isDefaultActive(); + /** + * Used for transforming standardized post-projection clip space positions + * into the backend's current clip space. + * Right now, the standard is: + * NDC y is [-1, 1] starting at the bottom (y-up). + * NDC z is [-1, 1]. + * Pixel coordinates are y-down. + * Pixel (0, 0) in a texture is the top-left. + * Aside from NDC z, this matches Metal and D3D12. + */ + static Vector4 computeClipSpaceParams(uint32 clipSpaceTransformFlags); + /** * Returns any warnings this Shader may have generated. **/ virtual std::string getWarnings() const = 0; + const std::string &getDebugName() const { return debugName; } + virtual int getVertexAttributeIndex(const std::string &name) = 0; - virtual const UniformInfo *getUniformInfo(const std::string &name) const = 0; + const UniformInfo *getUniformInfo(const std::string &name) const; virtual const UniformInfo *getUniformInfo(BuiltinUniform builtin) const = 0; virtual void updateUniform(const UniformInfo *info, int count) = 0; @@ -231,7 +255,7 @@ public: * Gets whether a uniform with the specified name exists and is actively * used in the shader. **/ - virtual bool hasUniform(const std::string &name) const = 0; + bool hasUniform(const std::string &name) const; /** * Sets the textures used when rendering a video. For internal use only. @@ -243,6 +267,11 @@ public: void getLocalThreadgroupSize(int *x, int *y, int *z); + const std::vector *getBufferFormat(const std::string &name) const; + + bool isUsingDeprecatedTextureFunctions() const; + bool isUsingDeprecatedTextureUniform() const; + static SourceInfo getSourceInfo(const std::string &src); static std::string createShaderStageCode(Graphics *gfx, ShaderStageType stage, const std::string &code, const CompileOptions &options, const SourceInfo &info, bool gles, bool checksystemfeatures); @@ -261,37 +290,36 @@ public: protected: - struct BufferReflection + struct Reflection { - size_t stride; - size_t memberCount; - Access access; - }; + std::map texelBuffers; + std::map storageBuffers; + std::map sampledTextures; + std::map storageTextures; + std::map localUniforms; - struct StorageTextureReflection - { - PixelFormat format; - Access access; - }; + std::map allUniforms; - struct LocalUniform - { - DataBaseType dataType; - std::vector initializerValues; - }; + std::map> localUniformInitializerValues; + + std::map> bufferFormats; + + int textureCount; + int bufferCount; - struct ValidationReflection - { - std::map storageBuffers; - std::map storageTextures; - std::map localUniforms; int localThreadgroupSize[3]; bool usesPointSize; }; - bool fillUniformReflectionData(UniformInfo &u); + std::string getShaderStageDebugName(ShaderStageType stage) const; - static bool validateInternal(StrongRef stages[], std::string& err, ValidationReflection &reflection); + void handleUnknownUniformName(const char *name); + + // std140 uniform buffer alignment-aware copy. + void copyToUniformBuffer(const UniformInfo *info, const void *src, void *dst, int count) const; + + static std::string canonicaliizeUniformName(const std::string &name); + static bool validateInternal(StrongRef stages[], std::string& err, Reflection &reflection); static DataBaseType getDataBaseType(PixelFormat format); static bool isResourceBaseTypeCompatible(DataBaseType a, DataBaseType b); @@ -300,7 +328,12 @@ protected: StrongRef stages[SHADERSTAGE_MAX_ENUM]; - ValidationReflection validationReflection; + Reflection reflection; + + std::vector activeTextures; + std::vector activeBuffers; + + std::string debugName; }; // Shader diff --git a/src/modules/graphics/ShaderStage.cpp b/src/modules/graphics/ShaderStage.cpp index 621c3b9af..ea628a7c2 100644 --- a/src/modules/graphics/ShaderStage.cpp +++ b/src/modules/graphics/ShaderStage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,114 +23,7 @@ #include "Graphics.h" #include "libraries/glslang/glslang/Public/ShaderLang.h" - -// TODO: Use love.graphics to determine actual limits? -static const TBuiltInResource defaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 16384, - /* .MaxVaryingFloats = */ 128, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 16384, - /* .MaxDrawBuffers = */ 8, - /* .MaxVertexUniformVectors = */ 4096, - /* .MaxVaryingVectors = */ 32, - /* .MaxFragmentUniformVectors = */ 4096, - /* .MaxVertexOutputVectors = */ 32, - /* .MaxFragmentInputVectors = */ 31, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 32, - /* .MaxComputeImageUniforms = */ 16, - /* .MaxComputeAtomicCounters = */ 4096, - /* .MaxComputeAtomicCounterBuffers = */ 8, - /* .MaxVaryingComponents = */ 128, - /* .MaxVertexOutputComponents = */ 128, - /* .MaxGeometryInputComponents = */ 128, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 192, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, - /* .MaxCombinedShaderOutputResources = */ 144, - /* .MaxImageSamples = */ 32, - /* .MaxVertexImageUniforms = */ 16, - /* .MaxTessControlImageUniforms = */ 16, - /* .MaxTessEvaluationImageUniforms = */ 16, - /* .MaxGeometryImageUniforms = */ 16, - /* .MaxFragmentImageUniforms = */ 16, - /* .MaxCombinedImageUniforms = */ 80, - /* .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 = */ 4096, - /* .MaxTessControlAtomicCounters = */ 4096, - /* .MaxTessEvaluationAtomicCounters = */ 4096, - /* .MaxGeometryAtomicCounters = */ 4096, - /* .MaxFragmentAtomicCounters = */ 4096, - /* .MaxCombinedAtomicCounters = */ 4096, - /* .MaxAtomicCounterBindings = */ 8, - /* .MaxVertexAtomicCounterBuffers = */ 8, - /* .MaxTessControlAtomicCounterBuffers = */ 8, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, - /* .MaxGeometryAtomicCounterBuffers = */ 8, - /* .MaxFragmentAtomicCounterBuffers = */ 8, - /* .MaxCombinedAtomicCounterBuffers = */ 8, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 32, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 1, - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - } -}; +#include "libraries/glslang/glslang/Public/ResourceLimits.h" namespace love { @@ -155,21 +48,17 @@ ShaderStage::ShaderStage(Graphics *gfx, ShaderStageType stage, const std::string auto glslangShader = new glslang::TShader(glslangStage); - bool supportsGLSL3 = gfx->getCapabilities().features[Graphics::FEATURE_GLSL3]; - int defaultversion = gles ? 100 : 120; - EProfile defaultprofile = ENoProfile; + int defaultversion = gles ? 300 : 330; + EProfile defaultprofile = gles ? EEsProfile : ECoreProfile; const char *csrc = glsl.c_str(); int srclen = (int) glsl.length(); glslangShader->setStringsWithLengths(&csrc, &srclen, 1); bool forcedefault = false; - if (source.find("#define LOVE_GLSL1_ON_GLSL3") != std::string::npos) - forcedefault = true; + bool forwardcompat = true; - bool forwardcompat = supportsGLSL3 && !forcedefault; - - if (!glslangShader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) + if (!glslangShader->parse(GetResources(), defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) { const char *stagename = "unknown"; getConstant(stage, stagename); diff --git a/src/modules/graphics/ShaderStage.h b/src/modules/graphics/ShaderStage.h index 6ad62ee11..fda4e5b9c 100644 --- a/src/modules/graphics/ShaderStage.h +++ b/src/modules/graphics/ShaderStage.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,6 +48,14 @@ enum ShaderStageType SHADERSTAGE_MAX_ENUM }; +enum ShaderStageMask +{ + SHADERSTAGEMASK_NONE = 0, + SHADERSTAGEMASK_VERTEX = 1 << SHADERSTAGE_VERTEX, + SHADERSTAGEMASK_PIXEL = 1 << SHADERSTAGE_PIXEL, + SHADERSTAGEMASK_COMPUTE = 1 << SHADERSTAGE_COMPUTE, +}; + class ShaderStage : public love::Object { public: diff --git a/src/modules/graphics/SpriteBatch.cpp b/src/modules/graphics/SpriteBatch.cpp index 8fe6f5ea6..60fadf462 100644 --- a/src/modules/graphics/SpriteBatch.cpp +++ b/src/modules/graphics/SpriteBatch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -395,7 +395,10 @@ void SpriteBatch::draw(Graphics *gfx, const Matrix4 &m) count = std::min(count, next - start); if (count > 0) - gfx->drawQuads(start, count, attributes, buffers, texture); + { + Texture *tex = gfx->getTextureOrDefaultForActiveShader(texture); + gfx->drawQuads(start, count, attributes, buffers, tex); + } } } // graphics diff --git a/src/modules/graphics/SpriteBatch.h b/src/modules/graphics/SpriteBatch.h index 0ff879c29..dc9c924aa 100644 --- a/src/modules/graphics/SpriteBatch.h +++ b/src/modules/graphics/SpriteBatch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/StreamBuffer.cpp b/src/modules/graphics/StreamBuffer.cpp index 88718ce9b..489d1a81c 100644 --- a/src/modules/graphics/StreamBuffer.cpp +++ b/src/modules/graphics/StreamBuffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/StreamBuffer.h b/src/modules/graphics/StreamBuffer.h index 3557a5253..ceaa87f94 100644 --- a/src/modules/graphics/StreamBuffer.h +++ b/src/modules/graphics/StreamBuffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -57,6 +57,8 @@ public: BufferUsage getMode() const { return mode; } size_t getUsableSize() const { return bufferSize - frameGPUReadOffset; } + virtual size_t getGPUReadOffset() const = 0; + virtual MapInfo map(size_t minsize) = 0; virtual size_t unmap(size_t usedsize) = 0; virtual void markUsed(size_t usedsize) = 0; diff --git a/src/modules/graphics/TextBatch.cpp b/src/modules/graphics/TextBatch.cpp index 2a5deab46..d809418fc 100644 --- a/src/modules/graphics/TextBatch.cpp +++ b/src/modules/graphics/TextBatch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -36,7 +36,7 @@ TextBatch::TextBatch(Font *font, const std::vector &t , vertexData(nullptr) , modifiedVertices() , vertOffset(0) - , textureCacheID((uint32) -1) + , textureCacheID(font->getTextureCacheID()) { set(text); } @@ -290,7 +290,10 @@ void TextBatch::draw(Graphics *gfx, const Matrix4 &m) Graphics::TempTransform transform(gfx, m); for (const Font::DrawCommand &cmd : drawCommands) - gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, cmd.texture); + { + Texture *tex = gfx->getTextureOrDefaultForActiveShader(cmd.texture); + gfx->drawQuads(cmd.startvertex / 4, cmd.vertexcount / 4, vertexAttributes, vertexBuffers, tex); + } } } // graphics diff --git a/src/modules/graphics/TextBatch.h b/src/modules/graphics/TextBatch.h index 82763fc27..f6fc35d9a 100644 --- a/src/modules/graphics/TextBatch.h +++ b/src/modules/graphics/TextBatch.h @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index e9b7ab1f7..bd777df3d 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -167,8 +167,8 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) , renderTarget(settings.renderTarget) , computeWrite(settings.computeWrite) , readable(true) + , viewFormats(settings.viewFormats) , mipmapsMode(settings.mipmaps) - , sRGB(isGammaCorrect() && !settings.linear) , width(settings.width) , height(settings.height) , depth(settings.type == TEXTURE_VOLUME ? settings.layers : 1) @@ -179,6 +179,9 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) , requestedMSAA(settings.msaa > 1 ? settings.msaa : 0) , samplerState() , graphicsMemorySize(0) + , debugName(settings.debugName) + , rootView({this, 0, 0}) + , parentView({this, 0, 0}) { const auto &caps = gfx->getCapabilities(); int requestedMipmapCount = settings.mipmapCount; @@ -204,7 +207,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) love::image::ImageDataBase *slice = slices->get(0, 0); format = slice->getFormat(); - if (sRGB) + if (isGammaCorrect() && !slice->isLinear()) format = getSRGBPixelFormat(format); pixelWidth = slice->getWidth(); @@ -235,7 +238,9 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) else readable = !renderTarget || !isPixelFormatDepthStencil(format); - format = gfx->getSizedFormat(format, renderTarget, readable); + format = gfx->getSizedFormat(format); + if (!isGammaCorrect() || settings.linear) + format = getLinearPixelFormat(format); if (mipmapsMode == MIPMAPS_AUTO && isCompressed()) mipmapsMode = MIPMAPS_MANUAL; @@ -248,9 +253,6 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) mipmapCount = std::min(totalMipmapCount, requestedMipmapCount); else mipmapCount = totalMipmapCount; - - if (mipmapCount != totalMipmapCount && !caps.features[Graphics::FEATURE_MIPMAP_RANGE]) - throw love::Exception("Custom mipmap ranges for a texture are not supported on this system (%d mipmap levels are required but only %d levels were provided.)", totalMipmapCount, mipmapCount); } const char *miperr = nullptr; @@ -282,32 +284,30 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) if (isCompressed() && renderTarget) throw love::Exception("Compressed textures cannot be render targets."); - uint32 usage = PIXELFORMATUSAGEFLAGS_NONE; - if (renderTarget) - usage |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; - if (readable) - usage |= PIXELFORMATUSAGEFLAGS_SAMPLE; - if (computeWrite) - usage |= PIXELFORMATUSAGEFLAGS_COMPUTEWRITE; - - if (!gfx->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, sRGB)) + for (PixelFormat viewformat : viewFormats) { - const char *fstr = "unknown"; - love::getConstant(format, fstr); + if (getLinearPixelFormat(viewformat) == getLinearPixelFormat(format)) + continue; - const char *readablestr = ""; - if (readable != !isPixelFormatDepthStencil(format)) - readablestr = readable ? " readable" : " non-readable"; + if (isPixelFormatCompressed(format) || isPixelFormatCompressed(viewformat)) + throw love::Exception("Compressed textures cannot use different pixel formats for texture views, aside from sRGB versus linear variants of the same pixel format."); - const char *rtstr = ""; - if (computeWrite) - rtstr = " as a compute shader-writable texture"; - else if (renderTarget) - rtstr = " as a render target"; + if (isPixelFormatColor(viewformat) != isPixelFormatColor(format)) + throw love::Exception("Color-format textures cannot use depth/stencil pixel formats and vice versa, in texture views."); - throw love::Exception("The %s%s pixel format is not supported%s on this system.", fstr, readablestr, rtstr); + // TODO: depth[24|32f]_stencil8 -> stencil8 can work. + if (isPixelFormatDepthStencil(viewformat)) + throw love::Exception("Using different pixel formats for texture views is not currently supported for depth or stencil formats."); + + size_t viewbytes = getPixelFormatBlockSize(viewformat); + size_t basebytes = getPixelFormatBlockSize(format); + + if (viewbytes != basebytes) + throw love::Exception("Texture view pixel formats must have the same bits per pixel as the base texture's pixel format."); } + validatePixelFormat(gfx); + if (!caps.textureTypes[texType]) { const char *textypestr = "unknown"; @@ -328,10 +328,131 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices) ++textureCount; } +Texture::Texture(Graphics *gfx, Texture *base, const ViewSettings &viewsettings) + : texType(viewsettings.type.get(base->getTextureType())) + , format(viewsettings.format.get(base->getPixelFormat())) + , renderTarget(base->renderTarget) + , computeWrite(base->computeWrite) + , readable(base->readable) + , viewFormats(base->viewFormats) + , mipmapsMode(base->mipmapsMode) + , width(1) + , height(1) + , depth(1) + , layers(1) + , mipmapCount(1) + , pixelWidth(1) + , pixelHeight(1) + , requestedMSAA(base->requestedMSAA) + , samplerState(base->samplerState) + , quad(base->quad) + , graphicsMemorySize(0) + , debugName(viewsettings.debugName) + , rootView({base->rootView.texture, 0, 0}) + , parentView({base, viewsettings.mipmapStart.get(0), viewsettings.layerStart.get(0)}) +{ + width = base->getWidth(parentView.startMipmap); + height = base->getHeight(parentView.startMipmap); + + if (texType == TEXTURE_VOLUME) + depth = base->getDepth(parentView.startMipmap); + + if (texType == TEXTURE_2D_ARRAY) + { + int baselayers = base->getTextureType() == TEXTURE_CUBE ? 6 : base->getLayerCount(); + layers = viewsettings.layerCount.get(baselayers - parentView.startLayer); + } + + mipmapCount = viewsettings.mipmapCount.get(base->getMipmapCount() - parentView.startMipmap); + + pixelWidth = base->getPixelWidth(parentView.startMipmap); + pixelHeight = base->getPixelHeight(parentView.startMipmap); + + if (parentView.startMipmap < 0) + throw love::Exception("Invalid mipmap start value for texture view (out of range)."); + + if (mipmapCount < 0 || parentView.startMipmap + mipmapCount > base->getMipmapCount()) + throw love::Exception("Invalid mipmap start or count value for texture view (out of range)."); + + if (parentView.startLayer < 0) + throw love::Exception("Invalid layer start value for texture view (out of range)."); + + int baseLayerCount = base->getTextureType() == TEXTURE_CUBE ? 6 : base->getLayerCount(); + if (layers < 0 || parentView.startLayer + layers > baseLayerCount) + throw love::Exception("Invalid layer start or count value for texture view (out of range)."); + + if (texType == TEXTURE_CUBE && parentView.startLayer + 6 > baseLayerCount) + throw love::Exception("Cube texture view cannot fit in the base texture's layers with the given start layer."); + + ViewInfo nextView = { this, 0, 0 }; + while (nextView.texture != rootView.texture) + { + nextView = nextView.texture->parentView; + rootView.startMipmap += nextView.startMipmap; + rootView.startLayer += nextView.startLayer; + } + + const auto &caps = gfx->getCapabilities(); + if (!caps.features[Graphics::FEATURE_GLSL4]) + throw love::Exception("Texture views are not supported on this system (GLSL 4 support is necessary.)"); + + validatePixelFormat(gfx); + + if (!caps.textureTypes[texType]) + { + const char *textypestr = "unknown"; + Texture::getConstant(texType, textypestr); + throw love::Exception("%s textures are not supported on this system.", textypestr); + } + + if (!readable) + throw love::Exception("Texture views are not supported for non-readable textures."); + + if (base->getTextureType() == TEXTURE_2D) + { + if (texType != TEXTURE_2D && texType != TEXTURE_2D_ARRAY) + throw love::Exception("Texture views created from a 2D texture must use the 2d or array texture type."); + } + else if (base->getTextureType() == TEXTURE_2D_ARRAY || base->getTextureType() == TEXTURE_CUBE) + { + if (texType != TEXTURE_2D && texType != TEXTURE_2D_ARRAY && texType != TEXTURE_CUBE) + throw love::Exception("Texture views created from an array or cube texture must use the 2d, array, or cube texture type."); + } + else if (base->getTextureType() == TEXTURE_VOLUME) + { + if (texType != TEXTURE_VOLUME) + throw love::Exception("Texture views created from a volume texture must use the volume texture type."); + } + else + { + throw love::Exception("Unknown texture type."); + } + + if (format != base->getPixelFormat()) + { + if (std::find(viewFormats.begin(), viewFormats.end(), format) == viewFormats.end()) + throw love::Exception("Using a different pixel format in a texture view requires the original texture to be created with a 'viewformats' setting that includes the given format in its list."); + } + + const char *miperr = nullptr; + if (mipmapsMode == MIPMAPS_AUTO && !supportsGenerateMipmaps(miperr)) + mipmapsMode = MIPMAPS_MANUAL; + + rootView.texture->retain(); + parentView.texture->retain(); +} + Texture::~Texture() { - --textureCount; setGraphicsMemorySize(0); + + if (this == rootView.texture) + --textureCount; + + if (rootView.texture != this && rootView.texture != nullptr) + rootView.texture->release(); + if (parentView.texture != this && parentView.texture != nullptr) + parentView.texture->release(); } void Texture::setGraphicsMemorySize(int64 bytes) @@ -350,18 +471,18 @@ void Texture::draw(Graphics *gfx, const Matrix4 &m) void Texture::draw(Graphics *gfx, Quad *q, const Matrix4 &localTransform) { - if (!readable) - throw love::Exception("Textures with non-readable formats cannot be drawn."); - - if (renderTarget && gfx->isRenderTargetActive(this)) - throw love::Exception("Cannot render a Texture to itself."); - if (texType == TEXTURE_2D_ARRAY) { drawLayer(gfx, q->getLayer(), q, localTransform); return; } + if (!readable) + throw love::Exception("Textures with non-readable formats cannot be drawn."); + + if (renderTarget && gfx->isRenderTargetActive(this)) + throw love::Exception("Cannot render a Texture to itself."); + const Matrix4 &tm = gfx->getTransform(); bool is2D = tm.isAffine2DTransform(); @@ -449,14 +570,8 @@ void Texture::drawLayer(Graphics *gfx, int layer, Quad *q, const Matrix4 &m) void Texture::uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y) { - love::image::ImageData *id = dynamic_cast(d); - - love::thread::EmptyLock lock; - if (id != nullptr) - lock.setLock(id->getMutex()); - Rect rect = {x, y, d->getWidth(), d->getHeight()}; - uploadByteData(d->getFormat(), d->getData(), d->getSize(), level, slice, rect); + uploadByteData(d->getData(), d->getSize(), level, slice, rect); } void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap, int x, int y, bool reloadmipmaps) @@ -475,7 +590,9 @@ void Texture::replacePixels(love::image::ImageDataBase *d, int slice, int mipmap if (getHandle() == 0) return; - if (d->getFormat() != getPixelFormat()) + // ImageData format might be linear but intended to be used as sRGB, so we + // don't error if only the sRGBness is different. + if (getLinearPixelFormat(d->getFormat()) != getLinearPixelFormat(getPixelFormat())) throw love::Exception("Pixel formats must match."); if (mipmap < 0 || mipmap >= getMipmapCount()) @@ -531,7 +648,7 @@ void Texture::replacePixels(const void *data, size_t size, int slice, int mipmap Graphics::flushBatchedDrawsGlobal(); - uploadByteData(format, data, size, mipmap, slice, rect); + uploadByteData(data, size, mipmap, slice, rect); if (reloadmipmaps && mipmap == 0 && getMipmapCount() > 1) generateMipmaps(); @@ -581,39 +698,13 @@ void Texture::generateMipmaps() if (!supportsGenerateMipmaps(err)) throw love::Exception("%s", err); + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr && gfx->isRenderTargetActive(this)) + throw love::Exception("generateMipmaps cannot be called on this Texture while it's an active render target."); + generateMipmapsInternal(); } -TextureType Texture::getTextureType() const -{ - return texType; -} - -PixelFormat Texture::getPixelFormat() const -{ - return format; -} - -Texture::MipmapsMode Texture::getMipmapsMode() const -{ - return mipmapsMode; -} - -bool Texture::isRenderTarget() const -{ - return renderTarget; -} - -bool Texture::isComputeWritable() const -{ - return computeWrite; -} - -bool Texture::isReadable() const -{ - return readable; -} - bool Texture::isCompressed() const { return isPixelFormatCompressed(format); @@ -621,7 +712,7 @@ bool Texture::isCompressed() const bool Texture::isFormatLinear() const { - return isGammaCorrect() && !sRGB && !isPixelFormatSRGB(format); + return isGammaCorrect() && !isPixelFormatSRGB(format); } bool Texture::isValidSlice(int slice, int mip) const @@ -687,28 +778,39 @@ int Texture::getRequestedMSAA() const return requestedMSAA; } -void Texture::setSamplerState(const SamplerState &s) +const SamplerState &Texture::getSamplerState() const +{ + return samplerState; +} + +SamplerState Texture::validateSamplerState(SamplerState s) const { if (!readable) - return; + return s; if (s.depthSampleMode.hasValue && !isPixelFormatDepth(format)) throw love::Exception("Only depth textures can have a depth sample compare mode."); - Graphics::flushBatchedDrawsGlobal(); - - samplerState = s; - - if (samplerState.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE && getMipmapCount() == 1) - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + if (s.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE && getMipmapCount() == 1) + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; if (texType == TEXTURE_CUBE) - samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; -} + s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; -const SamplerState &Texture::getSamplerState() const -{ - return samplerState; + if (s.minFilter == SamplerState::FILTER_LINEAR || s.magFilter == SamplerState::FILTER_LINEAR || s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (!gfx->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_LINEAR)) + { + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + if (s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; + } + } + + Graphics::flushBatchedDrawsGlobal(); + + return s; } Quad *Texture::getQuad() const @@ -783,6 +885,35 @@ bool Texture::validateDimensions(bool throwException) const return success; } +void Texture::validatePixelFormat(Graphics *gfx) const +{ + uint32 usage = PIXELFORMATUSAGEFLAGS_NONE; + if (renderTarget) + usage |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; + if (readable) + usage |= PIXELFORMATUSAGEFLAGS_SAMPLE; + if (computeWrite) + usage |= PIXELFORMATUSAGEFLAGS_COMPUTEWRITE; + + if (!gfx->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage)) + { + const char *fstr = "unknown"; + love::getConstant(format, fstr); + + const char *readablestr = ""; + if (readable != !isPixelFormatDepthStencil(format)) + readablestr = readable ? " readable" : " non-readable"; + + const char *rtstr = ""; + if (computeWrite) + rtstr = " as a compute shader-writable texture"; + else if (renderTarget) + rtstr = " as a render target"; + + throw love::Exception("The %s%s pixel format is not supported%s on this system.", fstr, readablestr, rtstr); + } +} + Texture::Slices::Slices(TextureType textype) : textureType(textype) { @@ -885,6 +1016,7 @@ bool Texture::Slices::validate() const int w = firstdata->getWidth(); int h = firstdata->getHeight(); PixelFormat format = firstdata->getFormat(); + bool linear = firstdata->isLinear(); if (textureType == TEXTURE_CUBE && w != h) throw love::Exception("Cube textures must have equal widths and heights for each cube face."); @@ -924,6 +1056,9 @@ bool Texture::Slices::validate() const if (format != slicedata->getFormat()) throw love::Exception("All texture slices and mipmaps must have the same pixel format."); + + if (linear != slicedata->isLinear()) + throw love::Exception("All texture slices and mipmaps must have the same linear setting."); } mipw = std::max(mipw / 2, 1); @@ -969,7 +1104,9 @@ static StringMap::Entry setting { "msaa", Texture::SETTING_MSAA }, { "canvas", Texture::SETTING_RENDER_TARGET }, { "computewrite", Texture::SETTING_COMPUTE_WRITE }, + { "viewformats", Texture::SETTING_VIEW_FORMATS }, { "readable", Texture::SETTING_READABLE }, + { "debugname", Texture::SETTING_DEBUGNAME }, }; static StringMap settingTypes(settingTypeEntries, sizeof(settingTypeEntries)); diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 2132bf741..0f228848f 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,6 +39,7 @@ // C #include +#include namespace love { @@ -174,7 +175,9 @@ public: SETTING_MSAA, SETTING_RENDER_TARGET, SETTING_COMPUTE_WRITE, + SETTING_VIEW_FORMATS, SETTING_READABLE, + SETTING_DEBUGNAME, SETTING_MAX_ENUM }; @@ -193,7 +196,20 @@ public: int msaa = 1; bool renderTarget = false; bool computeWrite = false; + std::vector viewFormats; OptionalBool readable; + std::string debugName; + }; + + struct ViewSettings + { + Optional format; + Optional type; + OptionalInt mipmapStart; + OptionalInt mipmapCount; + OptionalInt layerStart; + OptionalInt layerCount; + std::string debugName; }; struct Slices @@ -226,10 +242,14 @@ public: }; // Slices - static int64 totalGraphicsMemory; + struct ViewInfo + { + Texture *texture; + int startMipmap; + int startLayer; + }; - Texture(Graphics *gfx, const Settings &settings, const Slices *slices); - virtual ~Texture(); + static int64 totalGraphicsMemory; // Drawable. void draw(Graphics *gfx, const Matrix4 &m) override; @@ -253,13 +273,15 @@ public: virtual ptrdiff_t getRenderTargetHandle() const = 0; virtual ptrdiff_t getSamplerHandle() const = 0; - TextureType getTextureType() const; - PixelFormat getPixelFormat() const; - MipmapsMode getMipmapsMode() const; + TextureType getTextureType() const { return texType; } + PixelFormat getPixelFormat() const { return format; } + MipmapsMode getMipmapsMode() const { return mipmapsMode; } - bool isRenderTarget() const; - bool isComputeWritable() const; - bool isReadable() const; + bool isRenderTarget() const { return renderTarget; } + bool isComputeWritable() const { return computeWrite; } + bool isReadable() const { return readable; } + + const std::vector &getViewFormats() const { return viewFormats; } bool isCompressed() const; bool isFormatLinear() const; @@ -283,11 +305,16 @@ public: int getRequestedMSAA() const; virtual int getMSAA() const = 0; - virtual void setSamplerState(const SamplerState &s); + virtual void setSamplerState(const SamplerState &s) = 0; const SamplerState &getSamplerState() const; Quad *getQuad() const; + const ViewInfo &getRootViewInfo() const { return rootView; } + const ViewInfo &getParentViewInfo() const { return parentView; } + + const std::string &getDebugName() const { return debugName; } + static int getTotalMipmapCount(int w, int h); static int getTotalMipmapCount(int w, int h, int d); @@ -306,15 +333,22 @@ public: protected: + Texture(Graphics *gfx, const Settings &settings, const Slices *slices); + Texture(Graphics *gfx, Texture *base, const ViewSettings &viewsettings); + virtual ~Texture(); + void setGraphicsMemorySize(int64 size); void uploadImageData(love::image::ImageDataBase *d, int level, int slice, int x, int y); - virtual void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) = 0; + virtual void uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) = 0; bool supportsGenerateMipmaps(const char *&outReason) const; virtual void generateMipmapsInternal() = 0; + SamplerState validateSamplerState(SamplerState s) const; + bool validateDimensions(bool throwException) const; + void validatePixelFormat(Graphics *gfx) const; TextureType texType; @@ -323,9 +357,9 @@ protected: bool computeWrite; bool readable; - MipmapsMode mipmapsMode; + std::vector viewFormats; - bool sRGB; + MipmapsMode mipmapsMode; int width; int height; @@ -345,6 +379,11 @@ protected: int64 graphicsMemorySize; + std::string debugName; + + ViewInfo rootView; + ViewInfo parentView; + }; // Texture } // graphics diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 7ba5a1098..b686f5d03 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -115,6 +115,15 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) { update(); + // setVideoTextures may call flushBatchedDraws before setting the textures, so + // we can't call it after requestBatchedDraw. + auto shader = Shader::current; + if (Shader::isDefaultActive()) + shader = Shader::standardShaders[Shader::STANDARD_VIDEO]; + + if (shader != nullptr) + shader->setVideoTextures(textures[0], textures[1], textures[2]); + const Matrix4 &tm = gfx->getTransform(); bool is2D = tm.isAffine2DTransform(); @@ -145,9 +154,6 @@ void Video::draw(Graphics *gfx, const Matrix4 &m) verts[i].color = c; } - if (Shader::current != nullptr) - Shader::current->setVideoTextures(textures[0], textures[1], textures[2]); - gfx->flushBatchedDraws(); } diff --git a/src/modules/graphics/Video.h b/src/modules/graphics/Video.h index a814bc83f..dd9568186 100644 --- a/src/modules/graphics/Video.h +++ b/src/modules/graphics/Video.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Volatile.cpp b/src/modules/graphics/Volatile.cpp index 2ee6a7879..fc098c96a 100644 --- a/src/modules/graphics/Volatile.cpp +++ b/src/modules/graphics/Volatile.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/Volatile.h b/src/modules/graphics/Volatile.h index 73d6cce15..c72582526 100644 --- a/src/modules/graphics/Volatile.h +++ b/src/modules/graphics/Volatile.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/Buffer.h b/src/modules/graphics/metal/Buffer.h index 1bd6d46e2..cba716057 100644 --- a/src/modules/graphics/metal/Buffer.h +++ b/src/modules/graphics/metal/Buffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -41,7 +41,6 @@ public: void *map(MapType map, size_t offset, size_t size) override; void unmap(size_t usedoffset, size_t usedsize) override; bool fill(size_t offset, size_t size, const void *data) override; - void clear(size_t offset, size_t size) override; void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override; ptrdiff_t getHandle() const override { return (ptrdiff_t) buffer; } @@ -49,6 +48,8 @@ public: private: + void clearInternal(size_t offset, size_t size) override; + id buffer; id texture; diff --git a/src/modules/graphics/metal/Buffer.mm b/src/modules/graphics/metal/Buffer.mm index c797ffa6d..82d2cbc53 100644 --- a/src/modules/graphics/metal/Buffer.mm +++ b/src/modules/graphics/metal/Buffer.mm @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,6 +21,8 @@ #include "Buffer.h" #include "Graphics.h" +#include "common/memory.h" + namespace love { namespace graphics @@ -65,6 +67,19 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id device, const Settin size = getSize(); arraylength = getArrayLength(); + if (usageFlags & BUFFERUSAGEFLAG_TEXEL) + { + if (@available(iOS 12, macOS 10.14, *)) + { + MTLPixelFormat pixformat = getMTLPixelFormat(getDataMember(0).decl.format); + NSUInteger alignment = 1; + if (pixformat != MTLPixelFormatInvalid) + alignment = [device minimumTextureBufferAlignmentForPixelFormat:pixformat]; + + size = alignUp(size, (size_t) alignment); + } + } + MTLResourceOptions opts = 0; if (settings.dataUsage == BUFFERDATAUSAGE_READBACK) opts |= MTLResourceStorageModeShared; @@ -76,12 +91,13 @@ Buffer::Buffer(love::graphics::Graphics *gfx, id device, const Settin if (buffer == nil) throw love::Exception("Could not create buffer with %d bytes (out of VRAM?)", size); + if (!debugName.empty()) + buffer.label = @(debugName.c_str()); + if (usageFlags & BUFFERUSAGEFLAG_TEXEL) { if (@available(iOS 12, macOS 10.14, *)) { - // TODO: minimumTextureBufferAlignmentForPixelFormat - MTLPixelFormat pixformat = getMTLPixelFormat(getDataMember(0).decl.format); if (pixformat == MTLPixelFormatInvalid) throw love::Exception("Could not create Metal texel buffer: invalid format."); @@ -206,17 +222,8 @@ bool Buffer::fill(size_t offset, size_t size, const void *data) return true; }} -void Buffer::clear(size_t offset, size_t size) +void Buffer::clearInternal(size_t offset, size_t size) { @autoreleasepool { - if (isImmutable()) - throw love::Exception("Cannot clear an immutable Buffer."); - else if (isMapped()) - throw love::Exception("Cannot clear a mapped Buffer."); - else if (offset + size > getSize()) - throw love::Exception("The given offset and size parameters to clear() are not within the Buffer's size."); - else if (offset % 4 != 0 || size % 4 != 0) - throw love::Exception("clear() must be used with offset and size parameters that are multiples of 4 bytes."); - auto gfx = Graphics::getInstance(); auto encoder = gfx->useBlitEncoder(); diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index ab2e8fc2b..c932ca9b2 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -60,16 +60,12 @@ public: Graphics(); virtual ~Graphics(); - // Implements Module. - const char *getName() const override { return "love.graphics.metal"; } - love::graphics::Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) override; + love::graphics::Texture *newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) override; love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) override; - Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override; - - void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; - bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; + void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; + bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; void unSetMode() override; void setActive(bool active) override; @@ -96,7 +92,7 @@ public: void setScissor(const Rect &rect) override; void setScissor() override; - void setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) override; + void setStencilState(const StencilState &s) override; void setDepthMode(CompareMode compare, bool write) override; @@ -110,8 +106,7 @@ public: void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; @@ -138,9 +133,10 @@ public: id getCachedSampler(const SamplerState &s); + bool isDepthCompareSamplerSupported() const; + StreamBuffer *getUniformBuffer() const { return uniformBuffer; } Buffer *getDefaultAttributesBuffer() const { return defaultAttributesBuffer; } - Texture *getDefaultTexture(TextureType textype) const { return defaultTextures[textype]; } int getClosestMSAASamples(int requestedsamples); @@ -198,7 +194,7 @@ private: }; love::graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; love::graphics::StreamBuffer *newStreamBuffer(BufferUsage usage, size_t size) override; love::graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; @@ -231,7 +227,6 @@ private: uint32 dirtyRenderState; CullMode lastCullMode; Shader::RenderPipelineKey lastRenderPipelineKey; - bool windowHasStencil; int shaderSwitches; StrongRef backbufferMSAA; @@ -245,11 +240,10 @@ private: StreamBuffer *uniformBuffer; StreamBuffer::MapInfo uniformBufferData; size_t uniformBufferOffset; + size_t uniformBufferGPUStart; Buffer *defaultAttributesBuffer; - Texture *defaultTextures[TEXTURE_MAX_ENUM]; - std::map cachedSamplers; std::unordered_map cachedDepthStencilStates; @@ -257,6 +251,8 @@ private: DeviceFamilies families; + bool isVMDevice; + }; // Graphics } // metal diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index f07433cd6..b481cfd8b 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -263,7 +263,8 @@ struct DefaultVertexAttributes Graphics *Graphics::graphicsInstance = nullptr; Graphics::Graphics() - : device(nil) + : love::graphics::Graphics("love.graphics.metal") + , device(nil) , commandQueue(nil) , commandBuffer(nil) , renderEncoder(nil) @@ -274,15 +275,15 @@ Graphics::Graphics() , dirtyRenderState(STATEBIT_ALL) , lastCullMode(CULL_MAX_ENUM) , lastRenderPipelineKey() - , windowHasStencil(false) , shaderSwitches(0) , requestedBackbufferMSAA(0) , attachmentStoreActions() , renderBindings() , uniformBufferOffset(0) + , uniformBufferGPUStart(0) , defaultAttributesBuffer(nullptr) - , defaultTextures() , families() + , isVMDevice(false) { @autoreleasepool { if (@available(macOS 10.15, iOS 13.0, *)) { @@ -296,6 +297,8 @@ Graphics::Graphics() throw love::Exception("LOVE's Metal graphics backend requires macOS 10.15+ or iOS 13+."); } + isVMDevice = [device.name containsString:@("Apple Paravirtual device")]; + #ifdef LOVE_MACOS // On multi-GPU macOS systems with a low and high power GPU (e.g. a 2016 // Macbook Pro), the OS doesn't activate the high power GPU for final @@ -328,7 +331,7 @@ Graphics::Graphics() initCapabilities(); - uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); + uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_UNIFORM, 1024 * 512 * 1); { std::vector dataformat = { @@ -342,21 +345,11 @@ Graphics::Graphics() }; Buffer::Settings attribsettings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); + attribsettings.debugName = "Default Vertex Attributes"; defaultAttributesBuffer = newBuffer(attribsettings, dataformat, &defaults, sizeof(DefaultVertexAttributes), 0); } - uint8 defaultpixel[] = {255, 255, 255, 255}; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - Texture::Settings settings; - settings.type = (TextureType) i; - settings.format = PIXELFORMAT_RGBA8_UNORM; - defaultTextures[i] = newTexture(settings); - Rect r = {0, 0, 1, 1}; - defaultTextures[i]->replacePixels(defaultpixel, sizeof(defaultpixel), 0, 0, r, false); - } - if (batchedDrawState.vb[0] == nullptr) { // Initial sizes that should be good enough for most cases. It will @@ -426,9 +419,6 @@ Graphics::~Graphics() commandQueue = nil; device = nil; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - defaultTextures[i]->release(); - for (auto &kvp : cachedSamplers) CFBridgingRelease(kvp.second); @@ -448,14 +438,19 @@ love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, return new Texture(this, device, settings, data); } +love::graphics::Texture *Graphics::newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) +{ + return new Texture(this, device, base, viewsettings); +} + love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) { return new ShaderStage(this, stage, source, gles, cachekey); } -love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(device, stages); + return new Shader(device, stages, options); } love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) @@ -473,19 +468,23 @@ love::graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod m return new GraphicsReadback(this, method, texture, slice, mipmap, rect, dest, destx, desty); } -Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool /*rendertotexture*/) const +void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { - uint32 flags = DEVICE_PROJECTION_FLIP_Y; - return calculateDeviceProjection(projection, flags); -} + bool sizechanged = width != this->width || height != this->height + || pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight; + + bool dschanged = backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth; + bool msaachanged = msaa != this->requestedBackbufferMSAA; -void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) -{ this->width = width; this->height = height; this->pixelWidth = pixelwidth; this->pixelHeight = pixelheight; + this->backbufferHasStencil = backbufferstencil; + this->backbufferHasDepth = backbufferdepth; + this->requestedBackbufferMSAA = msaa; + if (!isRenderTargetActive()) { dirtyRenderState |= STATEBIT_VIEWPORT | STATEBIT_SCISSOR; @@ -500,26 +499,38 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh settings.renderTarget = true; settings.readable.set(false); - backbufferMSAA.set(nullptr); - if (settings.msaa > 1) + if (sizechanged || msaachanged) { - settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM; - backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN); + backbufferMSAA.set(nullptr); + if (settings.msaa > 1) + { + settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM; + backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN); + } } - settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; - backbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN); + if (sizechanged || msaachanged || dschanged) + { + backbufferDepthStencil.set(nullptr); + if (backbufferstencil || backbufferdepth) + { + if (backbufferstencil && backbufferdepth) + settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; + else if (backbufferstencil) + settings.format = PIXELFORMAT_STENCIL8; + else if (backbufferdepth) + settings.format = PIXELFORMAT_DEPTH24_UNORM; + backbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN); + } + } } -bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) +bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { @autoreleasepool { this->width = width; this->height = height; this->metalLayer = (__bridge CAMetalLayer *) context; - this->windowHasStencil = windowhasstencil; - this->requestedBackbufferMSAA = msaa; - metalLayer.device = device; metalLayer.pixelFormat = isGammaCorrect() ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm; @@ -531,7 +542,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int metalLayer.magnificationFilter = kCAFilterNearest; #endif - setViewportSize(width, height, pixelwidth, pixelheight); + backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa); created = true; @@ -675,13 +686,15 @@ id Graphics::useRenderEncoder() passDesc.colorAttachments[0].depthPlane = 0; RenderTarget rt(backbufferDepthStencil); - setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth, false); - setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil, false); + if (rt.texture != nullptr && isPixelFormatDepth(rt.texture->getPixelFormat())) + setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth, false); + if (rt.texture != nullptr && isPixelFormatStencil(rt.texture->getPixelFormat())) + setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil, false); attachmentStoreActions.depth = MTLStoreActionDontCare; attachmentStoreActions.stencil = MTLStoreActionDontCare; auto &key = lastRenderPipelineKey; - key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_UNORM_sRGB : PIXELFORMAT_BGRA8_UNORM; + key.colorRenderTargetFormats = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM; key.depthStencilFormat = backbufferDepthStencil->getPixelFormat(); key.msaa = backbufferMSAA ? (uint8) backbufferMSAA->getMSAA() : 1; } @@ -715,11 +728,15 @@ void Graphics::submitRenderEncoder(SubmitType type) for (size_t i = 0; i < rts.colors.size(); i++) [renderEncoder setColorStoreAction:(store ? MTLStoreActionStore : actions.color[i]) atIndex:i]; - if (rts.depthStencil.texture.get() || rts.temporaryRTFlags != 0 || isbackbuffer) - { + love::graphics::Texture *ds = rts.depthStencil.texture.get(); + if (isbackbuffer) + ds = backbufferDepthStencil; + + if ((rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0 || (ds != nullptr && isPixelFormatDepth(ds->getPixelFormat()))) [renderEncoder setDepthStoreAction:store ? MTLStoreActionStore : actions.depth]; + + if ((rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0 || (ds != nullptr && isPixelFormatStencil(ds->getPixelFormat()))) [renderEncoder setStencilStoreAction:store ? MTLStoreActionStore : actions.stencil]; - } [renderEncoder endEncoding]; renderEncoder = nil; @@ -729,16 +746,22 @@ void Graphics::submitRenderEncoder(SubmitType type) for (int i = 0; i < MAX_COLOR_RENDER_TARGETS; i++) { passDesc.colorAttachments[i].loadAction = MTLLoadActionLoad; - passDesc.colorAttachments[i].texture = nil; - passDesc.colorAttachments[i].resolveTexture = nil; + if (type == SUBMIT_DONE) + { + passDesc.colorAttachments[i].texture = nil; + passDesc.colorAttachments[i].resolveTexture = nil; + } } passDesc.depthAttachment.loadAction = MTLLoadActionLoad; - passDesc.depthAttachment.texture = nil; - passDesc.depthAttachment.resolveTexture = nil; passDesc.stencilAttachment.loadAction = MTLLoadActionLoad; - passDesc.stencilAttachment.texture = nil; - passDesc.stencilAttachment.resolveTexture = nil; + if (type == SUBMIT_DONE) + { + passDesc.depthAttachment.texture = nil; + passDesc.depthAttachment.resolveTexture = nil; + passDesc.stencilAttachment.texture = nil; + passDesc.stencilAttachment.resolveTexture = nil; + } } } @@ -825,7 +848,7 @@ id Graphics::getCachedSampler(const SamplerState &s) desc.lodMinClamp = s.minLod; desc.lodMaxClamp = s.maxLod; - // TODO: This isn't supported on some older iOS devices... + // This isn't supported on some older iOS devices. Texture code checks for support. if (s.depthSampleMode.hasValue) desc.compareFunction = getMTLCompareFunction(s.depthSampleMode.value); @@ -837,6 +860,11 @@ id Graphics::getCachedSampler(const SamplerState &s) return sampler; }} +bool Graphics::isDepthCompareSamplerSupported() const +{ + return families.mac[1] || families.macCatalyst[1] || families.apple[3]; +} + id Graphics::getCachedDepthStencilState(const DepthState &depth, const StencilState &stencil) { uint64 key = (depth.compare << 0) | ((uint32)depth.write << 8) @@ -856,7 +884,7 @@ id Graphics::getCachedDepthStencilState(const DepthState & * example, if the compare function is GREATER then the stencil test will * pass if the reference value is greater than the value in the stencil * buffer. With our API it's more intuitive to assume that - * setStencilMode(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the + * setStencilState(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the * stencil buffer has a value greater than 4. **/ stencildesc.stencilCompareFunction = getMTLCompareFunction(getReversedCompareMode(stencil.compare)); @@ -896,8 +924,8 @@ void Graphics::applyRenderState(id encoder, const Verte const auto &rt = state.renderTargets.getFirstTarget(); if (rt.texture.get()) { - rtw = rt.texture->getPixelWidth(); - rth = rt.texture->getPixelHeight(); + rtw = rt.texture->getPixelWidth(rt.mipmap); + rth = rt.texture->getPixelHeight(rt.mipmap); } else { @@ -1011,14 +1039,19 @@ bool Graphics::applyShaderUniforms(id encoder, love::g if (uniformBuffer->getSize() < uniformBufferOffset + size) { size_t newsize = uniformBuffer->getSize() * 2; + if (uniformBufferOffset > 0) + uniformBuffer->nextFrame(); uniformBuffer->release(); - uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, newsize); + uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_UNIFORM, newsize); uniformBufferData = {}; uniformBufferOffset = 0; } if (uniformBufferData.data == nullptr) + { uniformBufferData = uniformBuffer->map(uniformBuffer->getSize()); + uniformBufferGPUStart = uniformBuffer->getGPUReadOffset(); + } memcpy(uniformBufferData.data + uniformBufferOffset, bufferdata, size); @@ -1026,7 +1059,7 @@ bool Graphics::applyShaderUniforms(id encoder, love::g int uniformindex = Shader::getUniformBufferBinding(); auto &bindings = renderBindings; - setBuffer(encoder, bindings, uniformindex, buffer, uniformBufferOffset); + setBuffer(encoder, bindings, uniformindex, buffer, uniformBufferGPUStart + uniformBufferOffset); uniformBufferOffset += alignUp(size, alignment); @@ -1046,7 +1079,7 @@ bool Graphics::applyShaderUniforms(id encoder, love::g if ((b.access & Shader::ACCESS_WRITE) != 0 && texture == nil) allWritableVariablesSet = false; } - + if (sampindex != LOVE_UINT8_MAX) setSampler(encoder, bindings, sampindex, samplertex); } @@ -1083,32 +1116,18 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo builtins->transformMatrix = getTransform(); builtins->projectionMatrix = getDeviceProjection(); - // The normal matrix is the transpose of the inverse of the rotation portion - // (top-left 3x3) of the transform matrix. - { - Matrix3 normalmatrix = Matrix3(builtins->transformMatrix).transposedInverse(); - const float *e = normalmatrix.getElements(); - for (int i = 0; i < 3; i++) - { - builtins->normalMatrix[i].x = e[i * 3 + 0]; - builtins->normalMatrix[i].y = e[i * 3 + 1]; - builtins->normalMatrix[i].z = e[i * 3 + 2]; - builtins->normalMatrix[i].w = 0.0f; - } - } + builtins->scaleParams.x = (float) getCurrentDPIScale(); + builtins->scaleParams.y = getPointSize(); - // Store DPI scale in an unused component of another vector. - builtins->normalMatrix[0].w = (float) getCurrentDPIScale(); - - // Same with point size. - builtins->normalMatrix[1].w = getPointSize(); + uint32 flags = Shader::CLIP_TRANSFORM_Z_NEG1_1_TO_0_1; + builtins->clipSpaceParams = Shader::computeClipSpaceParams(flags); builtins->screenSizeParams = Vector4(getPixelWidth(), getPixelHeight(), 1.0f, 0.0f); - auto rt = states.back().renderTargets.getFirstTarget().texture.get(); - if (rt != nullptr) + auto rt = states.back().renderTargets.getFirstTarget(); + if (rt.texture.get()) { - builtins->screenSizeParams.x = rt->getPixelWidth(); - builtins->screenSizeParams.y = rt->getPixelHeight(); + builtins->screenSizeParams.x = rt.texture->getPixelWidth(rt.mipmap); + builtins->screenSizeParams.y = rt.texture->getPixelHeight(rt.mipmap); } builtins->constantColor = getColor(); @@ -1117,14 +1136,19 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo if (uniformBuffer->getSize() < uniformBufferOffset + size) { size_t newsize = uniformBuffer->getSize() * 2; + if (uniformBufferOffset > 0) + uniformBuffer->nextFrame(); uniformBuffer->release(); - uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_VERTEX, newsize); + uniformBuffer = CreateStreamBuffer(device, BUFFERUSAGE_UNIFORM, newsize); uniformBufferData = {}; uniformBufferOffset = 0; } if (uniformBufferData.data == nullptr) + { uniformBufferData = uniformBuffer->map(uniformBuffer->getSize()); + uniformBufferGPUStart = uniformBuffer->getGPUReadOffset(); + } memcpy(uniformBufferData.data + uniformBufferOffset, bufferdata, size); @@ -1132,8 +1156,8 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo int uniformindex = Shader::getUniformBufferBinding(); auto &bindings = renderBindings; - setBuffer(renderEncoder, bindings, SHADERSTAGE_VERTEX, uniformindex, buffer, uniformBufferOffset); - setBuffer(renderEncoder, bindings, SHADERSTAGE_PIXEL, uniformindex, buffer, uniformBufferOffset); + setBuffer(renderEncoder, bindings, SHADERSTAGE_VERTEX, uniformindex, buffer, uniformBufferGPUStart + uniformBufferOffset); + setBuffer(renderEncoder, bindings, SHADERSTAGE_PIXEL, uniformindex, buffer, uniformBufferGPUStart + uniformBufferOffset); uniformBufferOffset += alignUp(size, alignment); @@ -1144,13 +1168,6 @@ void Graphics::applyShaderUniforms(id renderEncoder, lo if (b.isMainTexture) { - if (maintex == nullptr) - { - auto texinfo = shader->getMainTextureInfo(); - if (texinfo != nullptr && texinfo->textureType != TEXTURE_MAX_ENUM) - maintex = defaultTextures[texinfo->textureType]; - } - texture = getMTLTexture(maintex); samplertex = maintex; } @@ -1434,10 +1451,15 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int /*pixelw*/ } for (size_t i = rts.colors.size(); i < MAX_COLOR_RENDER_TARGETS; i++) + { passDesc.colorAttachments[i] = nil; + passDesc.colorAttachments[i].loadAction = MTLLoadActionLoad; + } passDesc.depthAttachment = nil; + passDesc.depthAttachment.loadAction = MTLLoadActionLoad; passDesc.stencilAttachment = nil; + passDesc.stencilAttachment.loadAction = MTLLoadActionLoad; auto ds = rts.depthStencil.texture; if (isbackbuffer && ds == nullptr) @@ -1492,12 +1514,6 @@ void Graphics::endPass(bool presenting) } submitRenderEncoder(SUBMIT_DONE); - - for (const auto &rt : rts.colors) - { - if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) - rt.texture->generateMipmaps(); - } } void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth) @@ -1777,34 +1793,20 @@ void Graphics::setScissor() } } -void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) +void Graphics::setStencilState(const StencilState &s) { - DisplayState &state = states.back(); - - if (action != STENCIL_KEEP) - { - const auto &rts = state.renderTargets; - love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); - - if (!isRenderTargetActive() && !windowHasStencil) - throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) - throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas."); - } + validateStencilState(s); flushBatchedDraws(); - state.stencil.action = action; - state.stencil.compare = compare; - state.stencil.value = value; - state.stencil.readMask = readmask; - state.stencil.writeMask = writemask; - + states.back().stencil = s; dirtyRenderState |= STATEBIT_STENCIL; } void Graphics::setDepthMode(CompareMode compare, bool write) { + validateDepthState(write); + DisplayState &state = states.back(); if (state.depthTest != compare || state.depthWrite != write) @@ -1864,31 +1866,9 @@ void Graphics::setWireframe(bool enable) } } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool /*rendertarget*/, bool /*readable*/) const +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { - switch (format) - { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; - } -} - -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) -{ - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; - bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); - - if (sRGB) - format = getSRGBPixelFormat(format); + format = getSizedFormat(format); const uint32 sample = PIXELFORMATUSAGEFLAGS_SAMPLE; const uint32 filter = PIXELFORMATUSAGEFLAGS_LINEAR; @@ -1902,7 +1882,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG uint32 flags = PIXELFORMATUSAGEFLAGS_NONE; - if (isPixelFormatCompressed(format) && rendertarget) + if (isPixelFormatCompressed(format) && (usage & rt) != 0) return false; // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf @@ -1946,8 +1926,13 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG // Requires texture swizzle support. if (@available(macOS 10.15, iOS 13, *)) { - if (families.apple[1] || families.mac[2] || families.macCatalyst[2]) - flags |= commonsample; + // As of early 2024, the VM device doesn't properly support texture swizzles + // (observed on GitHub's runners) which is required for LA8 support. + if (!isVMDevice) + { + if (families.apple[1] || families.mac[2] || families.macCatalyst[2]) + flags |= commonsample; + } } break; case PIXELFORMAT_RG16_UNORM: @@ -1977,8 +1962,8 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG case PIXELFORMAT_BGRA8_UNORM: flags |= all; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: + case PIXELFORMAT_BGRA8_sRGB: if (families.apple[1] || families.mac[1] || families.macCatalyst[1]) flags |= commonsample | commonrender; if (families.apple[2]) @@ -2027,7 +2012,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG case PIXELFORMAT_RGBA32_INT: case PIXELFORMAT_RGBA32_UINT: // If MSAA support for int formats is added this should be split up. - flags |= rt | computewrite; + flags |= sample | rt | computewrite; break; case PIXELFORMAT_RGBA4_UNORM: @@ -2077,8 +2062,11 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG break; case PIXELFORMAT_DXT1_UNORM: + case PIXELFORMAT_DXT1_sRGB: case PIXELFORMAT_DXT3_UNORM: + case PIXELFORMAT_DXT3_sRGB: case PIXELFORMAT_DXT5_UNORM: + case PIXELFORMAT_DXT5_sRGB: case PIXELFORMAT_BC4_UNORM: case PIXELFORMAT_BC4_SNORM: case PIXELFORMAT_BC5_UNORM: @@ -2086,22 +2074,30 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG case PIXELFORMAT_BC6H_UFLOAT: case PIXELFORMAT_BC6H_FLOAT: case PIXELFORMAT_BC7_UNORM: + case PIXELFORMAT_BC7_sRGB: if (families.mac[1] || families.macCatalyst[1]) flags |= commonsample; break; case PIXELFORMAT_PVR1_RGB2_UNORM: + case PIXELFORMAT_PVR1_RGB2_sRGB: case PIXELFORMAT_PVR1_RGB4_UNORM: + case PIXELFORMAT_PVR1_RGB4_sRGB: case PIXELFORMAT_PVR1_RGBA2_UNORM: + case PIXELFORMAT_PVR1_RGBA2_sRGB: case PIXELFORMAT_PVR1_RGBA4_UNORM: + case PIXELFORMAT_PVR1_RGBA4_sRGB: if (families.apple[1]) flags |= commonsample; break; case PIXELFORMAT_ETC1_UNORM: case PIXELFORMAT_ETC2_RGB_UNORM: + case PIXELFORMAT_ETC2_RGB_sRGB: case PIXELFORMAT_ETC2_RGBA_UNORM: + case PIXELFORMAT_ETC2_RGBA_sRGB: case PIXELFORMAT_ETC2_RGBA1_UNORM: + case PIXELFORMAT_ETC2_RGBA1_sRGB: case PIXELFORMAT_EAC_R_UNORM: case PIXELFORMAT_EAC_R_SNORM: case PIXELFORMAT_EAC_RG_UNORM: @@ -2110,20 +2106,34 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG flags |= commonsample; break; - case PIXELFORMAT_ASTC_4x4: - case PIXELFORMAT_ASTC_5x4: - case PIXELFORMAT_ASTC_5x5: - case PIXELFORMAT_ASTC_6x5: - case PIXELFORMAT_ASTC_6x6: - case PIXELFORMAT_ASTC_8x5: - case PIXELFORMAT_ASTC_8x6: - case PIXELFORMAT_ASTC_8x8: - case PIXELFORMAT_ASTC_10x5: - case PIXELFORMAT_ASTC_10x6: - case PIXELFORMAT_ASTC_10x8: - case PIXELFORMAT_ASTC_10x10: - case PIXELFORMAT_ASTC_12x10: - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_4x4_UNORM: + case PIXELFORMAT_ASTC_5x4_UNORM: + case PIXELFORMAT_ASTC_5x5_UNORM: + case PIXELFORMAT_ASTC_6x5_UNORM: + case PIXELFORMAT_ASTC_6x6_UNORM: + case PIXELFORMAT_ASTC_8x5_UNORM: + case PIXELFORMAT_ASTC_8x6_UNORM: + case PIXELFORMAT_ASTC_8x8_UNORM: + case PIXELFORMAT_ASTC_10x5_UNORM: + case PIXELFORMAT_ASTC_10x6_UNORM: + case PIXELFORMAT_ASTC_10x8_UNORM: + case PIXELFORMAT_ASTC_10x10_UNORM: + case PIXELFORMAT_ASTC_12x10_UNORM: + case PIXELFORMAT_ASTC_12x12_UNORM: + case PIXELFORMAT_ASTC_4x4_sRGB: + case PIXELFORMAT_ASTC_5x4_sRGB: + case PIXELFORMAT_ASTC_5x5_sRGB: + case PIXELFORMAT_ASTC_6x5_sRGB: + case PIXELFORMAT_ASTC_6x6_sRGB: + case PIXELFORMAT_ASTC_8x5_sRGB: + case PIXELFORMAT_ASTC_8x6_sRGB: + case PIXELFORMAT_ASTC_8x8_sRGB: + case PIXELFORMAT_ASTC_10x5_sRGB: + case PIXELFORMAT_ASTC_10x6_sRGB: + case PIXELFORMAT_ASTC_10x8_sRGB: + case PIXELFORMAT_ASTC_10x10_sRGB: + case PIXELFORMAT_ASTC_12x10_sRGB: + case PIXELFORMAT_ASTC_12x12_sRGB: if (families.apple[2]) flags |= commonsample; break; @@ -2207,10 +2217,6 @@ void Graphics::initCapabilities() families.macCatalyst[1 + i] = true; } } - else - { - // TODO: feature set API - } capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = true; capabilities.features[FEATURE_CLAMP_ZERO] = true; @@ -2221,7 +2227,6 @@ void Graphics::initCapabilities() if (families.mac[1] || families.macCatalyst[1] || families.apple[7]) capabilities.features[FEATURE_CLAMP_ONE] = true; } - capabilities.features[FEATURE_BLEND_MINMAX] = true; capabilities.features[FEATURE_LIGHTEN] = true; capabilities.features[FEATURE_FULL_NPOT] = true; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; @@ -2230,19 +2235,14 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_GLSL4] = true; capabilities.features[FEATURE_INSTANCING] = true; capabilities.features[FEATURE_TEXEL_BUFFER] = true; - capabilities.features[FEATURE_INDEX_BUFFER_32BIT] = true; - capabilities.features[FEATURE_COPY_BUFFER] = true; - capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = true; capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true; - capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = true; - capabilities.features[FEATURE_MIPMAP_RANGE] = true; if (families.mac[1] || families.macCatalyst[1] || families.apple[3]) capabilities.features[FEATURE_INDIRECT_DRAW] = true; else capabilities.features[FEATURE_INDIRECT_DRAW] = false; - static_assert(FEATURE_MAX_ENUM == 19, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); // https://developer.apple.com/metal/Metal-Feature-Set-Tables.pdf capabilities.limits[LIMIT_POINT_SIZE] = 511; diff --git a/src/modules/graphics/metal/GraphicsReadback.h b/src/modules/graphics/metal/GraphicsReadback.h index 7c9486019..7069a4a31 100644 --- a/src/modules/graphics/metal/GraphicsReadback.h +++ b/src/modules/graphics/metal/GraphicsReadback.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/GraphicsReadback.mm b/src/modules/graphics/metal/GraphicsReadback.mm index d74195d7a..808ca1e74 100644 --- a/src/modules/graphics/metal/GraphicsReadback.mm +++ b/src/modules/graphics/metal/GraphicsReadback.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/Metal.h b/src/modules/graphics/metal/Metal.h index e38b8f529..aaaaab220 100644 --- a/src/modules/graphics/metal/Metal.h +++ b/src/modules/graphics/metal/Metal.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,7 +43,7 @@ public: API_AVAILABLE(macos(10.15), ios(13.0)) MTLTextureSwizzleChannels swizzle; }; - static PixelFormatDesc convertPixelFormat(id device, PixelFormat format, bool &isSRGB); + static PixelFormatDesc convertPixelFormat(id device, PixelFormat format); }; // Metal diff --git a/src/modules/graphics/metal/Metal.mm b/src/modules/graphics/metal/Metal.mm index d547c3028..ff27cfb76 100644 --- a/src/modules/graphics/metal/Metal.mm +++ b/src/modules/graphics/metal/Metal.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -28,17 +28,11 @@ namespace graphics namespace metal { -Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelFormat format, bool &isSRGB) +Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelFormat format) { MTLPixelFormat mtlformat = MTLPixelFormatInvalid; PixelFormatDesc desc = {}; - if (isSRGB) - format = getSRGBPixelFormat(format); - - if (!isPixelFormatCompressed(format) && !isPixelFormatSRGB(format)) - isSRGB = false; - switch (format) { case PIXELFORMAT_R8_UNORM: @@ -50,13 +44,13 @@ Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelForm case PIXELFORMAT_RGBA8_UNORM: mtlformat = MTLPixelFormatRGBA8Unorm; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: mtlformat = MTLPixelFormatRGBA8Unorm_sRGB; break; case PIXELFORMAT_BGRA8_UNORM: mtlformat = MTLPixelFormatBGRA8Unorm; break; - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: mtlformat = MTLPixelFormatBGRA8Unorm_sRGB; break; case PIXELFORMAT_R16_UNORM: @@ -205,177 +199,264 @@ Metal::PixelFormatDesc Metal::convertPixelFormat(id device, PixelForm case PIXELFORMAT_DXT1_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC1_RGBA_sRGB : MTLPixelFormatBC1_RGBA; + mtlformat = MTLPixelFormatBC1_RGBA; +#endif + break; + case PIXELFORMAT_DXT1_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC1_RGBA_sRGB; #endif break; case PIXELFORMAT_DXT3_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC2_RGBA_sRGB : MTLPixelFormatBC2_RGBA; + mtlformat = MTLPixelFormatBC2_RGBA; +#endif + break; + case PIXELFORMAT_DXT3_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC2_RGBA_sRGB; #endif break; case PIXELFORMAT_DXT5_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC3_RGBA_sRGB : MTLPixelFormatBC3_RGBA; + mtlformat = MTLPixelFormatBC3_RGBA; +#endif + break; + case PIXELFORMAT_DXT5_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC3_RGBA_sRGB; #endif break; case PIXELFORMAT_BC4_UNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC4_RUnorm; #endif break; case PIXELFORMAT_BC4_SNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC4_RSnorm; #endif break; case PIXELFORMAT_BC5_UNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC5_RGUnorm; #endif break; case PIXELFORMAT_BC5_SNORM: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC5_RGSnorm; #endif break; case PIXELFORMAT_BC6H_UFLOAT: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC6H_RGBUfloat; #endif break; case PIXELFORMAT_BC6H_FLOAT: #ifndef LOVE_IOS - isSRGB = false; mtlformat = MTLPixelFormatBC6H_RGBFloat; #endif break; case PIXELFORMAT_BC7_UNORM: #ifndef LOVE_IOS - mtlformat = isSRGB ? MTLPixelFormatBC7_RGBAUnorm_sRGB : MTLPixelFormatBC7_RGBAUnorm; + mtlformat = MTLPixelFormatBC7_RGBAUnorm; +#endif + break; + case PIXELFORMAT_BC7_sRGB: +#ifndef LOVE_IOS + mtlformat = MTLPixelFormatBC7_RGBAUnorm_sRGB; #endif break; case PIXELFORMAT_PVR1_RGB2_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_2BPP_sRGB : MTLPixelFormatPVRTC_RGB_2BPP; + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP_sRGB; break; case PIXELFORMAT_PVR1_RGB4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_4BPP_sRGB : MTLPixelFormatPVRTC_RGB_4BPP; + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP_sRGB; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_2BPP_sRGB : MTLPixelFormatPVRTC_RGBA_2BPP; + mtlformat = MTLPixelFormatPVRTC_RGBA_2BPP; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_2BPP_sRGB; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatPVRTC_RGB_4BPP_sRGB : MTLPixelFormatPVRTC_RGBA_4BPP; + mtlformat = MTLPixelFormatPVRTC_RGBA_4BPP; break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatPVRTC_RGB_4BPP_sRGB; + break; + case PIXELFORMAT_ETC1_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8; + mtlformat = MTLPixelFormatETC2_RGB8; break; case PIXELFORMAT_ETC2_RGB_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8_sRGB : MTLPixelFormatETC2_RGB8; + mtlformat = MTLPixelFormatETC2_RGB8; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatETC2_RGB8_sRGB; break; case PIXELFORMAT_ETC2_RGBA_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatEAC_RGBA8_sRGB : MTLPixelFormatEAC_RGBA8; + mtlformat = MTLPixelFormatEAC_RGBA8; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatEAC_RGBA8_sRGB; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatETC2_RGB8A1_sRGB : MTLPixelFormatETC2_RGB8A1; + mtlformat = MTLPixelFormatETC2_RGB8A1; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatETC2_RGB8A1_sRGB; break; case PIXELFORMAT_EAC_R_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_R11Unorm; - } break; case PIXELFORMAT_EAC_R_SNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_R11Snorm; - } break; case PIXELFORMAT_EAC_RG_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_RG11Unorm; - } break; case PIXELFORMAT_EAC_RG_SNORM: if (@available(macOS 11.0, iOS 8.0, *)) - { - isSRGB = false; mtlformat = MTLPixelFormatEAC_RG11Snorm; - } break; - case PIXELFORMAT_ASTC_4x4: + case PIXELFORMAT_ASTC_4x4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_4x4_sRGB : MTLPixelFormatASTC_4x4_LDR; + mtlformat = MTLPixelFormatASTC_4x4_LDR; break; - case PIXELFORMAT_ASTC_5x4: + case PIXELFORMAT_ASTC_5x4_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_5x4_sRGB : MTLPixelFormatASTC_5x4_LDR; + mtlformat = MTLPixelFormatASTC_5x4_LDR; break; - case PIXELFORMAT_ASTC_5x5: + case PIXELFORMAT_ASTC_5x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_5x5_sRGB : MTLPixelFormatASTC_5x5_LDR; + mtlformat = MTLPixelFormatASTC_5x5_LDR; break; - case PIXELFORMAT_ASTC_6x5: + case PIXELFORMAT_ASTC_6x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_6x5_sRGB : MTLPixelFormatASTC_6x5_LDR; + mtlformat = MTLPixelFormatASTC_6x5_LDR; break; - case PIXELFORMAT_ASTC_6x6: + case PIXELFORMAT_ASTC_6x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_6x6_sRGB : MTLPixelFormatASTC_6x6_LDR; + mtlformat = MTLPixelFormatASTC_6x6_LDR; break; - case PIXELFORMAT_ASTC_8x5: + case PIXELFORMAT_ASTC_8x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x5_sRGB : MTLPixelFormatASTC_8x5_LDR; + mtlformat = MTLPixelFormatASTC_8x5_LDR; break; - case PIXELFORMAT_ASTC_8x6: + case PIXELFORMAT_ASTC_8x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x6_sRGB : MTLPixelFormatASTC_8x6_LDR; + mtlformat = MTLPixelFormatASTC_8x6_LDR; break; - case PIXELFORMAT_ASTC_8x8: + case PIXELFORMAT_ASTC_8x8_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_8x8_sRGB : MTLPixelFormatASTC_8x8_LDR; + mtlformat = MTLPixelFormatASTC_8x8_LDR; break; - case PIXELFORMAT_ASTC_10x5: + case PIXELFORMAT_ASTC_10x5_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x5_sRGB : MTLPixelFormatASTC_10x5_LDR; + mtlformat = MTLPixelFormatASTC_10x5_LDR; break; - case PIXELFORMAT_ASTC_10x6: + case PIXELFORMAT_ASTC_10x6_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x6_sRGB : MTLPixelFormatASTC_10x6_LDR; + mtlformat = MTLPixelFormatASTC_10x6_LDR; break; - case PIXELFORMAT_ASTC_10x8: + case PIXELFORMAT_ASTC_10x8_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x8_sRGB : MTLPixelFormatASTC_10x8_LDR; + mtlformat = MTLPixelFormatASTC_10x8_LDR; break; - case PIXELFORMAT_ASTC_10x10: + case PIXELFORMAT_ASTC_10x10_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_10x10_sRGB : MTLPixelFormatASTC_10x10_LDR; + mtlformat = MTLPixelFormatASTC_10x10_LDR; break; - case PIXELFORMAT_ASTC_12x10: + case PIXELFORMAT_ASTC_12x10_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_12x10_sRGB : MTLPixelFormatASTC_12x10_LDR; + mtlformat = MTLPixelFormatASTC_12x10_LDR; break; - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_12x12_UNORM: if (@available(macOS 11.0, iOS 8.0, *)) - mtlformat = isSRGB ? MTLPixelFormatASTC_12x12_sRGB : MTLPixelFormatASTC_12x12_LDR; + mtlformat = MTLPixelFormatASTC_12x12_LDR; + break; + case PIXELFORMAT_ASTC_4x4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_4x4_sRGB; + break; + case PIXELFORMAT_ASTC_5x4_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_5x4_sRGB; + break; + case PIXELFORMAT_ASTC_5x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_5x5_sRGB; + break; + case PIXELFORMAT_ASTC_6x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_6x5_sRGB; + break; + case PIXELFORMAT_ASTC_6x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_6x6_sRGB; + break; + case PIXELFORMAT_ASTC_8x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x5_sRGB; + break; + case PIXELFORMAT_ASTC_8x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x6_sRGB; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_8x8_sRGB; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x5_sRGB; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x6_sRGB; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x8_sRGB; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_10x10_sRGB; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_12x10_sRGB; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + if (@available(macOS 11.0, iOS 8.0, *)) + mtlformat = MTLPixelFormatASTC_12x12_sRGB; break; case PIXELFORMAT_UNKNOWN: diff --git a/src/modules/graphics/metal/Shader.h b/src/modules/graphics/metal/Shader.h index 49a6e2b7e..174902bfc 100644 --- a/src/modules/graphics/metal/Shader.h +++ b/src/modules/graphics/metal/Shader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -100,19 +100,17 @@ public: Access access; }; - Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM]); + Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options); virtual ~Shader(); // Implements Shader. void attach() override; std::string getWarnings() const override { return ""; } int getVertexAttributeIndex(const std::string &name) override; - const UniformInfo *getUniformInfo(const std::string &name) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; - bool hasUniform(const std::string &name) const override; ptrdiff_t getHandle() const override { return 0; } void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; @@ -140,13 +138,11 @@ private: }; void buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv_cross::SPIRType &type, size_t baseoffset, const std::string &basename); - void addImage(const spirv_cross::CompilerMSL &msl, const spirv_cross::Resource &resource, UniformType baseType); void compileFromGLSLang(id device, const glslang::TProgram &program); id functions[SHADERSTAGE_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; - std::map uniforms; uint8 *localUniformStagingData; uint8 *localUniformBufferData; diff --git a/src/modules/graphics/metal/Shader.mm b/src/modules/graphics/metal/Shader.mm index 5929e73ab..9bf1ec09c 100644 --- a/src/modules/graphics/metal/Shader.mm +++ b/src/modules/graphics/metal/Shader.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,11 +24,13 @@ // glslang #include "libraries/glslang/glslang/Public/ShaderLang.h" +#include "libraries/glslang/glslang/Public/ResourceLimits.h" #include "libraries/glslang/SPIRV/GlslangToSpv.h" #include "libraries/spirv_cross/spirv_msl.hpp" #include "libraries/spirv_cross/spirv_reflect.hpp" #include +#include namespace love { @@ -39,114 +41,6 @@ namespace metal static_assert(MAX_COLOR_RENDER_TARGETS <= 8, "Metal pipeline cache key only stores 8 render target pixel formats."); -// TODO: Use love.graphics to determine actual limits? -static const TBuiltInResource defaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 16384, - /* .MaxVaryingFloats = */ 128, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 16384, - /* .MaxDrawBuffers = */ 8, - /* .MaxVertexUniformVectors = */ 4096, - /* .MaxVaryingVectors = */ 32, - /* .MaxFragmentUniformVectors = */ 4096, - /* .MaxVertexOutputVectors = */ 32, - /* .MaxFragmentInputVectors = */ 31, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 32, - /* .MaxComputeImageUniforms = */ 16, - /* .MaxComputeAtomicCounters = */ 4096, - /* .MaxComputeAtomicCounterBuffers = */ 8, - /* .MaxVaryingComponents = */ 128, - /* .MaxVertexOutputComponents = */ 128, - /* .MaxGeometryInputComponents = */ 128, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 192, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, - /* .MaxCombinedShaderOutputResources = */ 144, - /* .MaxImageSamples = */ 32, - /* .MaxVertexImageUniforms = */ 16, - /* .MaxTessControlImageUniforms = */ 16, - /* .MaxTessEvaluationImageUniforms = */ 16, - /* .MaxGeometryImageUniforms = */ 16, - /* .MaxFragmentImageUniforms = */ 16, - /* .MaxCombinedImageUniforms = */ 80, - /* .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 = */ 4096, - /* .MaxTessControlAtomicCounters = */ 4096, - /* .MaxTessEvaluationAtomicCounters = */ 4096, - /* .MaxGeometryAtomicCounters = */ 4096, - /* .MaxFragmentAtomicCounters = */ 4096, - /* .MaxCombinedAtomicCounters = */ 4096, - /* .MaxAtomicCounterBindings = */ 8, - /* .MaxVertexAtomicCounterBuffers = */ 8, - /* .MaxTessControlAtomicCounterBuffers = */ 8, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, - /* .MaxGeometryAtomicCounterBuffers = */ 8, - /* .MaxFragmentAtomicCounterBuffers = */ 8, - /* .MaxCombinedAtomicCounterBuffers = */ 8, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 32, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 1, - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - } -}; - static MTLVertexFormat getMTLVertexFormat(DataFormat format) { switch (format) @@ -249,8 +143,8 @@ static EShLanguage getGLSLangStage(ShaderStageType stage) return EShLangCount; } -Shader::Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM]) - : love::graphics::Shader(stages) +Shader::Shader(id device, StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options) + : love::graphics::Shader(stages, options) , functions() , builtinUniformInfo() , localUniformStagingData(nullptr) @@ -314,7 +208,7 @@ Shader::Shader(id device, StrongRef stag forcedefault = true; #endif - if (!tshader->parse(&defaultTBuiltInResource, defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) + if (!tshader->parse(GetResources(), defaultversion, defaultprofile, forcedefault, forwardcompat, EShMsgSuppressWarnings)) { const char *stagename = "unknown"; ShaderStage::getConstant(stage, stagename); @@ -394,8 +288,20 @@ void Shader::buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv switch (membertype.basetype) { case SPIRType::Struct: - name += "."; - buildLocalUniforms(msl, membertype, offset, name); + if (membertype.op == spv::OpTypeArray) + { + size_t arraystride = msl.type_struct_member_array_stride(type, uindex); + for (uint32 i = 0; i < membertype.array[0]; i++) + { + std::string structname = name + "[" + std::to_string(i) + "]."; + buildLocalUniforms(msl, membertype, offset + i * arraystride, structname); + } + } + else + { + std::string structname = name + "."; + buildLocalUniforms(msl, membertype, offset, structname); + } continue; case SPIRType::Int: case SPIRType::UInt: @@ -405,150 +311,47 @@ void Shader::buildLocalUniforms(const spirv_cross::CompilerMSL &msl, const spirv continue; } + name = canonicaliizeUniformName(name); + if (offset + membersize > localUniformBufferSize) throw love::Exception("Invalid uniform offset + size for '%s' (offset=%d, size=%d, buffer size=%d)", name.c_str(), (int)offset, (int)membersize, (int)localUniformBufferSize); - UniformInfo u = {}; - u.name = name; + auto uniformit = reflection.allUniforms.find(name); + if (uniformit == reflection.allUniforms.end()) + { + handleUnknownUniformName(name.c_str()); + continue; + } + + UniformInfo &u = *(uniformit->second); + u.active = true; + + if (u.dataSize > 0) + continue; + u.dataSize = membersize; - u.count = membertype.array.empty() ? 1 : membertype.array[0]; - u.components = 1; - u.data = localUniformStagingData + offset; - if (membertype.columns == 1) - { - if (membertype.basetype == SPIRType::Int) - u.baseType = UNIFORM_INT; - else if (membertype.basetype == SPIRType::UInt) - u.baseType = UNIFORM_UINT; - else - u.baseType = UNIFORM_FLOAT; - u.components = membertype.vecsize; - } - else - { - u.baseType = UNIFORM_MATRIX; - u.matrix.rows = membertype.vecsize; - u.matrix.columns = membertype.columns; - } - const auto &reflectionit = validationReflection.localUniforms.find(u.name); - if (reflectionit != validationReflection.localUniforms.end()) + const auto &reflectionit = reflection.localUniformInitializerValues.find(u.name); + if (reflectionit != reflection.localUniformInitializerValues.end()) { - const auto &localuniform = reflectionit->second; - const auto &values = localuniform.initializerValues; + const auto &values = reflectionit->second; if (!values.empty()) memcpy(u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue))); } - uniforms[u.name] = u; - BuiltinUniform builtin = BUILTIN_MAX_ENUM; if (getConstant(u.name.c_str(), builtin)) { if (builtin == BUILTIN_UNIFORMS_PER_DRAW) builtinUniformDataOffset = offset; - builtinUniformInfo[builtin] = &uniforms[u.name]; + builtinUniformInfo[builtin] = &u; } updateUniform(&u, u.count); } } -void Shader::addImage(const spirv_cross::CompilerMSL &msl, const spirv_cross::Resource &resource, UniformType baseType) -{ - using namespace spirv_cross; - - const SPIRType &basetype = msl.get_type(resource.base_type_id); - const SPIRType &type = msl.get_type(resource.type_id); - const SPIRType &imagetype = msl.get_type(basetype.image.type); - - UniformInfo u = {}; - u.baseType = baseType; - u.name = resource.name; - u.count = type.array.empty() ? 1 : type.array[0]; - u.isDepthSampler = type.image.depth; - u.components = 1; - - auto it = uniforms.find(u.name); - if (it != uniforms.end()) - return; - - if (!fillUniformReflectionData(u)) - return; - - switch (imagetype.basetype) - { - case SPIRType::Float: - u.dataBaseType = DATA_BASETYPE_FLOAT; - break; - case SPIRType::Int: - u.dataBaseType = DATA_BASETYPE_INT; - break; - case SPIRType::UInt: - u.dataBaseType = DATA_BASETYPE_UINT; - break; - default: - break; - } - - switch (basetype.image.dim) - { - case spv::Dim2D: - u.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D; - u.textures = new love::graphics::Texture*[u.count]; - break; - case spv::Dim3D: - u.textureType = TEXTURE_VOLUME; - u.textures = new love::graphics::Texture*[u.count]; - break; - case spv::DimCube: - if (basetype.image.arrayed) - throw love::Exception("Cubemap Arrays are not currently supported."); - u.textureType = TEXTURE_CUBE; - u.textures = new love::graphics::Texture*[u.count]; - break; - case spv::DimBuffer: - u.baseType = UNIFORM_TEXELBUFFER; - u.buffers = new love::graphics::Buffer*[u.count]; - break; - default: - // TODO: error? continue? - break; - } - - u.dataSize = sizeof(int) * u.count; - u.data = malloc(u.dataSize); - for (int i = 0; i < u.count; i++) - u.ints[i] = -1; // Initialized below, after compiling. - - if (u.baseType == UNIFORM_SAMPLER) - { - auto tex = Graphics::getInstance()->getDefaultTexture(u.textureType); - for (int i = 0; i < u.count; i++) - { - tex->retain(); - u.textures[i] = tex; - } - } - else if (u.baseType == UNIFORM_TEXELBUFFER) - { - for (int i = 0; i < u.count; i++) - u.buffers[i] = nullptr; // TODO - } - else if (u.baseType == UNIFORM_STORAGETEXTURE) - { - for (int i = 0; i < u.count; i++) - u.textures[i] = nullptr; - } - - uniforms[u.name] = u; - - BuiltinUniform builtin; - if (getConstant(resource.name.c_str(), builtin)) - builtinUniformInfo[builtin] = &uniforms[u.name]; -} - void Shader::compileFromGLSLang(id device, const glslang::TProgram &program) { using namespace glslang; @@ -579,272 +382,287 @@ void Shader::compileFromGLSLang(id device, const glslang::TProgram &p std::string msgs = logger.getAllMessages(); // printf("spirv length: %ld, messages:\n%s\n", spirv.size(), msgs.c_str()); +// printf("GLSL INPUT SOURCE:\n\n%s\n\n", pixel->getSource().c_str()); + + std::unique_ptr mslpointer; + try { -// printf("GLSL INPUT SOURCE:\n\n%s\n\n", pixel->getSource().c_str()); - - CompilerMSL msl(std::move(spirv)); - - auto interfacevars = msl.get_active_interface_variables(); - - msl.set_enabled_interface_variables(interfacevars); - - ShaderResources resources = msl.get_shader_resources(); - - for (const auto &resource : resources.storage_images) - { - addImage(msl, resource, UNIFORM_STORAGETEXTURE); - } - - for (const auto &resource : resources.sampled_images) - { - addImage(msl, resource, UNIFORM_SAMPLER); - } - - for (const auto &resource : resources.uniform_buffers) - { - MSLResourceBinding binding; - binding.stage = msl.get_execution_model(); - binding.binding = msl.get_decoration(resource.id, spv::DecorationBinding); - binding.desc_set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet); - - if (resource.name == "gl_DefaultUniformBlock") - { - binding.msl_buffer = getUniformBufferBinding(); - msl.add_msl_resource_binding(binding); - - const SPIRType &type = msl.get_type(resource.base_type_id); - size_t size = msl.get_declared_struct_size(type); - - if (localUniformBufferSize != 0) - { - if (localUniformBufferSize != size) - throw love::Exception("Local uniform buffer size mismatch"); - continue; - } - - localUniformStagingData = new uint8[size]; - localUniformBufferData = new uint8[size]; - localUniformBufferSize = size; - - memset(localUniformStagingData, 0, size); - memset(localUniformBufferData, 0, size); - - std::string basename(""); - buildLocalUniforms(msl, type, 0, basename); - } - else - { - binding.msl_buffer = metalBufferIndices[stageindex]++; - msl.add_msl_resource_binding(binding); - } - } - - for (const auto &resource : resources.storage_buffers) - { - MSLResourceBinding binding; - binding.stage = msl.get_execution_model(); - binding.binding = msl.get_decoration(resource.id, spv::DecorationBinding); - binding.desc_set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet); - binding.msl_buffer = metalBufferIndices[stageindex]++; - msl.add_msl_resource_binding(binding); - - auto it = uniforms.find(resource.name); - if (it != uniforms.end()) - continue; - - const SPIRType &type = msl.get_type(resource.type_id); - - UniformInfo u = {}; - u.baseType = UNIFORM_STORAGEBUFFER; - u.components = 1; - u.name = resource.name; - u.count = type.array.empty() ? 1 : type.array[0]; - - if (!fillUniformReflectionData(u)) - continue; - - u.buffers = new love::graphics::Buffer*[u.count]; - u.dataSize = sizeof(int) * u.count; - u.data = malloc(u.dataSize); - - for (int i = 0; i < u.count; i++) - { - u.ints[i] = -1; // Initialized below, after compiling. - u.buffers[i] = nullptr; // TODO - } - - uniforms[u.name] = u; - } - - if (stageindex == SHADERSTAGE_VERTEX) - { - int nextattributeindex = ATTRIB_MAX_ENUM; - - for (const auto &var : interfacevars) - { - spv::StorageClass storage = msl.get_storage_class(var); - const std::string &name = msl.get_name(var); - - if (storage == spv::StorageClassInput) - { - int index = 0; - - BuiltinVertexAttribute builtinattribute; - if (graphics::getConstant(name.c_str(), builtinattribute)) - index = (int) builtinattribute; - else - index = nextattributeindex++; - - msl.set_decoration(var, spv::DecorationLocation, index); - attributes[name] = msl.get_decoration(var, spv::DecorationLocation); - } - } - - for (const auto &varying : resources.stage_outputs) - { -// printf("vertex shader output %s: %d\n", inp.name.c_str(), msl.get_decoration(inp.id, spv::DecorationLocation)); - varyings[varying.name] = nextVaryingLocation; - msl.set_decoration(varying.id, spv::DecorationLocation, nextVaryingLocation++); - } - } - else if (stageindex == SHADERSTAGE_PIXEL) - { - for (const auto &varying : resources.stage_inputs) - { - const auto it = varyings.find(varying.name); - if (it != varyings.end()) - msl.set_decoration(varying.id, spv::DecorationLocation, it->second); - } - } - - CompilerMSL::Options options; - options.set_msl_version(2, 1); - options.texture_buffer_native = true; -#ifdef LOVE_IOS - options.platform = CompilerMSL::Options::iOS; -#else - options.platform = CompilerMSL::Options::macOS; -#endif - - msl.set_msl_options(options); - - std::string source = msl.compile(); -// printf("// MSL SOURCE for stage %d:\n\n%s\n\n", stageindex, source.c_str()); - - NSString *nssource = [[NSString alloc] initWithBytes:source.c_str() - length:source.length() - encoding:NSUTF8StringEncoding]; - - MTLCompileOptions *opts = [MTLCompileOptions new]; - - // Silences warning. We already only use metal on these OS versions. - if (@available(macOS 10.14, iOS 12.0, *)) - opts.languageVersion = MTLLanguageVersion2_1; - - NSError *err = nil; - id library = [device newLibraryWithSource:nssource options:opts error:&err]; - if (library == nil && err != nil) - { - NSLog(@"errors: %@", err); - throw love::Exception("Error compiling converted Metal shader code"); - } - - functions[stageindex] = [library newFunctionWithName:library.functionNames[0]]; - - auto setTextureBinding = [this](CompilerMSL &msl, int stageindex, const spirv_cross::Resource &resource) -> void - { - auto it = uniforms.find(resource.name); - if (it == uniforms.end()) - return; - - UniformInfo &u = it->second; - - uint32 texturebinding = msl.get_automatic_msl_resource_binding(resource.id); - uint32 samplerbinding = msl.get_automatic_msl_resource_binding_secondary(resource.id); - - if (texturebinding == (uint32)-1) - return; - - for (int i = 0; i < u.count; i++) - { - if (u.ints[i] == -1) - { - u.ints[i] = (int)textureBindings.size(); - TextureBinding b = {}; - b.access = u.access; - - if (u.baseType == UNIFORM_TEXELBUFFER) - { - // TODO - } - else - { - b.texture = getMTLTexture(u.textures[i]); - b.samplerTexture = u.textures[i]; - - BuiltinUniform builtin = BUILTIN_MAX_ENUM; - if (getConstant(u.name.c_str(), builtin) && builtin == BUILTIN_TEXTURE_MAIN) - b.isMainTexture = true; - } - - for (uint8 &stagebinding : b.textureStages) - stagebinding = LOVE_UINT8_MAX; - for (uint8 &stagebinding : b.samplerStages) - stagebinding = LOVE_UINT8_MAX; - - textureBindings.push_back(b); - } - - auto &b = textureBindings[u.ints[i]]; - b.textureStages[stageindex] = (uint8) texturebinding; - b.samplerStages[stageindex] = (uint8) samplerbinding; - } - }; - - for (const auto &resource : resources.sampled_images) - { - setTextureBinding(msl, stageindex, resource); - } - - for (const auto &resource : resources.storage_images) - { - setTextureBinding(msl, stageindex, resource); - } - - for (const auto &resource : resources.storage_buffers) - { - auto it = uniforms.find(resource.name); - if (it == uniforms.end()) - continue; - - UniformInfo &u = it->second; - - uint32 bufferbinding = msl.get_automatic_msl_resource_binding(resource.id); - if (bufferbinding == (uint32)-1) - continue; - - for (int i = 0; i < u.count; i++) - { - if (u.ints[i] == -1) - { - u.ints[i] = (int)bufferBindings.size(); - BufferBinding b = {}; - b.access = u.access; - - for (uint8 &stagebinding : b.stages) - stagebinding = LOVE_UINT8_MAX; - - bufferBindings.push_back(b); - } - - bufferBindings[u.ints[i]].stages[stageindex] = (uint8) bufferbinding; - } - } + mslpointer.reset(new CompilerMSL(std::move(spirv))); } catch (std::exception &e) { - printf("Error parsing SPIR-V shader source: %s\n", e.what()); + throw love::Exception("Error parsing SPIR-V shader source: %s", e.what()); + } + + auto &msl = *mslpointer; + + auto interfacevars = msl.get_active_interface_variables(); + ShaderResources resources = msl.get_shader_resources(interfacevars); + + msl.set_enabled_interface_variables(interfacevars); + + for (const auto &resource : resources.uniform_buffers) + { + MSLResourceBinding binding; + binding.stage = msl.get_execution_model(); + binding.binding = msl.get_decoration(resource.id, spv::DecorationBinding); + binding.desc_set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet); + + if (resource.name == "gl_DefaultUniformBlock") + { + binding.msl_buffer = getUniformBufferBinding(); + msl.add_msl_resource_binding(binding); + + const SPIRType &type = msl.get_type(resource.base_type_id); + size_t size = msl.get_declared_struct_size(type); + + if (localUniformBufferSize != 0) + { + if (localUniformBufferSize != size) + throw love::Exception("Local uniform buffer size mismatch"); + continue; + } + + localUniformStagingData = new uint8[size]; + localUniformBufferData = new uint8[size]; + localUniformBufferSize = size; + + memset(localUniformStagingData, 0, size); + memset(localUniformBufferData, 0, size); + + std::string basename(""); + buildLocalUniforms(msl, type, 0, basename); + } + else + { + binding.msl_buffer = metalBufferIndices[stageindex]++; + msl.add_msl_resource_binding(binding); + } + } + + for (const auto &resource : resources.storage_buffers) + { + MSLResourceBinding binding; + binding.stage = msl.get_execution_model(); + binding.binding = msl.get_decoration(resource.id, spv::DecorationBinding); + binding.desc_set = msl.get_decoration(resource.id, spv::DecorationDescriptorSet); + binding.msl_buffer = metalBufferIndices[stageindex]++; + msl.add_msl_resource_binding(binding); + } + + if (stageindex == SHADERSTAGE_VERTEX) + { + int nextattributeindex = ATTRIB_MAX_ENUM; + + for (const auto &var : interfacevars) + { + spv::StorageClass storage = msl.get_storage_class(var); + const std::string &name = msl.get_name(var); + + if (storage == spv::StorageClassInput) + { + int index = 0; + + BuiltinVertexAttribute builtinattribute; + if (graphics::getConstant(name.c_str(), builtinattribute)) + index = (int) builtinattribute; + else + index = nextattributeindex++; + + msl.set_decoration(var, spv::DecorationLocation, index); + attributes[name] = msl.get_decoration(var, spv::DecorationLocation); + } + } + + for (const auto &varying : resources.stage_outputs) + { + varyings[varying.name] = nextVaryingLocation; + msl.set_decoration(varying.id, spv::DecorationLocation, nextVaryingLocation); + + const auto &type = msl.get_type(varying.base_type_id); + int count = type.array.empty() ? 1 : type.array[0]; + if (type.op == spv::OpTypeMatrix) + count *= type.columns; + + nextVaryingLocation += count; + } + } + else if (stageindex == SHADERSTAGE_PIXEL) + { + for (const auto &varying : resources.stage_inputs) + { + const auto it = varyings.find(varying.name); + if (it != varyings.end()) + msl.set_decoration(varying.id, spv::DecorationLocation, it->second); + } + } + + CompilerMSL::Options options; + options.set_msl_version(2, 1); + options.texture_buffer_native = true; +#ifdef LOVE_IOS + options.platform = CompilerMSL::Options::iOS; +#else + options.platform = CompilerMSL::Options::macOS; +#endif + + msl.set_msl_options(options); + + std::string source = msl.compile(); +// printf("// MSL SOURCE for stage %d:\n\n%s\n\n", stageindex, source.c_str()); + + NSString *nssource = [[NSString alloc] initWithBytes:source.c_str() + length:source.length() + encoding:NSUTF8StringEncoding]; + + MTLCompileOptions *opts = [MTLCompileOptions new]; + + // Silences warning. We already only use metal on these OS versions. + if (@available(macOS 10.14, iOS 12.0, *)) + opts.languageVersion = MTLLanguageVersion2_1; + + NSError *err = nil; + id library = [device newLibraryWithSource:nssource options:opts error:&err]; + if (library == nil && err != nil) + { + NSLog(@"errors: %@", err); + NSString *errorstr = err.localizedDescription; + throw love::Exception("Error compiling converted Metal shader code:\n\n%s", errorstr.UTF8String); + } + + functions[stageindex] = [library newFunctionWithName:library.functionNames[0]]; + + std::string debugname = getShaderStageDebugName((ShaderStageType)stageindex); + if (!debugname.empty()) + functions[stageindex].label = @(debugname.c_str()); + + auto setTextureBinding = [this](CompilerMSL &msl, int stageindex, const spirv_cross::Resource &resource) -> void + { + std::string name = canonicaliizeUniformName(resource.name); + auto it = reflection.allUniforms.find(name); + if (it == reflection.allUniforms.end()) + { + handleUnknownUniformName(name.c_str()); + return; + } + + UniformInfo &u = *(it->second); + + uint32 texturebinding = msl.get_automatic_msl_resource_binding(resource.id); + uint32 samplerbinding = msl.get_automatic_msl_resource_binding_secondary(resource.id); + + if (texturebinding == (uint32)-1) + { + // No valid binding, the uniform was likely optimized out because it's not used. + return; + } + + u.active = true; + + if (u.location < 0) + { + u.location = (int)textureBindings.size(); + for (int i = 0; i < u.count; i++) + { + TextureBinding b = {}; + b.access = u.access; + + if (u.baseType == UNIFORM_SAMPLER) + { + BuiltinUniform builtin = BUILTIN_MAX_ENUM; + if (getConstant(u.name.c_str(), builtin) && builtin == BUILTIN_TEXTURE_MAIN) + b.isMainTexture = true; + } + + for (uint8 &stagebinding : b.textureStages) + stagebinding = LOVE_UINT8_MAX; + for (uint8 &stagebinding : b.samplerStages) + stagebinding = LOVE_UINT8_MAX; + + textureBindings.push_back(b); + } + } + + for (int i = 0; i < u.count; i++) + { + auto &b = textureBindings[u.location + i]; + b.textureStages[stageindex] = (uint8) texturebinding; + b.samplerStages[stageindex] = (uint8) samplerbinding; + } + + BuiltinUniform builtin; + if (getConstant(name.c_str(), builtin)) + builtinUniformInfo[builtin] = &u; + }; + + for (const auto &resource : resources.sampled_images) + { + setTextureBinding(msl, stageindex, resource); + } + + for (const auto &resource : resources.storage_images) + { + setTextureBinding(msl, stageindex, resource); + } + + for (const auto &resource : resources.storage_buffers) + { + std::string name = canonicaliizeUniformName(resource.name); + auto it = reflection.storageBuffers.find(name); + if (it == reflection.storageBuffers.end()) + { + handleUnknownUniformName(name.c_str()); + continue; + } + + UniformInfo &u = it->second; + + uint32 bufferbinding = msl.get_automatic_msl_resource_binding(resource.id); + if (bufferbinding == (uint32)-1) + { + // No valid binding, the uniform was likely optimized out because it's not used. + continue; + } + + u.active = true; + + if (u.location < 0) + { + u.location = (int)bufferBindings.size(); + for (int i = 0; i < u.count; i++) + { + BufferBinding b = {}; + b.access = u.access; + + for (uint8 &stagebinding : b.stages) + stagebinding = LOVE_UINT8_MAX; + + bufferBindings.push_back(b); + } + } + + for (int i = 0; i < u.count; i++) + bufferBindings[u.location + i].stages[stageindex] = (uint8) bufferbinding; + } + } + + // Initialize default resource bindings. + for (const auto &kvp : reflection.allUniforms) + { + const UniformInfo *info = kvp.second; + switch (info->baseType) + { + case UNIFORM_SAMPLER: + case UNIFORM_STORAGETEXTURE: + sendTextures(info, &activeTextures[info->resourceIndex], info->count); + break; + case UNIFORM_TEXELBUFFER: + case UNIFORM_STORAGEBUFFER: + sendBuffers(info, &activeBuffers[info->resourceIndex], info->count); + break; + default: + break; } } @@ -861,31 +679,6 @@ Shader::~Shader() cachedRenderPipelines.clear(); - for (const auto &it : uniforms) - { - const auto &u = it.second; - if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_STORAGETEXTURE) - { - free(u.data); - for (int i = 0; i < u.count; i++) - { - if (u.textures[i] != nullptr) - u.textures[i]->release(); - } - delete[] u.textures; - } - else if (u.baseType == UNIFORM_TEXELBUFFER || u.baseType == UNIFORM_STORAGEBUFFER) - { - free(u.data); - for (int i = 0; i < u.count; i++) - { - if (u.buffers[i] != nullptr) - u.buffers[i]->release(); - } - delete[] u.buffers; - } - } - delete[] localUniformStagingData; delete[] localUniformBufferData; }} @@ -907,12 +700,6 @@ int Shader::getVertexAttributeIndex(const std::string &name) return it != attributes.end() ? it->second : -1; } -const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const -{ - const auto it = uniforms.find(name); - return it != uniforms.end() ? &(it->second) : nullptr; -} - const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const { return builtinUniformInfo[(int)builtin]; @@ -920,45 +707,18 @@ const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const void Shader::updateUniform(const UniformInfo *info, int count) { + if (info->dataSize == 0) + return; + if (current == this) Graphics::flushBatchedDrawsGlobal(); count = std::min(count, info->count); - // TODO: store some of this in UniformInfo. - size_t elementsize = info->components * 4; - if (info->baseType == UNIFORM_MATRIX) - elementsize = info->matrix.columns * info->matrix.rows * 4; - size_t offset = (const uint8 *)info->data - localUniformStagingData; + uint8 *dst = localUniformBufferData + offset; - // Assuming std140 packing rules, the source data can only be direct-copied - // to the uniform buffer in certain cases because it's tightly packed whereas - // the buffer's data isn't. - if (elementsize * info->count == info->dataSize || (count == 1 && info->baseType != UNIFORM_MATRIX)) - { - memcpy(localUniformBufferData + offset, info->data, elementsize * count); - } - else - { - int veccount = count; - int comp = info->components; - - if (info->baseType == UNIFORM_MATRIX) - { - veccount *= info->matrix.rows; - comp = info->matrix.columns; - } - - const int *src = info->ints; - int *dst = (int *) (localUniformBufferData + offset); - - for (int i = 0; i < veccount; i++) - { - for (int c = 0; c < comp; c++) - dst[i * 4 + c] = src[i * comp + c]; - } - } + copyToUniformBuffer(info, info->data, dst, count); } void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) @@ -974,6 +734,7 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex for (int i = 0; i < count; i++) { love::graphics::Texture *tex = textures[i]; + bool isdefault = tex == nullptr; if (tex != nullptr) { @@ -983,18 +744,36 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex else { auto gfx = Graphics::getInstance(); - tex = gfx->getDefaultTexture(info->textureType); + tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); } tex->retain(); - if (info->textures[i] != nullptr) - info->textures[i]->release(); + int resourceindex = info->resourceIndex + i; - info->textures[i] = tex; + if (activeTextures[resourceindex] != nullptr) + activeTextures[resourceindex]->release(); - textureBindings[info->ints[i]].texture = getMTLTexture(tex); - textureBindings[info->ints[i]].samplerTexture = tex; + activeTextures[resourceindex] = tex; + + if (info->location < 0) + continue; + + int bindingindex = info->location + i; + if (bindingindex < 0) + continue; + + auto &binding = textureBindings[bindingindex]; + if (isdefault && (binding.access & ACCESS_WRITE) != 0) + { + binding.texture = nil; + binding.samplerTexture = nullptr; + } + else + { + binding.texture = getMTLTexture(tex); + binding.samplerTexture = tex; + } } }} @@ -1011,31 +790,49 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe count = std::min(count, info->count); - // Bind the textures to the texture units. for (int i = 0; i < count; i++) { love::graphics::Buffer *buffer = buffers[i]; + bool isdefault = buffer == nullptr; if (buffer != nullptr) { if (!validateBuffer(info, buffer, false)) continue; - buffer->retain(); + } + else + { + auto gfx = Graphics::getInstance(); + if (texelbinding) + buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); + else + buffer = gfx->getDefaultStorageBuffer(); } - if (info->buffers[i] != nullptr) - info->buffers[i]->release(); + buffer->retain(); - info->buffers[i] = buffer; + int resourceindex = info->resourceIndex + i; - if (texelbinding) + if (activeBuffers[resourceindex] != nullptr) + activeBuffers[resourceindex]->release(); + + activeBuffers[resourceindex] = buffer; + + if (info->location < 0) + continue; + + int bindingindex = info->location + i; + if (texelbinding && bindingindex >= 0) { - textureBindings[info->ints[i]].texture = getMTLTexture(buffer); + textureBindings[bindingindex].texture = getMTLTexture(buffer); } - else if (storagebinding) + else if (storagebinding && bindingindex >= 0) { - // TODO - bufferBindings[info->ints[i]].buffer = getMTLBuffer(buffer); + auto &binding = bufferBindings[bindingindex]; + if (isdefault && (binding.access & ACCESS_WRITE) != 0) + binding.buffer = nil; + else + binding.buffer = getMTLBuffer(buffer); } } } @@ -1058,11 +855,6 @@ void Shader::setVideoTextures(love::graphics::Texture *ytexture, love::graphics: } } -bool Shader::hasUniform(const std::string &name) const -{ - return uniforms.find(name) != uniforms.end(); -} - id Shader::getCachedRenderPipeline(const RenderPipelineKey &key) { auto it = cachedRenderPipelines.find(key); @@ -1087,8 +879,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK MTLRenderPipelineColorAttachmentDescriptor *attachment = desc.colorAttachments[i]; - bool isSRGB = false; - auto formatdesc = Metal::convertPixelFormat(device, format, isSRGB); + auto formatdesc = Metal::convertPixelFormat(device, format); attachment.pixelFormat = formatdesc.format; if (key.blend.enable) @@ -1124,8 +915,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK { // We already don't really support metal on older systems, this just // silences a compiler warning about it. - bool isSRGB = false; - auto formatdesc = Metal::convertPixelFormat(device, dsformat, isSRGB); + auto formatdesc = Metal::convertPixelFormat(device, dsformat); if (isPixelFormatDepth(dsformat)) desc.depthAttachmentPixelFormat = formatdesc.format; if (isPixelFormatStencil(dsformat)) @@ -1146,7 +936,7 @@ id Shader::getCachedRenderPipeline(const RenderPipelineK const auto &attrib = attributes.attribs[i]; int metalBufferIndex = firstVertexBufferBinding + attrib.bufferIndex; - vertdesc.attributes[i].format = getMTLVertexFormat(attrib.format); + vertdesc.attributes[i].format = getMTLVertexFormat(attrib.getFormat()); vertdesc.attributes[i].offset = attrib.offsetFromVertex; vertdesc.attributes[i].bufferIndex = metalBufferIndex; diff --git a/src/modules/graphics/metal/ShaderStage.h b/src/modules/graphics/metal/ShaderStage.h index 6720aeffc..95bf98431 100644 --- a/src/modules/graphics/metal/ShaderStage.h +++ b/src/modules/graphics/metal/ShaderStage.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/ShaderStage.mm b/src/modules/graphics/metal/ShaderStage.mm index b56610c76..ac91169b1 100644 --- a/src/modules/graphics/metal/ShaderStage.mm +++ b/src/modules/graphics/metal/ShaderStage.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/StreamBuffer.h b/src/modules/graphics/metal/StreamBuffer.h index 87b99488a..ce3520bc5 100644 --- a/src/modules/graphics/metal/StreamBuffer.h +++ b/src/modules/graphics/metal/StreamBuffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/metal/StreamBuffer.mm b/src/modules/graphics/metal/StreamBuffer.mm index 7a7fae5a9..00d3e33c9 100644 --- a/src/modules/graphics/metal/StreamBuffer.mm +++ b/src/modules/graphics/metal/StreamBuffer.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,6 +48,8 @@ public: if (buffer == nil) throw love::Exception("Out of graphics memory."); + buffer.label = [NSString stringWithFormat:@"StreamBuffer (usage: %d, size: %ld)", usage, size]; + data = (uint8 *) buffer.contents; for (int i = 0; i < BUFFER_FRAMES; i++) @@ -65,6 +67,11 @@ public: } }} + size_t getGPUReadOffset() const override + { + return (frameIndex * bufferSize) + frameGPUReadOffset; + } + MapInfo map(size_t /*minsize*/) override { // Make sure this frame's section of the buffer is done being used. diff --git a/src/modules/graphics/metal/Texture.h b/src/modules/graphics/metal/Texture.h index 89730a1f1..01c6e57ec 100644 --- a/src/modules/graphics/metal/Texture.h +++ b/src/modules/graphics/metal/Texture.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,6 +38,7 @@ class Texture final : public love::graphics::Texture public: Texture(love::graphics::Graphics *gfx, id device, const Settings &settings, const Slices *data); + Texture(love::graphics::Graphics *gfx, id device, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings); virtual ~Texture(); void copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset, int sourcewidth, size_t size, int slice, int mipmap, const Rect &rect) override; @@ -55,14 +56,14 @@ public: private: - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; + void uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) override; void generateMipmapsInternal() override; - id texture; - id msaaTexture; - id sampler; + id texture = nil; + id msaaTexture = nil; + id sampler = nil; - int actualMSAASamples; + int actualMSAASamples = 1; }; // Texture diff --git a/src/modules/graphics/metal/Texture.mm b/src/modules/graphics/metal/Texture.mm index 8421cbcc1..e880495ae 100644 --- a/src/modules/graphics/metal/Texture.mm +++ b/src/modules/graphics/metal/Texture.mm @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,10 +43,6 @@ static MTLTextureType getMTLTextureType(TextureType type, int msaa) Texture::Texture(love::graphics::Graphics *gfxbase, id device, const Settings &settings, const Slices *data) : love::graphics::Texture(gfxbase, settings, data) - , texture(nil) - , msaaTexture(nil) - , sampler(nil) - , actualMSAASamples(1) { @autoreleasepool { auto gfx = (Graphics *) gfxbase; @@ -62,7 +58,7 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const desc.mipmapLevelCount = mipmapCount; desc.textureType = getMTLTextureType(texType, 1); - auto formatdesc = Metal::convertPixelFormat(device, format, sRGB); + auto formatdesc = Metal::convertPixelFormat(device, format); desc.pixelFormat = formatdesc.format; if (formatdesc.swizzled) { @@ -81,11 +77,23 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const if (computeWrite) desc.usage |= MTLTextureUsageShaderWrite; + for (PixelFormat viewformat : viewFormats) + { + if (getLinearPixelFormat(viewformat) != getLinearPixelFormat(format)) + { + desc.usage |= MTLTextureUsagePixelFormatView; + break; + } + } + texture = [device newTextureWithDescriptor:desc]; if (texture == nil) throw love::Exception("Out of graphics memory."); + if (!debugName.empty()) + texture.label = @(debugName.c_str()); + actualMSAASamples = gfx->getClosestMSAASamples(getRequestedMSAA()); if (actualMSAASamples > 1) @@ -100,6 +108,9 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const texture = nil; throw love::Exception("Out of graphics memory."); } + + if (!debugName.empty()) + msaaTexture.label = [@(debugName.c_str()) stringByAppendingString:@" (MSAA buffer)"]; } int mipcount = getMipmapCount(); @@ -143,7 +154,7 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const emptydata.resize(getPixelFormatSliceSize(format, w, h)); Rect r = {0, 0, getPixelWidth(mip), getPixelHeight(mip)}; - uploadByteData(format, emptydata.data(), emptydata.size(), mip, slice, r); + uploadByteData(emptydata.data(), emptydata.size(), mip, slice, r); } else if (isRenderTarget()) { @@ -206,6 +217,41 @@ Texture::Texture(love::graphics::Graphics *gfxbase, id device, const setSamplerState(samplerState); }} +Texture::Texture(love::graphics::Graphics *gfx, id device, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) + : love::graphics::Texture(gfx, base, viewsettings) +{ + id basetex = ((Texture *) base)->texture; + auto formatdesc = Metal::convertPixelFormat(device, format); + int slices = texType == TEXTURE_CUBE ? 6 : getLayerCount(); + + if (formatdesc.swizzled) + { + if (@available(macOS 10.15, iOS 13, *)) + { + texture = [basetex newTextureViewWithPixelFormat:formatdesc.format + textureType:getMTLTextureType(texType, 1) + levels:NSMakeRange(parentView.startMipmap, mipmapCount) + slices:NSMakeRange(parentView.startLayer, slices) + swizzle:formatdesc.swizzle]; + } + } + else + { + texture = [basetex newTextureViewWithPixelFormat:formatdesc.format + textureType:getMTLTextureType(texType, 1) + levels:NSMakeRange(parentView.startMipmap, mipmapCount) + slices:NSMakeRange(parentView.startLayer, slices)]; + } + + if (texture == nil) + throw love::Exception("Could not create Metal texture view."); + + if (!debugName.empty()) + texture.label = @(debugName.c_str()); + + setSamplerState(samplerState); +} + Texture::~Texture() { @autoreleasepool { texture = nil; @@ -213,15 +259,13 @@ Texture::~Texture() sampler = nil; }} -void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) +void Texture::uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) { @autoreleasepool { auto gfx = Graphics::getInstance(); id buffer = [gfx->device newBufferWithBytes:data length:size options:MTLResourceStorageModeShared]; - memcpy(buffer.contents, data, size); - id encoder = gfx->useBlitEncoder(); int z = 0; @@ -233,7 +277,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s MTLBlitOption options = MTLBlitOptionNone; - switch (pixelformat) + switch (format) { case PIXELFORMAT_PVR1_RGB2_UNORM: case PIXELFORMAT_PVR1_RGB4_UNORM: @@ -333,10 +377,11 @@ void Texture::copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, void Texture::setSamplerState(const SamplerState &s) { @autoreleasepool { - // Base class does common validation and assigns samplerState. - love::graphics::Texture::setSamplerState(s); + if (s.depthSampleMode.hasValue && !Graphics::getInstance()->isDepthCompareSamplerSupported()) + throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - sampler = Graphics::getInstance()->getCachedSampler(s); + samplerState = validateSamplerState(s); + sampler = Graphics::getInstance()->getCachedSampler(samplerState); }} } // metal diff --git a/src/modules/graphics/opengl/Buffer.cpp b/src/modules/graphics/opengl/Buffer.cpp index 787caf630..f1c5daa2e 100644 --- a/src/modules/graphics/opengl/Buffer.cpp +++ b/src/modules/graphics/opengl/Buffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -164,6 +164,9 @@ bool Buffer::load(const void *initialdata) glTexBuffer(target, glformat, buffer); } + if (!debugName.empty() && (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2)) + glObjectLabel(GL_BUFFER, buffer, -1, debugName.c_str()); + return (glGetError() == GL_NO_ERROR); } @@ -193,11 +196,7 @@ void *Buffer::map(MapType map, size_t offset, size_t size) if (map == MAP_READ_ONLY) { gl.bindBuffer(mapUsage, buffer); - - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0) - data = (char *) glMapBufferRange(target, offset, size, GL_MAP_READ_BIT); - else if (GLAD_VERSION_1_1) - data = (char *) glMapBuffer(target, GL_READ_ONLY) + offset; + data = (char *) glMapBufferRange(target, offset, size, GL_MAP_READ_BIT); } else if (ownsMemoryMap) { @@ -296,17 +295,8 @@ bool Buffer::fill(size_t offset, size_t size, const void *data) return true; } -void Buffer::clear(size_t offset, size_t size) +void Buffer::clearInternal(size_t offset, size_t size) { - if (isImmutable()) - throw love::Exception("Cannot clear an immutable Buffer."); - else if (isMapped()) - throw love::Exception("Cannot clear a mapped Buffer."); - else if (offset + size > getSize()) - throw love::Exception("The given offset and size parameters to clear() are not within the Buffer's size."); - else if (offset % 4 != 0 || size % 4 != 0) - throw love::Exception("clear() must be used with offset and size parameters that are multiples of 4 bytes."); - if (GLAD_VERSION_4_3) { gl.bindBuffer(mapUsage, buffer); diff --git a/src/modules/graphics/opengl/Buffer.h b/src/modules/graphics/opengl/Buffer.h index acee82aa7..ea4846b2e 100644 --- a/src/modules/graphics/opengl/Buffer.h +++ b/src/modules/graphics/opengl/Buffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -53,7 +53,6 @@ public: void *map(MapType map, size_t offset, size_t size) override; void unmap(size_t usedoffset, size_t usedsize) override; bool fill(size_t offset, size_t size, const void *data) override; - void clear(size_t offset, size_t size) override; void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override; ptrdiff_t getHandle() const override { return buffer; }; @@ -66,6 +65,8 @@ private: bool load(const void *initialdata); bool supportsOrphan() const; + void clearInternal(size_t offset, size_t size) override; + BufferUsage mapUsage = BUFFERUSAGE_VERTEX; GLenum target = 0; diff --git a/src/modules/graphics/opengl/FenceSync.cpp b/src/modules/graphics/opengl/FenceSync.cpp index 09ced0f30..664e2194c 100644 --- a/src/modules/graphics/opengl/FenceSync.cpp +++ b/src/modules/graphics/opengl/FenceSync.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/FenceSync.h b/src/modules/graphics/opengl/FenceSync.h index 90d4a3231..898f7a759 100644 --- a/src/modules/graphics/opengl/FenceSync.h +++ b/src/modules/graphics/opengl/FenceSync.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 664d26fa7..be0191cf9 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -106,13 +106,13 @@ love::graphics::Graphics *createInstance() } Graphics::Graphics() - : windowHasStencil(false) + : love::graphics::Graphics("love.graphics.opengl") + , windowHasStencil(false) , mainVAO(0) , internalBackbufferFBO(0) , requestedBackbufferMSAA(0) , bufferMapMemory(nullptr) , bufferMapMemorySize(2 * 1024 * 1024) - , defaultBuffers() , pixelFormatUsage() { gl = OpenGL(); @@ -148,11 +148,6 @@ Graphics::~Graphics() delete[] bufferMapMemory; } -const char *Graphics::getName() const -{ - return "love.graphics.opengl"; -} - love::graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) { return CreateStreamBuffer(type, size); @@ -163,14 +158,19 @@ love::graphics::Texture *Graphics::newTexture(const Texture::Settings &settings, return new Texture(this, settings, data); } +love::graphics::Texture *Graphics::newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) +{ + return new Texture(this, base, viewsettings); +} + love::graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) { return new ShaderStage(this, stage, source, gles, cachekey); } -love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +love::graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(stages); + return new Shader(stages, options); } love::graphics::Buffer *Graphics::newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) @@ -188,25 +188,23 @@ love::graphics::GraphicsReadback *Graphics::newReadbackInternal(ReadbackMethod m return new GraphicsReadback(this, method, texture, slice, mipmap, rect, dest, destx, desty); } -Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const +void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { - uint32 flags = DEVICE_PROJECTION_DEFAULT; + bool changed = width != this->width || height != this->height + || pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight; - // The projection matrix is flipped compared to rendering to a texture, due - // to OpenGL considering (0,0) bottom-left instead of top-left. - if (!rendertotexture) - flags |= DEVICE_PROJECTION_FLIP_Y; + changed |= backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth; + changed |= msaa != this->requestedBackbufferMSAA; - return calculateDeviceProjection(projection, flags); -} - -void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) -{ this->width = width; this->height = height; this->pixelWidth = pixelwidth; this->pixelHeight = pixelheight; + this->backbufferHasStencil = backbufferstencil; + this->backbufferHasDepth = backbufferdepth; + this->requestedBackbufferMSAA = msaa; + if (!isRenderTargetActive()) { // Set the viewport to top-left corner. @@ -220,23 +218,13 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh resetProjection(); } - updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA); -} + if (!changed) + return; -void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int pixelheight, int msaa) -{ bool useinternalbackbuffer = false; if (msaa > 1) useinternalbackbuffer = true; - // Our internal backbuffer code needs glBlitFramebuffer. - if (!(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_ES_VERSION_3_0 - || GLAD_EXT_framebuffer_blit || GLAD_ANGLE_framebuffer_blit || GLAD_NV_framebuffer_blit)) - { - if (!(msaa > 1 && GLAD_APPLE_framebuffer_multisample)) - useinternalbackbuffer = false; - } - GLuint prevFBO = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); bool restoreFBO = prevFBO != getInternalBackbufferFBO(); @@ -250,11 +238,20 @@ void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int p settings.renderTarget = true; settings.readable.set(false); - settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_UNORM_sRGB : PIXELFORMAT_RGBA8_UNORM; + settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_sRGB : PIXELFORMAT_RGBA8_UNORM; internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN); - settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; - internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN); + internalBackbufferDepthStencil.set(nullptr); + if (backbufferstencil || backbufferdepth) + { + if (backbufferstencil && backbufferdepth) + settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; + else if (backbufferstencil) + settings.format = PIXELFORMAT_STENCIL8; + else if (backbufferdepth) + settings.format = PIXELFORMAT_DEPTH24_UNORM; + internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN); + } RenderTargets rts; rts.colors.push_back(internalBackbuffer.get()); @@ -269,8 +266,6 @@ void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int p internalBackbufferFBO = 0; } - requestedBackbufferMSAA = msaa; - if (restoreFBO) gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, prevFBO); } @@ -300,14 +295,8 @@ GLuint Graphics::getSystemBackbufferFBO() const #endif } -bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) +bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { - this->width = width; - this->height = height; - - this->windowHasStencil = windowhasstencil; - this->requestedBackbufferMSAA = msaa; - // Okay, setup OpenGL. gl.initContext(); @@ -353,8 +342,7 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); // Set whether drawing converts input from linear -> sRGB colorspace. - if (!gl.bugs.brokenSRGB && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB - || GLAD_EXT_framebuffer_sRGB || GLAD_ES_VERSION_3_0)) + if (!gl.bugs.brokenSRGB) { if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control) gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect()); @@ -364,7 +352,7 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, setDebug(isDebugEnabled()); - setViewportSize(width, height, pixelwidth, pixelheight); + backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa); if (batchedDrawState.vb[0] == nullptr) { @@ -375,43 +363,6 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, batchedDrawState.indexBuffer = CreateStreamBuffer(BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); } - // TODO: one buffer each for float, int, uint - if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERUSAGE_TEXEL].get() == nullptr) - { - Buffer::Settings settings(BUFFERUSAGEFLAG_TEXEL, BUFFERDATAUSAGE_STATIC); - std::vector format = {{"", DATAFORMAT_FLOAT_VEC4, 0}}; - - const float texel[] = {0.0f, 0.0f, 0.0f, 1.0f}; - - auto buffer = newBuffer(settings, format, texel, sizeof(texel), 1); - defaultBuffers[BUFFERUSAGE_TEXEL].set(buffer, Acquire::NORETAIN); - } - - if (capabilities.features[FEATURE_GLSL4] && defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get() == nullptr) - { - Buffer::Settings settings(BUFFERUSAGEFLAG_SHADER_STORAGE, BUFFERDATAUSAGE_STATIC); - std::vector format = {{"", DATAFORMAT_FLOAT, 0}}; - - std::vector data; - data.resize(Buffer::SHADER_STORAGE_BUFFER_MAX_STRIDE / 4); - - auto buffer = newBuffer(settings, format, data.data(), data.size() * sizeof(float), data.size()); - defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].set(buffer, Acquire::NORETAIN); - } - - // Load default resources before other Volatile. - for (int i = 0; i < BUFFERUSAGE_MAX_ENUM; i++) - { - if (defaultBuffers[i].get()) - ((Buffer *) defaultBuffers[i].get())->loadVolatile(); - } - - if (defaultBuffers[BUFFERUSAGE_TEXEL].get()) - gl.setDefaultTexelBuffer((GLuint) defaultBuffers[BUFFERUSAGE_TEXEL]->getTexelBufferHandle()); - - if (defaultBuffers[BUFFERUSAGE_SHADER_STORAGE].get()) - gl.setDefaultStorageBuffer((GLuint) defaultBuffers[BUFFERUSAGE_SHADER_STORAGE]->getHandle()); - // Reload all volatile objects. if (!Volatile::loadAll()) ::printf("Could not reload all volatile objects.\n"); @@ -426,28 +377,13 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, { auto stype = (Shader::StandardShader) i; - if (i == Shader::STANDARD_ARRAY && !capabilities.textureTypes[TEXTURE_2D_ARRAY]) - continue; - - // Apparently some intel GMA drivers on windows fail to compile shaders - // which use array textures despite claiming support for the extension. - try + if (!Shader::standardShaders[i]) { - if (!Shader::standardShaders[i]) - { - std::vector stages; - Shader::CompileOptions opts; - stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX)); - stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL)); - Shader::standardShaders[i] = newShader(stages, opts); - } - } - catch (love::Exception &) - { - if (i == Shader::STANDARD_ARRAY) - capabilities.textureTypes[TEXTURE_2D_ARRAY] = false; - else - throw; + std::vector stages; + Shader::CompileOptions opts; + stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_VERTEX)); + stages.push_back(Shader::getDefaultCode(stype, SHADERSTAGE_PIXEL)); + Shader::standardShaders[i] = newShader(stages, opts); } } @@ -736,24 +672,27 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute static void APIENTRY debugCB(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei /*len*/, const GLchar *msg, const GLvoid* /*usr*/) { + if (severity == GL_DEBUG_SEVERITY_NOTIFICATION) + return; + // Human-readable strings for the debug info. const char *sourceStr = OpenGL::debugSourceString(source); const char *typeStr = OpenGL::debugTypeString(type); const char *severityStr = OpenGL::debugSeverityString(severity); - const char *fmt = "OpenGL: %s [source=%s, type=%s, severity=%s, id=%d]\n"; - printf(fmt, msg, sourceStr, typeStr, severityStr, id); + const char *fmt = "OpenGL: [source=%s, type=%s, severity=%s, id=%d]: %s\n"; + printf(fmt, sourceStr, typeStr, severityStr, id, msg); } void Graphics::setDebug(bool enable) { // Make sure debug output is supported. The AMD ext. is a bit different // so we don't make use of it, since AMD drivers now support KHR_debug. - if (!(GLAD_VERSION_4_3 || GLAD_KHR_debug || GLAD_ARB_debug_output)) + if (!(GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2 || GLAD_KHR_debug || GLAD_ARB_debug_output)) return; // TODO: We don't support GL_KHR_debug in GLES yet. - if (GLAD_ES_VERSION_2_0) + if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_2) return; // Ugly hack to reduce code duplication. @@ -769,7 +708,7 @@ void Graphics::setDebug(bool enable) glDebugMessageCallback(nullptr, nullptr); // We can disable debug output entirely with KHR_debug. - if (GLAD_VERSION_4_3 || GLAD_KHR_debug) + if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2 || GLAD_KHR_debug) glDisable(GL_DEBUG_OUTPUT); return; @@ -787,7 +726,7 @@ void Graphics::setDebug(bool enable) glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE); - if (GLAD_VERSION_4_3 || GLAD_KHR_debug) + if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2 || GLAD_KHR_debug) glEnable(GL_DEBUG_OUTPUT); ::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n"); @@ -898,17 +837,34 @@ void Graphics::endPass(bool presenting) glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, mask, GL_NEAREST); } } - - // generateMipmaps can't be used for depth/stencil textures. - for (const auto &rt : rts.colors) - { - if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0) - rt.texture->generateMipmaps(); - } } void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth) { + if (c.hasValue) + { + bool hasintegerformat = false; + + const auto &rts = states.back().renderTargets; + for (const auto &rt : rts.colors) + { + if (rt.texture.get() && isPixelFormatInteger(rt.texture->getPixelFormat())) + hasintegerformat = true; + } + + // This variant of clear() uses glClear() which can't clear integer formats, + // so we switch to the MRT variant if needed. + if (hasintegerformat) + { + std::vector colors(rts.colors.size()); + for (size_t i = 0; i < colors.size(); i++) + colors[i] = c; + + clear(colors, stencil, depth); + return; + } + } + if (c.hasValue || stencil.hasValue || depth.hasValue) flushBatchedDraws(); @@ -922,36 +878,23 @@ void Graphics::clear(OptionalColorD c, OptionalInt stencil, OptionalDouble depth flags |= GL_COLOR_BUFFER_BIT; } - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); flags |= GL_STENCIL_BUFFER_BIT; } - bool hadDepthWrites = gl.hasDepthWrites(); - if (depth.hasValue) { - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - gl.clearDepth(depth.value); flags |= GL_DEPTH_BUFFER_BIT; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (c.hasValue && gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -980,7 +923,6 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten flushBatchedDraws(); - bool drawbuffersmodified = false; ncolors = std::min(ncolors, ncolorRTs); for (int i = 0; i < ncolors; i++) @@ -994,83 +936,44 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten ColorD c = colors[i].value; - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0) + if (datatype == PIXELFORMATTYPE_SINT) { - if (datatype == PIXELFORMATTYPE_SINT) - { - const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a}; - glClearBufferiv(GL_COLOR, i, carray); - } - else if (datatype == PIXELFORMATTYPE_UINT) - { - const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a}; - glClearBufferuiv(GL_COLOR, i, carray); - } - else - { - Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a); - gammaCorrectColor(cf); - const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a}; - glClearBufferfv(GL_COLOR, i, carray); - } + const GLint carray[] = {(GLint)c.r, (GLint)c.g, (GLint)c.b, (GLint)c.a}; + glClearBufferiv(GL_COLOR, i, carray); + } + else if (datatype == PIXELFORMATTYPE_UINT) + { + const GLuint carray[] = {(GLuint)c.r, (GLuint)c.g, (GLuint)c.b, (GLuint)c.a}; + glClearBufferuiv(GL_COLOR, i, carray); } else { Colorf cf((float)c.r, (float)c.g, (float)c.b, (float)c.a); gammaCorrectColor(cf); - - glDrawBuffer(GL_COLOR_ATTACHMENT0 + i); - glClearColor(cf.r, cf.g, cf.b, cf.a); - glClear(GL_COLOR_BUFFER_BIT); - - drawbuffersmodified = true; + const GLfloat carray[] = {cf.r, cf.g, cf.b, cf.a}; + glClearBufferfv(GL_COLOR, i, carray); } } - // Revert to the expected draw buffers once we're done, if glClearBuffer - // wasn't supported. - if (drawbuffersmodified) - { - GLenum bufs[MAX_COLOR_RENDER_TARGETS]; - - for (int i = 0; i < ncolorRTs; i++) - bufs[i] = GL_COLOR_ATTACHMENT0 + i; - - glDrawBuffers(ncolorRTs, bufs); - } - GLbitfield flags = 0; - uint32 stencilwrites = gl.getStencilWriteMask(); - if (stencil.hasValue) { - if (stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); - glClearStencil(stencil.value); flags |= GL_STENCIL_BUFFER_BIT; } - bool hadDepthWrites = gl.hasDepthWrites(); - if (depth.hasValue) { - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - gl.clearDepth(depth.value); flags |= GL_DEPTH_BUFFER_BIT; } if (flags != 0) + { + OpenGL::CleanClearState cs(flags); glClear(flags); - - if (stencil.hasValue && stencilwrites != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrites); - - if (depth.hasValue && !hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + } if (gl.bugs.clearRequiresDriverTextureStateUpdate && Shader::current) { @@ -1102,7 +1005,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector attachments.reserve(colorbuffers.size()); // glDiscardFramebuffer uses different attachment enums for the default FBO. - if (!isRenderTargetActive() && getInternalBackbufferFBO() == 0) + if (gl.getFramebuffer(target) == 0) { if (colorbuffers.size() > 0 && colorbuffers[0]) attachments.push_back(GL_COLOR); @@ -1191,8 +1094,7 @@ GLuint Graphics::bindCachedFBO(const RenderTargets &targets) auto attachRT = [&](const RenderTarget &rt) { bool renderbuffer = msaa > 1 || !rt.texture->isReadable(); - bool srgb = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat(), renderbuffer, srgb); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(rt.texture->getPixelFormat()); if (fmt.framebufferAttachments[0] == GL_COLOR_ATTACHMENT0) { @@ -1230,14 +1132,10 @@ GLuint Graphics::bindCachedFBO(const RenderTargets &targets) if (ncolortargets > 1) glDrawBuffers(ncolortargets, drawbuffers); - else if (ncolortargets == 0 && hasDS && (GLAD_ES_VERSION_3_0 || !GLAD_ES_VERSION_2_0)) + else if (ncolortargets == 0 && hasDS) { - // glDrawBuffers is an ext in GL2. glDrawBuffer doesn't exist in ES3. GLenum none = GL_NONE; - if (GLAD_ES_VERSION_3_0) - glDrawBuffers(1, &none); - else - glDrawBuffer(GL_NONE); + glDrawBuffers(1, &none); glReadBuffer(GL_NONE); } @@ -1437,30 +1335,19 @@ void Graphics::setScissor() gl.setEnableState(OpenGL::ENABLE_SCISSOR_TEST, false); } -void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) +void Graphics::setStencilState(const StencilState &s) { - DisplayState &state = states.back(); - - if (action != STENCIL_KEEP) - { - const auto &rts = state.renderTargets; - love::graphics::Texture *dstexture = rts.depthStencil.texture.get(); - - if (!isRenderTargetActive() && !windowHasStencil) - throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer."); - else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat()))) - throw love::Exception("Drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type texture to be used, in setRenderTarget."); - } + validateStencilState(s); flushBatchedDraws(); - bool enablestencil = action != STENCIL_KEEP || compare != COMPARE_ALWAYS; + bool enablestencil = s.action != STENCIL_KEEP || s.compare != COMPARE_ALWAYS; if (enablestencil != gl.isStateEnabled(OpenGL::ENABLE_STENCIL_TEST)) gl.setEnableState(OpenGL::ENABLE_STENCIL_TEST, enablestencil); GLenum glaction = GL_KEEP; - switch (action) + switch (s.action) { case STENCIL_KEEP: glaction = GL_KEEP; @@ -1496,29 +1383,27 @@ void Graphics::setStencilMode(StencilAction action, CompareMode compare, int val * example, if the compare function is GREATER then the stencil test will * pass if the reference value is greater than the value in the stencil * buffer. With our API it's more intuitive to assume that - * setStencilMode(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the + * setStencilState(STENCIL_KEEP, COMPARE_GREATER, 4) will make it pass if the * stencil buffer has a value greater than 4. **/ - GLenum glcompare = OpenGL::getGLCompareMode(getReversedCompareMode(compare)); + GLenum glcompare = OpenGL::getGLCompareMode(getReversedCompareMode(s.compare)); if (enablestencil) { - glStencilFunc(glcompare, value, readmask); + glStencilFunc(glcompare, s.value, s.readMask); glStencilOp(GL_KEEP, GL_KEEP, glaction); } - if (writemask != gl.getStencilWriteMask()) - gl.setStencilWriteMask(writemask); + if (s.writeMask != gl.getStencilWriteMask()) + gl.setStencilWriteMask(s.writeMask); - state.stencil.action = action; - state.stencil.compare = compare; - state.stencil.value = value; - state.stencil.readMask = readmask; - state.stencil.writeMask = writemask; + states.back().stencil = s; } void Graphics::setDepthMode(CompareMode compare, bool write) { + validateDepthState(write); + DisplayState &state = states.back(); if (state.depthTest != compare || state.depthWrite != write) @@ -1568,7 +1453,11 @@ void Graphics::setColorMask(ColorChannelMask mask) { flushBatchedDraws(); - glColorMask(mask.r, mask.g, mask.b, mask.a); + uint32 maskbits = + ((mask.r ? 1 : 0) << 0) | ((mask.g ? 1 : 0) << 1) | + ((mask.b ? 1 : 0) << 2) | ((mask.a ? 1 : 0) << 3); + + gl.setColorWriteMask(maskbits); states.back().colorMask = mask; } @@ -1577,13 +1466,6 @@ void Graphics::setBlendState(const BlendState &blend) if (!(blend == states.back().blend)) flushBatchedDraws(); - if (blend.operationRGB == BLENDOP_MAX || blend.operationA == BLENDOP_MAX - || blend.operationRGB == BLENDOP_MIN || blend.operationA == BLENDOP_MIN) - { - if (!capabilities.features[FEATURE_BLEND_MINMAX]) - throw love::Exception("The 'min' and 'max' blend operations are not supported on this system."); - } - if (blend.enable != gl.isStateEnabled(OpenGL::ENABLE_BLEND)) gl.setEnableState(OpenGL::ENABLE_BLEND, blend.enable); @@ -1685,26 +1567,20 @@ void Graphics::getAPIStats(int &shaderswitches) const void Graphics::initCapabilities() { - capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = gl.isMultiFormatMRTSupported(); + capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = true; capabilities.features[FEATURE_CLAMP_ZERO] = gl.isClampZeroOneTextureWrapSupported(); capabilities.features[FEATURE_CLAMP_ONE] = gl.isClampZeroOneTextureWrapSupported(); - capabilities.features[FEATURE_BLEND_MINMAX] = GLAD_VERSION_1_4 || GLAD_ES_VERSION_3_0 || GLAD_EXT_blend_minmax; - capabilities.features[FEATURE_LIGHTEN] = capabilities.features[FEATURE_BLEND_MINMAX]; - capabilities.features[FEATURE_FULL_NPOT] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot; - capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = gl.isPixelShaderHighpSupported(); - capabilities.features[FEATURE_SHADER_DERIVATIVES] = GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_standard_derivatives; - capabilities.features[FEATURE_GLSL3] = GLAD_ES_VERSION_3_0 || gl.isCoreProfile(); + capabilities.features[FEATURE_LIGHTEN] = true; + capabilities.features[FEATURE_FULL_NPOT] = true; + capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; + capabilities.features[FEATURE_SHADER_DERIVATIVES] = true; + capabilities.features[FEATURE_GLSL3] = true; capabilities.features[FEATURE_GLSL4] = GLAD_ES_VERSION_3_1 || (gl.isCoreProfile() && GLAD_VERSION_4_3); - capabilities.features[FEATURE_INSTANCING] = gl.isInstancingSupported(); + capabilities.features[FEATURE_INSTANCING] = true; capabilities.features[FEATURE_TEXEL_BUFFER] = gl.isBufferUsageSupported(BUFFERUSAGE_TEXEL); - capabilities.features[FEATURE_INDEX_BUFFER_32BIT] = GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_element_index_uint; - capabilities.features[FEATURE_COPY_BUFFER] = gl.isCopyBufferSupported(); - capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = gl.isCopyBufferToTextureSupported(); capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = gl.isCopyTextureToBufferSupported(); - capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = gl.isCopyRenderTargetToBufferSupported(); - capabilities.features[FEATURE_MIPMAP_RANGE] = GLAD_VERSION_1_2 || GLAD_ES_VERSION_3_0; capabilities.features[FEATURE_INDIRECT_DRAW] = capabilities.features[FEATURE_GLSL4]; - static_assert(FEATURE_MAX_ENUM == 19, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); capabilities.limits[LIMIT_POINT_SIZE] = gl.getMaxPointSize(); capabilities.limits[LIMIT_TEXTURE_SIZE] = gl.getMax2DTextureSize(); @@ -1722,7 +1598,7 @@ void Graphics::initCapabilities() static_assert(LIMIT_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new system limit!"); for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - capabilities.textureTypes[i] = gl.isTextureTypeSupported((TextureType) i); + capabilities.textureTypes[i] = true; for (int i = 0; i < PIXELFORMAT_MAX_ENUM; i++) { @@ -1730,31 +1606,17 @@ void Graphics::initCapabilities() pixelFormatUsage[i][0] = computePixelFormatUsage(format, false); pixelFormatUsage[i][1] = computePixelFormatUsage(format, true); } -} -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const -{ - uint32 requiredflags = 0; - if (rendertarget) - requiredflags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; - if (readable) - requiredflags |= PIXELFORMATUSAGEFLAGS_SAMPLE; - - switch (format) +#ifdef LOVE_ANDROID + // This can't be done in initContext with the rest of the bug checks because + // isPixelFormatSupported relies on state initialized here / after init. + if (GLAD_ES_VERSION_3_0 && !isPixelFormatSupported(PIXELFORMAT_R8_UNORM, PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET)) { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else if ((OpenGL::getPixelFormatUsageFlags(PIXELFORMAT_RGBA8_UNORM) & requiredflags) != requiredflags) - // 32-bit render targets don't have guaranteed support on GLES2. - return PIXELFORMAT_RGBA4_UNORM; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; - default: - return format; + gl.bugs.brokenR8PixelFormat = true; + pixelFormatUsage[PIXELFORMAT_R8_UNORM][0] = computePixelFormatUsage(PIXELFORMAT_R8_UNORM, false); + pixelFormatUsage[PIXELFORMAT_R8_UNORM][1] = computePixelFormatUsage(PIXELFORMAT_R8_UNORM, true); } +#endif } uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) @@ -1777,9 +1639,8 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) { GLuint texture = 0; GLuint renderbuffer = 0; - bool sRGB = isPixelFormatSRGB(format); - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, !readable, sRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format); GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -1790,7 +1651,10 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) // Make sure at least something is bound to a color attachment. I believe // this is required on ES2 but I'm not positive. if (isPixelFormatDepthStencil(format)) - gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, gl.getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT), 0, 0, 0); + { + love::graphics::Texture *tex = getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT, false); + gl.framebufferTexture(GL_COLOR_ATTACHMENT0, TEXTURE_2D, (GLuint) tex->getHandle(), 0, 0, 0); + } if (readable) { @@ -1801,7 +1665,7 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; gl.setSamplerState(TEXTURE_2D, s); - gl.rawTexStorage(TEXTURE_2D, 1, format, sRGB, 1, 1); + gl.rawTexStorage(TEXTURE_2D, 1, format, 1, 1); } else { @@ -1837,16 +1701,11 @@ uint32 Graphics::computePixelFormatUsage(PixelFormat format, bool readable) return usage; } -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { - if (sRGB) - format = getSRGBPixelFormat(format); + format = getSizedFormat(format); - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); - return (usage & pixelFormatUsage[format][readable ? 1 : 0]) == usage; } diff --git a/src/modules/graphics/opengl/Graphics.h b/src/modules/graphics/opengl/Graphics.h index 997239c15..351532b39 100644 --- a/src/modules/graphics/opengl/Graphics.h +++ b/src/modules/graphics/opengl/Graphics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -56,16 +56,12 @@ public: Graphics(); virtual ~Graphics(); - // Implements Module. - const char *getName() const override; - love::graphics::Texture *newTexture(const Texture::Settings &settings, const Texture::Slices *data = nullptr) override; + love::graphics::Texture *newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) override; love::graphics::Buffer *newBuffer(const Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) override; - Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override; - - void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; - bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; + void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; + bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; void unSetMode() override; void setActive(bool active) override; @@ -92,7 +88,7 @@ public: void setScissor(const Rect &rect) override; void setScissor() override; - void setStencilMode(StencilAction action, CompareMode compare, int value, uint32 readmask, uint32 writemask) override; + void setStencilState(const StencilState &s) override; void setDepthMode(CompareMode compare, bool write) override; @@ -106,8 +102,7 @@ public: void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB = false) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; @@ -140,7 +135,7 @@ private: }; love::graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + love::graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; love::graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override; love::graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; @@ -174,9 +169,6 @@ private: char *bufferMapMemory; size_t bufferMapMemorySize; - // Only needed for buffer types that can be bound to shaders. - StrongRef defaultBuffers[BUFFERUSAGE_MAX_ENUM]; - // [non-readable, readable] uint32 pixelFormatUsage[PIXELFORMAT_MAX_ENUM][2]; diff --git a/src/modules/graphics/opengl/GraphicsReadback.cpp b/src/modules/graphics/opengl/GraphicsReadback.cpp index b5eb13f1f..1c903f8f7 100644 --- a/src/modules/graphics/opengl/GraphicsReadback.cpp +++ b/src/modules/graphics/opengl/GraphicsReadback.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -68,8 +68,6 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod { void *dest = prepareReadbackDest(size); - love::thread::Lock lock(imageData->getMutex()); - // Direct readback without copying avoids the need for a staging buffer, // and lowers the system requirements of immediate RT readback. Texture *t = (Texture *) texture; diff --git a/src/modules/graphics/opengl/GraphicsReadback.h b/src/modules/graphics/opengl/GraphicsReadback.h index dd3272d14..46efa3278 100644 --- a/src/modules/graphics/opengl/GraphicsReadback.h +++ b/src/modules/graphics/opengl/GraphicsReadback.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b169a06a9..cb8f8a1f3 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -62,7 +62,7 @@ static void *LOVEGetProcAddress(const char *name) return proc; #endif - return SDL_GL_GetProcAddress(name); + return (void *) SDL_GL_GetProcAddress(name); } OpenGL::TempDebugGroup::TempDebugGroup(const char *name) @@ -91,12 +91,48 @@ OpenGL::TempDebugGroup::~TempDebugGroup() } } +OpenGL::CleanClearState::CleanClearState(GLbitfield clearFlags) + : clearFlags(clearFlags) + , colorWriteMask(gl.getColorWriteMask()) + , stencilWriteMask(gl.getStencilWriteMask()) + , depthWrites(gl.hasDepthWrites()) + , scissor(gl.isStateEnabled(ENABLE_SCISSOR_TEST)) +{ + if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) + gl.setColorWriteMask(LOVE_UINT32_MAX); + + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && !depthWrites) + gl.setDepthWrites(true); + + if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) + gl.setStencilWriteMask(LOVE_UINT32_MAX); + + if (clearFlags != 0 && scissor) + gl.setEnableState(ENABLE_SCISSOR_TEST, false); +} + +OpenGL::CleanClearState::~CleanClearState() +{ + if ((clearFlags & GL_COLOR_BUFFER_BIT) != 0 && colorWriteMask != LOVE_UINT32_MAX) + gl.setColorWriteMask(colorWriteMask); + + if ((clearFlags & GL_DEPTH_BUFFER_BIT) != 0 && !depthWrites) + gl.setDepthWrites(depthWrites); + + if ((clearFlags & GL_STENCIL_BUFFER_BIT) != 0 && (stencilWriteMask & 0xFF) != 0xFF) + gl.setStencilWriteMask(stencilWriteMask); + + if (clearFlags != 0 && scissor) + gl.setEnableState(ENABLE_SCISSOR_TEST, scissor); +} + OpenGL::OpenGL() : stats() + , bugs() , contextInitialized(false) - , pixelShaderHighpSupported(false) , baseVertexSupported(false) , maxAnisotropy(1.0f) + , maxLODBias(0.0f) , max2DTextureSize(0) , max3DTextureSize(0) , maxCubeTextureSize(0) @@ -129,16 +165,6 @@ bool OpenGL::initContext() bugs = {}; - if (GLAD_ES_VERSION_3_0 && !GLAD_ES_VERSION_3_1) - { - const char *device = (const char *) glGetString(GL_RENDERER); - if (getVendor() == VENDOR_VIVANTE && strstr(device, "Vivante GC7000UL")) - bugs.brokenGLES3 = true; - } - - if (bugs.brokenGLES3) - GLAD_ES_VERSION_3_0 = false; - if (GLAD_VERSION_3_2) { GLint profileMask = 0; @@ -222,11 +248,6 @@ void OpenGL::setupContext() glGetIntegerv(GL_SCISSOR_BOX, (GLint *) &state.scissor.x); state.scissor.y = state.viewport.h - (state.scissor.y + state.scissor.h); - if (GLAD_VERSION_1_0) - glGetFloatv(GL_POINT_SIZE, &state.pointSize); - else - state.pointSize = 1.0f; - for (int i = 0; i < 2; i++) state.boundFramebuffers[i] = std::numeric_limits::max(); bindFramebuffer(FRAMEBUFFER_ALL, getDefaultFBO()); @@ -237,11 +258,8 @@ void OpenGL::setupContext() setEnableState(ENABLE_SCISSOR_TEST, state.enableState[ENABLE_SCISSOR_TEST]); setEnableState(ENABLE_FACE_CULL, state.enableState[ENABLE_FACE_CULL]); - if (!bugs.brokenSRGB && (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB - || GLAD_EXT_framebuffer_sRGB || GLAD_EXT_sRGB_write_control)) - { + if (!bugs.brokenSRGB) setEnableState(ENABLE_FRAMEBUFFER_SRGB, state.enableState[ENABLE_FRAMEBUFFER_SRGB]); - } else state.enableState[ENABLE_FRAMEBUFFER_SRGB] = false; @@ -273,9 +291,7 @@ void OpenGL::setupContext() for (int j = 0; j < TEXTURE_MAX_ENUM; j++) { TextureType textype = (TextureType) j; - - if (isTextureTypeSupported(textype)) - glBindTexture(getGLTextureType(textype), 0); + glBindTexture(getGLTextureType(textype), 0); } } @@ -284,18 +300,9 @@ void OpenGL::setupContext() setDepthWrites(state.depthWritesEnabled); setStencilWriteMask(state.stencilWriteMask); - - createDefaultTexture(); + setColorWriteMask(state.colorWriteMask); contextInitialized = true; - -#ifdef LOVE_ANDROID - // This can't be done in initContext with the rest of the bug checks because - // isPixelFormatSupported relies on state initialized here / after init. - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (GLAD_ES_VERSION_3_0 && gfx != nullptr && !gfx->isPixelFormatSupported(PIXELFORMAT_R8_UNORM, PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET)) - bugs.brokenR8PixelFormat = true; -#endif } void OpenGL::deInitContext() @@ -303,18 +310,6 @@ void OpenGL::deInitContext() if (!contextInitialized) return; - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - for (int datatype = DATA_BASETYPE_FLOAT; datatype <= DATA_BASETYPE_UINT; datatype++) - { - if (state.defaultTexture[i][datatype] != 0) - { - gl.deleteTexture(state.defaultTexture[i][datatype]); - state.defaultTexture[i][datatype] = 0; - } - } - } - contextInitialized = false; } @@ -358,89 +353,6 @@ void OpenGL::initVendor() void OpenGL::initOpenGLFunctions() { - // Alias extension-suffixed framebuffer functions to core versions since - // there are so many different-named extensions that do the same things... - if (!(GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)) - { - if (GLAD_VERSION_1_0 && GLAD_EXT_framebuffer_object) - { - fp_glBindRenderbuffer = fp_glBindRenderbufferEXT; - fp_glDeleteRenderbuffers = fp_glDeleteRenderbuffersEXT; - fp_glGenRenderbuffers = fp_glGenRenderbuffersEXT; - fp_glRenderbufferStorage = fp_glRenderbufferStorageEXT; - fp_glGetRenderbufferParameteriv = fp_glGetRenderbufferParameterivEXT; - fp_glBindFramebuffer = fp_glBindFramebufferEXT; - fp_glDeleteFramebuffers = fp_glDeleteFramebuffersEXT; - fp_glGenFramebuffers = fp_glGenFramebuffersEXT; - fp_glCheckFramebufferStatus = fp_glCheckFramebufferStatusEXT; - fp_glFramebufferTexture2D = fp_glFramebufferTexture2DEXT; - fp_glFramebufferTexture3D = fp_glFramebufferTexture3DEXT; - fp_glFramebufferRenderbuffer = fp_glFramebufferRenderbufferEXT; - fp_glGetFramebufferAttachmentParameteriv = fp_glGetFramebufferAttachmentParameterivEXT; - fp_glGenerateMipmap = fp_glGenerateMipmapEXT; - } - - if (GLAD_VERSION_1_0 && GLAD_EXT_texture_array) - fp_glFramebufferTextureLayer = fp_glFramebufferTextureLayerEXT; - - if (GLAD_EXT_framebuffer_blit) - fp_glBlitFramebuffer = fp_glBlitFramebufferEXT; - else if (GLAD_ANGLE_framebuffer_blit) - fp_glBlitFramebuffer = fp_glBlitFramebufferANGLE; - else if (GLAD_NV_framebuffer_blit) - fp_glBlitFramebuffer = fp_glBlitFramebufferNV; - - if (GLAD_EXT_framebuffer_multisample) - fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleEXT; - else if (GLAD_APPLE_framebuffer_multisample) - fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleAPPLE; - else if (GLAD_ANGLE_framebuffer_multisample) - fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleANGLE; - else if (GLAD_NV_framebuffer_multisample) - fp_glRenderbufferStorageMultisample = fp_glRenderbufferStorageMultisampleNV; - } - - if (isInstancingSupported() && !(GLAD_VERSION_3_3 || GLAD_ES_VERSION_3_0)) - { - if (GLAD_ARB_instanced_arrays) - { - fp_glDrawArraysInstanced = fp_glDrawArraysInstancedARB; - fp_glDrawElementsInstanced = fp_glDrawElementsInstancedARB; - fp_glVertexAttribDivisor = fp_glVertexAttribDivisorARB; - } - else if (GLAD_EXT_instanced_arrays) - { - fp_glDrawArraysInstanced = fp_glDrawArraysInstancedEXT; - fp_glDrawElementsInstanced = fp_glDrawElementsInstancedEXT; - fp_glVertexAttribDivisor = fp_glVertexAttribDivisorEXT; - } - else if (GLAD_ANGLE_instanced_arrays) - { - fp_glDrawArraysInstanced = fp_glDrawArraysInstancedANGLE; - fp_glDrawElementsInstanced = fp_glDrawElementsInstancedANGLE; - fp_glVertexAttribDivisor = fp_glVertexAttribDivisorANGLE; - } - } - - if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0) - { - // The Nvidia Tegra 3 driver (used by Ouya) claims to support GL_EXT_texture_array but - // segfaults if you actually try to use it. OpenGL ES 2.0 devices should use OES_texture_3D. - // GL_EXT_texture_array is for desktops. - GLAD_EXT_texture_array = false; - - if (GLAD_OES_texture_3D) - { - // Function signatures don't match, we'll have to conditionally call it - //fp_glTexImage3D = fp_glTexImage3DOES; - fp_glTexSubImage3D = fp_glTexSubImage3DOES; - fp_glCopyTexSubImage3D = fp_glCopyTexSubImage3DOES; - fp_glCompressedTexImage3D = fp_glCompressedTexImage3DOES; - fp_glCompressedTexSubImage3D = fp_glCompressedTexSubImage3DOES; - fp_glFramebufferTexture3D = fp_glFramebufferTexture3DOES; - } - } - if (!GLAD_VERSION_3_2 && !GLAD_ES_VERSION_3_2 && !GLAD_ARB_draw_elements_base_vertex) { if (GLAD_OES_draw_elements_base_vertex) @@ -470,16 +382,6 @@ void OpenGL::initOpenGLFunctions() void OpenGL::initMaxValues() { - if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0) - { - GLint range = 0; - GLint precision = 0; - glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, &range, &precision); - pixelShaderHighpSupported = range > 0; - } - else - pixelShaderHighpSupported = true; - baseVertexSupported = GLAD_VERSION_3_2 || GLAD_ES_VERSION_3_2 || GLAD_ARB_draw_elements_base_vertex || GLAD_OES_draw_elements_base_vertex || GLAD_EXT_draw_elements_base_vertex; @@ -491,16 +393,8 @@ void OpenGL::initMaxValues() glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max2DTextureSize); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &maxCubeTextureSize); - - if (isTextureTypeSupported(TEXTURE_VOLUME)) - glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize); - else - max3DTextureSize = 0; - - if (isTextureTypeSupported(TEXTURE_2D_ARRAY)) - glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureArrayLayers); - else - maxTextureArrayLayers = 0; + glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max3DTextureSize); + glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &maxTextureArrayLayers); if (isBufferUsageSupported(BUFFERUSAGE_TEXEL)) glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &maxTexelBufferSize); @@ -533,23 +427,12 @@ void OpenGL::initMaxValues() int maxattachments = 1; int maxdrawbuffers = 1; - - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_0) - { - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments); - glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers); - } + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &maxattachments); + glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxdrawbuffers); maxRenderTargets = std::max(std::min(maxattachments, maxdrawbuffers), 1); - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object - || GLAD_EXT_framebuffer_multisample || GLAD_APPLE_framebuffer_multisample - || GLAD_ANGLE_framebuffer_multisample) - { - glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); - } - else - maxSamples = 1; + glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); @@ -566,73 +449,6 @@ void OpenGL::initMaxValues() maxLODBias = 0.0f; } -void OpenGL::createDefaultTexture() -{ - // Set the 'default' texture as a repeating white pixel. Otherwise, texture - // calls inside a shader would return black when drawing graphics primitives - // which would create the need to use different "passthrough" shaders for - // untextured primitives vs images. - const GLubyte pix[] = {255, 255, 255, 255}; - const GLubyte intpix[] = {1, 1, 1, 1}; - - SamplerState s; - s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; - s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; - - for (int i = 0; i < TEXTURE_MAX_ENUM; i++) - { - for (int datatype = (int)DATA_BASETYPE_FLOAT; datatype <= (int)DATA_BASETYPE_UINT; datatype++) - { - state.defaultTexture[i][datatype] = 0; - - TextureType type = (TextureType) i; - - if (!isTextureTypeSupported(type)) - continue; - - if (datatype != DATA_BASETYPE_FLOAT && !(GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0)) - continue; - - GLuint curtexture = state.boundTextures[type][0]; - - glGenTextures(1, &state.defaultTexture[type][datatype]); - bindTextureToUnit(type, state.defaultTexture[type][datatype], 0, false); - - setSamplerState(type, s); - - PixelFormat format = PIXELFORMAT_RGBA8_UNORM; - if (datatype == DATA_BASETYPE_INT) - format = PIXELFORMAT_RGBA8_INT; - else if (datatype == DATA_BASETYPE_UINT) - format = PIXELFORMAT_RGBA8_UINT; - - const GLubyte *p = datatype == DATA_BASETYPE_FLOAT ? pix : intpix; - - bool isSRGB = false; - rawTexStorage(type, 1, format, isSRGB, 1, 1); - - TextureFormat fmt = convertPixelFormat(format, false, isSRGB); - - int slices = type == TEXTURE_CUBE ? 6 : 1; - - for (int slice = 0; slice < slices; slice++) - { - GLenum gltarget = getGLTextureType(type); - - if (type == TEXTURE_CUBE) - gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; - - if (type == TEXTURE_2D || type == TEXTURE_CUBE) - glTexSubImage2D(gltarget, 0, 0, 0, 1, 1, fmt.externalformat, fmt.type, p); - else if (type == TEXTURE_2D_ARRAY || type == TEXTURE_VOLUME) - glTexSubImage3D(gltarget, 0, 0, 0, slice, 1, 1, 1, fmt.externalformat, fmt.type, p); - } - - bindTextureToUnit(type, curtexture, 0, false); - } - } -} - void OpenGL::prepareDraw(love::graphics::Graphics *gfx) { TempDebugGroup debuggroup("Prepare OpenGL draw"); @@ -666,6 +482,7 @@ GLenum OpenGL::getGLBufferType(BufferUsage usage) case BUFFERUSAGE_VERTEX: return GL_ARRAY_BUFFER; case BUFFERUSAGE_INDEX: return GL_ELEMENT_ARRAY_BUFFER; case BUFFERUSAGE_TEXEL: return GL_TEXTURE_BUFFER; + case BUFFERUSAGE_UNIFORM: return GL_UNIFORM_BUFFER; case BUFFERUSAGE_SHADER_STORAGE: return GL_SHADER_STORAGE_BUFFER; case BUFFERUSAGE_INDIRECT_ARGUMENTS: return GL_DRAW_INDIRECT_BUFFER; case BUFFERUSAGE_MAX_ENUM: return GL_ZERO; @@ -844,8 +661,7 @@ GLenum OpenGL::getGLBufferDataUsage(BufferDataUsage usage) case BUFFERDATAUSAGE_STREAM: return GL_STREAM_DRAW; case BUFFERDATAUSAGE_DYNAMIC: return GL_DYNAMIC_DRAW; case BUFFERDATAUSAGE_STATIC: return GL_STATIC_DRAW; - case BUFFERDATAUSAGE_READBACK: - return (GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0) ? GL_STREAM_READ : GL_STREAM_DRAW; + case BUFFERDATAUSAGE_READBACK: return GL_STREAM_READ; default: return 0; } } @@ -912,7 +728,7 @@ void OpenGL::setVertexAttributes(const VertexAttributes &attributes, const Buffe int components = 0; GLboolean normalized = GL_FALSE; bool intformat = false; - GLenum gltype = getGLVertexDataType(attrib.format, components, normalized, intformat); + GLenum gltype = getGLVertexDataType(attrib.getFormat(), components, normalized, intformat); const void *offsetpointer = reinterpret_cast(bufferinfo.offset + attrib.offsetFromVertex); @@ -1125,6 +941,17 @@ uint32 OpenGL::getStencilWriteMask() const return state.stencilWriteMask; } +void OpenGL::setColorWriteMask(uint32 mask) +{ + glColorMask(mask & (1 << 0), mask & (1 << 1), mask & (1 << 2), mask & (1 << 3)); + state.colorWriteMask = mask; +} + +uint32 OpenGL::getColorWriteMask() const +{ + return state.colorWriteMask; +} + void OpenGL::useProgram(GLuint program) { glUseProgram(program); @@ -1144,11 +971,6 @@ GLuint OpenGL::getDefaultFBO() const #endif } -GLuint OpenGL::getDefaultTexture(TextureType type, DataBaseType datatype) const -{ - return state.defaultTexture[type][datatype]; -} - void OpenGL::setTextureUnit(int textureunit) { if (textureunit != state.curTextureUnit) @@ -1187,31 +1009,8 @@ void OpenGL::bindBufferTextureToUnit(GLuint texture, int textureunit, bool resto void OpenGL::bindTextureToUnit(Texture *texture, int textureunit, bool restoreprev, bool bindforedit) { - TextureType textype = TEXTURE_2D; - GLuint handle = 0; - - if (texture != nullptr) - { - textype = texture->getTextureType(); - handle = (GLuint) texture->getHandle(); - } - else - { - DataBaseType datatype = DATA_BASETYPE_FLOAT; - - if (textureunit == 0 && Shader::current != nullptr) - { - const Shader::UniformInfo *info = Shader::current->getMainTextureInfo(); - if (info != nullptr) - { - textype = info->textureType; - datatype = info->dataBaseType; - } - } - - handle = getDefaultTexture(textype, datatype); - } - + TextureType textype = texture->getTextureType(); + GLuint handle = (GLuint) texture->getHandle(); bindTextureToUnit(textype, handle, textureunit, restoreprev, bindforedit); } @@ -1352,42 +1151,27 @@ void OpenGL::setSamplerState(TextureType target, SamplerState &s) s.maxAnisotropy = 1; } - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0) + glTexParameterf(gltarget, GL_TEXTURE_MIN_LOD, (float)s.minLod); + glTexParameterf(gltarget, GL_TEXTURE_MAX_LOD, (float)s.maxLod); + + if (s.depthSampleMode.hasValue) { - glTexParameterf(gltarget, GL_TEXTURE_MIN_LOD, (float)s.minLod); - glTexParameterf(gltarget, GL_TEXTURE_MAX_LOD, (float)s.maxLod); + // See the comment in renderstate.h + GLenum glmode = getGLCompareMode(getReversedCompareMode(s.depthSampleMode.value)); + + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_FUNC, glmode); } else { - s.minLod = 0; - s.maxLod = LOVE_UINT8_MAX; - } - - if (isDepthCompareSampleSupported()) - { - if (s.depthSampleMode.hasValue) - { - // See the comment in renderstate.h - GLenum glmode = getGLCompareMode(getReversedCompareMode(s.depthSampleMode.value)); - - glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(gltarget, GL_TEXTURE_COMPARE_FUNC, glmode); - } - else - { - glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - } - else - { - s.depthSampleMode.hasValue = false; + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_NONE); } } -bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth) +bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, int width, int height, int depth) { GLenum gltarget = getGLTextureType(target); - TextureFormat fmt = convertPixelFormat(pixelformat, false, isSRGB); + TextureFormat fmt = convertPixelFormat(pixelformat); // This shouldn't be needed for glTexStorage, but some drivers don't follow // the spec apparently. @@ -1403,7 +1187,17 @@ bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelform glTexParameteri(gltarget, GL_TEXTURE_SWIZZLE_A, fmt.swizzle[3]); } - if (isTexStorageSupported()) + bool usetexstorage = isTexStorageSupported(); + + // The fallback for bugs.brokenR8PixelFormat is GL_LUMINANCE, which doesn't have a sized + // version in ES3 so it can't be used with glTexStorage. + if (pixelformat == PIXELFORMAT_R8_UNORM && bugs.brokenR8PixelFormat && GLAD_ES_VERSION_3_0) + { + usetexstorage = false; + fmt.internalformat = fmt.externalformat; + } + + if (usetexstorage) { if (target == TEXTURE_2D || target == TEXTURE_CUBE) glTexStorage2D(gltarget, levels, fmt.internalformat, width, height); @@ -1432,16 +1226,8 @@ bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelform } else if (target == TEXTURE_2D_ARRAY || target == TEXTURE_VOLUME) { - if (target == TEXTURE_VOLUME && GLAD_ES_VERSION_2_0 && GLAD_OES_texture_3D && !GLAD_ES_VERSION_3_0) - { - glTexImage3DOES(gltarget, level, fmt.internalformat, w, h, - d, 0, fmt.externalformat, fmt.type, nullptr); - } - else - { - glTexImage3D(gltarget, level, fmt.internalformat, w, h, d, - 0, fmt.externalformat, fmt.type, nullptr); - } + glTexImage3D(gltarget, level, fmt.internalformat, w, h, d, + 0, fmt.externalformat, fmt.type, nullptr); } w = std::max(w / 2, 1); @@ -1463,24 +1249,6 @@ bool OpenGL::isTexStorageSupported() return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_2 || GLAD_ARB_texture_storage; } -bool OpenGL::isTextureTypeSupported(TextureType type) const -{ - switch (type) - { - case TEXTURE_2D: - return true; - case TEXTURE_VOLUME: - return GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_3D; - case TEXTURE_2D_ARRAY: - return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_array; - case TEXTURE_CUBE: - return GLAD_VERSION_1_3 || GLAD_ES_VERSION_2_0; - case TEXTURE_MAX_ENUM: - return false; - } - return false; -} - bool OpenGL::isBufferUsageSupported(BufferUsage usage) const { switch (usage) @@ -1490,6 +1258,8 @@ bool OpenGL::isBufferUsageSupported(BufferUsage usage) const return true; case BUFFERUSAGE_TEXEL: return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_2; + case BUFFERUSAGE_UNIFORM: + return true; case BUFFERUSAGE_SHADER_STORAGE: return (GLAD_VERSION_4_3 && isCoreProfile()) || GLAD_ES_VERSION_3_1; case BUFFERUSAGE_INDIRECT_ARGUMENTS: @@ -1505,24 +1275,6 @@ bool OpenGL::isClampZeroOneTextureWrapSupported() const return GLAD_VERSION_1_3 || GLAD_EXT_texture_border_clamp || GLAD_NV_texture_border_clamp; } -bool OpenGL::isPixelShaderHighpSupported() const -{ - return pixelShaderHighpSupported; -} - -bool OpenGL::isInstancingSupported() const -{ - return GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_3 - || GLAD_ARB_instanced_arrays || GLAD_EXT_instanced_arrays || GLAD_ANGLE_instanced_arrays; -} - -bool OpenGL::isDepthCompareSampleSupported() const -{ - // Our official API only supports this in GLSL3 shaders, but unofficially - // the requirements are more lax. - return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_shadow_samplers; -} - bool OpenGL::isSamplerLODBiasSupported() const { return GLAD_VERSION_1_4; @@ -1533,34 +1285,12 @@ bool OpenGL::isBaseVertexSupported() const return baseVertexSupported; } -bool OpenGL::isMultiFormatMRTSupported() const -{ - return getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object); -} - -bool OpenGL::isCopyBufferSupported() const -{ - return GLAD_VERSION_3_1 || GLAD_ES_VERSION_3_0; -} - -bool OpenGL::isCopyBufferToTextureSupported() const -{ - // Requires pixel unpack buffer binding support. - return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0; -} - bool OpenGL::isCopyTextureToBufferSupported() const { // Requires glGetTextureSubImage support. return GLAD_VERSION_4_5 || GLAD_ARB_get_texture_sub_image; } -bool OpenGL::isCopyRenderTargetToBufferSupported() const -{ - // Requires pixel pack buffer binding support. - return GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0; -} - int OpenGL::getMax2DTextureSize() const { return std::max(max2DTextureSize, 1); @@ -1651,16 +1381,14 @@ OpenGL::Vendor OpenGL::getVendor() const return vendor; } -OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB) +OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat) { TextureFormat f; f.framebufferAttachments[0] = GL_COLOR_ATTACHMENT0; f.framebufferAttachments[1] = GL_NONE; - if (isSRGB) - pixelformat = getSRGBPixelFormat(pixelformat); - else if (pixelformat == PIXELFORMAT_ETC1_UNORM) + if (pixelformat == PIXELFORMAT_ETC1_UNORM) { // The ETC2 format can load ETC1 textures. if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) @@ -1670,8 +1398,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r switch (pixelformat) { case PIXELFORMAT_R8_UNORM: - if ((GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_texture_rg || GLAD_EXT_texture_rg) - && !gl.bugs.brokenR8PixelFormat) + if (!gl.bugs.brokenR8PixelFormat) { f.internalformat = GL_R8; f.externalformat = GL_RED; @@ -1693,16 +1420,13 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r f.externalformat = GL_RGBA; f.type = GL_UNSIGNED_BYTE; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: f.internalformat = GL_SRGB8_ALPHA8; f.type = GL_UNSIGNED_BYTE; - if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0) - f.externalformat = GL_SRGB_ALPHA; - else - f.externalformat = GL_RGBA; + f.externalformat = GL_RGBA; break; case PIXELFORMAT_BGRA8_UNORM: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: // Not supported right now. break; case PIXELFORMAT_R16_UNORM: @@ -1898,28 +1622,10 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r case PIXELFORMAT_STENCIL8: // Prefer a combined depth/stencil buffer due to driver issues. - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object) - { - f.internalformat = GL_DEPTH24_STENCIL8; - f.externalformat = GL_DEPTH_STENCIL; - f.type = GL_UNSIGNED_INT_24_8; - f.framebufferAttachments[0] = GL_DEPTH_STENCIL_ATTACHMENT; - } - else if (GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil) - { - f.internalformat = GL_DEPTH24_STENCIL8; - f.externalformat = GL_DEPTH_STENCIL; - f.type = GL_UNSIGNED_INT_24_8; - f.framebufferAttachments[0] = GL_DEPTH_ATTACHMENT; - f.framebufferAttachments[1] = GL_STENCIL_ATTACHMENT; - } - else - { - f.internalformat = GL_STENCIL_INDEX8; - f.externalformat = GL_STENCIL; - f.type = GL_UNSIGNED_BYTE; - f.framebufferAttachments[0] = GL_STENCIL_ATTACHMENT; - } + f.internalformat = GL_DEPTH24_STENCIL8; + f.externalformat = GL_DEPTH_STENCIL; + f.type = GL_UNSIGNED_INT_24_8; + f.framebufferAttachments[0] = GL_DEPTH_STENCIL_ATTACHMENT; break; case PIXELFORMAT_DEPTH16_UNORM: @@ -1930,21 +1636,10 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r break; case PIXELFORMAT_DEPTH24_UNORM: - if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0 && !GLAD_OES_depth24 && GLAD_OES_packed_depth_stencil) - { - f.internalformat = GL_DEPTH24_STENCIL8; - f.externalformat = GL_DEPTH_STENCIL; - f.type = GL_UNSIGNED_INT_24_8; - f.framebufferAttachments[0] = GL_DEPTH_ATTACHMENT; - f.framebufferAttachments[1] = GL_STENCIL_ATTACHMENT; - } - else - { - f.internalformat = GL_DEPTH_COMPONENT24; - f.externalformat = GL_DEPTH_COMPONENT; - f.type = GL_UNSIGNED_INT; - f.framebufferAttachments[0] = GL_DEPTH_ATTACHMENT; - } + f.internalformat = GL_DEPTH_COMPONENT24; + f.externalformat = GL_DEPTH_COMPONENT; + f.type = GL_UNSIGNED_INT; + f.framebufferAttachments[0] = GL_DEPTH_ATTACHMENT; break; case PIXELFORMAT_DEPTH32_FLOAT: @@ -1958,15 +1653,7 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r f.internalformat = GL_DEPTH24_STENCIL8; f.externalformat = GL_DEPTH_STENCIL; f.type = GL_UNSIGNED_INT_24_8; - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object) - { - f.framebufferAttachments[0] = GL_DEPTH_STENCIL_ATTACHMENT; - } - else if (GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil) - { - f.framebufferAttachments[0] = GL_DEPTH_ATTACHMENT; - f.framebufferAttachments[1] = GL_STENCIL_ATTACHMENT; - } + f.framebufferAttachments[0] = GL_DEPTH_STENCIL_ATTACHMENT; break; case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8: @@ -1977,123 +1664,190 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r break; case PIXELFORMAT_DXT1_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT; + break; + case PIXELFORMAT_DXT1_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT; break; case PIXELFORMAT_DXT3_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT; + break; + case PIXELFORMAT_DXT3_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT; break; case PIXELFORMAT_DXT5_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + f.internalformat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + break; + case PIXELFORMAT_DXT5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT; break; case PIXELFORMAT_BC4_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RED_RGTC1; break; case PIXELFORMAT_BC4_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RED_RGTC1; break; case PIXELFORMAT_BC5_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RG_RGTC2; break; case PIXELFORMAT_BC5_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RG_RGTC2; break; case PIXELFORMAT_BC6H_UFLOAT: - isSRGB = false; f.internalformat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; break; case PIXELFORMAT_BC6H_FLOAT: - isSRGB = false; f.internalformat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; break; case PIXELFORMAT_BC7_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : GL_COMPRESSED_RGBA_BPTC_UNORM; + f.internalformat = GL_COMPRESSED_RGBA_BPTC_UNORM; break; + case PIXELFORMAT_BC7_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM; + break; + case PIXELFORMAT_PVR1_RGB2_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGB4_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + f.internalformat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT; + break; + case PIXELFORMAT_ETC1_UNORM: - isSRGB = false; f.internalformat = GL_ETC1_RGB8_OES; break; case PIXELFORMAT_ETC2_RGB_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2; + f.internalformat = GL_COMPRESSED_RGB8_ETC2; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ETC2; break; case PIXELFORMAT_ETC2_RGBA_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC; + f.internalformat = GL_COMPRESSED_RGBA8_ETC2_EAC; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + f.internalformat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2; break; case PIXELFORMAT_EAC_R_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_R11_EAC; break; case PIXELFORMAT_EAC_R_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_R11_EAC; break; case PIXELFORMAT_EAC_RG_UNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_RG11_EAC; break; case PIXELFORMAT_EAC_RG_SNORM: - isSRGB = false; f.internalformat = GL_COMPRESSED_SIGNED_RG11_EAC; break; - case PIXELFORMAT_ASTC_4x4: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : GL_COMPRESSED_RGBA_ASTC_4x4_KHR; + + case PIXELFORMAT_ASTC_4x4_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR; break; - case PIXELFORMAT_ASTC_5x4: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : GL_COMPRESSED_RGBA_ASTC_5x4_KHR; + case PIXELFORMAT_ASTC_4x4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR; break; - case PIXELFORMAT_ASTC_5x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : GL_COMPRESSED_RGBA_ASTC_5x5_KHR; + case PIXELFORMAT_ASTC_5x4_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_5x4_KHR; break; - case PIXELFORMAT_ASTC_6x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : GL_COMPRESSED_RGBA_ASTC_6x5_KHR; + case PIXELFORMAT_ASTC_5x4_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR; break; - case PIXELFORMAT_ASTC_6x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : GL_COMPRESSED_RGBA_ASTC_6x6_KHR; + case PIXELFORMAT_ASTC_5x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_5x5_KHR; break; - case PIXELFORMAT_ASTC_8x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : GL_COMPRESSED_RGBA_ASTC_8x5_KHR; + case PIXELFORMAT_ASTC_5x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR; break; - case PIXELFORMAT_ASTC_8x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : GL_COMPRESSED_RGBA_ASTC_8x6_KHR; + case PIXELFORMAT_ASTC_6x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_6x5_KHR; break; - case PIXELFORMAT_ASTC_8x8: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + case PIXELFORMAT_ASTC_6x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR; break; - case PIXELFORMAT_ASTC_10x5: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + case PIXELFORMAT_ASTC_6x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_6x6_KHR; break; - case PIXELFORMAT_ASTC_10x6: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + case PIXELFORMAT_ASTC_6x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR; break; - case PIXELFORMAT_ASTC_10x8: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + case PIXELFORMAT_ASTC_8x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x5_KHR; break; - case PIXELFORMAT_ASTC_10x10: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + case PIXELFORMAT_ASTC_8x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR; break; - case PIXELFORMAT_ASTC_12x10: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + case PIXELFORMAT_ASTC_8x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x6_KHR; break; - case PIXELFORMAT_ASTC_12x12: - f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + case PIXELFORMAT_ASTC_8x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR; + break; + case PIXELFORMAT_ASTC_8x8_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR; + break; + case PIXELFORMAT_ASTC_10x5_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x5_KHR; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR; + break; + case PIXELFORMAT_ASTC_10x6_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x6_KHR; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR; + break; + case PIXELFORMAT_ASTC_10x8_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x8_KHR; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR; + break; + case PIXELFORMAT_ASTC_10x10_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_10x10_KHR; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR; + break; + case PIXELFORMAT_ASTC_12x10_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_12x10_KHR; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR; + break; + case PIXELFORMAT_ASTC_12x12_UNORM: + f.internalformat = GL_COMPRESSED_RGBA_ASTC_12x12_KHR; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + f.internalformat = GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR; break; default: @@ -2101,25 +1855,6 @@ OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool r break; } - if (!isPixelFormatCompressed(pixelformat)) - { - // glTexImage in OpenGL ES 2 only accepts internal format enums that - // match the external format. GLES3 doesn't have that restriction - - // except for GL_LUMINANCE_ALPHA which doesn't have a sized version in - // ES3. However we always use RG8 for PIXELFORMAT_LA8 on GLES3 so it - // doesn't matter there. - // Also note that GLES2+extension sRGB format enums are different from - // desktop GL and GLES3+ (this is handled above). - if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0 - && !renderbuffer && !isTexStorageSupported()) - { - f.internalformat = f.externalformat; - } - - if (!isPixelFormatSRGB(pixelformat)) - isSRGB = false; - } - return f; } @@ -2135,40 +1870,27 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) { case PIXELFORMAT_R8_UNORM: case PIXELFORMAT_RG8_UNORM: - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_texture_rg || GLAD_EXT_texture_rg) - flags |= commonsample | commonrender; - else if (pixelformat == PIXELFORMAT_R8_UNORM && (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_1)) - flags |= commonsample; // We'll use OpenGL's luminance format internally. + flags |= commonsample | commonrender; if (GLAD_VERSION_4_3) flags |= computewrite; break; case PIXELFORMAT_RGBA8_UNORM: - flags |= commonsample; - if (GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8) - flags |= commonrender; + flags |= commonsample | commonrender; if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1) flags |= computewrite; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: if (gl.bugs.brokenSRGB) break; - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB) - flags |= commonsample; - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 - || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB) && (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB))) - flags |= commonrender; - if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1) - flags |= computewrite; + flags |= commonsample | commonrender; break; case PIXELFORMAT_BGRA8_UNORM: - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: // Not supported right now. break; case PIXELFORMAT_R16_UNORM: case PIXELFORMAT_RG16_UNORM: - if (GLAD_VERSION_3_0 - || (GLAD_VERSION_1_1 && GLAD_ARB_texture_rg) - || (GLAD_EXT_texture_norm16 && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg))) + if (GLAD_VERSION_3_0 || (GLAD_EXT_texture_norm16 && GLAD_ES_VERSION_3_0)) flags |= commonsample | commonrender; if (GLAD_VERSION_4_3) flags |= computewrite; @@ -2181,26 +1903,20 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) break; case PIXELFORMAT_R16_FLOAT: case PIXELFORMAT_RG16_FLOAT: - if (GLAD_VERSION_1_0 && (GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel && GLAD_ARB_texture_rg))) - flags |= commonsample | commonrender; - if (GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_half_float && GLAD_EXT_texture_rg)) - flags |= commonsample; - if (GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg)) + flags |= commonsample; + if (GLAD_VERSION_3_0) + flags |= commonrender; + if ((GLAD_EXT_color_buffer_half_float || GLAD_EXT_color_buffer_float) && GLAD_ES_VERSION_3_0) flags |= commonrender; - if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear)) - flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR; if (GLAD_VERSION_4_3) flags |= computewrite; break; case PIXELFORMAT_RGBA16_FLOAT: - if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel)) - flags |= commonsample | commonrender; - if (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float) - flags |= commonsample; - if (GLAD_EXT_color_buffer_half_float) + flags |= commonsample; + if (GLAD_VERSION_3_0) + flags |= commonrender; + if (GLAD_EXT_color_buffer_half_float || GLAD_EXT_color_buffer_float) flags |= commonrender; - if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear)) - flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR; if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1) flags |= computewrite; break; @@ -2209,67 +1925,68 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) flags |= computewrite; // Fallthrough. case PIXELFORMAT_RG32_FLOAT: - if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float && GLAD_ARB_texture_rg)) - flags |= commonsample | commonrender; - if (GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_float && GLAD_EXT_texture_rg)) - flags |= commonsample; - if (!(GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear)) + flags |= commonsample; + if (GLAD_VERSION_3_0) + flags |= commonrender; + if (GLAD_EXT_color_buffer_float) + flags |= commonrender; + if (!(GLAD_VERSION_1_1 || GLAD_OES_texture_float_linear)) flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR; if (GLAD_VERSION_4_3) flags |= computewrite; break; case PIXELFORMAT_RGBA32_FLOAT: - if (GLAD_VERSION_3_0 || (GLAD_VERSION_1_0 && GLAD_ARB_texture_float)) - flags |= commonsample | commonrender; - if (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float) - flags |= commonsample; + flags |= commonsample; + if (GLAD_VERSION_3_0) + flags |= commonrender; + if (GLAD_EXT_color_buffer_float) + flags |= commonrender; if (!(GLAD_VERSION_1_1 || GLAD_OES_texture_float_linear)) flags &= ~PIXELFORMATUSAGEFLAGS_LINEAR; if (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_1) flags |= computewrite; break; - case PIXELFORMAT_R8_INT: - case PIXELFORMAT_R8_UINT: - case PIXELFORMAT_RG8_INT: - case PIXELFORMAT_RG8_UINT: - case PIXELFORMAT_RGBA8_INT: - case PIXELFORMAT_RGBA8_UINT: - case PIXELFORMAT_R16_INT: - case PIXELFORMAT_R16_UINT: - case PIXELFORMAT_RG16_INT: - case PIXELFORMAT_RG16_UINT: - case PIXELFORMAT_RGBA16_INT: - case PIXELFORMAT_RGBA16_UINT: - case PIXELFORMAT_R32_INT: - case PIXELFORMAT_R32_UINT: - case PIXELFORMAT_RG32_INT: - case PIXELFORMAT_RG32_UINT: - case PIXELFORMAT_RGBA32_INT: - case PIXELFORMAT_RGBA32_UINT: - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0) - flags |= PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; - if (GLAD_VERSION_4_3) - flags |= computewrite; - if (GLAD_ES_VERSION_3_1) + case PIXELFORMAT_R8_INT: + case PIXELFORMAT_R8_UINT: + case PIXELFORMAT_RG8_INT: + case PIXELFORMAT_RG8_UINT: + case PIXELFORMAT_RGBA8_INT: + case PIXELFORMAT_RGBA8_UINT: + case PIXELFORMAT_R16_INT: + case PIXELFORMAT_R16_UINT: + case PIXELFORMAT_RG16_INT: + case PIXELFORMAT_RG16_UINT: + case PIXELFORMAT_RGBA16_INT: + case PIXELFORMAT_RGBA16_UINT: + case PIXELFORMAT_R32_INT: + case PIXELFORMAT_R32_UINT: + case PIXELFORMAT_RG32_INT: + case PIXELFORMAT_RG32_UINT: + case PIXELFORMAT_RGBA32_INT: + case PIXELFORMAT_RGBA32_UINT: + flags |= PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; + if (GLAD_VERSION_4_3) + flags |= computewrite; + if (GLAD_ES_VERSION_3_1) + { + switch (pixelformat) { - switch (pixelformat) - { - case PIXELFORMAT_RGBA8_INT: - case PIXELFORMAT_RGBA8_UINT: - case PIXELFORMAT_RGBA16_INT: - case PIXELFORMAT_RGBA16_UINT: - case PIXELFORMAT_R32_INT: - case PIXELFORMAT_R32_UINT: - case PIXELFORMAT_RGBA32_INT: - case PIXELFORMAT_RGBA32_UINT: - flags |= computewrite; - break; - default: - break; - } + case PIXELFORMAT_RGBA8_INT: + case PIXELFORMAT_RGBA8_UINT: + case PIXELFORMAT_RGBA16_INT: + case PIXELFORMAT_RGBA16_UINT: + case PIXELFORMAT_R32_INT: + case PIXELFORMAT_R32_UINT: + case PIXELFORMAT_RGBA32_INT: + case PIXELFORMAT_RGBA32_UINT: + flags |= computewrite; + break; + default: + break; } - break; + } + break; case PIXELFORMAT_LA8_UNORM: flags |= commonsample; @@ -2284,16 +2001,17 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) flags |= commonsample | commonrender; break; case PIXELFORMAT_RGB10A2_UNORM: - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0) - flags |= commonsample | commonrender; + flags |= commonsample | commonrender; if (GLAD_VERSION_4_3) flags |= computewrite; break; case PIXELFORMAT_RG11B10_FLOAT: - if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float) + if (GLAD_ES_VERSION_3_1 || GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float) flags |= commonsample; if (GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float) flags |= commonrender; + if (GLAD_EXT_color_buffer_float) + flags |= commonrender; if (GLAD_VERSION_4_3) flags |= computewrite; break; @@ -2303,42 +2021,34 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) break; case PIXELFORMAT_DEPTH16_UNORM: - flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; - if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth_texture) - flags |= commonsample; + flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; break; case PIXELFORMAT_DEPTH24_UNORM: - if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_depth24 || GLAD_OES_depth_texture) - flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; - - if (GLAD_VERSION_2_0 || GLAD_ES_VERSION_3_0 || (GLAD_OES_depth_texture && (GLAD_OES_depth24 || GLAD_OES_depth_texture))) - flags |= commonsample; + flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; break; case PIXELFORMAT_DEPTH24_UNORM_STENCIL8: - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || GLAD_OES_packed_depth_stencil) - flags |= PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; - - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_EXT_packed_depth_stencil || (GLAD_OES_depth_texture && GLAD_OES_packed_depth_stencil)) - flags |= commonsample; + flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; break; case PIXELFORMAT_DEPTH32_FLOAT: case PIXELFORMAT_DEPTH32_FLOAT_STENCIL8: - if (GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_depth_buffer_float) - flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; + flags |= commonsample | PIXELFORMATUSAGEFLAGS_RENDERTARGET | PIXELFORMATUSAGEFLAGS_MSAA; break; case PIXELFORMAT_DXT1_UNORM: + case PIXELFORMAT_DXT1_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1) flags |= commonsample; break; case PIXELFORMAT_DXT3_UNORM: + case PIXELFORMAT_DXT3_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3) flags |= commonsample; break; case PIXELFORMAT_DXT5_UNORM: + case PIXELFORMAT_DXT5_sRGB: if (GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5) flags |= commonsample; break; @@ -2352,6 +2062,7 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) case PIXELFORMAT_BC6H_UFLOAT: case PIXELFORMAT_BC6H_FLOAT: case PIXELFORMAT_BC7_UNORM: + case PIXELFORMAT_BC7_sRGB: if (GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc) flags |= commonsample; break; @@ -2362,14 +2073,24 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) if (GLAD_IMG_texture_compression_pvrtc) flags |= commonsample; break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + case PIXELFORMAT_PVR1_RGB4_sRGB: + case PIXELFORMAT_PVR1_RGBA2_sRGB: + case PIXELFORMAT_PVR1_RGBA4_sRGB: + if (GLAD_EXT_pvrtc_sRGB) + flags |= commonsample; + break; case PIXELFORMAT_ETC1_UNORM: // ETC2 support guarantees ETC1 support as well. - if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture) + if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) flags |= commonsample; break; case PIXELFORMAT_ETC2_RGB_UNORM: + case PIXELFORMAT_ETC2_RGB_sRGB: case PIXELFORMAT_ETC2_RGBA_UNORM: + case PIXELFORMAT_ETC2_RGBA_sRGB: case PIXELFORMAT_ETC2_RGBA1_UNORM: + case PIXELFORMAT_ETC2_RGBA1_sRGB: case PIXELFORMAT_EAC_R_UNORM: case PIXELFORMAT_EAC_R_SNORM: case PIXELFORMAT_EAC_RG_UNORM: @@ -2377,20 +2098,34 @@ uint32 OpenGL::getPixelFormatUsageFlags(PixelFormat pixelformat) if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility) flags |= commonsample; break; - case PIXELFORMAT_ASTC_4x4: - case PIXELFORMAT_ASTC_5x4: - case PIXELFORMAT_ASTC_5x5: - case PIXELFORMAT_ASTC_6x5: - case PIXELFORMAT_ASTC_6x6: - case PIXELFORMAT_ASTC_8x5: - case PIXELFORMAT_ASTC_8x6: - case PIXELFORMAT_ASTC_8x8: - case PIXELFORMAT_ASTC_10x5: - case PIXELFORMAT_ASTC_10x6: - case PIXELFORMAT_ASTC_10x8: - case PIXELFORMAT_ASTC_10x10: - case PIXELFORMAT_ASTC_12x10: - case PIXELFORMAT_ASTC_12x12: + case PIXELFORMAT_ASTC_4x4_UNORM: + case PIXELFORMAT_ASTC_5x4_UNORM: + case PIXELFORMAT_ASTC_5x5_UNORM: + case PIXELFORMAT_ASTC_6x5_UNORM: + case PIXELFORMAT_ASTC_6x6_UNORM: + case PIXELFORMAT_ASTC_8x5_UNORM: + case PIXELFORMAT_ASTC_8x6_UNORM: + case PIXELFORMAT_ASTC_8x8_UNORM: + case PIXELFORMAT_ASTC_10x5_UNORM: + case PIXELFORMAT_ASTC_10x6_UNORM: + case PIXELFORMAT_ASTC_10x8_UNORM: + case PIXELFORMAT_ASTC_10x10_UNORM: + case PIXELFORMAT_ASTC_12x10_UNORM: + case PIXELFORMAT_ASTC_12x12_UNORM: + case PIXELFORMAT_ASTC_4x4_sRGB: + case PIXELFORMAT_ASTC_5x4_sRGB: + case PIXELFORMAT_ASTC_5x5_sRGB: + case PIXELFORMAT_ASTC_6x5_sRGB: + case PIXELFORMAT_ASTC_6x6_sRGB: + case PIXELFORMAT_ASTC_8x5_sRGB: + case PIXELFORMAT_ASTC_8x6_sRGB: + case PIXELFORMAT_ASTC_8x8_sRGB: + case PIXELFORMAT_ASTC_10x5_sRGB: + case PIXELFORMAT_ASTC_10x6_sRGB: + case PIXELFORMAT_ASTC_10x8_sRGB: + case PIXELFORMAT_ASTC_10x10_sRGB: + case PIXELFORMAT_ASTC_12x10_sRGB: + case PIXELFORMAT_ASTC_12x12_sRGB: if (GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr) flags |= commonsample; break; @@ -2473,6 +2208,8 @@ const char *OpenGL::debugSeverityString(GLenum severity) return "medium"; case GL_DEBUG_SEVERITY_LOW: return "low"; + case GL_DEBUG_SEVERITY_NOTIFICATION: + return "notification"; default: return "unknown"; } diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 6f2d26746..624d3a1d9 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -124,6 +124,21 @@ public: ~TempDebugGroup(); }; + // glClear() is affected by various OpenGL state... + class CleanClearState + { + public: + CleanClearState(GLbitfield clearFlags); + ~CleanClearState(); + + private: + GLenum clearFlags; + uint32 colorWriteMask; + uint32 stencilWriteMask; + bool depthWrites; + bool scissor; + }; + struct Stats { int shaderSwitches; @@ -185,13 +200,6 @@ public: **/ bool brokenSRGB; - /** - * Some Android graphics drivers claim to support GLES3.0 but have bugs - * with certain aspects that users expect to work. For example: - * https://github.com/love2d/love-android/issues/204 - **/ - bool brokenGLES3; - /** * Other bugs which have workarounds that don't use conditional code at * the moment: @@ -301,6 +309,9 @@ public: void setStencilWriteMask(uint32 mask); uint32 getStencilWriteMask() const; + void setColorWriteMask(uint32 mask); + uint32 getColorWriteMask() const; + /** * Calls glUseProgram. **/ @@ -312,20 +323,6 @@ public: **/ GLuint getDefaultFBO() const; - /** - * Gets the ID for love's default texture (used for "untextured" primitives.) - **/ - GLuint getDefaultTexture(TextureType type, DataBaseType datatype) const; - - /** - * Gets the texture ID for love's default texel buffer. - **/ - GLuint getDefaultTexelBuffer() const { return state.defaultTexelBuffer; } - void setDefaultTexelBuffer(GLuint tex) { state.defaultTexelBuffer = tex; } - - GLuint getDefaultStorageBuffer() const { return state.defaultStorageBuffer; } - void setDefaultStorageBuffer(GLuint buf) { state.defaultStorageBuffer = buf; } - /** * Helper for setting the active texture unit. * @@ -363,21 +360,13 @@ public: * to glTexImage2D/3D for all levels and slices of a texture otherwise. * NOTE: this does not handle compressed texture formats. **/ - bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth = 1); + bool rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, int width, int height, int depth = 1); - bool isTextureTypeSupported(TextureType type) const; bool isBufferUsageSupported(BufferUsage usage) const; bool isClampZeroOneTextureWrapSupported() const; - bool isPixelShaderHighpSupported() const; - bool isInstancingSupported() const; - bool isDepthCompareSampleSupported() const; bool isSamplerLODBiasSupported() const; bool isBaseVertexSupported() const; - bool isMultiFormatMRTSupported() const; - bool isCopyBufferSupported() const; - bool isCopyBufferToTextureSupported() const; bool isCopyTextureToBufferSupported() const; - bool isCopyRenderTargetToBufferSupported() const; /** * Returns the maximum supported width or height of a texture. @@ -457,7 +446,7 @@ public: static GLint getGLWrapMode(SamplerState::WrapMode wmode); static GLint getGLCompareMode(CompareMode mode); - static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB); + static TextureFormat convertPixelFormat(PixelFormat pixelformat); static bool isTexStorageSupported(); static uint32 getPixelFormatUsageFlags(PixelFormat pixelformat); @@ -474,11 +463,9 @@ private: void initVendor(); void initOpenGLFunctions(); void initMaxValues(); - void createDefaultTexture(); bool contextInitialized; - bool pixelShaderHighpSupported; bool baseVertexSupported; float maxAnisotropy; @@ -524,17 +511,12 @@ private: Rect viewport; Rect scissor; - float pointSize; - bool depthWritesEnabled = true; uint32 stencilWriteMask = LOVE_UINT32_MAX; + uint32 colorWriteMask = LOVE_UINT32_MAX; GLuint boundFramebuffers[2]; - GLuint defaultTexture[TEXTURE_MAX_ENUM][DATA_BASETYPE_MAX_ENUM]; - GLuint defaultTexelBuffer; - GLuint defaultStorageBuffer; - } state; }; // OpenGL diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index d4d2b65ca..99568ebfc 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,15 +38,9 @@ namespace graphics namespace opengl { -static bool isBuffer(Shader::UniformType utype) -{ - return utype == Shader::UNIFORM_TEXELBUFFER || utype == Shader::UNIFORM_STORAGEBUFFER; -} - -Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]) - : love::graphics::Shader(stages) +Shader::Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options) + : love::graphics::Shader(stages, options) , program(0) - , splitUniformsPerDraw(false) , builtinUniforms() , builtinUniformInfo() { @@ -58,32 +52,11 @@ Shader::~Shader() { unloadVolatile(); - for (const auto &p : uniforms) + for (const auto &p : reflection.allUniforms) { // Allocated with malloc(). - if (p.second.data != nullptr) - free(p.second.data); - - if (p.second.baseType == UNIFORM_SAMPLER || p.second.baseType == UNIFORM_STORAGETEXTURE) - { - for (int i = 0; i < p.second.count; i++) - { - if (p.second.textures[i] != nullptr) - p.second.textures[i]->release(); - } - - delete[] p.second.textures; - } - else if (isBuffer(p.second.baseType)) - { - for (int i = 0; i < p.second.count; i++) - { - if (p.second.buffers[i] != nullptr) - p.second.buffers[i]->release(); - } - - delete[] p.second.buffers; - } + if (p.second->data != nullptr) + free(p.second->data); } } @@ -96,6 +69,26 @@ void Shader::mapActiveUniforms() builtinUniformInfo[i] = nullptr; } + // Make sure all stored resources have their Volatiles loaded before + // the sendTextures/sendBuffers calls below, since they call getHandle(). + for (love::graphics::Texture *tex : activeTextures) + { + if (tex == nullptr) + continue; + Volatile *v = dynamic_cast(tex); + if (v != nullptr) + v->loadVolatile(); + } + + for (love::graphics::Buffer *buffer : activeBuffers) + { + if (buffer == nullptr) + continue; + Volatile *v = dynamic_cast(buffer); + if (v != nullptr) + v->loadVolatile(); + } + GLint activeprogram = 0; glGetIntegerv(GL_CURRENT_PROGRAM, &activeprogram); @@ -107,57 +100,46 @@ void Shader::mapActiveUniforms() GLchar cname[256]; const GLint bufsize = (GLint) (sizeof(cname) / sizeof(GLchar)); - std::map olduniforms = uniforms; - uniforms.clear(); - for (int uindex = 0; uindex < numuniforms; uindex++) { GLsizei namelen = 0; GLenum gltype = 0; - UniformInfo u = {}; + int count = 0; - glGetActiveUniform(program, (GLuint) uindex, bufsize, &namelen, &u.count, &gltype, cname); + glGetActiveUniform(program, (GLuint) uindex, bufsize, &namelen, &count, &gltype, cname); - u.name = std::string(cname, (size_t) namelen); - u.location = glGetUniformLocation(program, u.name.c_str()); - u.access = ACCESS_READ; - computeUniformTypeInfo(gltype, u); + std::string name(cname, (size_t) namelen); + int location = glGetUniformLocation(program, name.c_str()); - // glGetActiveUniform appends "[0]" to the end of array uniform names... - if (u.name.length() > 3) + if (location == -1) + continue; + + name = canonicaliizeUniformName(name); + + const auto &uniformit = reflection.allUniforms.find(name); + if (uniformit == reflection.allUniforms.end()) { - size_t findpos = u.name.find("[0]"); - if (findpos != std::string::npos && findpos == u.name.length() - 3) - u.name.erase(u.name.length() - 3); + handleUnknownUniformName(name.c_str()); + continue; } + UniformInfo &u = *uniformit->second; + + u.active = true; + u.location = location; + // If this is a built-in (LOVE-created) uniform, store the location. BuiltinUniform builtin = BUILTIN_MAX_ENUM; if (getConstant(u.name.c_str(), builtin)) builtinUniforms[int(builtin)] = u.location; - if (u.location == -1) - continue; - - if (!fillUniformReflectionData(u)) - continue;; - if ((u.baseType == UNIFORM_SAMPLER && builtin != BUILTIN_TEXTURE_MAIN) || u.baseType == UNIFORM_TEXELBUFFER) { TextureUnit unit; unit.type = u.textureType; unit.active = true; - - if (u.baseType == UNIFORM_TEXELBUFFER) - { - unit.isTexelBuffer = true; - unit.texture = gl.getDefaultTexelBuffer(); - } - else - { - unit.isTexelBuffer = false; - unit.texture = gl.getDefaultTexture(u.textureType, u.dataBaseType); - } + unit.texture = 0; // Handled below. + unit.isTexelBuffer = u.baseType == UNIFORM_TEXELBUFFER; for (int i = 0; i < u.count; i++) textureUnits.push_back(unit); @@ -165,7 +147,7 @@ void Shader::mapActiveUniforms() else if (u.baseType == UNIFORM_STORAGETEXTURE) { StorageTextureBinding binding = {}; - binding.gltexture = gl.getDefaultTexture(u.textureType, u.dataBaseType); + binding.gltexture = 0; // Handled below. binding.type = u.textureType; if ((u.access & (ACCESS_READ | ACCESS_WRITE)) != 0) @@ -175,172 +157,58 @@ void Shader::mapActiveUniforms() else if ((u.access & ACCESS_READ) != 0) binding.access = GL_READ_ONLY; - bool sRGB = false; - auto fmt = OpenGL::convertPixelFormat(u.storageTextureFormat, false, sRGB); + auto fmt = OpenGL::convertPixelFormat(u.storageTextureFormat); binding.internalFormat = fmt.internalformat; for (int i = 0; i < u.count; i++) storageTextureBindings.push_back(binding); } - // Make sure previously set uniform data is preserved, and shader- - // initialized values are retrieved. - auto oldu = olduniforms.find(u.name); - if (oldu != olduniforms.end()) + if (u.dataSize == 0) { - u.data = oldu->second.data; - u.dataSize = oldu->second.dataSize; - u.textures = oldu->second.textures; + if (u.baseType == UNIFORM_MATRIX) + u.dataSize = sizeof(uint32) * u.matrix.rows * u.matrix.columns * u.count; + else + u.dataSize = sizeof(uint32) * u.components * u.count; - updateUniform(&u, u.count, true); + u.data = malloc(u.dataSize); + memset(u.data, 0, u.dataSize); + + const auto &valuesit = reflection.localUniformInitializerValues.find(u.name); + if (valuesit != reflection.localUniformInitializerValues.end()) + { + const auto &values = valuesit->second; + if (!values.empty()) + memcpy(u.data, values.data(), std::min(u.dataSize, sizeof(LocalUniformValue) * values.size())); + } } - else + + if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_TEXELBUFFER) { - u.dataSize = 0; + int startunit = (int) textureUnits.size() - u.count; - switch (u.baseType) - { - case UNIFORM_FLOAT: - u.dataSize = sizeof(float) * u.components * u.count; - u.data = malloc(u.dataSize); - break; - case UNIFORM_INT: - case UNIFORM_BOOL: - case UNIFORM_SAMPLER: - case UNIFORM_STORAGETEXTURE: - case UNIFORM_TEXELBUFFER: - u.dataSize = sizeof(int) * u.components * u.count; - u.data = malloc(u.dataSize); - break; - case UNIFORM_UINT: - u.dataSize = sizeof(unsigned int) * u.components * u.count; - u.data = malloc(u.dataSize); - break; - case UNIFORM_MATRIX: - u.dataSize = sizeof(float) * ((size_t)u.matrix.rows * u.matrix.columns) * u.count; - u.data = malloc(u.dataSize); - break; - default: - break; - } + if (builtin == BUILTIN_TEXTURE_MAIN) + startunit = 0; - if (u.dataSize > 0) - { - memset(u.data, 0, u.dataSize); - - if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_TEXELBUFFER) - { - int startunit = (int) textureUnits.size() - u.count; - - if (builtin == BUILTIN_TEXTURE_MAIN) - startunit = 0; - - for (int i = 0; i < u.count; i++) - u.ints[i] = startunit + i; - - glUniform1iv(u.location, u.count, u.ints); - - if (u.baseType == UNIFORM_TEXELBUFFER) - { - u.buffers = new love::graphics::Buffer*[u.count]; - memset(u.buffers, 0, sizeof(Buffer *) * u.count); - } - else - { - u.textures = new love::graphics::Texture*[u.count]; - memset(u.textures, 0, sizeof(Texture *) * u.count); - } - } - else if (u.baseType == UNIFORM_STORAGETEXTURE) - { - int startbinding = (int) storageTextureBindings.size() - u.count; - for (int i = 0; i < u.count; i++) - u.ints[i] = startbinding + i; - - glUniform1iv(u.location, u.count, u.ints); - - u.textures = new love::graphics::Texture*[u.count]; - memset(u.textures, 0, sizeof(Texture *) * u.count); - } - } - - size_t offset = 0; - - // Store any shader-initialized values in our own memory. for (int i = 0; i < u.count; i++) - { - GLint location = u.location; - - if (u.count > 1) - { - std::ostringstream ss; - ss << i; - - std::string indexname = u.name + "[" + ss.str() + "]"; - location = glGetUniformLocation(program, indexname.c_str()); - } - - if (location == -1) - continue; - - switch (u.baseType) - { - case UNIFORM_FLOAT: - glGetUniformfv(program, location, &u.floats[offset]); - offset += u.components; - break; - case UNIFORM_INT: - case UNIFORM_BOOL: - glGetUniformiv(program, location, &u.ints[offset]); - offset += u.components; - break; - case UNIFORM_UINT: - glGetUniformuiv(program, location, &u.uints[offset]); - offset += u.components; - break; - case UNIFORM_MATRIX: - glGetUniformfv(program, location, &u.floats[offset]); - offset += (size_t)u.matrix.rows * u.matrix.columns; - break; - default: - break; - } - } + u.ints[i] = startunit + i; + } + else if (u.baseType == UNIFORM_STORAGETEXTURE) + { + int startbinding = (int) storageTextureBindings.size() - u.count; + for (int i = 0; i < u.count; i++) + u.ints[i] = startbinding + i; } - uniforms[u.name] = u; + updateUniform(&u, u.count, true); if (builtin != BUILTIN_MAX_ENUM) - builtinUniformInfo[(int)builtin] = &uniforms[u.name]; + builtinUniformInfo[(int)builtin] = &u; if (u.baseType == UNIFORM_SAMPLER || u.baseType == UNIFORM_STORAGETEXTURE) - { - // Make sure all stored textures have their Volatiles loaded before - // the sendTextures call, since it calls getHandle(). - for (int i = 0; i < u.count; i++) - { - if (u.textures[i] == nullptr) - continue; - Volatile *v = dynamic_cast(u.textures[i]); - if (v != nullptr) - v->loadVolatile(); - } - - sendTextures(&u, u.textures, u.count, true); - } + sendTextures(&u, &activeTextures[u.resourceIndex], u.count, true); else if (u.baseType == UNIFORM_TEXELBUFFER) - { - for (int i = 0; i < u.count; i++) - { - if (u.buffers[i] == nullptr) - continue; - Volatile *v = dynamic_cast(u.buffers[i]); - if (v != nullptr) - v->loadVolatile(); - } - - sendBuffers(&u, u.buffers, u.count, true); - } + sendBuffers(&u, &activeBuffers[u.resourceIndex], u.count, true); } if (gl.isBufferUsageSupported(BUFFERUSAGE_SHADER_STORAGE)) @@ -353,37 +221,28 @@ void Shader::mapActiveUniforms() for (int sindex = 0; sindex < numstoragebuffers; sindex++) { - UniformInfo u = {}; - u.baseType = UNIFORM_STORAGEBUFFER; - u.access = ACCESS_READ; - GLsizei namelength = 0; glGetProgramResourceName(program, GL_SHADER_STORAGE_BLOCK, sindex, 2048, &namelength, namebuffer); - u.name = std::string(namebuffer, namelength); - u.count = 1; + std::string name = canonicaliizeUniformName(std::string(namebuffer, namelength)); - if (!fillUniformReflectionData(u)) + const auto &uniformit = reflection.storageBuffers.find(name); + if (uniformit == reflection.storageBuffers.end()) + { + handleUnknownUniformName(name.c_str()); continue; - - // Make sure previously set uniform data is preserved, and shader- - // initialized values are retrieved. - auto oldu = olduniforms.find(u.name); - if (oldu != olduniforms.end()) - { - u.data = oldu->second.data; - u.dataSize = oldu->second.dataSize; - u.buffers = oldu->second.buffers; } - else + + UniformInfo &u = uniformit->second; + + u.active = true; + + if (u.dataSize == 0) { - u.dataSize = sizeof(int) * 1; + u.dataSize = sizeof(int) * u.count; u.data = malloc(u.dataSize); - - u.ints[0] = -1; - - u.buffers = new love::graphics::Buffer * [u.count]; - memset(u.buffers, 0, sizeof(Buffer*)* u.count); + for (int i = 0; i < u.count; i++) + u.ints[i] = -1; } // Unlike local uniforms and attributes, OpenGL doesn't auto-assign storage @@ -394,7 +253,7 @@ void Shader::mapActiveUniforms() BufferBinding binding; binding.bindingindex = u.ints[0]; - binding.buffer = gl.getDefaultStorageBuffer(); + binding.buffer = 0; if (binding.bindingindex >= 0) { @@ -406,56 +265,13 @@ void Shader::mapActiveUniforms() if (u.access & ACCESS_WRITE) { p.second = (int)activeWritableStorageBuffers.size(); - activeWritableStorageBuffers.push_back(u.buffers[0]); + activeWritableStorageBuffers.push_back(activeBuffers[u.resourceIndex]); } storageBufferBindingIndexToActiveBinding[binding.bindingindex] = p; } - uniforms[u.name] = u; - - for (int i = 0; i < u.count; i++) - { - if (u.buffers[i] == nullptr) - continue; - Volatile* v = dynamic_cast(u.buffers[i]); - if (v != nullptr) - v->loadVolatile(); - } - - sendBuffers(&u, u.buffers, u.count, true); - } - } - - // Make sure uniforms that existed before but don't exist anymore are - // cleaned up. This theoretically shouldn't happen, but... - for (const auto &p : olduniforms) - { - if (uniforms.find(p.first) == uniforms.end()) - { - if (p.second.data != nullptr) - free(p.second.data); - - if (p.second.baseType == UNIFORM_SAMPLER || p.second.baseType == UNIFORM_STORAGETEXTURE) - { - for (int i = 0; i < p.second.count; i++) - { - if (p.second.textures[i] != nullptr) - p.second.textures[i]->release(); - } - - delete[] p.second.textures; - } - else if (isBuffer(p.second.baseType)) - { - for (int i = 0; i < p.second.count; i++) - { - if (p.second.buffers[i] != nullptr) - p.second.buffers[i]->release(); - } - - delete[] p.second.buffers; - } + sendBuffers(&u, &activeBuffers[u.resourceIndex], u.count, true); } } @@ -466,11 +282,6 @@ bool Shader::loadVolatile() { OpenGL::TempDebugGroup debuggroup("Shader load"); - // love::graphics::Shader sets up the shader code-side of this. - auto gfx = Module::getInstance(Module::M_GRAPHICS); - if (gfx != nullptr) - splitUniformsPerDraw = !gfx->getCapabilities().features[Graphics::FEATURE_PIXEL_SHADER_HIGHP]; - // zero out active texture list textureUnits.clear(); textureUnits.push_back(TextureUnit()); @@ -492,6 +303,9 @@ bool Shader::loadVolatile() if (program == 0) throw love::Exception("Cannot create shader program object."); + if (!debugName.empty() && (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2)) + glObjectLabel(GL_PROGRAM, program, -1, debugName.c_str()); + for (const auto &stage : stages) { if (stage.get() != nullptr) @@ -586,7 +400,7 @@ std::string Shader::getWarnings() const const std::string &stagewarnings = stage->getWarnings(); - if (ShaderStage::getConstant(stage->getStageType(), stagestr)) + if (!stagewarnings.empty() && ShaderStage::getConstant(stage->getStageType(), stagestr)) warnings += std::string(stagestr) + std::string(" shader:\n") + stagewarnings; } @@ -635,16 +449,6 @@ void Shader::attach() } } -const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const -{ - const auto it = uniforms.find(name); - - if (it == uniforms.end()) - return nullptr; - - return &(it->second); -} - const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const { return builtinUniformInfo[(int)builtin]; @@ -773,43 +577,52 @@ void Shader::sendTextures(const UniformInfo *info, love::graphics::Texture **tex for (int i = 0; i < count; i++) { love::graphics::Texture *tex = textures[i]; + bool isdefault = tex == nullptr; if (tex != nullptr) { if (!validateTexture(info, tex, internalUpdate)) continue; - tex->retain(); + } + else + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + tex = gfx->getDefaultTexture(info->textureType, info->dataBaseType, info->isDepthSampler); } - if (info->textures[i] != nullptr) - info->textures[i]->release(); + tex->retain(); - info->textures[i] = tex; + int resourceindex = info->resourceIndex + i; + + if (activeTextures[resourceindex] != nullptr) + activeTextures[resourceindex]->release(); + + activeTextures[resourceindex] = tex; if (isstoragetex) { - GLuint gltex = 0; - if (tex != nullptr) - gltex = (GLuint) tex->getHandle(); - else - gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType); + GLuint gltex = (GLuint) tex->getHandle(); int bindingindex = info->ints[i]; auto &binding = storageTextureBindings[bindingindex]; - binding.texture = tex; - binding.gltexture = gltex; + if (isdefault && (info->access & ACCESS_WRITE) != 0) + { + binding.texture = nullptr; + binding.gltexture = 0; + } + else + { + binding.texture = tex; + binding.gltexture = gltex; - if (shaderactive) - glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat); + if (shaderactive) + glBindImageTexture(bindingindex, binding.gltexture, 0, GL_TRUE, 0, binding.access, binding.internalFormat); + } } else { - GLuint gltex = 0; - if (textures[i] != nullptr) - gltex = (GLuint) tex->getHandle(); - else - gltex = gl.getDefaultTexture(info->textureType, info->dataBaseType); + GLuint gltex = (GLuint) tex->getHandle(); int texunit = info->ints[i]; @@ -846,27 +659,34 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe for (int i = 0; i < count; i++) { love::graphics::Buffer *buffer = buffers[i]; + bool isdefault = buffer == nullptr; if (buffer != nullptr) { if (!validateBuffer(info, buffer, internalUpdate)) continue; - buffer->retain(); + } + else + { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (texelbinding) + buffer = gfx->getDefaultTexelBuffer(info->dataBaseType); + else + buffer = gfx->getDefaultStorageBuffer(); } - if (info->buffers[i] != nullptr) - info->buffers[i]->release(); + buffer->retain(); - info->buffers[i] = buffer; + int resourceindex = info->resourceIndex + i; + + if (activeBuffers[resourceindex] != nullptr) + activeBuffers[resourceindex]->release(); + + activeBuffers[resourceindex] = buffer; if (texelbinding) { - GLuint gltex = 0; - if (buffer != nullptr) - gltex = (GLuint) buffer->getTexelBufferHandle(); - else - gltex = gl.getDefaultTexelBuffer(); - + GLuint gltex = (GLuint) buffer->getTexelBufferHandle(); int texunit = info->ints[i]; if (shaderactive) @@ -877,14 +697,9 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe } else if (storagebinding) { + GLuint glbuffer = (GLuint)buffer->getHandle(); int bindingindex = info->ints[i]; - GLuint glbuffer = 0; - if (buffer != nullptr) - glbuffer = (GLuint) buffer->getHandle(); - else - glbuffer = gl.getDefaultStorageBuffer(); - if (shaderactive) gl.bindIndexedBuffer(glbuffer, BUFFERUSAGE_SHADER_STORAGE, bindingindex); @@ -894,7 +709,7 @@ void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffe activeStorageBufferBindings[activeindex.first].buffer = glbuffer; if (activeindex.second >= 0) - activeWritableStorageBuffers[activeindex.second] = buffer; + activeWritableStorageBuffers[activeindex.second] = isdefault ? nullptr : buffer; } } } @@ -905,11 +720,6 @@ void Shader::flushBatchedDraws() const Graphics::flushBatchedDrawsGlobal(); } -bool Shader::hasUniform(const std::string &name) const -{ - return uniforms.find(name) != uniforms.end(); -} - ptrdiff_t Shader::getHandle() const { return program; @@ -951,30 +761,28 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, if (current != this) return; + bool rt = gfx->isRenderTargetActive(); + BuiltinUniformData data; data.transformMatrix = gfx->getTransform(); data.projectionMatrix = gfx->getDeviceProjection(); - // The normal matrix is the transpose of the inverse of the rotation portion - // (top-left 3x3) of the transform matrix. - { - Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse(); - const float *e = normalmatrix.getElements(); - for (int i = 0; i < 3; i++) - { - data.normalMatrix[i].x = e[i * 3 + 0]; - data.normalMatrix[i].y = e[i * 3 + 1]; - data.normalMatrix[i].z = e[i * 3 + 2]; - data.normalMatrix[i].w = 0.0f; - } - } + data.scaleParams.x = (float) gfx->getCurrentDPIScale(); + data.scaleParams.y = gfx->getPointSize(); - // Store DPI scale in an unused component of another vector. - data.normalMatrix[0].w = (float) gfx->getCurrentDPIScale(); - - // Same with point size. - data.normalMatrix[1].w = gfx->getPointSize(); + // Users expect to work with y-up NDC, y-down pixel coordinates and textures + // (see graphics/Shader.h). + // OpenGL has y-up NDC and y-up pixel coordinates and textures. If we just flip + // NDC y when rendering to a texture, it's enough to make (0, 0) on the texture + // match what we expect when sampling from it - so it's the same as if textures + // are y-down with y-up NDC. + // Windowing systems treat (0, 0) on the backbuffer texture as the bottom left, + // so we don't need to do that there. + uint32 clipflags = 0; + if (rt) + clipflags |= CLIP_TRANSFORM_FLIP_Y; + data.clipSpaceParams = computeClipSpaceParams(clipflags); data.screenSizeParams.x = viewportW; data.screenSizeParams.y = viewportH; @@ -982,7 +790,7 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, // The shader does pixcoord.y = gl_FragCoord.y * params.z + params.w. // This lets us flip pixcoord.y when needed, to be consistent (drawing // with no RT active makes the pixel coordinates y-flipped.) - if (gfx->isRenderTargetActive()) + if (rt) { // No flipping: pixcoord.y = gl_FragCoord.y * 1.0 + 0.0. data.screenSizeParams.z = 1.0f; @@ -999,314 +807,9 @@ void Shader::updateBuiltinUniforms(love::graphics::Graphics *gfx, int viewportW, data.constantColor = gfx->getColor(); gammaCorrectColor(data.constantColor); - // This branch is to avoid always declaring the whole array as highp in the - // vertex shader and mediump in the pixel shader for love's default shaders, - // on systems that don't support highp in pixel shaders. The default shaders - // use the transform matrices in vertex shaders and screen size params in - // pixel shaders. If there's a single array containing both and each shader - // stage declares a different precision, that's a compile error. - if (splitUniformsPerDraw) - { - GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; - if (location >= 0) - glUniform4fv(location, 12, (const GLfloat *) &data); - GLint location2 = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW_2]; - if (location2 >= 0) - glUniform4fv(location2, 1, (const GLfloat *) &data.screenSizeParams); - } - else - { - GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; - if (location >= 0) - glUniform4fv(location, 13, (const GLfloat *) &data); - } -} - -int Shader::getUniformTypeComponents(GLenum type) const -{ - switch (type) - { - case GL_INT: - case GL_UNSIGNED_INT: - case GL_FLOAT: - case GL_BOOL: - return 1; - case GL_INT_VEC2: - case GL_UNSIGNED_INT_VEC2: - case GL_FLOAT_VEC2: - case GL_FLOAT_MAT2: - case GL_BOOL_VEC2: - return 2; - case GL_INT_VEC3: - case GL_UNSIGNED_INT_VEC3: - case GL_FLOAT_VEC3: - case GL_FLOAT_MAT3: - case GL_BOOL_VEC3: - return 3; - case GL_INT_VEC4: - case GL_UNSIGNED_INT_VEC4: - case GL_FLOAT_VEC4: - case GL_FLOAT_MAT4: - case GL_BOOL_VEC4: - return 4; - default: - return 1; - } -} - -Shader::MatrixSize Shader::getMatrixSize(GLenum type) const -{ - MatrixSize m; - - switch (type) - { - case GL_FLOAT_MAT2: - m.columns = m.rows = 2; - break; - case GL_FLOAT_MAT3: - m.columns = m.rows = 3; - break; - case GL_FLOAT_MAT4: - m.columns = m.rows = 4; - break; - case GL_FLOAT_MAT2x3: - m.columns = 2; - m.rows = 3; - break; - case GL_FLOAT_MAT2x4: - m.columns = 2; - m.rows = 4; - break; - case GL_FLOAT_MAT3x2: - m.columns = 3; - m.rows = 2; - break; - case GL_FLOAT_MAT3x4: - m.columns = 3; - m.rows = 4; - break; - case GL_FLOAT_MAT4x2: - m.columns = 4; - m.rows = 2; - break; - case GL_FLOAT_MAT4x3: - m.columns = 4; - m.rows = 3; - break; - default: - m.columns = m.rows = 0; - break; - } - - return m; -} - -void Shader::computeUniformTypeInfo(GLenum type, UniformInfo &u) -{ - u.isDepthSampler = false; - u.components = getUniformTypeComponents(type); - u.baseType = UNIFORM_UNKNOWN; - - switch (type) - { - case GL_INT: - case GL_INT_VEC2: - case GL_INT_VEC3: - case GL_INT_VEC4: - u.baseType = UNIFORM_INT; - u.dataBaseType = DATA_BASETYPE_INT; - break; - case GL_UNSIGNED_INT: - case GL_UNSIGNED_INT_VEC2: - case GL_UNSIGNED_INT_VEC3: - case GL_UNSIGNED_INT_VEC4: - u.baseType = UNIFORM_UINT; - u.dataBaseType = DATA_BASETYPE_UINT; - break; - case GL_FLOAT: - case GL_FLOAT_VEC2: - case GL_FLOAT_VEC3: - case GL_FLOAT_VEC4: - u.baseType = UNIFORM_FLOAT; - u.dataBaseType = DATA_BASETYPE_FLOAT; - break; - case GL_FLOAT_MAT2: - case GL_FLOAT_MAT3: - case GL_FLOAT_MAT4: - case GL_FLOAT_MAT2x3: - case GL_FLOAT_MAT2x4: - case GL_FLOAT_MAT3x2: - case GL_FLOAT_MAT3x4: - case GL_FLOAT_MAT4x2: - case GL_FLOAT_MAT4x3: - u.baseType = UNIFORM_MATRIX; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.matrix = getMatrixSize(type); - break; - case GL_BOOL: - case GL_BOOL_VEC2: - case GL_BOOL_VEC3: - case GL_BOOL_VEC4: - u.baseType = UNIFORM_BOOL; - u.dataBaseType = DATA_BASETYPE_BOOL; - break; - - case GL_SAMPLER_2D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D; - break; - case GL_SAMPLER_2D_SHADOW: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D; - u.isDepthSampler = true; - break; - case GL_INT_SAMPLER_2D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_2D; - break; - case GL_UNSIGNED_INT_SAMPLER_2D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_2D; - break; - case GL_SAMPLER_2D_ARRAY: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_SAMPLER_2D_ARRAY_SHADOW: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D_ARRAY; - u.isDepthSampler = true; - break; - case GL_INT_SAMPLER_2D_ARRAY: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_SAMPLER_3D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_INT_SAMPLER_3D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_UNSIGNED_INT_SAMPLER_3D: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_SAMPLER_CUBE: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_CUBE; - break; - case GL_SAMPLER_CUBE_SHADOW: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_CUBE; - u.isDepthSampler = true; - break; - case GL_INT_SAMPLER_CUBE: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_CUBE; - break; - case GL_UNSIGNED_INT_SAMPLER_CUBE: - u.baseType = UNIFORM_SAMPLER; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_CUBE; - break; - - case GL_SAMPLER_BUFFER: - u.baseType = UNIFORM_TEXELBUFFER; - u.dataBaseType = DATA_BASETYPE_FLOAT; - break; - case GL_INT_SAMPLER_BUFFER: - u.baseType = UNIFORM_TEXELBUFFER; - u.dataBaseType = DATA_BASETYPE_INT; - break; - case GL_UNSIGNED_INT_SAMPLER_BUFFER: - u.baseType = UNIFORM_TEXELBUFFER; - u.dataBaseType = DATA_BASETYPE_UINT; - break; - - case GL_IMAGE_2D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D; - break; - case GL_INT_IMAGE_2D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_2D; - break; - case GL_UNSIGNED_INT_IMAGE_2D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_2D; - break; - case GL_IMAGE_2D_ARRAY: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_INT_IMAGE_2D_ARRAY: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_UNSIGNED_INT_IMAGE_2D_ARRAY: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_2D_ARRAY; - break; - case GL_IMAGE_3D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_INT_IMAGE_3D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_UNSIGNED_INT_IMAGE_3D: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_VOLUME; - break; - case GL_IMAGE_CUBE: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_FLOAT; - u.textureType = TEXTURE_CUBE; - break; - case GL_INT_IMAGE_CUBE: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_INT; - u.textureType = TEXTURE_CUBE; - break; - case GL_UNSIGNED_INT_IMAGE_CUBE: - u.baseType = UNIFORM_STORAGETEXTURE; - u.dataBaseType = DATA_BASETYPE_UINT; - u.textureType = TEXTURE_CUBE; - break; - - default: - break; - } + GLint location = builtinUniforms[BUILTIN_UNIFORMS_PER_DRAW]; + if (location >= 0) + glUniform4fv(location, 12, (const GLfloat *) &data); } } // opengl diff --git a/src/modules/graphics/opengl/Shader.h b/src/modules/graphics/opengl/Shader.h index 5f38a5196..078debc56 100644 --- a/src/modules/graphics/opengl/Shader.h +++ b/src/modules/graphics/opengl/Shader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -52,7 +52,7 @@ public: GLenum internalFormat; }; - Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM]); + Shader(StrongRef stages[SHADERSTAGE_MAX_ENUM], const CompileOptions &options); virtual ~Shader(); // Implements Volatile @@ -63,12 +63,10 @@ public: void attach() override; std::string getWarnings() const override; int getVertexAttributeIndex(const std::string &name) override; - const UniformInfo *getUniformInfo(const std::string &name) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count) override; void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; - bool hasUniform(const std::string &name) const override; ptrdiff_t getHandle() const override; void setVideoTextures(love::graphics::Texture *ytexture, love::graphics::Texture *cbtexture, love::graphics::Texture *crtexture) override; @@ -100,10 +98,6 @@ private: void sendTextures(const UniformInfo *info, love::graphics::Texture **textures, int count, bool internalupdate); void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count, bool internalupdate); - int getUniformTypeComponents(GLenum type) const; - void computeUniformTypeInfo(GLenum type, UniformInfo &u); - MatrixSize getMatrixSize(GLenum type) const; - void flushBatchedDraws() const; // Get any warnings or errors generated only by the shader program object. @@ -112,17 +106,12 @@ private: // volatile GLuint program; - bool splitUniformsPerDraw; - // Location values for any built-in uniform variables. GLint builtinUniforms[BUILTIN_MAX_ENUM]; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; std::map attributes; - // Uniform location buffer map - std::map uniforms; - // Texture unit pool for setting textures std::vector textureUnits; diff --git a/src/modules/graphics/opengl/ShaderStage.cpp b/src/modules/graphics/opengl/ShaderStage.cpp index babd1b777..4001404e0 100644 --- a/src/modules/graphics/opengl/ShaderStage.cpp +++ b/src/modules/graphics/opengl/ShaderStage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/ShaderStage.h b/src/modules/graphics/opengl/ShaderStage.h index db21b6322..1481fdc39 100644 --- a/src/modules/graphics/opengl/ShaderStage.h +++ b/src/modules/graphics/opengl/ShaderStage.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/StreamBuffer.cpp b/src/modules/graphics/opengl/StreamBuffer.cpp index df304b5a9..9317ead3a 100644 --- a/src/modules/graphics/opengl/StreamBuffer.cpp +++ b/src/modules/graphics/opengl/StreamBuffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -63,6 +63,11 @@ public: delete[] data; } + size_t getGPUReadOffset() const override + { + return (size_t) data; + } + MapInfo map(size_t /*minsize*/) override { return MapInfo(data, bufferSize); @@ -111,6 +116,11 @@ public: delete[] data; } + size_t getGPUReadOffset() const override + { + return frameGPUReadOffset; + } + MapInfo map(size_t /*minsize*/) override { if (orphan) @@ -192,6 +202,11 @@ public: virtual ~StreamBufferSync() {} + size_t getGPUReadOffset() const override + { + return (frameIndex * bufferSize) + frameGPUReadOffset; + } + void nextFrame() override { // Insert a GPU fence for this frame's section of the data, we'll wait diff --git a/src/modules/graphics/opengl/StreamBuffer.h b/src/modules/graphics/opengl/StreamBuffer.h index f6c036176..0fa184a09 100644 --- a/src/modules/graphics/opengl/StreamBuffer.h +++ b/src/modules/graphics/opengl/StreamBuffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/opengl/Texture.cpp b/src/modules/graphics/opengl/Texture.cpp index 70fdbd344..bd5b9591b 100644 --- a/src/modules/graphics/opengl/Texture.cpp +++ b/src/modules/graphics/opengl/Texture.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,19 +45,14 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo if (texture != 0) { - if (isPixelFormatDepthStencil(format) && (GLAD_ES_VERSION_3_0 || !GLAD_ES_VERSION_2_0)) + if (isPixelFormatDepthStencil(format)) { - // glDrawBuffers is an ext in GL2. glDrawBuffer doesn't exist in ES3. GLenum none = GL_NONE; - if (GLAD_ES_VERSION_3_0) - glDrawBuffers(1, &none); - else - glDrawBuffer(GL_NONE); + glDrawBuffers(1, &none); glReadBuffer(GL_NONE); } - bool unusedSRGB = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, unusedSRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format); int faces = texType == TEXTURE_CUBE ? 6 : 1; @@ -78,33 +73,38 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo gl.framebufferTexture(attachment, texType, texture, mip, layer, face); } - if (clear) + if (clear && isPixelFormatInteger(format)) { - if (isPixelFormatDepthStencil(format)) + PixelFormatType datatype = getPixelFormatInfo(format).dataType; + if (datatype == PIXELFORMATTYPE_SINT) { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); + const GLint carray[] = { 0, 0, 0, 0 }; + glClearBufferiv(GL_COLOR, 0, carray); + } + else + { + const GLuint carray[] = { 0, 0, 0, 0 }; + glClearBufferuiv(GL_COLOR, 0, carray); + } + } + else if (clear) + { + bool ds = isPixelFormatDepthStencil(format); - uint32 stencilwrite = gl.getStencilWriteMask(); - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(LOVE_UINT32_MAX); + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + if (ds) + { gl.clearDepth(1.0); glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); - - if (stencilwrite != LOVE_UINT32_MAX) - gl.setStencilWriteMask(stencilwrite); } else { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); } + + glClear(clearflags); } } } @@ -120,8 +120,7 @@ static GLenum createFBO(GLuint &framebuffer, TextureType texType, PixelFormat fo static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer) { - bool unusedSRGB = false; - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, true, unusedSRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat); GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL); @@ -130,14 +129,10 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p glGenFramebuffers(1, &fbo); gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, fbo); - if (isPixelFormatDepthStencil(pixelformat) && (GLAD_ES_VERSION_3_0 || !GLAD_ES_VERSION_2_0)) + if (isPixelFormatDepthStencil(pixelformat)) { - // glDrawBuffers is an ext in GL2. glDrawBuffer doesn't exist in ES3. GLenum none = GL_NONE; - if (GLAD_ES_VERSION_3_0) - glDrawBuffers(1, &none); - else - glDrawBuffer(GL_NONE); + glDrawBuffers(1, &none); glReadBuffer(GL_NONE); } @@ -167,24 +162,39 @@ static GLenum newRenderbuffer(int width, int height, int &samples, PixelFormat p if (status == GL_FRAMEBUFFER_COMPLETE) { - if (isPixelFormatDepthStencil(pixelformat)) + if (isPixelFormatInteger(pixelformat)) { - bool hadDepthWrites = gl.hasDepthWrites(); - if (!hadDepthWrites) // glDepthMask also affects glClear. - gl.setDepthWrites(true); - - gl.clearDepth(1.0); - glClearStencil(0); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - - if (!hadDepthWrites) - gl.setDepthWrites(hadDepthWrites); + PixelFormatType datatype = getPixelFormatInfo(pixelformat).dataType; + if (datatype == PIXELFORMATTYPE_SINT) + { + const GLint carray[] = { 0, 0, 0, 0 }; + glClearBufferiv(GL_COLOR, 0, carray); + } + else + { + const GLuint carray[] = { 0, 0, 0, 0 }; + glClearBufferuiv(GL_COLOR, 0, carray); + } } else { - // Initialize the buffer to transparent black. - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT); + bool ds = isPixelFormatDepthStencil(pixelformat); + + GLbitfield clearflags = ds ? GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT : GL_COLOR_BUFFER_BIT; + OpenGL::CleanClearState cleanClearState(clearflags); + + if (ds) + { + gl.clearDepth(1.0); + glClearStencil(0); + } + else + { + // Initialize the buffer to transparent black. + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + } + + glClear(clearflags); } } else @@ -226,6 +236,25 @@ Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const slices.clear(); } +Texture::Texture(love::graphics::Graphics *gfx, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) + : love::graphics::Texture(gfx, base, viewsettings) + , slices(viewsettings.type.get(base->getTextureType())) + , fbo(0) + , texture(0) + , renderbuffer(0) + , framebufferStatus(GL_FRAMEBUFFER_COMPLETE) + , textureGLError(GL_NO_ERROR) + , actualSamples(1) +{ + if (!loadVolatile()) + { + if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE) + throw love::Exception("Cannot create texture view (OpenGL framebuffer error: %s)", OpenGL::framebufferStatusString(framebufferStatus)); + if (textureGLError != GL_NO_ERROR) + throw love::Exception("Cannot create texture view (OpenGL error: %s)", OpenGL::errorString(textureGLError)); + } +} + Texture::~Texture() { unloadVolatile(); @@ -236,11 +265,26 @@ void Texture::createTexture() // The base class handles some validation. For example, if ImageData is // given then it must exist for all mip levels, a render target can't use // a compressed format, etc. - glGenTextures(1, &texture); + GLenum gltype = OpenGL::getGLTextureType(texType); + + if (parentView.texture != this) + { + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format); + Texture *basetex = (Texture *) parentView.texture; + int layers = texType == TEXTURE_CUBE ? 6 : getLayerCount(); + + glTextureView(texture, gltype, basetex->texture, fmt.internalformat, + parentView.startMipmap, getMipmapCount(), + parentView.startLayer, layers); + + gl.bindTextureToUnit(this, 0, false); + setSamplerState(samplerState); + return; + } + gl.bindTextureToUnit(this, 0, false); - GLenum gltype = OpenGL::getGLTextureType(texType); if (renderTarget && GLAD_ANGLE_texture_usage) glTexParameteri(gltype, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); @@ -262,17 +306,17 @@ void Texture::createTexture() // remember some driver issues on some old Android systems, maybe... // For now, the base class enforces data on init for compressed textures. if (!isCompressed()) - gl.rawTexStorage(texType, mipcount, format, sRGB, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); + gl.rawTexStorage(texType, mipcount, format, pixelWidth, pixelHeight, texType == TEXTURE_VOLUME ? depth : layers); // rawTexStorage handles this for uncompressed textures. - if (isCompressed() && (GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0)) + if (isCompressed()) glTexParameteri(gltype, GL_TEXTURE_MAX_LEVEL, mipcount - 1); int w = pixelWidth; int h = pixelHeight; int d = depth; - OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, sRGB); + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format); for (int mip = 0; mip < mipcount; mip++) { @@ -338,7 +382,7 @@ void Texture::createTexture() int slices = texType == TEXTURE_VOLUME ? getDepth(mip) : layers; slices = texType == TEXTURE_CUBE ? 6 : slices; for (int i = 0; i < slices; i++) - uploadByteData(format, emptydata.data(), emptydata.size(), mip, i, r); + uploadByteData(emptydata.data(), emptydata.size(), mip, i, r); } } @@ -353,16 +397,14 @@ bool Texture::loadVolatile() if (texture != 0 || renderbuffer != 0) return true; - OpenGL::TempDebugGroup debuggroup("Texture load"); - - // NPOT textures don't support mipmapping without full NPOT support. - if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) - && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) + if (parentView.texture != this) { - mipmapCount = 1; - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + Texture *basetex = (Texture *) parentView.texture; + basetex->loadVolatile(); } + OpenGL::TempDebugGroup debuggroup("Texture load"); + actualSamples = std::max(1, std::min(getRequestedMSAA(), gl.getMaxSamples())); while (glGetError() != GL_NO_ERROR); // Clear errors. @@ -404,6 +446,20 @@ bool Texture::loadVolatile() setGraphicsMemorySize(memsize); + if (!debugName.empty() && (GLAD_VERSION_4_3 || GLAD_ES_VERSION_3_2)) + { + if (texture) + glObjectLabel(GL_TEXTURE, texture, -1, debugName.c_str()); + + if (renderbuffer) + { + std::string rname = debugName; + if (actualSamples > 1) + rname += " (MSAA buffer)"; + glObjectLabel(GL_RENDERBUFFER, renderbuffer, -1, rname.c_str()); + } + } + return true; } @@ -434,19 +490,19 @@ void Texture::unloadVolatile() setGraphicsMemorySize(0); } -void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) +void Texture::uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) { OpenGL::TempDebugGroup debuggroup("Texture data upload"); gl.bindTextureToUnit(this, 0, false); - OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, false, sRGB); + OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format); GLenum gltarget = OpenGL::getGLTextureType(texType); if (texType == TEXTURE_CUBE) gltarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice; - if (isPixelFormatCompressed(pixelformat)) + if (isPixelFormatCompressed(format)) { if (texType == TEXTURE_2D || texType == TEXTURE_CUBE) { @@ -483,13 +539,12 @@ void Texture::generateMipmapsInternal() void Texture::readbackInternal(int slice, int mipmap, const Rect &rect, int destwidth, size_t size, void *dest) { // Not supported in GL with compressed textures... - if ((GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0) && !isCompressed()) + if (!isCompressed()) glPixelStorei(GL_PACK_ROW_LENGTH, destwidth); gl.bindTextureToUnit(this, 0, false); - bool isSRGB = false; - OpenGL::TextureFormat fmt = gl.convertPixelFormat(format, false, isSRGB); + OpenGL::TextureFormat fmt = gl.convertPixelFormat(format); if (gl.isCopyTextureToBufferSupported()) { @@ -518,7 +573,7 @@ void Texture::readbackInternal(int slice, int mipmap, const Rect &rect, int dest gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, current_fbo); } - if ((GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0) && !isCompressed()) + if (!isCompressed()) glPixelStorei(GL_PACK_ROW_LENGTH, 0); } @@ -535,7 +590,7 @@ void Texture::copyFromBuffer(love::graphics::Buffer *source, size_t sourceoffset // glTexSubImage and friends copy from the active pixel_unpack_buffer by // treating the pointer as a byte offset. const uint8 *byteoffset = (const uint8 *)(ptrdiff_t)sourceoffset; - uploadByteData(format, byteoffset, size, mipmap, slice, rect); + uploadByteData(byteoffset, size, mipmap, slice, rect); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); @@ -559,28 +614,7 @@ void Texture::copyToBuffer(love::graphics::Buffer *dest, int slice, int mipmap, void Texture::setSamplerState(const SamplerState &s) { - if (s.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) - throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - - // Base class does common validation and assigns samplerState. - love::graphics::Texture::setSamplerState(s); - - auto supportedflags = OpenGL::getPixelFormatUsageFlags(getPixelFormat()); - - if ((supportedflags & PIXELFORMATUSAGEFLAGS_LINEAR) == 0) - { - samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - - if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) - samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; - } - - // If we only have limited NPOT support then the wrap mode must be CLAMP. - if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) - && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) - { - samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; - } + samplerState = validateSamplerState(s); gl.bindTextureToUnit(this, 0, false); gl.setSamplerState(texType, samplerState); diff --git a/src/modules/graphics/opengl/Texture.h b/src/modules/graphics/opengl/Texture.h index 8ee52db9c..4e507fb2f 100644 --- a/src/modules/graphics/opengl/Texture.h +++ b/src/modules/graphics/opengl/Texture.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,6 +39,7 @@ class Texture final : public love::graphics::Texture, public Volatile public: Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data); + Texture(love::graphics::Graphics *gfx, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings); virtual ~Texture(); @@ -61,9 +62,10 @@ public: void readbackInternal(int slice, int mipmap, const Rect &rect, int destwidth, size_t size, void *dest); private: + void createTexture(); - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; + void uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) override; void generateMipmapsInternal() override; @@ -78,7 +80,6 @@ private: GLenum textureGLError; int actualSamples; - }; // Texture } // opengl diff --git a/src/modules/graphics/renderstate.cpp b/src/modules/graphics/renderstate.cpp index 133db2bb0..f52afd4f9 100644 --- a/src/modules/graphics/renderstate.cpp +++ b/src/modules/graphics/renderstate.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -28,7 +28,7 @@ namespace graphics // These are all with premultiplied alpha. computeBlendState adjusts for // alpha-multiply if needed. -static const BlendState states[BLEND_MAX_ENUM] = +static const BlendState blendStates[BLEND_MAX_ENUM] = { // BLEND_ALPHA {BLENDOP_ADD, BLENDOP_ADD, BLENDFACTOR_ONE, BLENDFACTOR_ONE, BLENDFACTOR_ONE_MINUS_SRC_ALPHA, BLENDFACTOR_ONE_MINUS_SRC_ALPHA}, @@ -63,7 +63,7 @@ static const BlendState states[BLEND_MAX_ENUM] = BlendState computeBlendState(BlendMode mode, BlendAlpha alphamode) { - BlendState s = states[mode]; + BlendState s = blendStates[mode]; // We can only do alpha-multiplication when srcRGB would have been unmodified. if (s.srcFactorRGB == BLENDFACTOR_ONE && alphamode == BLENDALPHA_MULTIPLY && mode != BLEND_NONE) @@ -87,7 +87,7 @@ BlendMode computeBlendMode(BlendState s, BlendAlpha &alphamode) for (int i = 0; i < (int) BLEND_MAX_ENUM; i++) { - if (i != (int) BLEND_CUSTOM && states[i] == s) + if (i != (int) BLEND_CUSTOM && blendStates[i] == s) { alphamode = alphamultiply ? BLENDALPHA_MULTIPLY : BLENDALPHA_PREMULTIPLIED; return (BlendMode) i; @@ -111,6 +111,39 @@ bool isAlphaMultiplyBlendSupported(BlendMode mode) } } +static const StencilState stencilStates[STENCIL_MODE_MAX_ENUM] = +{ + // STENCIL_MODE_OFF + {}, + + // STENCIL_MODE_DRAW + {COMPARE_ALWAYS, STENCIL_REPLACE}, + + // STENCIL_MODE_TEST + {COMPARE_EQUAL, STENCIL_KEEP}, + + // STENCIL_MODE_CUSTOM - N/A + {}, +}; + +StencilState computeStencilState(StencilMode mode, int value) +{ + StencilState s = stencilStates[mode]; + s.value = value; + return s; +} + +StencilMode computeStencilMode(const StencilState &s) +{ + for (int i = 0; i < (int)STENCIL_MODE_MAX_ENUM; i++) + { + if (stencilStates[i].action == s.action && stencilStates[i].compare == s.compare) + return (StencilMode) i; + } + + return STENCIL_MODE_CUSTOM; +} + CompareMode getReversedCompareMode(CompareMode mode) { switch (mode) @@ -171,6 +204,15 @@ STRINGMAP_BEGIN(BlendOperation, BLENDOP_MAX_ENUM, blendOperation) } STRINGMAP_END(BlendOperation, BLENDOP_MAX_ENUM, blendOperation) +STRINGMAP_BEGIN(StencilMode, STENCIL_MODE_MAX_ENUM, stencilMode) +{ + { "off", STENCIL_MODE_OFF }, + { "draw", STENCIL_MODE_DRAW }, + { "test", STENCIL_MODE_TEST }, + { "custom", STENCIL_MODE_CUSTOM }, +} +STRINGMAP_END(StencilMode, STENCIL_MODE_MAX_ENUM, stencilMode) + STRINGMAP_BEGIN(StencilAction, STENCIL_MAX_ENUM, stencilAction) { { "keep", STENCIL_KEEP }, diff --git a/src/modules/graphics/renderstate.h b/src/modules/graphics/renderstate.h index fb86f0489..662b5cd11 100644 --- a/src/modules/graphics/renderstate.h +++ b/src/modules/graphics/renderstate.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -83,6 +83,15 @@ enum BlendOperation BLENDOP_MAX_ENUM }; +enum StencilMode // High level wrappers. +{ + STENCIL_MODE_OFF, + STENCIL_MODE_DRAW, + STENCIL_MODE_TEST, + STENCIL_MODE_CUSTOM, + STENCIL_MODE_MAX_ENUM +}; + enum StencilAction { STENCIL_KEEP, @@ -194,6 +203,9 @@ BlendState computeBlendState(BlendMode mode, BlendAlpha alphamode); BlendMode computeBlendMode(BlendState s, BlendAlpha &alphamode); bool isAlphaMultiplyBlendSupported(BlendMode mode); +StencilState computeStencilState(StencilMode mode, int value); +StencilMode computeStencilMode(const StencilState &s); + /** * GPU APIs do the comparison in the opposite way of what makes sense for some * of love's APIs. For example in OpenGL if the compare function is GL_GREATER, @@ -208,6 +220,7 @@ STRINGMAP_DECLARE(BlendMode); STRINGMAP_DECLARE(BlendAlpha); STRINGMAP_DECLARE(BlendFactor); STRINGMAP_DECLARE(BlendOperation); +STRINGMAP_DECLARE(StencilMode); STRINGMAP_DECLARE(StencilAction); STRINGMAP_DECLARE(CompareMode); diff --git a/src/modules/graphics/vertex.cpp b/src/modules/graphics/vertex.cpp index d916ebe12..b2e5f098e 100644 --- a/src/modules/graphics/vertex.cpp +++ b/src/modules/graphics/vertex.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,6 +26,8 @@ namespace love namespace graphics { +static_assert(sizeof(VertexAttributeInfo) == 4, "Unexpected sizeof(VertexAttributeInfo)"); + static_assert(sizeof(Color32) == 4, "sizeof(Color32) incorrect!"); static_assert(sizeof(STf_RGBAub) == sizeof(float)*2 + sizeof(Color32), "sizeof(STf_RGBAub) incorrect!"); static_assert(sizeof(STPf_RGBAub) == sizeof(float)*3 + sizeof(Color32), "sizeof(STPf_RGBAub) incorrect!"); @@ -110,17 +112,17 @@ static const DataFormatInfo dataFormatInfo[] { DATA_BASETYPE_FLOAT, false, 3, 0, 0, 4, 12 }, // DATAFORMAT_FLOAT_VEC3 { DATA_BASETYPE_FLOAT, false, 4, 0, 0, 4, 16 }, // DATAFORMAT_FLOAT_VEC4 - { DATA_BASETYPE_FLOAT, true, 0, 2, 2, 4, 16 }, // DATAFORMAT_FLOAT_MAT2X2 - { DATA_BASETYPE_FLOAT, true, 0, 2, 3, 4, 24 }, // DATAFORMAT_FLOAT_MAT2X3 - { DATA_BASETYPE_FLOAT, true, 0, 2, 4, 4, 32 }, // DATAFORMAT_FLOAT_MAT2X4 + { DATA_BASETYPE_FLOAT, true, 4, 2, 2, 4, 16 }, // DATAFORMAT_FLOAT_MAT2X2 + { DATA_BASETYPE_FLOAT, true, 6, 2, 3, 4, 24 }, // DATAFORMAT_FLOAT_MAT2X3 + { DATA_BASETYPE_FLOAT, true, 8, 2, 4, 4, 32 }, // DATAFORMAT_FLOAT_MAT2X4 - { DATA_BASETYPE_FLOAT, true, 0, 3, 2, 4, 24 }, // DATAFORMAT_FLOAT_MAT3X2 - { DATA_BASETYPE_FLOAT, true, 0, 3, 3, 4, 36 }, // DATAFORMAT_FLOAT_MAT3X3 - { DATA_BASETYPE_FLOAT, true, 0, 3, 4, 4, 48 }, // DATAFORMAT_FLOAT_MAT3X4 + { DATA_BASETYPE_FLOAT, true, 6, 3, 2, 4, 24 }, // DATAFORMAT_FLOAT_MAT3X2 + { DATA_BASETYPE_FLOAT, true, 9, 3, 3, 4, 36 }, // DATAFORMAT_FLOAT_MAT3X3 + { DATA_BASETYPE_FLOAT, true, 12, 3, 4, 4, 48 }, // DATAFORMAT_FLOAT_MAT3X4 - { DATA_BASETYPE_FLOAT, true, 0, 4, 2, 4, 32 }, // DATAFORMAT_FLOAT_MAT4X2 - { DATA_BASETYPE_FLOAT, true, 0, 4, 3, 4, 48 }, // DATAFORMAT_FLOAT_MAT4X3 - { DATA_BASETYPE_FLOAT, true, 0, 4, 4, 4, 64 }, // DATAFORMAT_FLOAT_MAT4X4 + { DATA_BASETYPE_FLOAT, true, 8, 4, 2, 4, 32 }, // DATAFORMAT_FLOAT_MAT4X2 + { DATA_BASETYPE_FLOAT, true, 12, 4, 3, 4, 48 }, // DATAFORMAT_FLOAT_MAT4X3 + { DATA_BASETYPE_FLOAT, true, 16, 4, 4, 4, 64 }, // DATAFORMAT_FLOAT_MAT4X4 { DATA_BASETYPE_INT, false, 1, 0, 0, 4, 4 }, // DATAFORMAT_INT32 { DATA_BASETYPE_INT, false, 2, 0, 0, 4, 8 }, // DATAFORMAT_INT32_VEC2 @@ -336,7 +338,7 @@ bool VertexAttributes::operator == (const VertexAttributes &other) const { const auto &a = attribs[i]; const auto &b = other.attribs[i]; - if (a.bufferIndex != b.bufferIndex || a.format != b.format || a.offsetFromVertex != b.offsetFromVertex) + if (a.bufferIndex != b.bufferIndex || a.packedFormat != b.packedFormat || a.offsetFromVertex != b.offsetFromVertex) return false; if (bufferLayouts[a.bufferIndex].stride != other.bufferLayouts[a.bufferIndex].stride) diff --git a/src/modules/graphics/vertex.h b/src/modules/graphics/vertex.h index 044ba2c44..7669c407d 100644 --- a/src/modules/graphics/vertex.h +++ b/src/modules/graphics/vertex.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -298,9 +298,12 @@ struct BufferBindings struct VertexAttributeInfo { - uint8 bufferIndex; - DataFormat format : 8; uint16 offsetFromVertex; + uint8 packedFormat; + uint8 bufferIndex; + + void setFormat(DataFormat format) { packedFormat = (uint8)format; } + DataFormat getFormat() const { return (DataFormat)packedFormat; } }; struct VertexBufferLayout @@ -335,7 +338,7 @@ struct VertexAttributes enableBits |= (1u << index); attribs[index].bufferIndex = bufferindex; - attribs[index].format = format; + attribs[index].setFormat(format); attribs[index].offsetFromVertex = offsetfromvertex; } diff --git a/src/modules/graphics/vulkan/Buffer.cpp b/src/modules/graphics/vulkan/Buffer.cpp index 6a6226db1..4cf4f45d4 100644 --- a/src/modules/graphics/vulkan/Buffer.cpp +++ b/src/modules/graphics/vulkan/Buffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -108,6 +108,18 @@ bool Buffer::loadVolatile() else coherent = false; + if (!debugName.empty() && vgfx->getEnabledOptionalInstanceExtensions().debugInfo) + { + auto device = vgfx->getDevice(); + + VkDebugUtilsObjectNameInfoEXT nameInfo{}; + nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + nameInfo.objectType = VK_OBJECT_TYPE_BUFFER; + nameInfo.objectHandle = (uint64_t)buffer; + nameInfo.pObjectName = debugName.c_str(); + vkSetDebugUtilsObjectNameEXT(device, &nameInfo); + } + return true; } @@ -254,17 +266,8 @@ void Buffer::unmap(size_t usedoffset, size_t usedsize) } } -void Buffer::clear(size_t offset, size_t size) +void Buffer::clearInternal(size_t offset, size_t size) { - if (isImmutable()) - throw love::Exception("Cannot clear an immutable Buffer."); - else if (isMapped()) - throw love::Exception("Cannot clear a mapped Buffer."); - else if (offset + size > getSize()) - throw love::Exception("The given offset and size parameters to clear() are not within the Buffer's size."); - else if (offset % 4 != 0 || size % 4 != 0) - throw love::Exception("clear() must be used with offset and size parameters that are multiples of 4 bytes."); - vkCmdFillBuffer(vgfx->getCommandBufferForDataTransfer(), buffer, offset, size, 0); } diff --git a/src/modules/graphics/vulkan/Buffer.h b/src/modules/graphics/vulkan/Buffer.h index e6dd674b3..41d64b6cd 100644 --- a/src/modules/graphics/vulkan/Buffer.h +++ b/src/modules/graphics/vulkan/Buffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -51,12 +51,14 @@ public: void *map(MapType map, size_t offset, size_t size) override; void unmap(size_t usedoffset, size_t usedsize) override; bool fill(size_t offset, size_t size, const void *data) override; - void clear(size_t offset, size_t size) override; void copyTo(love::graphics::Buffer *dest, size_t sourceoffset, size_t destoffset, size_t size) override; ptrdiff_t getHandle() const override; ptrdiff_t getTexelBufferHandle() const override; private: + + void clearInternal(size_t offset, size_t size) override; + bool zeroInitialize; const void *initialData; VkBuffer buffer = VK_NULL_HANDLE; diff --git a/src/modules/graphics/vulkan/Graphics.cpp b/src/modules/graphics/vulkan/Graphics.cpp index 8a4f7500f..6ca5c59c8 100644 --- a/src/modules/graphics/vulkan/Graphics.cpp +++ b/src/modules/graphics/vulkan/Graphics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,6 +21,7 @@ #include "common/Exception.h" #include "common/pixelformat.h" #include "common/version.h" +#include "common/memory.h" #include "window/Window.h" #include "Buffer.h" #include "Graphics.h" @@ -28,6 +29,7 @@ #include "Shader.h" #include "Vulkan.h" +#include #include #include @@ -60,33 +62,116 @@ static const std::vector deviceExtensions = { constexpr uint32_t USAGES_POLL_INTERVAL = 5000; -const char *Graphics::getName() const -{ - return "love.graphics.vulkan"; -} +constexpr int DEFAULT_VERTEX_BUFFER_BINDING = 0; +constexpr int VERTEX_BUFFER_BINDING_START = 1; -const VkDevice Graphics::getDevice() const +VkDevice Graphics::getDevice() const { return device; } -const VmaAllocator Graphics::getVmaAllocator() const +VmaAllocator Graphics::getVmaAllocator() const { return vmaAllocator; } +static void checkOptionalInstanceExtensions(OptionalInstanceExtensions& ext) +{ + uint32_t count; + + vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); + + std::vector extensions(count); + + vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data()); + + for (const auto& extension : extensions) + { + if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) + ext.physicalDeviceProperties2 = true; + if (strcmp(extension.extensionName, VK_EXT_DEBUG_UTILS_EXTENSION_NAME) == 0) + ext.debugInfo = true; + } +} + Graphics::Graphics() + : love::graphics::Graphics("love.graphics.vulkan") { if (SDL_Vulkan_LoadLibrary(nullptr)) throw love::Exception("could not find vulkan"); volkInitializeCustom((PFN_vkGetInstanceProcAddr)SDL_Vulkan_GetVkGetInstanceProcAddr()); + + if (isDebugEnabled() && !checkValidationSupport()) + throw love::Exception("validation layers requested, but not available"); + + VkApplicationInfo appInfo{}; + appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; + appInfo.pApplicationName = "LOVE"; + appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else? + appInfo.pEngineName = "LOVE Game Framework"; + appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV); + appInfo.apiVersion = VK_API_VERSION_1_3; + + VkInstanceCreateInfo createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.pApplicationInfo = &appInfo; + createInfo.pNext = nullptr; + + // GetInstanceExtensions works with a null window parameter as long as + // SDL_Vulkan_LoadLibrary has been called (which we do earlier). + unsigned int count; +#if SDL_VERSION_ATLEAST(3, 0, 0) + char const* const* extensions_string = SDL_Vulkan_GetInstanceExtensions(&count); + if (extensions_string == nullptr) + throw love::Exception("couldn't retrieve sdl vulkan extensions"); + + std::vector extensions(extensions_string, extensions_string + count); +#else + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) + throw love::Exception("couldn't retrieve sdl vulkan extensions"); + + std::vector extensions = {}; +#endif + + checkOptionalInstanceExtensions(optionalInstanceExtensions); + + if (optionalInstanceExtensions.physicalDeviceProperties2) + extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); + if (optionalInstanceExtensions.debugInfo) + extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME); + +#if !SDL_VERSION_ATLEAST(3, 0, 0) + size_t additional_extension_count = extensions.size(); + extensions.resize(additional_extension_count + count); + + if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) + throw love::Exception("couldn't retrieve sdl vulkan extensions"); +#endif + + createInfo.enabledExtensionCount = static_cast(extensions.size()); + createInfo.ppEnabledExtensionNames = extensions.data(); + + if (isDebugEnabled()) + { + createInfo.enabledLayerCount = static_cast(validationLayers.size()); + createInfo.ppEnabledLayerNames = validationLayers.data(); + } + + if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) + throw love::Exception("couldn't create vulkan instance"); + + volkLoadInstance(instance); } Graphics::~Graphics() { - defaultConstantColor.set(nullptr); - defaultTexture.set(nullptr); + defaultVertexBuffer.set(nullptr); + localUniformBuffer.set(nullptr); + + Volatile::unloadAll(); + cleanup(); + vkDestroyInstance(instance, nullptr); SDL_Vulkan_UnloadLibrary(); } @@ -98,6 +183,11 @@ love::graphics::Texture *Graphics::newTexture(const love::graphics::Texture::Set return new Texture(this, settings, data); } +love::graphics::Texture *Graphics::newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) +{ + return new Texture(this, base, viewsettings); +} + love::graphics::Buffer *Graphics::newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector &format, const void *data, size_t size, size_t arraylength) { return new Buffer(this, settings, format, data, size, arraylength); @@ -108,89 +198,12 @@ void Graphics::clear(OptionalColorD color, OptionalInt stencil, OptionalDouble d if (!color.hasValue && !stencil.hasValue && !depth.hasValue) return; - flushBatchedDraws(); + std::vector colors; - if (renderPassState.active) - { - VkClearAttachment attachment{}; + if (color.hasValue) + colors.resize(std::max(1, (int)states.back().renderTargets.colors.size()), color); - if (color.hasValue) - { - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - - attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.clearValue.color.float32[0] = static_cast(cf.r); - attachment.clearValue.color.float32[1] = static_cast(cf.g); - attachment.clearValue.color.float32[2] = static_cast(cf.b); - attachment.clearValue.color.float32[3] = static_cast(cf.a); - } - - VkClearAttachment depthStencilAttachment{}; - - if (stencil.hasValue) - { - depthStencilAttachment.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; - depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); - } - if (depth.hasValue) - { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); - } - - std::array attachments = { - attachment, - depthStencilAttachment - }; - - VkClearRect rect{}; - rect.layerCount = 1; - rect.rect.extent.width = static_cast(renderPassState.width); - rect.rect.extent.height = static_cast(renderPassState.height); - - vkCmdClearAttachments( - commandBuffers[currentFrame], - static_cast(attachments.size()), attachments.data(), - 1, &rect); - } - else - { - if (color.hasValue) - { - renderPassState.renderPassConfiguration.colorAttachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - - renderPassState.clearColors[0].color.float32[0] = static_cast(cf.r); - renderPassState.clearColors[0].color.float32[1] = static_cast(cf.g); - renderPassState.clearColors[0].color.float32[2] = static_cast(cf.b); - renderPassState.clearColors[0].color.float32[3] = static_cast(cf.a); - } - - if (depth.hasValue) - { - renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[1].depthStencil.depth = static_cast(depth.value); - } - - if (stencil.hasValue) - { - renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[1].depthStencil.stencil = static_cast(stencil.value); - } - - if (renderPassState.isWindow) - { - renderPassState.windowClearRequested = true; - renderPassState.mainWindowClearColorValue = color; - renderPassState.mainWindowClearDepthValue = depth; - renderPassState.mainWindowClearStencilValue = stencil; - } - else - startRenderPass(); - } + clear(colors, stencil, depth); } void Graphics::clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) @@ -200,40 +213,52 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten flushBatchedDraws(); + const auto &rts = states.back().renderTargets; + bool rtactive = isRenderTargetActive(); + size_t ncolorbuffers = rtactive ? rts.colors.size() : 1; + size_t ncolors = std::min(ncolorbuffers, colors.size()); + if (renderPassState.active) { std::vector attachments; - for (const auto &color : colors) + for (size_t i = 0; i < ncolors; i++) { + const OptionalColorD &color = colors[i]; VkClearAttachment attachment{}; if (color.hasValue) { - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - + auto texture = i < rts.colors.size() ? rts.colors[i].texture.get() : nullptr; attachment.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - attachment.clearValue.color.float32[0] = static_cast(cf.r); - attachment.clearValue.color.float32[1] = static_cast(cf.g); - attachment.clearValue.color.float32[2] = static_cast(cf.b); - attachment.clearValue.color.float32[3] = static_cast(cf.a); + attachment.clearValue.color = Texture::getClearColor(texture, color.value); } attachments.push_back(attachment); } VkClearAttachment depthStencilAttachment{}; + auto dstexture = rts.depthStencil.texture.get(); + if (stencil.hasValue) { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + if ((!rtactive && backbufferHasStencil) + || (dstexture && isPixelFormatStencil(dstexture->getPixelFormat())) || (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0) + { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; + depthStencilAttachment.clearValue.depthStencil.stencil = static_cast(stencil.value); + } } if (depth.hasValue) { - depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; - depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + if ((!rtactive && backbufferHasDepth) + || (dstexture && isPixelFormatDepth(dstexture->getPixelFormat())) || (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0) + { + depthStencilAttachment.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + depthStencilAttachment.clearValue.depthStencil.depth = static_cast(depth.value); + } } - attachments.push_back(depthStencilAttachment); + if (depthStencilAttachment.aspectMask != 0) + attachments.push_back(depthStencilAttachment); VkClearRect rect{}; rect.layerCount = 1; @@ -247,36 +272,38 @@ void Graphics::clear(const std::vector &colors, OptionalInt sten } else { - for (size_t i = 0; i < colors.size(); i++) + for (size_t i = 0; i < ncolors; i++) { if (colors[i].hasValue) { renderPassState.renderPassConfiguration.colorAttachments[i].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - auto &color = colors[i]; - Colorf cf((float)color.value.r, (float)color.value.g, (float)color.value.b, (float)color.value.a); - gammaCorrectColor(cf); - - renderPassState.clearColors[i].color.float32[0] = static_cast(cf.r); - renderPassState.clearColors[i].color.float32[1] = static_cast(cf.g); - renderPassState.clearColors[i].color.float32[2] = static_cast(cf.b); - renderPassState.clearColors[i].color.float32[3] = static_cast(cf.a); + auto texture = i < rts.colors.size() ? rts.colors[i].texture.get() : nullptr; + renderPassState.clearColors[i].color = Texture::getClearColor(texture, colors[i].value); } } if (depth.hasValue) { renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.depthLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[colors.size()].depthStencil.depth = static_cast(depth.value); + renderPassState.clearColors[ncolorbuffers].depthStencil.depth = static_cast(depth.value); } if (stencil.hasValue) { renderPassState.renderPassConfiguration.staticData.depthStencilAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - renderPassState.clearColors[colors.size()].depthStencil.stencil = static_cast(stencil.value); + renderPassState.clearColors[ncolorbuffers].depthStencil.stencil = static_cast(stencil.value); } - startRenderPass(); + if (renderPassState.isWindow) + { + renderPassState.windowClearRequested = true; + renderPassState.mainWindowClearColorValue = colors.empty() ? OptionalColorD() : colors[0]; + renderPassState.mainWindowClearDepthValue = depth; + renderPassState.mainWindowClearStencilValue = stencil; + } + else + startRenderPass(); } } @@ -302,70 +329,63 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) startRenderPass(); } -void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) +void Graphics::submitGpuCommands(SubmitMode submitMode, void *screenshotCallbackData) { flushBatchedDraws(); if (renderPassState.active) endRenderPass(); - if (present) + VkBuffer screenshotBuffer = VK_NULL_HANDLE; + VmaAllocation screenshotAllocation = VK_NULL_HANDLE; + VmaAllocationInfo screenshotAllocationInfo = {}; + + VkImage backbufferImage = fakeBackbuffer != nullptr ? (VkImage)fakeBackbuffer->getHandle() : swapChainImages.at(imageIndex); + + if (submitMode == SUBMIT_PRESENT) { if (pendingScreenshotCallbacks.empty()) - Vulkan::cmdTransitionImageLayout( - commandBuffers.at(currentFrame), - swapChainImages.at(imageIndex), - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + { + if (fakeBackbuffer == nullptr) + { + Vulkan::cmdTransitionImageLayout( + commandBuffers.at(currentFrame), + backbufferImage, + swapChainPixelFormat, + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); + } + } else { + VkBufferCreateInfo bufferInfo{}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = 4ll * swapChainExtent.width * swapChainExtent.height; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VmaAllocationCreateInfo allocCreateInfo{}; + allocCreateInfo.usage = VMA_MEMORY_USAGE_AUTO; + allocCreateInfo.flags = VMA_ALLOCATION_CREATE_HOST_ACCESS_RANDOM_BIT | VMA_ALLOCATION_CREATE_MAPPED_BIT; + + auto result = vmaCreateBuffer( + vmaAllocator, + &bufferInfo, + &allocCreateInfo, + &screenshotBuffer, + &screenshotAllocation, + &screenshotAllocationInfo); + + if (result != VK_SUCCESS) + throw love::Exception("failed to create screenshot readback buffer"); + Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), - swapChainImages.at(imageIndex), + backbufferImage, + swapChainPixelFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - Vulkan::cmdTransitionImageLayout( - commandBuffers.at(currentFrame), - screenshotReadbackBuffers.at(currentFrame).image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkImageBlit blit{}; - blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.layerCount = 1; - blit.srcOffsets[1] = { - static_cast(swapChainExtent.width), - static_cast(swapChainExtent.height), - 1 - }; - blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.layerCount = 1; - blit.dstOffsets[1] = { - static_cast(swapChainExtent.width), - static_cast(swapChainExtent.height), - 1 - }; - - vkCmdBlitImage( - commandBuffers.at(currentFrame), - swapChainImages.at(imageIndex), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - screenshotReadbackBuffers.at(currentFrame).image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, - VK_FILTER_NEAREST); - - Vulkan::cmdTransitionImageLayout( - commandBuffers.at(currentFrame), - swapChainImages.at(imageIndex), - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - VK_IMAGE_LAYOUT_PRESENT_SRC_KHR); - - Vulkan::cmdTransitionImageLayout( - commandBuffers.at(currentFrame), - screenshotReadbackBuffers.at(currentFrame).image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); - VkBufferImageCopy region{}; region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; region.imageSubresource.layerCount = 1; @@ -377,40 +397,28 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) vkCmdCopyImageToBuffer( commandBuffers.at(currentFrame), - screenshotReadbackBuffers.at(currentFrame).image, + backbufferImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - screenshotReadbackBuffers.at(currentFrame).buffer, + screenshotBuffer, 1, ®ion); - addReadbackCallback([ - w = swapChainExtent.width, - h = swapChainExtent.height, - pendingScreenshotCallbacks = pendingScreenshotCallbacks, - screenShotReadbackBuffer = screenshotReadbackBuffers.at(currentFrame), - screenshotCallbackData = screenshotCallbackData]() { - auto imageModule = Module::getInstance(M_IMAGE); - - for (const auto &info : pendingScreenshotCallbacks) - { - image::ImageData *img = imageModule->newImageData( - w, - h, - PIXELFORMAT_RGBA8_UNORM, - screenShotReadbackBuffer.allocationInfo.pMappedData); - info.callback(&info, img, screenshotCallbackData); - img->release(); - } - }); - - pendingScreenshotCallbacks.clear(); + Vulkan::cmdTransitionImageLayout( + commandBuffers.at(currentFrame), + backbufferImage, + swapChainPixelFormat, + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + fakeBackbuffer == nullptr ? VK_IMAGE_LAYOUT_PRESENT_SRC_KHR : VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); } } endRecordingGraphicsCommands(); - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) - vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); - imagesInFlight[imageIndex] = inFlightFences[currentFrame]; + if (!imagesInFlight.empty()) + { + if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) + vkWaitForFences(device, 1, &imagesInFlight.at(imageIndex), VK_TRUE, UINT64_MAX); + imagesInFlight[imageIndex] = inFlightFences[currentFrame]; + } std::array submitCommandbuffers = { commandBuffers.at(currentFrame) }; @@ -435,10 +443,13 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) VkFence fence = VK_NULL_HANDLE; - if (present) + if (submitMode == SUBMIT_PRESENT) { - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphores; + if (!swapChainImages.empty()) + { + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + } vkResetFences(device, 1, &inFlightFences[currentFrame]); fence = inFlightFences[currentFrame]; @@ -447,7 +458,7 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, fence) != VK_SUCCESS) throw love::Exception("failed to submit draw command buffer"); - if (!present) + if (submitMode == SUBMIT_NOPRESENT || submitMode == SUBMIT_RESTART || screenshotBuffer != VK_NULL_HANDLE) { vkQueueWaitIdle(graphicsQueue); @@ -458,7 +469,66 @@ void Graphics::submitGpuCommands(bool present, void *screenshotCallbackData) callbacks.clear(); } - startRecordingGraphicsCommands(); + if (screenshotBuffer != VK_NULL_HANDLE) + { + auto imageModule = Module::getInstance(M_IMAGE); + + for (int i = 0; i < (int)pendingScreenshotCallbacks.size(); i++) + { + const auto &info = pendingScreenshotCallbacks[i]; + image::ImageData *img = nullptr; + + try + { + img = imageModule->newImageData( + swapChainExtent.width, + swapChainExtent.height, + PIXELFORMAT_RGBA8_UNORM, + screenshotAllocationInfo.pMappedData); + } + catch (love::Exception &) + { + info.callback(&info, nullptr, nullptr); + for (int j = i + 1; j < (int)pendingScreenshotCallbacks.size(); j++) + { + const auto& ninfo = pendingScreenshotCallbacks[j]; + ninfo.callback(&ninfo, nullptr, nullptr); + } + vmaDestroyBuffer(vmaAllocator, screenshotBuffer, screenshotAllocation); + pendingScreenshotCallbacks.clear(); + throw; + } + + uint8 *screenshot = (uint8*)img->getData(); + + if (swapChainImageFormat == VK_FORMAT_B8G8R8A8_UNORM || swapChainImageFormat == VK_FORMAT_B8G8R8A8_SRGB) + { + // Convert from BGRA to RGBA and replace alpha with full opacity. + for (size_t i = 0; i < img->getSize(); i += 4) + { + uint8 r = screenshot[i + 2]; + screenshot[i + 2] = screenshot[i + 0]; + screenshot[i + 0] = r; + screenshot[i + 3] = 255; + } + } + else + { + // Replace alpha with full opacity. + for (size_t i = 0; i < img->getSize(); i += 4) + screenshot[i + 3] = 255; + } + + info.callback(&info, img, screenshotCallbackData); + img->release(); + } + + vmaDestroyBuffer(vmaAllocator, screenshotBuffer, screenshotAllocation); + pendingScreenshotCallbacks.clear(); + } + + if (submitMode == SUBMIT_RESTART) + startRecordingGraphicsCommands(); } } @@ -475,17 +545,34 @@ void Graphics::present(void *screenshotCallbackdata) deprecations.draw(this); - submitGpuCommands(true, screenshotCallbackdata); + submitGpuCommands(SUBMIT_PRESENT, screenshotCallbackdata); - VkPresentInfoKHR presentInfo{}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = &renderFinishedSemaphores.at(currentFrame); - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = &swapChain; - presentInfo.pImageIndices = &imageIndex; + VkResult result = VK_SUCCESS; - VkResult result = vkQueuePresentKHR(presentQueue, &presentInfo); + if (!swapChainImages.empty()) + { + VkPresentInfoKHR presentInfo{}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = &renderFinishedSemaphores.at(currentFrame); + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = &swapChain; + presentInfo.pImageIndices = &imageIndex; + + result = vkQueuePresentKHR(presentQueue, &presentInfo); + } + else + { + // Presenting without a real swap chain can happen if the window is minimized. + // Check every frame to see if a proper one can be created, in this situation. + VkSurfaceCapabilitiesKHR capabilities = {}; + if (vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities) == VK_SUCCESS) + { + VkExtent2D extent = chooseSwapExtent(capabilities); + if (extent.width > 0 && extent.height > 0) + swapChainRecreationRequested = true; + } + } if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR || swapChainRecreationRequested) { @@ -512,9 +599,10 @@ void Graphics::present(void *screenshotCallbackdata) beginFrame(); } -void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight) +void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { - if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height)) + if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height + || backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth || msaa != requestedMsaa)) requestSwapchainRecreation(); this->width = width; @@ -522,17 +610,21 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh this->pixelWidth = pixelwidth; this->pixelHeight = pixelheight; + this->backbufferHasStencil = backbufferstencil; + this->backbufferHasDepth = backbufferdepth; + this->requestedMsaa = msaa; + if (!isRenderTargetActive()) resetProjection(); + + if (swapChain != VK_NULL_HANDLE) + msaaSamples = getMsaaCount(requestedMsaa); } -bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) +bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) { - requestedMsaa = msaa; - windowHasStencil = windowhasstencil; - // Must be called before the swapchain is created. - setViewportSize(width, height, pixelwidth, pixelheight); + backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa); cleanUpFunctions.clear(); cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT); @@ -540,64 +632,101 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int readbackCallbacks.clear(); readbackCallbacks.resize(MAX_FRAMES_IN_FLIGHT); - createVulkanInstance(); + bool createBaseObjects = physicalDevice == VK_NULL_HANDLE; + createSurface(); - pickPhysicalDevice(); - createLogicalDevice(); - createPipelineCache(); - initVMA(); - initCapabilities(); + + if (createBaseObjects) + { + pickPhysicalDevice(); + createLogicalDevice(); + createPipelineCache(); + initVMA(); + initCapabilities(); + } + + msaaSamples = getMsaaCount(requestedMsaa); + createSwapChain(); createImageViews(); - createScreenshotCallbackBuffers(); - createSyncObjects(); createColorResources(); createDepthResources(); transitionColorDepthLayouts = true; - createCommandPool(); - createCommandBuffers(); + + if (createBaseObjects) + { + createCommandPool(); + createCommandBuffers(); + createSyncObjects(); + } + + if (localUniformBuffer == nullptr) + localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, 1024 * 512 * 1), Acquire::NORETAIN); beginFrame(); - if (batchedDrawState.vb[0] == nullptr) + if (createBaseObjects) { - // Initial sizes that should be good enough for most cases. It will - // resize to fit if needed, later. - batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); - batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1); - batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); - } + if (batchedDrawState.vb[0] == nullptr) + { + // Initial sizes that should be good enough for most cases. It will + // resize to fit if needed, later. + batchedDrawState.vb[0] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 1024 * 1024 * 1); + batchedDrawState.vb[1] = new StreamBuffer(this, BUFFERUSAGE_VERTEX, 256 * 1024 * 1); + batchedDrawState.indexBuffer = new StreamBuffer(this, BUFFERUSAGE_INDEX, sizeof(uint16) * LOVE_UINT16_MAX); + } - // sometimes the VertexTexCoord is not set, so we manually adjust it to (0, 0) - if (defaultConstantTexCoord == nullptr) - { - float zeroTexCoord[2] = { 0.0f, 0.0f }; - Buffer::DataDeclaration format("ConstantTexCoord", DATAFORMAT_FLOAT_VEC2); - Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); - defaultConstantTexCoord = newBuffer(settings, { format }, zeroTexCoord, sizeof(zeroTexCoord), 1); - } + if (defaultVertexBuffer == nullptr) + { + struct DefaultData + { + float floats[4]; + int ints[4]; + float color[4]; + } data; - // sometimes the VertexColor is not set, so we manually adjust it to white color - if (defaultConstantColor == nullptr) - { - uint8 whiteColor[] = { 255, 255, 255, 255 }; - Buffer::DataDeclaration format("ConstantColor", DATAFORMAT_UNORM8_VEC4); - Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); - defaultConstantColor = newBuffer(settings, { format }, whiteColor, sizeof(whiteColor), 1); - } + data.floats[0] = 0.0f; + data.floats[1] = 0.0f; + data.floats[2] = 0.0f; + data.floats[3] = 1.0f; - createDefaultTexture(); - createDefaultShaders(); - Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; - createQuadIndexBuffer(); - createFanIndexBuffer(); + data.ints[0] = 0; + data.ints[1] = 0; + data.ints[2] = 0; + data.ints[3] = 1; + + data.color[0] = 1.0f; + data.color[1] = 1.0f; + data.color[2] = 1.0f; + data.color[3] = 1.0f; + + std::vector format = { + Buffer::DataDeclaration("Floats", DATAFORMAT_FLOAT_VEC4), + Buffer::DataDeclaration("Ints", DATAFORMAT_INT32_VEC4), + Buffer::DataDeclaration("Color", DATAFORMAT_FLOAT_VEC4) + }; + + Buffer::Settings settings(BUFFERUSAGEFLAG_VERTEX, BUFFERDATAUSAGE_STATIC); + defaultVertexBuffer.set(newBuffer(settings, format, &data, sizeof(DefaultData), 1), Acquire::NORETAIN); + + VkBuffer buffer = (VkBuffer)defaultVertexBuffer->getHandle(); + VkDeviceSize offset = 0; + vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), DEFAULT_VERTEX_BUFFER_BINDING, 1, &buffer, &offset); + } + + createDefaultShaders(); + Shader::current = Shader::standardShaders[Shader::StandardShader::STANDARD_DEFAULT]; + createQuadIndexBuffer(); + createFanIndexBuffer(); + + frameCounter = 0; + currentFrame = 0; + } restoreState(states.back()); Vulkan::resetShaderSwitches(); - frameCounter = 0; - currentFrame = 0; created = true; drawCalls = 0; drawCallsBatched = 0; @@ -610,7 +739,6 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_MULTI_RENDER_TARGET_FORMATS] = true; capabilities.features[FEATURE_CLAMP_ZERO] = true; capabilities.features[FEATURE_CLAMP_ONE] = true; - capabilities.features[FEATURE_BLEND_MINMAX] = true; capabilities.features[FEATURE_LIGHTEN] = true; capabilities.features[FEATURE_FULL_NPOT] = true; capabilities.features[FEATURE_PIXEL_SHADER_HIGHP] = true; @@ -619,14 +747,9 @@ void Graphics::initCapabilities() capabilities.features[FEATURE_GLSL4] = true; capabilities.features[FEATURE_INSTANCING] = true; capabilities.features[FEATURE_TEXEL_BUFFER] = true; - capabilities.features[FEATURE_INDEX_BUFFER_32BIT] = true; - capabilities.features[FEATURE_COPY_BUFFER] = true; - capabilities.features[FEATURE_COPY_BUFFER_TO_TEXTURE] = true; capabilities.features[FEATURE_COPY_TEXTURE_TO_BUFFER] = true; - capabilities.features[FEATURE_COPY_RENDER_TARGET_TO_BUFFER] = true; - capabilities.features[FEATURE_MIPMAP_RANGE] = true; capabilities.features[FEATURE_INDIRECT_DRAW] = true; - static_assert(FEATURE_MAX_ENUM == 19, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); + static_assert(FEATURE_MAX_ENUM == 13, "Graphics::initCapabilities must be updated when adding a new graphics feature!"); VkPhysicalDeviceProperties properties; vkGetPhysicalDeviceProperties(physicalDevice, &properties); @@ -659,14 +782,12 @@ void Graphics::getAPIStats(int &shaderswitches) const void Graphics::unSetMode() { - renderPassUsages.clear(); - framebufferUsages.clear(); - pipelineUsages.clear(); - + submitGpuCommands(SUBMIT_NOPRESENT); + created = false; - vkDeviceWaitIdle(device); - Volatile::unloadAll(); - cleanup(); + + cleanupSwapChain(); + vkDestroySurfaceKHR(instance, surface, nullptr); } void Graphics::setActive(bool enable) @@ -808,7 +929,7 @@ void Graphics::drawQuads(int start, int count, const VertexAttributes &attribute const int MAX_VERTICES_PER_DRAW = LOVE_UINT16_MAX; const int MAX_QUADS_PER_DRAW = MAX_VERTICES_PER_DRAW / 4; - prepareDraw(attributes, buffers, texture, PRIMITIVE_TRIANGLES, CULL_BACK); + prepareDraw(attributes, buffers, texture, PRIMITIVE_TRIANGLES, CULL_NONE); vkCmdBindIndexBuffer( commandBuffers.at(currentFrame), @@ -845,59 +966,42 @@ void Graphics::setColor(Colorf c) states.back().color = c; } -static VkRect2D computeScissor(const Rect &r, double bufferWidth, double bufferHeight, double dpiScale, VkSurfaceTransformFlagBitsKHR preTransform) +void Graphics::applyScissor() { - double x = static_cast(r.x) * dpiScale; - double y = static_cast(r.y) * dpiScale; - double w = static_cast(r.w) * dpiScale; - double h = static_cast(r.h) * dpiScale; + VkRect2D scissor{}; - double scissorX, scissorY, scissorW, scissorH; - - switch (preTransform) + if (renderPassState.isWindow) + scissor.extent = swapChainExtent; + else { - case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR: - scissorX = bufferWidth - h - y; - scissorY = x; - scissorW = h; - scissorH = w; - break; - case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR: - scissorX = bufferWidth - w - x; - scissorY = bufferHeight - h - y; - scissorW = w; - scissorH = h; - break; - case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR: - scissorX = y; - scissorY = bufferHeight - w - x; - scissorW = h; - scissorH = w; - break; - default: - scissorX = x; - scissorY = y; - scissorW = w; - scissorH = h; - break; + scissor.extent.width = renderPassState.width; + scissor.extent.height = renderPassState.height; } - VkRect2D scissor = { - {static_cast(scissorX), static_cast(scissorY)}, - {static_cast(scissorW), static_cast(scissorH)} - }; - return scissor; + if (states.back().scissor) + { + const Rect &rect = states.back().scissorRect; + double dpiScale = getCurrentDPIScale(); + + // TODO: clamp this to the above viewport size. + scissor.offset.x = (int)(rect.x * dpiScale); + scissor.offset.y = (int)(rect.y * dpiScale); + scissor.extent.width = (uint32)(rect.w * dpiScale); + scissor.extent.height = (uint32)(rect.h * dpiScale); + } + + vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor); } void Graphics::setScissor(const Rect &rect) { flushBatchedDraws(); - VkRect2D scissor = computeScissor(rect, static_cast(swapChainExtent.width), static_cast(swapChainExtent.height), getCurrentDPIScale(), preTransform); - vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor); - states.back().scissor = true; states.back().scissorRect = rect; + + if (renderPassState.active) + applyScissor(); } void Graphics::setScissor() @@ -906,49 +1010,35 @@ void Graphics::setScissor() states.back().scissor = false; - VkRect2D scissor{}; - scissor.offset = { 0, 0 }; - scissor.extent = swapChainExtent; - - vkCmdSetScissor(commandBuffers.at(currentFrame), 0, 1, &scissor); + if (renderPassState.active) + applyScissor(); } -void Graphics::setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) +void Graphics::setStencilState(const StencilState &s) { - if (action != STENCIL_KEEP) - { - const auto& rts = states.back().renderTargets; - auto dsTexture = rts.depthStencil.texture.get(); - - if (!isRenderTargetActive() && !windowHasStencil) - throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer"); - else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dsTexture == nullptr || !isPixelFormatStencil(dsTexture->getPixelFormat()))) - throw love::Exception("drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type to be used, in setRenderTarget"); - } + validateStencilState(s); flushBatchedDraws(); - vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, writemask); + vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, s.writeMask); - vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, readmask); - vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, value); + vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, s.readMask); + vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, s.value); if (optionalDeviceExtensions.extendedDynamicState) vkCmdSetStencilOpEXT( commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, - VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(action), - VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(getReversedCompareMode(compare))); + VK_STENCIL_OP_KEEP, Vulkan::getStencilOp(s.action), + VK_STENCIL_OP_KEEP, Vulkan::getCompareOp(getReversedCompareMode(s.compare))); - states.back().stencil.action = action; - states.back().stencil.compare = compare; - states.back().stencil.value = value; - states.back().stencil.readMask = readmask; - states.back().stencil.writeMask = writemask; + states.back().stencil = s; } void Graphics::setDepthMode(CompareMode compare, bool write) { + validateDepthState(write); + flushBatchedDraws(); if (optionalDeviceExtensions.extendedDynamicState) @@ -971,30 +1061,27 @@ void Graphics::setWireframe(bool enable) states.back().wireframe = enable; } -PixelFormat Graphics::getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const +bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage) { + format = getSizedFormat(format); + switch (format) { - case PIXELFORMAT_NORMAL: - if (isGammaCorrect()) - return PIXELFORMAT_RGBA8_UNORM_sRGB; - else - return PIXELFORMAT_RGBA8_UNORM; - case PIXELFORMAT_HDR: - return PIXELFORMAT_RGBA16_FLOAT; + case PIXELFORMAT_PVR1_RGB2_UNORM: + case PIXELFORMAT_PVR1_RGB2_sRGB: + case PIXELFORMAT_PVR1_RGB4_UNORM: + case PIXELFORMAT_PVR1_RGB4_sRGB: + case PIXELFORMAT_PVR1_RGBA2_UNORM: + case PIXELFORMAT_PVR1_RGBA2_sRGB: + case PIXELFORMAT_PVR1_RGBA4_UNORM: + case PIXELFORMAT_PVR1_RGBA4_sRGB: + // Lets not support these in Vulkan - they're deprecated. + return false; default: - return format; + break; } -} -bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) -{ - bool rendertarget = (usage & PIXELFORMATUSAGEFLAGS_RENDERTARGET) != 0; - bool readable = (usage & PIXELFORMATUSAGEFLAGS_SAMPLE) != 0; - - format = getSizedFormat(format, rendertarget, readable); - - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkFormatProperties formatProperties; vkGetPhysicalDeviceFormatProperties(physicalDevice, vulkanFormat.internalFormat, &formatProperties); @@ -1012,7 +1099,7 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRG return false; } - if (usage & PIXELFORMATUSAGE_LINEAR) + if (usage & PIXELFORMATUSAGEFLAGS_LINEAR) { if (!(featureFlags & VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT)) return false; @@ -1081,9 +1168,9 @@ graphics::ShaderStage *Graphics::newShaderStageInternal(ShaderStageType stage, c return new ShaderStage(this, stage, source, gles, cachekey); } -graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) +graphics::Shader *Graphics::newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) { - return new Shader(stages); + return new Shader(stages, options); } graphics::StreamBuffer *Graphics::newStreamBuffer(BufferUsage type, size_t size) @@ -1125,12 +1212,6 @@ bool Graphics::dispatch(love::graphics::Shader *shader, love::graphics::Buffer * return true; } -Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const -{ - uint32 flags = DEVICE_PROJECTION_DEFAULT; - return calculateDeviceProjection(projection, flags); -} - void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) { if (renderPassState.active) @@ -1147,11 +1228,6 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int pixelw, in void Graphics::initDynamicState() { - if (states.back().scissor) - setScissor(states.back().scissorRect); - else - setScissor(); - vkCmdSetStencilWriteMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.writeMask); vkCmdSetStencilCompareMask(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.readMask); vkCmdSetStencilReference(commandBuffers.at(currentFrame), VK_STENCIL_FRONT_AND_BACK, states.back().stencil.value); @@ -1185,21 +1261,28 @@ void Graphics::beginFrame() frameCounter = 0; } - while (true) + if (swapChain != VK_NULL_HANDLE) { - VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - if (result == VK_ERROR_OUT_OF_DATE_KHR) + while (true) { - recreateSwapChain(); - continue; + VkResult result = vkAcquireNextImageKHR(device, swapChain, UINT64_MAX, imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); + if (result == VK_ERROR_OUT_OF_DATE_KHR) + { + recreateSwapChain(); + continue; + } + else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) + throw love::Exception("failed to acquire swap chain image"); + + break; } - else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) - throw love::Exception("failed to acquire swap chain image"); - break; + imageRequested = true; + } + else + { + imageRequested = false; } - - imageRequested = true; for (auto &readbackCallback : readbackCallbacks.at(currentFrame)) readbackCallback(); @@ -1211,24 +1294,31 @@ void Graphics::beginFrame() startRecordingGraphicsCommands(); - Vulkan::cmdTransitionImageLayout( - commandBuffers.at(currentFrame), - swapChainImages[imageIndex], - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); - - if (transitionColorDepthLayouts) + if (!swapChainImages.empty()) { Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), - depthImage, + swapChainImages[imageIndex], + swapChainPixelFormat, VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); + VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } + + if (transitionColorDepthLayouts) + { + if (depthImage) + Vulkan::cmdTransitionImageLayout( + commandBuffers.at(currentFrame), + depthImage, + depthStencilPixelFormat, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL); if (colorImage) Vulkan::cmdTransitionImageLayout( commandBuffers.at(currentFrame), colorImage, + swapChainPixelFormat, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -1237,9 +1327,11 @@ void Graphics::beginFrame() Vulkan::resetShaderSwitches(); - for (const auto shader : usedShadersInFrame) + for (const auto &shader : usedShadersInFrame) shader->newFrame(); usedShadersInFrame.clear(); + + localUniformBuffer->nextFrame(); } void Graphics::startRecordingGraphicsCommands() @@ -1254,7 +1346,28 @@ void Graphics::startRecordingGraphicsCommands() initDynamicState(); + // This must be done after vkBeginCommandBuffer (since newTexture needs an + // active command buffer for layout transitions), and before setDefaultRenderPass + // (since that tries to use fakeBackbuffer). + if (swapChainImages.empty() && fakeBackbuffer == nullptr) + { + Texture::Settings settings; + settings.format = swapChainPixelFormat; + settings.width = swapChainExtent.width; + settings.height = swapChainExtent.height; + settings.renderTarget = true; + settings.readable.set(false); + fakeBackbuffer.set((Texture*)newTexture(settings, nullptr), Acquire::NORETAIN); + } + setDefaultRenderPass(); + + if (defaultVertexBuffer) + { + VkBuffer buffer = (VkBuffer)defaultVertexBuffer->getHandle(); + VkDeviceSize offset = 0; + vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), DEFAULT_VERTEX_BUFFER_BINDING, 1, &buffer, &offset); + } } void Graphics::endRecordingGraphicsCommands() { @@ -1265,11 +1378,6 @@ void Graphics::endRecordingGraphicsCommands() { throw love::Exception("failed to record command buffer"); } -const VkDeviceSize Graphics::getMinUniformBufferOffsetAlignment() const -{ - return minUniformBufferOffsetAlignment; -} - VkCommandBuffer Graphics::getCommandBufferForDataTransfer() { if (renderPassState.active) @@ -1293,30 +1401,27 @@ graphics::Shader::BuiltinUniformData Graphics::getCurrentBuiltinUniformData() love::graphics::Shader::BuiltinUniformData data; data.transformMatrix = getTransform(); - data.projectionMatrix = displayRotation * getDeviceProjection(); + data.projectionMatrix = getDeviceProjection(); - // The normal matrix is the transpose of the inverse of the rotation portion - // (top-left 3x3) of the transform matrix. + data.scaleParams.x = (float) getCurrentDPIScale(); + data.scaleParams.y = getPointSize(); + + // Flip y to convert input y-up [-1, 1] to vulkan's y-down [-1, 1]. + // Convert input z [-1, 1] to vulkan [0, 1]. + uint32 flags = Shader::CLIP_TRANSFORM_FLIP_Y | Shader::CLIP_TRANSFORM_Z_NEG1_1_TO_0_1; + data.clipSpaceParams = Shader::computeClipSpaceParams(flags); + + const auto &rt = states.back().renderTargets.getFirstTarget(); + if (rt.texture != nullptr) { - Matrix3 normalmatrix = Matrix3(data.transformMatrix).transposedInverse(); - const float *e = normalmatrix.getElements(); - for (int i = 0; i < 3; i++) - { - data.normalMatrix[i].x = e[i * 3 + 0]; - data.normalMatrix[i].y = e[i * 3 + 1]; - data.normalMatrix[i].z = e[i * 3 + 2]; - data.normalMatrix[i].w = 0.0f; - } + data.screenSizeParams.x = rt.texture->getPixelWidth(rt.mipmap); + data.screenSizeParams.y = rt.texture->getPixelHeight(rt.mipmap); + } + else + { + data.screenSizeParams.x = getPixelWidth(); + data.screenSizeParams.y = getPixelHeight(); } - - // Store DPI scale in an unused component of another vector. - data.normalMatrix[0].w = (float)getCurrentDPIScale(); - - // Same with point size. - data.normalMatrix[1].w = getPointSize(); - - data.screenSizeParams.x = static_cast(swapChainExtent.width); - data.screenSizeParams.y = static_cast(swapChainExtent.height); data.screenSizeParams.z = 1.0f; data.screenSizeParams.w = 0.0f; @@ -1332,73 +1437,9 @@ const OptionalDeviceExtensions &Graphics::getEnabledOptionalDeviceExtensions() c return optionalDeviceExtensions; } -static void checkOptionalInstanceExtensions(OptionalInstanceExtensions &ext) +const OptionalInstanceExtensions &Graphics::getEnabledOptionalInstanceExtensions() const { - uint32_t count; - - vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr); - - std::vector extensions(count); - - vkEnumerateInstanceExtensionProperties(nullptr, &count, extensions.data()); - - for (const auto &extension : extensions) - { - if (strcmp(extension.extensionName, VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME) == 0) - ext.physicalDeviceProperties2 = true; - } -} - -void Graphics::createVulkanInstance() -{ - if (isDebugEnabled() && !checkValidationSupport()) - throw love::Exception("validation layers requested, but not available"); - - VkApplicationInfo appInfo{}; - appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; - appInfo.pApplicationName = "LOVE"; - appInfo.applicationVersion = VK_MAKE_API_VERSION(0, 1, 0, 0); // get this version from somewhere else? - appInfo.pEngineName = "LOVE Game Framework"; - appInfo.engineVersion = VK_MAKE_API_VERSION(0, VERSION_MAJOR, VERSION_MINOR, VERSION_REV); - appInfo.apiVersion = VK_API_VERSION_1_3; - - VkInstanceCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.pApplicationInfo = &appInfo; - createInfo.pNext = nullptr; - - // GetInstanceExtensions works with a null window parameter as long as - // SDL_Vulkan_LoadLibrary has been called (which we do earlier). - unsigned int count; - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, nullptr) != SDL_TRUE) - throw love::Exception("couldn't retrieve sdl vulkan extensions"); - - std::vector extensions = {}; - - checkOptionalInstanceExtensions(optionalInstanceExtensions); - - if (optionalInstanceExtensions.physicalDeviceProperties2) - extensions.push_back(VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME); - - size_t additional_extension_count = extensions.size(); - extensions.resize(additional_extension_count + count); - - if (SDL_Vulkan_GetInstanceExtensions(nullptr, &count, extensions.data() + additional_extension_count) != SDL_TRUE) - throw love::Exception("couldn't retrieve sdl vulkan extensions"); - - createInfo.enabledExtensionCount = static_cast(extensions.size()); - createInfo.ppEnabledExtensionNames = extensions.data(); - - if (isDebugEnabled()) - { - createInfo.enabledLayerCount = static_cast(validationLayers.size()); - createInfo.ppEnabledLayerNames = validationLayers.data(); - } - - if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) - throw love::Exception("couldn't create vulkan instance"); - - volkLoadInstance(instance); + return optionalInstanceExtensions; } bool Graphics::checkValidationSupport() @@ -1458,8 +1499,19 @@ void Graphics::pickPhysicalDevice() minUniformBufferOffsetAlignment = properties.limits.minUniformBufferOffsetAlignment; deviceApiVersion = properties.apiVersion; - msaaSamples = getMsaaCount(requestedMsaa); depthStencilFormat = findDepthFormat(); + switch (depthStencilFormat) + { + case VK_FORMAT_D32_SFLOAT_S8_UINT: + depthStencilPixelFormat = PIXELFORMAT_DEPTH32_FLOAT_STENCIL8; + break; + case VK_FORMAT_D24_UNORM_S8_UINT: + depthStencilPixelFormat = PIXELFORMAT_DEPTH24_UNORM_STENCIL8; + break; + default: + throw love::Exception("Failed to convert vulkan depth/stencil swapchain pixel format %d to love PixelFormat.", depthStencilFormat); + break; + } } bool Graphics::checkDeviceExtensionSupport(VkPhysicalDevice device) @@ -1573,7 +1625,7 @@ static void findOptionalDeviceExtensions(VkPhysicalDevice physicalDevice, Option optionalDeviceExtensions.memoryRequirements2 = true; if (strcmp(extension.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME) == 0) optionalDeviceExtensions.dedicatedAllocation = true; - if (strcmp(extension.extensionName, VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME) == 0) + if (strcmp(extension.extensionName, VK_EXT_MEMORY_BUDGET_EXTENSION_NAME) == 0) optionalDeviceExtensions.memoryBudget = true; if (strcmp(extension.extensionName, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME) == 0) optionalDeviceExtensions.shaderFloatControls = true; @@ -1733,8 +1785,13 @@ void Graphics::createSurface() { auto window = Module::getInstance(M_WINDOW); const void *handle = window->getHandle(); +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, nullptr, &surface) != SDL_TRUE) + throw love::Exception("failed to create window surface"); +#else if (SDL_Vulkan_CreateSurface((SDL_Window*)handle, instance, &surface) != SDL_TRUE) throw love::Exception("failed to create window surface"); +#endif } SwapChainSupportDetails Graphics::querySwapChainSupport(VkPhysicalDevice device) @@ -1772,83 +1829,88 @@ void Graphics::createSwapChain() VkPresentModeKHR presentMode = chooseSwapPresentMode(swapChainSupport.presentModes); VkExtent2D extent = chooseSwapExtent(swapChainSupport.capabilities); - if ((swapChainSupport.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) || - (swapChainSupport.capabilities.currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR)) + if (extent.width > 0 && extent.height > 0) { - uint32_t width, height; - width = extent.width; - height = extent.height; - extent.width = height; - extent.height = width; - } + uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1; + if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) + imageCount = swapChainSupport.capabilities.maxImageCount; - auto currentTransform = swapChainSupport.capabilities.currentTransform; - constexpr float PI = 3.14159265358979323846f; - float angle = 0.0f; - if (currentTransform & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) - angle = 0.0f; - else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR) - angle = -PI / 2.0f; - else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR) - angle = -PI; - else if (currentTransform & VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR) - angle = -3.0f * PI / 2.0f; + VkSwapchainCreateInfoKHR createInfo{}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; - float data[] = { - cosf(angle), -sinf(angle), 0.0f, 0.0f, - sinf(angle), cosf(angle), 0.0f, 0.0f, - 0.0f, 0.0f, 1.0f, 0.0f, - 0.0f, 0.0f, 0.0f, 1.0f, - }; - displayRotation = Matrix4(data); + createInfo.minImageCount = imageCount; + createInfo.imageFormat = surfaceFormat.format; + createInfo.imageColorSpace = surfaceFormat.colorSpace; + createInfo.imageExtent = extent; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - uint32_t imageCount = swapChainSupport.capabilities.minImageCount + 1; - if (swapChainSupport.capabilities.maxImageCount > 0 && imageCount > swapChainSupport.capabilities.maxImageCount) - imageCount = swapChainSupport.capabilities.maxImageCount; + QueueFamilyIndices indices = findQueueFamilies(physicalDevice); + uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value, indices.presentFamily.value }; - VkSwapchainCreateInfoKHR createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = surface; + if (indices.graphicsFamily.value != indices.presentFamily.value) + { + createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; + createInfo.queueFamilyIndexCount = 2; + createInfo.pQueueFamilyIndices = queueFamilyIndices; + } + else + { + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.queueFamilyIndexCount = 0; + createInfo.pQueueFamilyIndices = nullptr; + } - createInfo.minImageCount = imageCount; - createInfo.imageFormat = surfaceFormat.format; - createInfo.imageColorSpace = surfaceFormat.colorSpace; - createInfo.imageExtent = extent; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + createInfo.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR; + createInfo.compositeAlpha = chooseCompositeAlpha(swapChainSupport.capabilities); + createInfo.presentMode = presentMode; + createInfo.clipped = VK_TRUE; + createInfo.oldSwapchain = VK_NULL_HANDLE; - QueueFamilyIndices indices = findQueueFamilies(physicalDevice); - uint32_t queueFamilyIndices[] = { indices.graphicsFamily.value, indices.presentFamily.value }; + if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) + throw love::Exception("failed to create swap chain"); - if (indices.graphicsFamily.value != indices.presentFamily.value) - { - createInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - createInfo.queueFamilyIndexCount = 2; - createInfo.pQueueFamilyIndices = queueFamilyIndices; + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); + swapChainImages.resize(imageCount); + vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); } else { - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.queueFamilyIndexCount = 0; - createInfo.pQueueFamilyIndices = nullptr; + // Use a fake backbuffer. Creation is deferred until startRecordingGraphicsCommands + // because newTexture needs an active command buffer to do its initial + // layout transitions. + swapChainImages.clear(); + extent.width = std::max(1, pixelWidth); + extent.height = std::max(1, pixelHeight); + + if (isGammaCorrect()) + surfaceFormat.format = VK_FORMAT_R8G8B8A8_SRGB; + else + surfaceFormat.format = VK_FORMAT_R8G8B8A8_UNORM; } - createInfo.preTransform = swapChainSupport.capabilities.currentTransform; - createInfo.compositeAlpha = chooseCompositeAlpha(swapChainSupport.capabilities); - createInfo.presentMode = presentMode; - createInfo.clipped = VK_TRUE; - createInfo.oldSwapchain = VK_NULL_HANDLE; - - if (vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapChain) != VK_SUCCESS) - throw love::Exception("failed to create swap chain"); - - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, nullptr); - swapChainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapChain, &imageCount, swapChainImages.data()); - swapChainImageFormat = surfaceFormat.format; swapChainExtent = extent; - preTransform = swapChainSupport.capabilities.currentTransform; + + switch (swapChainImageFormat) + { + case VK_FORMAT_B8G8R8A8_SRGB: + swapChainPixelFormat = PIXELFORMAT_BGRA8_sRGB; + break; + case VK_FORMAT_B8G8R8A8_UNORM: + swapChainPixelFormat = PIXELFORMAT_BGRA8_UNORM; + break; + case VK_FORMAT_R8G8B8A8_SRGB: + swapChainPixelFormat = PIXELFORMAT_RGBA8_sRGB; + break; + case VK_FORMAT_R8G8B8A8_UNORM: + swapChainPixelFormat = PIXELFORMAT_RGBA8_UNORM; + break; + default: + throw love::Exception("Failed to convert vulkan depth/stencil swapchain image format %d to love PixelFormat.", swapChainImageFormat); + break; + } } VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector &availableFormats) @@ -1860,15 +1922,15 @@ VkSurfaceFormatKHR Graphics::chooseSwapSurfaceFormat(const std::vector attachments; @@ -2226,100 +2229,83 @@ VkRenderPass Graphics::getRenderPass(RenderPassConfiguration &configuration) } void Graphics::createVulkanVertexFormat( - VertexAttributes vertexAttributes, + Shader *shader, + const VertexAttributes &attributes, std::vector &bindingDescriptions, std::vector &attributeDescriptions) { std::set usedBuffers; - auto enableBits = vertexAttributes.enableBits; - auto allBits = enableBits; - - bool usesColor = false; - bool usesTexCoord = false; - - uint8_t highestBufferBinding = 0; - - uint32_t i = 0; - while (allBits) + for (const auto &pair : shader->getVertexAttributeIndices()) { + int i = pair.second.index; uint32 bit = 1u << i; - if (enableBits & bit) + + VkVertexInputAttributeDescription attribdesc{}; + attribdesc.location = i; + + if (attributes.enableBits & bit) { - if (i == ATTRIB_TEXCOORD) - usesTexCoord = true; - if (i == ATTRIB_COLOR) - usesColor = true; + const auto &attrib = attributes.attribs[i]; - auto attrib = vertexAttributes.attribs[i]; - auto bufferBinding = attrib.bufferIndex; - if (usedBuffers.find(bufferBinding) == usedBuffers.end()) + int bufferbinding = VERTEX_BUFFER_BINDING_START + attrib.bufferIndex; + + attribdesc.binding = bufferbinding; + attribdesc.offset = attrib.offsetFromVertex; + attribdesc.format = Vulkan::getVulkanVertexFormat(attrib.getFormat()); + + if (usedBuffers.find(bufferbinding) == usedBuffers.end()) { - usedBuffers.insert(bufferBinding); + usedBuffers.insert(bufferbinding); - VkVertexInputBindingDescription bindingDescription{}; - bindingDescription.binding = bufferBinding; - if (vertexAttributes.instanceBits & (1u << bufferBinding)) - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; + VkVertexInputBindingDescription bindingdesc{}; + bindingdesc.binding = bufferbinding; + if (attributes.instanceBits & (1u << attrib.bufferIndex)) + bindingdesc.inputRate = VK_VERTEX_INPUT_RATE_INSTANCE; else - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - bindingDescription.stride = vertexAttributes.bufferLayouts[bufferBinding].stride; - bindingDescriptions.push_back(bindingDescription); + bindingdesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + bindingdesc.stride = attributes.bufferLayouts[attrib.bufferIndex].stride; + bindingDescriptions.push_back(bindingdesc); + } + } + else + { + attribdesc.binding = DEFAULT_VERTEX_BUFFER_BINDING; - highestBufferBinding = std::max(highestBufferBinding, bufferBinding); + // Indices should match the creation parameters for defaultVertexBuffer. + switch (pair.second.baseType) + { + case DATA_BASETYPE_INT: + attribdesc.offset = defaultVertexBuffer->getDataMember(1).offset; + attribdesc.format = Vulkan::getVulkanVertexFormat(DATAFORMAT_INT32_VEC4); + break; + case DATA_BASETYPE_UINT: + attribdesc.offset = defaultVertexBuffer->getDataMember(1).offset; + attribdesc.format = Vulkan::getVulkanVertexFormat(DATAFORMAT_UINT32_VEC4); + break; + case DATA_BASETYPE_FLOAT: + default: + if (i == ATTRIB_COLOR) + attribdesc.offset = defaultVertexBuffer->getDataMember(2).offset; + else + attribdesc.offset = defaultVertexBuffer->getDataMember(0).offset; + attribdesc.format = Vulkan::getVulkanVertexFormat(DATAFORMAT_FLOAT_VEC4); + break; } - VkVertexInputAttributeDescription attributeDescription{}; - attributeDescription.location = i; - attributeDescription.binding = bufferBinding; - attributeDescription.offset = attrib.offsetFromVertex; - attributeDescription.format = Vulkan::getVulkanVertexFormat(attrib.format); + if (usedBuffers.find(DEFAULT_VERTEX_BUFFER_BINDING) == usedBuffers.end()) + { + usedBuffers.insert(DEFAULT_VERTEX_BUFFER_BINDING); - attributeDescriptions.push_back(attributeDescription); + VkVertexInputBindingDescription bindingdesc{}; + bindingdesc.binding = DEFAULT_VERTEX_BUFFER_BINDING; + bindingdesc.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + bindingdesc.stride = 0; // no stride, will always read the same coord multiple times. + bindingDescriptions.push_back(bindingdesc); + } } - i++; - allBits >>= 1; - } - - if (!usesTexCoord) - { - // FIXME: is there a case where gaps happen between buffer bindings? - // then this doesn't work. We might need to enable null buffers again. - const auto constantTexCoordBufferBinding = ++highestBufferBinding; - - VkVertexInputBindingDescription bindingDescription{}; - bindingDescription.binding = constantTexCoordBufferBinding; - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - bindingDescription.stride = 0; // no stride, will always read the same coord multiple times. - bindingDescriptions.push_back(bindingDescription); - - VkVertexInputAttributeDescription attributeDescription{}; - attributeDescription.binding = constantTexCoordBufferBinding; - attributeDescription.location = ATTRIB_TEXCOORD; - attributeDescription.offset = 0; - attributeDescription.format = VK_FORMAT_R32G32_SFLOAT; - attributeDescriptions.push_back(attributeDescription); - } - - if (!usesColor) - { - // FIXME: is there a case where gaps happen between buffer bindings? - // then this doesn't work. We might need to enable null buffers again. - const auto constantColorBufferBinding = ++highestBufferBinding; - - VkVertexInputBindingDescription bindingDescription{}; - bindingDescription.binding = constantColorBufferBinding; - bindingDescription.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; - bindingDescription.stride = 0; // no stride, will always read the same color multiple times. - bindingDescriptions.push_back(bindingDescription); - - VkVertexInputAttributeDescription attributeDescription{}; - attributeDescription.binding = constantColorBufferBinding; - attributeDescription.location = ATTRIB_COLOR; - attributeDescription.offset = 0; - attributeDescription.format = VK_FORMAT_R32G32B32A32_SFLOAT; - attributeDescriptions.push_back(attributeDescription); + attributeDescriptions.push_back(attribdesc); } } @@ -2354,39 +2340,36 @@ void Graphics::prepareDraw(const VertexAttributes &attributes, const BufferBindi configuration.dynamicState.cullmode = cullmode; } - std::vector bufferVector; - std::vector offsets; - - for (uint32_t i = 0; i < VertexAttributes::MAX; i++) - { - if (buffers.useBits & (1u << i)) - { - bufferVector.push_back((VkBuffer)buffers.info[i].buffer->getHandle()); - offsets.push_back((VkDeviceSize)buffers.info[i].offset); - } - } - - if (!(attributes.enableBits & (1u << ATTRIB_TEXCOORD))) - { - bufferVector.push_back((VkBuffer)defaultConstantTexCoord->getHandle()); - offsets.push_back((VkDeviceSize)0); - } - - if (!(attributes.enableBits & (1u << ATTRIB_COLOR))) - { - bufferVector.push_back((VkBuffer)defaultConstantColor->getHandle()); - offsets.push_back((VkDeviceSize)0); - } - - if (texture == nullptr) - configuration.shader->setMainTex(defaultTexture); - else - configuration.shader->setMainTex(texture); + configuration.shader->setMainTex(texture); ensureGraphicsPipelineConfiguration(configuration); configuration.shader->cmdPushDescriptorSets(commandBuffers.at(currentFrame), VK_PIPELINE_BIND_POINT_GRAPHICS); - vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), 0, static_cast(bufferVector.size()), bufferVector.data(), offsets.data()); + + VkBuffer vkbuffers[BufferBindings::MAX]; + VkDeviceSize vkoffsets[BufferBindings::MAX]; + uint32 buffercount = 0; + + uint32 allbits = buffers.useBits; + uint32 i = 0; + while (allbits) + { + uint32 bit = 1u << i; + + // TODO: handle split ranges. + if (buffers.useBits & bit) + { + vkbuffers[buffercount] = (VkBuffer)buffers.info[i].buffer->getHandle(); + vkoffsets[buffercount] = (VkDeviceSize)buffers.info[i].offset; + buffercount++; + } + + i++; + allbits >>= 1; + } + + if (buffercount > 0) + vkCmdBindVertexBuffers(commandBuffers.at(currentFrame), VERTEX_BUFFER_BINDING_START, buffercount, vkbuffers, vkoffsets); } void Graphics::setDefaultRenderPass() @@ -2425,13 +2408,19 @@ void Graphics::setDefaultRenderPass() if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) { - framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); + if (!swapChainImageViews.empty()) + framebufferConfiguration.colorViews.push_back(swapChainImageViews.at(imageIndex)); + else + framebufferConfiguration.colorViews.push_back(fakeBackbuffer->getRenderTargetView(0, 0)); framebufferConfiguration.staticData.resolveView = VK_NULL_HANDLE; } else { framebufferConfiguration.colorViews.push_back(colorImageView); - framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); + if (!swapChainImageViews.empty()) + framebufferConfiguration.staticData.resolveView = swapChainImageViews.at(imageIndex); + else + framebufferConfiguration.staticData.resolveView = fakeBackbuffer->getRenderTargetView(0, 0); } renderPassState.renderPassConfiguration = std::move(renderPassConfiguration); @@ -2447,27 +2436,44 @@ void Graphics::setRenderPass(const RenderTargets &rts, int pixelw, int pixelh, b RenderPassConfiguration renderPassConfiguration{}; for (const auto &color : rts.colors) renderPassConfiguration.colorAttachments.push_back({ - Vulkan::getTextureFormat(color.texture->getPixelFormat(), isPixelFormatSRGB(color.texture->getPixelFormat())).internalFormat, + Vulkan::getTextureFormat(color.texture->getPixelFormat()).internalFormat, VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(color.texture)->getMsaaSamples() }); if (rts.depthStencil.texture != nullptr) renderPassConfiguration.staticData.depthStencilAttachment = { - Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat(), false).internalFormat, + Vulkan::getTextureFormat(rts.depthStencil.texture->getPixelFormat()).internalFormat, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_LOAD_OP_LOAD, dynamic_cast(rts.depthStencil.texture)->getMsaaSamples() }; FramebufferConfiguration configuration{}; - std::vector transitionImages; + std::vector> transitionImages; for (const auto &color : rts.colors) { - configuration.colorViews.push_back(dynamic_cast(color.texture)->getRenderTargetView(color.mipmap, color.slice)); - transitionImages.push_back((VkImage) color.texture->getHandle()); + auto tex = (Texture*)color.texture; + configuration.colorViews.push_back(tex->getRenderTargetView(color.mipmap, color.slice)); + const Texture::ViewInfo &viewinfo = tex->getRootViewInfo(); + VkImageLayout imagelayout = tex->getImageLayout(); + if (imagelayout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL) + { + transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, + viewinfo.startMipmap + color.mipmap, viewinfo.startLayer + color.slice }); + } } if (rts.depthStencil.texture != nullptr) - configuration.staticData.depthView = dynamic_cast(rts.depthStencil.texture)->getRenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice); + { + auto tex = (Texture*)rts.depthStencil.texture; + configuration.staticData.depthView = tex->getRenderTargetView(rts.depthStencil.mipmap, rts.depthStencil.slice); + const Texture::ViewInfo &viewinfo = tex->getRootViewInfo(); + VkImageLayout imagelayout = tex->getImageLayout(); + if (imagelayout != VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) + { + transitionImages.push_back({ (VkImage)tex->getHandle(), tex->getPixelFormat(), imagelayout, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, + viewinfo.startMipmap + rts.depthStencil.mipmap, viewinfo.startLayer + rts.depthStencil.slice }); + } + } configuration.staticData.width = static_cast(pixelw); configuration.staticData.height = static_cast(pixelh); @@ -2517,10 +2523,12 @@ void Graphics::startRenderPass() renderPassState.framebufferConfiguration.staticData.renderPass = renderPassState.beginInfo.renderPass; renderPassState.beginInfo.framebuffer = getFramebuffer(renderPassState.framebufferConfiguration); - for (const auto &image : renderPassState.transitionImages) - Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) + Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, imageLayout, renderLayout, rootmip, 1, rootlayer, 1); vkCmdBeginRenderPass(commandBuffers.at(currentFrame), &renderPassState.beginInfo, VK_SUBPASS_CONTENTS_INLINE); + + applyScissor(); } void Graphics::endRenderPass() @@ -2529,8 +2537,8 @@ void Graphics::endRenderPass() vkCmdEndRenderPass(commandBuffers.at(currentFrame)); - for (const auto &image : renderPassState.transitionImages) - Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + for (const auto &[image, format, imageLayout, renderLayout, rootmip, rootlayer] : renderPassState.transitionImages) + Vulkan::cmdTransitionImageLayout(commandBuffers.at(currentFrame), image, format, renderLayout, imageLayout, rootmip, 1, rootlayer, 1); for (auto &colorAttachment : renderPassState.renderPassConfiguration.colorAttachments) colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; @@ -2651,7 +2659,7 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi std::vector bindingDescriptions; std::vector attributeDescriptions; - createVulkanVertexFormat(configuration.vertexAttributes, bindingDescriptions, attributeDescriptions); + createVulkanVertexFormat(configuration.shader, configuration.vertexAttributes, bindingDescriptions, attributeDescriptions); VkPipelineVertexInputStateCreateInfo vertexInputInfo{}; vertexInputInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -2795,7 +2803,8 @@ VkPipeline Graphics::createGraphicsPipeline(GraphicsPipelineConfiguration &confi return graphicsPipeline; } -void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration) { +void Graphics::ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration) +{ auto it = graphicsPipelines.find(configuration); if (it != graphicsPipelines.end()) { @@ -2859,6 +2868,23 @@ int Graphics::getVsync() const return vsync; } +void Graphics::mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo) +{ + size_t alignedSize = alignUp(size, minUniformBufferOffsetAlignment); + + if (localUniformBuffer->getUsableSize() < alignedSize) + localUniformBuffer.set(new StreamBuffer(this, BUFFERUSAGE_UNIFORM, localUniformBuffer->getSize() * 2), Acquire::NORETAIN); + + auto mapInfo = localUniformBuffer->map(size); + memcpy(mapInfo.data, data, size); + + bufferInfo.buffer = (VkBuffer)localUniformBuffer->getHandle(); + bufferInfo.offset = localUniformBuffer->unmap(size); + bufferInfo.range = size; + + localUniformBuffer->markUsed(alignedSize); +} + void Graphics::createColorResources() { if (msaaSamples & VK_SAMPLE_COUNT_1_BIT) @@ -2938,6 +2964,13 @@ VkFormat Graphics::findDepthFormat() void Graphics::createDepthResources() { + if (!backbufferHasDepth && !backbufferHasStencil) + { + depthImage = VK_NULL_HANDLE; + depthImageView = VK_NULL_HANDLE; + return; + } + VkImageCreateInfo imageInfo{}; imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; imageInfo.imageType = VK_IMAGE_TYPE_2D; @@ -2969,8 +3002,9 @@ void Graphics::createDepthResources() imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - if (windowHasStencil) + if (backbufferHasDepth) + imageViewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (backbufferHasStencil) imageViewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; imageViewInfo.subresourceRange.baseMipLevel = 0; imageViewInfo.subresourceRange.levelCount = 1; @@ -3029,19 +3063,8 @@ void Graphics::createSyncObjects() throw love::Exception("failed to create synchronization objects for a frame!"); } -void Graphics::createDefaultTexture() -{ - Texture::Settings settings; - defaultTexture.set(newTexture(settings, nullptr), Acquire::NORETAIN); - - uint8_t whitePixels[] = {255, 255, 255, 255}; - defaultTexture->replacePixels(whitePixels, sizeof(whitePixels), 0, 0, { 0, 0, 1, 1 }, false); -} - void Graphics::cleanup() { - cleanupSwapChain(); - for (auto &cleanUpFns : cleanUpFunctions) for (auto &cleanUpFn : cleanUpFns) cleanUpFn(); @@ -3076,25 +3099,26 @@ void Graphics::cleanup() vkDestroyCommandPool(device, commandPool, nullptr); vkDestroyPipelineCache(device, pipelineCache, nullptr); vkDestroyDevice(device, nullptr); - vkDestroySurfaceKHR(instance, surface, nullptr); - vkDestroyInstance(instance, nullptr); } void Graphics::cleanupSwapChain() { - for (const auto &readbackBuffer : screenshotReadbackBuffers) + if (colorImage) { - vmaDestroyBuffer(vmaAllocator, readbackBuffer.buffer, readbackBuffer.allocation); - vmaDestroyImage(vmaAllocator, readbackBuffer.image, readbackBuffer.imageAllocation); + vkDestroyImageView(device, colorImageView, nullptr); + vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); + } + if (depthImage) + { + vkDestroyImageView(device, depthImageView, nullptr); + vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation); } - vkDestroyImageView(device, colorImageView, nullptr); - vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation); - vkDestroyImageView(device, depthImageView, nullptr); - vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation); for (const auto &swapChainImageView : swapChainImageViews) vkDestroyImageView(device, swapChainImageView, nullptr); swapChainImageViews.clear(); vkDestroySwapchainKHR(device, swapChain, nullptr); + swapChainImages.clear(); + fakeBackbuffer.set(nullptr); swapChain = VK_NULL_HANDLE; } @@ -3107,7 +3131,6 @@ void Graphics::recreateSwapChain() createSwapChain(); createImageViews(); - createScreenshotCallbackBuffers(); createColorResources(); createDepthResources(); diff --git a/src/modules/graphics/vulkan/Graphics.h b/src/modules/graphics/vulkan/Graphics.h index 04161b9e8..1fb624d9c 100644 --- a/src/modules/graphics/vulkan/Graphics.h +++ b/src/modules/graphics/vulkan/Graphics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -37,7 +37,7 @@ #include #include #include - +#include namespace love { @@ -144,6 +144,9 @@ struct OptionalInstanceExtensions { // VK_KHR_get_physical_device_properties2 bool physicalDeviceProperties2 = false; + + // VK_EXT_debug_info + bool debugInfo = false; }; struct OptionalDeviceExtensions @@ -233,7 +236,7 @@ struct RenderpassState RenderPassConfiguration renderPassConfiguration{}; FramebufferConfiguration framebufferConfiguration{}; VkPipeline pipeline = VK_NULL_HANDLE; - std::vector transitionImages; + std::vector> transitionImages; uint32_t numColorAttachments = 0; float width = 0.0f; float height = 0.0f; @@ -246,14 +249,12 @@ struct RenderpassState OptionalInt mainWindowClearStencilValue; }; -struct ScreenshotReadbackBuffer +enum SubmitMode { - VkBuffer buffer; - VmaAllocation allocation; - VmaAllocationInfo allocationInfo; - - VkImage image; - VmaAllocation imageAllocation; + SUBMIT_PRESENT, + SUBMIT_NOPRESENT, + SUBMIT_RESTART, + SUBMIT_MAXENUM, }; class Graphics final : public love::graphics::Graphics @@ -263,18 +264,17 @@ public: ~Graphics(); // implementation for virtual functions - const char *getName() const override; love::graphics::Texture *newTexture(const love::graphics::Texture::Settings &settings, const love::graphics::Texture::Slices *data) override; + love::graphics::Texture *newTextureView(love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) override; love::graphics::Buffer *newBuffer(const love::graphics::Buffer::Settings &settings, const std::vector& format, const void *data, size_t size, size_t arraylength) override; graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Buffer *buffer, size_t offset, size_t size, data::ByteData *dest, size_t destoffset) override; graphics::GraphicsReadback *newReadbackInternal(ReadbackMethod method, love::graphics::Texture *texture, int slice, int mipmap, const Rect &rect, image::ImageData *dest, int destx, int desty) override; void clear(OptionalColorD color, OptionalInt stencil, OptionalDouble depth) override; void clear(const std::vector &colors, OptionalInt stencil, OptionalDouble depth) override; - Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override; void discard(const std::vector& colorbuffers, bool depthstencil) override; void present(void *screenshotCallbackdata) override; - void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override; - bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override; + void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; + bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override; void unSetMode() override; void setActive(bool active) override; int getRequestedBackbufferMSAA() const override; @@ -282,15 +282,14 @@ public: void setColor(Colorf c) override; void setScissor(const Rect &rect) override; void setScissor() override; - void setStencilMode(StencilAction action, CompareMode compare, int value, love::uint32 readmask, love::uint32 writemask) override; + void setStencilState(const StencilState &s) override; void setDepthMode(CompareMode compare, bool write) override; void setFrontFaceWinding(Winding winding) override; void setColorMask(ColorChannelMask mask) override; void setBlendState(const BlendState &blend) override; void setPointSize(float size) override; void setWireframe(bool enable) override; - PixelFormat getSizedFormat(PixelFormat format, bool rendertarget, bool readable) const override; - bool isPixelFormatSupported(PixelFormat format, uint32 usage, bool sRGB) override; + bool isPixelFormatSupported(PixelFormat format, uint32 usage) override; Renderer getRenderer() const override; bool usesGLSLES() const override; RendererInfo getRendererInfo() const override; @@ -300,24 +299,27 @@ public: // internal functions. - const VkDevice getDevice() const; - const VmaAllocator getVmaAllocator() const; + VkDevice getDevice() const; + VmaAllocator getVmaAllocator() const; VkCommandBuffer getCommandBufferForDataTransfer(); void queueCleanUp(std::function cleanUp); void addReadbackCallback(std::function callback); - void submitGpuCommands(bool present, void *screenshotCallbackData = nullptr); - const VkDeviceSize getMinUniformBufferOffsetAlignment() const; + void submitGpuCommands(SubmitMode, void *screenshotCallbackData = nullptr); VkSampler getCachedSampler(const SamplerState &sampler); void setComputeShader(Shader *computeShader); graphics::Shader::BuiltinUniformData getCurrentBuiltinUniformData(); const OptionalDeviceExtensions &getEnabledOptionalDeviceExtensions() const; + const OptionalInstanceExtensions &getEnabledOptionalInstanceExtensions() const; VkSampleCountFlagBits getMsaaCount(int requestedMsaa) const; void setVsync(int vsync); int getVsync() const; + void mapLocalUniformData(void *data, size_t size, VkDescriptorBufferInfo &bufferInfo); + + uint32 getDeviceApiVersion() const { return deviceApiVersion; } protected: graphics::ShaderStage *newShaderStageInternal(ShaderStageType stage, const std::string &cachekey, const std::string &source, bool gles) override; - graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM]) override; + graphics::Shader *newShaderInternal(StrongRef stages[SHADERSTAGE_MAX_ENUM], const Shader::CompileOptions &options) override; graphics::StreamBuffer *newStreamBuffer(BufferUsage type, size_t size) override; bool dispatch(love::graphics::Shader *shader, int x, int y, int z) override; bool dispatch(love::graphics::Shader *shader, love::graphics::Buffer *indirectargs, size_t argsoffset) override; @@ -326,7 +328,6 @@ protected: void setRenderTargetsInternal(const RenderTargets &rts, int pixelw, int pixelh, bool hasSRGBtexture) override; private: - void createVulkanInstance(); bool checkValidationSupport(); void pickPhysicalDevice(); int rateDeviceSuitability(VkPhysicalDevice device); @@ -343,7 +344,6 @@ private: VkCompositeAlphaFlagBitsKHR chooseCompositeAlpha(const VkSurfaceCapabilitiesKHR &capabilities); void createSwapChain(); void createImageViews(); - void createScreenshotCallbackBuffers(); VkFramebuffer createFramebuffer(FramebufferConfiguration &configuration); VkFramebuffer getFramebuffer(FramebufferConfiguration &configuration); void createDefaultShaders(); @@ -357,7 +357,6 @@ private: void createCommandPool(); void createCommandBuffers(); void createSyncObjects(); - void createDefaultTexture(); void cleanup(); void cleanupSwapChain(); void recreateSwapChain(); @@ -367,7 +366,8 @@ private: void endRecordingGraphicsCommands(); void ensureGraphicsPipelineConfiguration(GraphicsPipelineConfiguration &configuration); void createVulkanVertexFormat( - VertexAttributes vertexAttributes, + Shader *shader, + const VertexAttributes &attributes, std::vector &bindingDescriptions, std::vector &attributeDescriptions); void prepareDraw( @@ -378,6 +378,7 @@ private: void setDefaultRenderPass(); void startRenderPass(); void endRenderPass(); + void applyScissor(); VkSampler createSampler(const SamplerState &sampler); void cleanupUnusedObjects(); void requestSwapchainRecreation(); @@ -385,7 +386,6 @@ private: VkInstance instance = VK_NULL_HANDLE; VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; uint32_t deviceApiVersion = VK_API_VERSION_1_0; - bool windowHasStencil = false; int requestedMsaa = 0; VkDevice device = VK_NULL_HANDLE; OptionalInstanceExtensions optionalInstanceExtensions; @@ -394,11 +394,12 @@ private: VkQueue presentQueue = VK_NULL_HANDLE; VkSurfaceKHR surface = VK_NULL_HANDLE; VkSwapchainKHR swapChain = VK_NULL_HANDLE; - VkSurfaceTransformFlagBitsKHR preTransform = {}; - Matrix4 displayRotation; std::vector swapChainImages; + StrongRef fakeBackbuffer; VkFormat swapChainImageFormat = VK_FORMAT_UNDEFINED; + PixelFormat swapChainPixelFormat = PIXELFORMAT_UNKNOWN; VkFormat depthStencilFormat = VK_FORMAT_UNDEFINED; + PixelFormat depthStencilPixelFormat = PIXELFORMAT_UNKNOWN; VkExtent2D swapChainExtent = VkExtent2D(); std::vector swapChainImageViews; VkSampleCountFlagBits msaaSamples = VK_SAMPLE_COUNT_1_BIT; @@ -432,15 +433,13 @@ private: bool swapChainRecreationRequested = false; bool transitionColorDepthLayouts = false; VmaAllocator vmaAllocator = VK_NULL_HANDLE; - StrongRef defaultTexture; - StrongRef defaultConstantColor; - StrongRef defaultConstantTexCoord; + StrongRef defaultVertexBuffer; + StrongRef localUniformBuffer; // functions that need to be called to cleanup objects that were needed for rendering a frame. // We need a vector for each frame in flight. std::vector>> cleanUpFunctions; std::vector>> readbackCallbacks; - std::vector screenshotReadbackBuffers; - std::set usedShadersInFrame; + std::set> usedShadersInFrame; RenderpassState renderPassState; }; diff --git a/src/modules/graphics/vulkan/GraphicsReadback.cpp b/src/modules/graphics/vulkan/GraphicsReadback.cpp index 51a8a01b8..8a9af2628 100644 --- a/src/modules/graphics/vulkan/GraphicsReadback.cpp +++ b/src/modules/graphics/vulkan/GraphicsReadback.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -44,7 +44,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod if (method == READBACK_IMMEDIATE) { - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); if (stagingBuffer.get()) { status = readbackBuffer(stagingBuffer, 0, size); gfx->releaseTemporaryBuffer(stagingBuffer); @@ -79,7 +79,7 @@ GraphicsReadback::GraphicsReadback(love::graphics::Graphics *gfx, ReadbackMethod }); if (method == READBACK_IMMEDIATE) - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); } GraphicsReadback::~GraphicsReadback() @@ -89,7 +89,7 @@ GraphicsReadback::~GraphicsReadback() void GraphicsReadback::wait() { if (status == STATUS_WAITING) - vgfx->submitGpuCommands(false); + vgfx->submitGpuCommands(SUBMIT_RESTART); } void GraphicsReadback::update() diff --git a/src/modules/graphics/vulkan/GraphicsReadback.h b/src/modules/graphics/vulkan/GraphicsReadback.h index c502927ba..12069fd6b 100644 --- a/src/modules/graphics/vulkan/GraphicsReadback.h +++ b/src/modules/graphics/vulkan/GraphicsReadback.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/vulkan/Shader.cpp b/src/modules/graphics/vulkan/Shader.cpp index 3ad661164..54be10bd5 100644 --- a/src/modules/graphics/vulkan/Shader.cpp +++ b/src/modules/graphics/vulkan/Shader.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,10 +21,13 @@ #include "graphics/vertex.h" #include "Shader.h" #include "Graphics.h" +#include "common/Range.h" #include "libraries/glslang/glslang/Public/ShaderLang.h" +#include "libraries/glslang/glslang/Public/ResourceLimits.h" #include "libraries/glslang/SPIRV/GlslangToSpv.h" +#include namespace love { @@ -33,172 +36,81 @@ namespace graphics namespace vulkan { -static const TBuiltInResource defaultTBuiltInResource = { - /* .MaxLights = */ 32, - /* .MaxClipPlanes = */ 6, - /* .MaxTextureUnits = */ 32, - /* .MaxTextureCoords = */ 32, - /* .MaxVertexAttribs = */ 64, - /* .MaxVertexUniformComponents = */ 16384, - /* .MaxVaryingFloats = */ 128, - /* .MaxVertexTextureImageUnits = */ 32, - /* .MaxCombinedTextureImageUnits = */ 80, - /* .MaxTextureImageUnits = */ 32, - /* .MaxFragmentUniformComponents = */ 16384, - /* .MaxDrawBuffers = */ 8, - /* .MaxVertexUniformVectors = */ 4096, - /* .MaxVaryingVectors = */ 32, - /* .MaxFragmentUniformVectors = */ 4096, - /* .MaxVertexOutputVectors = */ 32, - /* .MaxFragmentInputVectors = */ 31, - /* .MinProgramTexelOffset = */ -8, - /* .MaxProgramTexelOffset = */ 7, - /* .MaxClipDistances = */ 8, - /* .MaxComputeWorkGroupCountX = */ 65535, - /* .MaxComputeWorkGroupCountY = */ 65535, - /* .MaxComputeWorkGroupCountZ = */ 65535, - /* .MaxComputeWorkGroupSizeX = */ 1024, - /* .MaxComputeWorkGroupSizeY = */ 1024, - /* .MaxComputeWorkGroupSizeZ = */ 64, - /* .MaxComputeUniformComponents = */ 1024, - /* .MaxComputeTextureImageUnits = */ 32, - /* .MaxComputeImageUniforms = */ 16, - /* .MaxComputeAtomicCounters = */ 4096, - /* .MaxComputeAtomicCounterBuffers = */ 8, - /* .MaxVaryingComponents = */ 128, - /* .MaxVertexOutputComponents = */ 128, - /* .MaxGeometryInputComponents = */ 128, - /* .MaxGeometryOutputComponents = */ 128, - /* .MaxFragmentInputComponents = */ 128, - /* .MaxImageUnits = */ 192, - /* .MaxCombinedImageUnitsAndFragmentOutputs = */ 144, - /* .MaxCombinedShaderOutputResources = */ 144, - /* .MaxImageSamples = */ 32, - /* .MaxVertexImageUniforms = */ 16, - /* .MaxTessControlImageUniforms = */ 16, - /* .MaxTessEvaluationImageUniforms = */ 16, - /* .MaxGeometryImageUniforms = */ 16, - /* .MaxFragmentImageUniforms = */ 16, - /* .MaxCombinedImageUniforms = */ 80, - /* .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 = */ 4096, - /* .MaxTessControlAtomicCounters = */ 4096, - /* .MaxTessEvaluationAtomicCounters = */ 4096, - /* .MaxGeometryAtomicCounters = */ 4096, - /* .MaxFragmentAtomicCounters = */ 4096, - /* .MaxCombinedAtomicCounters = */ 4096, - /* .MaxAtomicCounterBindings = */ 8, - /* .MaxVertexAtomicCounterBuffers = */ 8, - /* .MaxTessControlAtomicCounterBuffers = */ 8, - /* .MaxTessEvaluationAtomicCounterBuffers = */ 8, - /* .MaxGeometryAtomicCounterBuffers = */ 8, - /* .MaxFragmentAtomicCounterBuffers = */ 8, - /* .MaxCombinedAtomicCounterBuffers = */ 8, - /* .MaxAtomicCounterBufferSize = */ 16384, - /* .MaxTransformFeedbackBuffers = */ 4, - /* .MaxTransformFeedbackInterleavedComponents = */ 64, - /* .MaxCullDistances = */ 8, - /* .MaxCombinedClipAndCullDistances = */ 8, - /* .MaxSamples = */ 32, - /* .maxMeshOutputVerticesNV = */ 256, - /* .maxMeshOutputPrimitivesNV = */ 512, - /* .maxMeshWorkGroupSizeX_NV = */ 32, - /* .maxMeshWorkGroupSizeY_NV = */ 1, - /* .maxMeshWorkGroupSizeZ_NV = */ 1, - /* .maxTaskWorkGroupSizeX_NV = */ 32, - /* .maxTaskWorkGroupSizeY_NV = */ 1, - /* .maxTaskWorkGroupSizeZ_NV = */ 1, - /* .maxMeshViewCountNV = */ 4, - /* .maxDualSourceDrawBuffersEXT = */ 1, - /* .limits = */ { - /* .nonInductiveForLoops = */ 1, - /* .whileLoops = */ 1, - /* .doWhileLoops = */ 1, - /* .generalUniformIndexing = */ 1, - /* .generalAttributeMatrixVectorIndexing = */ 1, - /* .generalVaryingIndexing = */ 1, - /* .generalSamplerIndexing = */ 1, - /* .generalVariableIndexing = */ 1, - /* .generalConstantMatrixVectorIndexing = */ 1, - } -}; - -static const uint32_t STREAMBUFFER_DEFAULT_SIZE = 16; static const uint32_t DESCRIPTOR_POOL_SIZE = 1000; class BindingMapper { public: - uint32_t operator()(spirv_cross::CompilerGLSL &comp, std::vector &spirv, const std::string &name, const spirv_cross::ID &id) + + BindingMapper(spv::Decoration decoration) + : decoration(decoration) + {} + + uint32_t operator()(spirv_cross::CompilerGLSL &comp, std::vector &spirv, const std::string &name, int count, const spirv_cross::ID &id) { auto it = bindingMappings.find(name); if (it == bindingMappings.end()) { auto binding = comp.get_decoration(id, spv::DecorationBinding); - if (isFreeBinding(binding)) + if (isFreeBinding(binding, count)) { - bindingMappings[name] = binding; + bindingMappings[name] = Range(binding, count); return binding; } else { - uint32_t freeBinding = getFreeBinding(); + uint32_t freeBinding = getFreeBinding(count); uint32_t binaryBindingOffset; - if (!comp.get_binary_offset_for_decoration(id, spv::DecorationBinding, binaryBindingOffset)) - throw love::Exception("could not get binary offset for binding"); + if (!comp.get_binary_offset_for_decoration(id, decoration, binaryBindingOffset)) + throw love::Exception("could not get binary offset for uniform %s binding", name.c_str()); spirv[binaryBindingOffset] = freeBinding; - bindingMappings[name] = freeBinding; + bindingMappings[name] = Range(freeBinding, count); return freeBinding; } } else - return it->second; + { + auto binding = (uint32_t)it->second.getOffset(); + + uint32_t binaryBindingOffset; + if (!comp.get_binary_offset_for_decoration(id, decoration, binaryBindingOffset)) + throw love::Exception("could not get binary offset for uniform %s binding", name.c_str()); + + spirv[binaryBindingOffset] = binding; + + return binding; + } }; private: - uint32_t getFreeBinding() + uint32_t getFreeBinding(int count) { for (uint32_t i = 0;; i++) { - if (isFreeBinding(i)) + if (isFreeBinding(i, count)) return i; } } - bool isFreeBinding(uint32_t binding) + bool isFreeBinding(uint32_t binding, int count) { + Range r(binding, count); for (const auto &entry : bindingMappings) { - if (entry.second == binding) + if (entry.second.intersects(r)) return false; } return true; } - std::map bindingMappings; + spv::Decoration decoration; + std::map bindingMappings; }; @@ -217,6 +129,18 @@ static VkShaderStageFlagBits getStageBit(ShaderStageType type) } } +static VkShaderStageFlags getStageFlags(ShaderStageMask mask) +{ + VkShaderStageFlags flags = 0; + if (mask & SHADERSTAGEMASK_VERTEX) + flags |= VK_SHADER_STAGE_VERTEX_BIT; + if (mask & SHADERSTAGEMASK_PIXEL) + flags |= VK_SHADER_STAGE_FRAGMENT_BIT; + if (mask & SHADERSTAGEMASK_COMPUTE) + flags |= VK_SHADER_STAGE_COMPUTE_BIT; + return flags; +} + static EShLanguage getGlslShaderType(ShaderStageType stage) { switch (stage) @@ -241,8 +165,8 @@ static bool usesLocalUniformData(const graphics::Shader::UniformInfo *info) info->baseType == graphics::Shader::UNIFORM_UINT; } -Shader::Shader(StrongRef stages[]) - : graphics::Shader(stages) +Shader::Shader(StrongRef stages[], const CompileOptions &options) + : graphics::Shader(stages, options) { auto gfx = Module::getInstance(Module::ModuleType::M_GRAPHICS); vgfx = dynamic_cast(gfx); @@ -260,14 +184,11 @@ bool Shader::loadVolatile() builtinUniformInfo[i] = nullptr; compileShaders(); - calculateUniformBufferSizeAligned(); createDescriptorSetLayout(); createPipelineLayout(); createDescriptorPoolSizes(); - createStreamBuffers(); descriptorPools.resize(MAX_FRAMES_IN_FLIGHT); currentFrame = 0; - currentUsedUniformStreamBuffersCount = 0; newFrame(); return true; @@ -278,31 +199,6 @@ void Shader::unloadVolatile() if (shaderModules.empty()) return; - for (const auto &uniform : uniformInfos) - { - switch (uniform.second.baseType) - { - case UNIFORM_SAMPLER: - case UNIFORM_STORAGETEXTURE: - for (int i = 0; i < uniform.second.count; i++) - { - if (uniform.second.textures[i] != nullptr) - uniform.second.textures[i]->release(); - } - delete[] uniform.second.textures; - break; - case UNIFORM_TEXELBUFFER: - case UNIFORM_STORAGEBUFFER: - for (int i = 0; i < uniform.second.count; i++) - { - if (uniform.second.buffers[i] != nullptr) - uniform.second.buffers[i]->release(); - } - delete[] uniform.second.buffers; - break; - } - } - vgfx->queueCleanUp([shaderModules = std::move(shaderModules), device = device, descriptorSetLayout = descriptorSetLayout, pipelineLayout = pipelineLayout, descriptorPools = descriptorPools, computePipeline = computePipeline](){ for (const auto &pools : descriptorPools) { @@ -317,12 +213,8 @@ void Shader::unloadVolatile() vkDestroyPipeline(device, computePipeline, nullptr); }); - for (const auto streamBuffer : streamBuffers) - streamBuffer->release(); - shaderModules.clear(); shaderStages.clear(); - streamBuffers.clear(); descriptorPools.clear(); } @@ -345,22 +237,9 @@ void Shader::newFrame() { currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; - currentUsedUniformStreamBuffersCount = 0; currentDescriptorPool = 0; - - if (streamBuffers.size() > 1) - { - size_t newSize = 0; - for (auto streamBuffer : streamBuffers) - { - newSize += streamBuffer->getSize(); - streamBuffer->release(); - } - streamBuffers.clear(); - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, newSize)); - } - else - streamBuffers.at(0)->nextFrame(); + currentDescriptorSet = VK_NULL_HANDLE; + resourceDescriptorsDirty = true; for (VkDescriptorPool pool : descriptorPools[currentFrame]) vkResetDescriptorPool(device, pool, 0); @@ -368,159 +247,71 @@ void Shader::newFrame() void Shader::cmdPushDescriptorSets(VkCommandBuffer commandBuffer, VkPipelineBindPoint bindPoint) { - VkDescriptorSet currentDescriptorSet = allocateDescriptorSet(); - - std::vector bufferInfos; - bufferInfos.reserve(numBuffers); - - std::vector imageInfos; - imageInfos.reserve(numTextures); - - std::vector bufferViews; - bufferViews.reserve(numBufferViews); - - std::vector descriptorWrites; + bool useLocalUniformOffset = false; + uint32 localUniformOffset = 0; if (!localUniformData.empty()) { - auto usedStreamBufferMemory = currentUsedUniformStreamBuffersCount * uniformBufferSizeAligned; - if (usedStreamBufferMemory >= streamBuffers.back()->getSize()) - { - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned)); - currentUsedUniformStreamBuffersCount = 0; - } - if (builtinUniformDataOffset.hasValue) { auto builtinData = vgfx->getCurrentBuiltinUniformData(); - auto dst = localUniformData.data() + builtinUniformDataOffset.value; + auto dst = (BuiltinUniformData *) (localUniformData.data() + builtinUniformDataOffset.value); memcpy(dst, &builtinData, sizeof(builtinData)); } - auto currentStreamBuffer = streamBuffers.back(); + VkDescriptorBufferInfo info = {}; + vgfx->mapLocalUniformData(localUniformData.data(), localUniformData.size(), info); - auto mapInfo = currentStreamBuffer->map(uniformBufferSizeAligned); - memcpy(mapInfo.data, localUniformData.data(), localUniformData.size()); - auto offset = currentStreamBuffer->unmap(uniformBufferSizeAligned); - currentStreamBuffer->markUsed(uniformBufferSizeAligned); + // This is a dynamic uniform buffer, so the offset is specified in BindDescriptorSets + // and it only needs to update the descriptor sets if the buffer changes. + if (info.buffer != descriptorBuffers[0].buffer) + resourceDescriptorsDirty = true; - VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = (VkBuffer)currentStreamBuffer->getHandle(); - bufferInfo.offset = offset; - bufferInfo.range = localUniformData.size(); + descriptorBuffers[0].buffer = info.buffer; + descriptorBuffers[0].range = info.range; + descriptorBuffers[0].offset = 0; - bufferInfos.push_back(bufferInfo); - - VkWriteDescriptorSet uniformWrite{}; - uniformWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - uniformWrite.dstSet = currentDescriptorSet; - uniformWrite.dstBinding = localUniformLocation; - uniformWrite.dstArrayElement = 0; - uniformWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - uniformWrite.descriptorCount = 1; - uniformWrite.pBufferInfo = &bufferInfos[bufferInfos.size() - 1]; - - descriptorWrites.push_back(uniformWrite); - - currentUsedUniformStreamBuffersCount++; + useLocalUniformOffset = true; + localUniformOffset = info.offset; } - for (const auto &u : uniformInfos) + // Sampler updates need to happen here because the handles may change after sendTextures. + for (const auto &u : reflection.sampledTextures) { - auto &info = u.second; - - if (usesLocalUniformData(&info)) + const auto &info = u.second; + if (!info.active) continue; - if (info.baseType == UNIFORM_SAMPLER || info.baseType == UNIFORM_STORAGETEXTURE) + for (int i = 0; i < info.count; i++) { - bool isSampler = info.baseType == UNIFORM_SAMPLER; + auto vkTexture = dynamic_cast(activeTextures[info.resourceIndex + i]); - for (int i = 0; i < info.count; i++) + if (vkTexture == nullptr) + throw love::Exception("uniform variable %s is not set.", info.name.c_str()); + + auto sampler = (VkSampler)vkTexture->getSamplerHandle(); + + VkDescriptorImageInfo &imageInfo = descriptorImages[info.bindingStartIndex + i]; + if (sampler != imageInfo.sampler) { - auto vkTexture = dynamic_cast(info.textures[i]); - - if (vkTexture == nullptr) - throw love::Exception("uniform variable %s is not set.", info.name.c_str()); - - VkDescriptorImageInfo imageInfo{}; - - imageInfo.imageLayout = vkTexture->getImageLayout(); - imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); - if (isSampler) - imageInfo.sampler = (VkSampler)vkTexture->getSamplerHandle(); - - imageInfos.push_back(imageInfo); + imageInfo.sampler = sampler; + resourceDescriptorsDirty = true; } - - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info.location; - write.dstArrayElement = 0; - if (isSampler) - write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - else - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; - write.descriptorCount = static_cast(info.count); - write.pImageInfo = &imageInfos[imageInfos.size() - info.count]; - - descriptorWrites.push_back(write); - } - if (info.baseType == UNIFORM_STORAGEBUFFER) - { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info.location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - write.descriptorCount = info.count; - - for (int i = 0; i < info.count; i++) - { - if (info.buffers[i] == nullptr) - throw love::Exception("uniform variable %s is not set.", info.name.c_str()); - - VkDescriptorBufferInfo bufferInfo{}; - bufferInfo.buffer = (VkBuffer)info.buffers[i]->getHandle();; - bufferInfo.offset = 0; - bufferInfo.range = info.buffers[i]->getSize(); - - bufferInfos.push_back(bufferInfo); - } - - write.pBufferInfo = &bufferInfos[bufferInfos.size() - info.count]; - - descriptorWrites.push_back(write); - } - if (info.baseType == UNIFORM_TEXELBUFFER) - { - VkWriteDescriptorSet write{}; - write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - write.dstSet = currentDescriptorSet; - write.dstBinding = info.location; - write.dstArrayElement = 0; - write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER; - write.descriptorCount = info.count; - - for (int i = 0; i < info.count; i++) - { - if (info.buffers[i] == nullptr) - throw love::Exception("uniform variable %s is not set.", info.name.c_str()); - - bufferViews.push_back((VkBufferView)info.buffers[i]->getTexelBufferHandle()); - } - - write.pTexelBufferView = &bufferViews[bufferViews.size() - info.count]; - - descriptorWrites.push_back(write); } } - vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + if (resourceDescriptorsDirty || currentDescriptorSet == VK_NULL_HANDLE) + { + currentDescriptorSet = allocateDescriptorSet(); - vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, 0, nullptr); + for (auto &write : descriptorWrites) + write.dstSet = currentDescriptorSet; + + vkUpdateDescriptorSets(device, descriptorWrites.size(), descriptorWrites.data(), 0, nullptr); + resourceDescriptorsDirty = false; + } + + vkCmdBindDescriptorSets(commandBuffer, bindPoint, pipelineLayout, 0, 1, ¤tDescriptorSet, useLocalUniformOffset ? 1 : 0, &localUniformOffset); } Shader::~Shader() @@ -546,12 +337,7 @@ void Shader::attach() int Shader::getVertexAttributeIndex(const std::string &name) { auto it = attributes.find(name); - return it == attributes.end() ? -1 : it->second; -} - -const Shader::UniformInfo *Shader::getUniformInfo(const std::string &name) const -{ - return &uniformInfos.at(name); + return it == attributes.end() ? -1 : it->second.index; } const Shader::UniformInfo *Shader::getUniformInfo(BuiltinUniform builtin) const @@ -564,40 +350,52 @@ void Shader::updateUniform(const UniformInfo *info, int count) if (current == this) Graphics::flushBatchedDrawsGlobal(); - if (usesLocalUniformData(info)) - memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size()); + count = std::min(count, info->count); + + if (info->data != nullptr) + { + size_t offset = (const uint8*)info->data - localUniformStagingData.data(); + uint8 *dst = localUniformData.data() + offset; + copyToUniformBuffer(info, info->data, dst, count); + } } void Shader::sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) { + if (current == this) + Graphics::flushBatchedDrawsGlobal(); + for (int i = 0; i < count; i++) { - auto oldTexture = info->textures[i]; - info->textures[i] = textures[i]; - info->textures[i]->retain(); - if (oldTexture) - oldTexture->release(); + int resourceindex = info->resourceIndex + i; + auto prevtexture = activeTextures[resourceindex]; + activeTextures[resourceindex] = textures[i]; + activeTextures[resourceindex]->retain(); + if (prevtexture) + prevtexture->release(); + + if (textures[i] != prevtexture) + setTextureDescriptor(info, textures[i], i); } } void Shader::sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) { + if (current == this) + Graphics::flushBatchedDrawsGlobal(); + for (int i = 0; i < count; i++) { - auto oldBuffer = info->buffers[i]; - info->buffers[i] = buffers[i]; - info->buffers[i]->retain(); - if (oldBuffer) - oldBuffer->release(); - } -} + int resourceindex = info->resourceIndex + i; + auto prevbuffer = activeBuffers[resourceindex]; + activeBuffers[resourceindex] = buffers[i]; + activeBuffers[resourceindex]->retain(); + if (prevbuffer) + prevbuffer->release(); -void Shader::calculateUniformBufferSizeAligned() -{ - auto minAlignment = vgfx->getMinUniformBufferOffsetAlignment(); - size_t size = localUniformStagingData.size(); - auto factor = static_cast(std::ceil(static_cast(size) / static_cast(minAlignment))); - uniformBufferSizeAligned = factor * minAlignment; + if (buffers[i] != prevbuffer) + setBufferDescriptor(info, buffers[i], i); + } } void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename) @@ -617,8 +415,20 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: switch (memberType.basetype) { case SPIRType::Struct: - name += "."; - buildLocalUniforms(comp, memberType, offset, name); + if (memberType.op == spv::OpTypeArray) + { + size_t arraystride = comp.type_struct_member_array_stride(type, uindex); + for (uint32 i = 0; i < memberType.array[0]; i++) + { + std::string structname = name + "[" + std::to_string(i) + "]."; + buildLocalUniforms(comp, memberType, offset + i * arraystride, structname); + } + } + else + { + std::string structname = name + "."; + buildLocalUniforms(comp, memberType, offset, structname); + } continue; case SPIRType::Int: case SPIRType::UInt: @@ -628,50 +438,43 @@ void Shader::buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross:: continue; } - UniformInfo u{}; - u.name = name; + name = canonicaliizeUniformName(name); + + auto uniformit = reflection.allUniforms.find(name); + if (uniformit == reflection.allUniforms.end()) + { + handleUnknownUniformName(name.c_str()); + continue; + } + + UniformInfo &u = *(uniformit->second); + + u.active = true; u.dataSize = memberSize; - u.count = memberType.array.empty() ? 1 : memberType.array[0]; - u.components = 1; u.data = localUniformStagingData.data() + offset; - if (memberType.columns == 1) + const auto &valuesit = reflection.localUniformInitializerValues.find(name); + if (valuesit != reflection.localUniformInitializerValues.end()) { - if (memberType.basetype == SPIRType::Int) - u.baseType = UNIFORM_INT; - else if (memberType.basetype == SPIRType::UInt) - u.baseType = UNIFORM_UINT; - else - u.baseType = UNIFORM_FLOAT; - u.components = memberType.vecsize; - } - else - { - u.baseType = UNIFORM_MATRIX; - u.matrix.rows = memberType.vecsize; - u.matrix.columns = memberType.columns; - } - - const auto &reflectionIt = validationReflection.localUniforms.find(u.name); - if (reflectionIt != validationReflection.localUniforms.end()) - { - const auto &localUniform = reflectionIt->second; - const auto &values = localUniform.initializerValues; + const auto &values = valuesit->second; if (!values.empty()) + { memcpy( u.data, values.data(), std::min(u.dataSize, values.size() * sizeof(LocalUniformValue))); - } - uniformInfos[u.name] = u; + uint8 *dst = localUniformData.data() + offset; + copyToUniformBuffer(&u, u.data, dst, u.count); + } + } BuiltinUniform builtin = BUILTIN_MAX_ENUM; if (getConstant(u.name.c_str(), builtin)) { if (builtin == BUILTIN_UNIFORMS_PER_DRAW) builtinUniformDataOffset = offset; - builtinUniformInfo[builtin] = &uniformInfos[u.name]; + builtinUniformInfo[builtin] = &u; } } } @@ -722,7 +525,7 @@ void Shader::compileShaders() bool forceDefault = false; bool forwardCompat = true; - if (!tshader->parse(&defaultTBuiltInResource, defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) + if (!tshader->parse(GetResources(), defaultVersion, defaultProfile, forceDefault, forwardCompat, EShMsgSuppressWarnings)) { const char *stageName = "unknown"; ShaderStage::getConstant(stage, stageName); @@ -744,9 +547,8 @@ void Shader::compileShaders() if (!program->mapIO()) throw love::Exception("mapIO failed"); - uniformInfos.clear(); - - BindingMapper bindingMapper; + BindingMapper bindingMapper(spv::DecorationBinding); + BindingMapper ioLocationMapper(spv::DecorationLocation); for (int i = 0; i < SHADERSTAGE_MAX_ENUM; i++) { @@ -761,18 +563,28 @@ void Shader::compileShaders() glslang::SpvOptions opt; opt.validate = true; - std::vector spirv; + std::vector spirv; + GlslangToSpv(*intermediate, spirv, &logger, &opt); - spirv_cross::CompilerGLSL comp(spirv); + auto compiler = std::make_unique(spirv); + auto &comp = *compiler; - // we only care about variables that are actually getting used. - auto active = comp.get_active_interface_variables(); - auto shaderResources = comp.get_shader_resources(active); - comp.set_enabled_interface_variables(std::move(active)); + // We aren't recompiling the SPIR-V to something else, so + // set_enabled_interface_variables wouldn't do much. + // Vulkan has various rules about making sure bindings to inputs and + // resources are valid, so we can't skip inactive ones here. + // Unfortunately GlslangToSpv doesn't strip unused resources even + // though it knows about them... + auto active = compiler->get_active_interface_variables(); + auto shaderResources = comp.get_shader_resources(); for (const auto &resource : shaderResources.uniform_buffers) { + // TODO: Do something smarter here. + if (active.find(resource.id) == active.end()) + continue; + if (resource.name == "gl_DefaultUniformBlock") { const auto &type = comp.get_type(resource.base_type_id); @@ -780,15 +592,13 @@ void Shader::compileShaders() localUniformStagingData.resize(defaultUniformBlockSize); localUniformData.resize(defaultUniformBlockSize); - localUniformLocation = bindingMapper(comp, spirv, resource.name, resource.id); + localUniformLocation = bindingMapper(comp, spirv, resource.name, 1, resource.id); memset(localUniformStagingData.data(), 0, defaultUniformBlockSize); memset(localUniformData.data(), 0, defaultUniformBlockSize); std::string basename(""); buildLocalUniforms(comp, type, 0, basename); - - memcpy(localUniformData.data(), localUniformStagingData.data(), localUniformStagingData.size()); } else throw love::Exception("unimplemented: non default uniform blocks."); @@ -796,125 +606,71 @@ void Shader::compileShaders() for (const auto &r : shaderResources.sampled_images) { - const SPIRType &basetype = comp.get_type(r.base_type_id); - const SPIRType &type = comp.get_type(r.type_id); - const SPIRType &imagetype = comp.get_type(basetype.image.type); + // TODO: Do something smarter here. + if (active.find(r.id) == active.end()) + continue; - graphics::Shader::UniformInfo info; - info.location = bindingMapper(comp, spirv, r.name, r.id); - info.baseType = UNIFORM_SAMPLER; - info.name = r.name; - info.count = type.array.empty() ? 1 : type.array[0]; - info.isDepthSampler = type.image.depth; - info.components = 1; - - switch (imagetype.basetype) + std::string name = canonicaliizeUniformName(r.name); + auto uniformit = reflection.allUniforms.find(name); + if (uniformit == reflection.allUniforms.end()) { - case SPIRType::Float: - info.dataBaseType = DATA_BASETYPE_FLOAT; - break; - case SPIRType::Int: - info.dataBaseType = DATA_BASETYPE_INT; - break; - case SPIRType::UInt: - info.dataBaseType = DATA_BASETYPE_UINT; - break; - default: - break; + handleUnknownUniformName(name.c_str()); + continue; } - switch (basetype.image.dim) - { - case spv::Dim2D: - info.textureType = basetype.image.arrayed ? TEXTURE_2D_ARRAY : TEXTURE_2D; - info.textures = new love::graphics::Texture *[info.count]; - break; - case spv::Dim3D: - info.textureType = TEXTURE_VOLUME; - info.textures = new love::graphics::Texture *[info.count]; - break; - case spv::DimCube: - if (basetype.image.arrayed) { - throw love::Exception("cubemap arrays are not currently supported"); - } - info.textureType = TEXTURE_CUBE; - info.textures = new love::graphics::Texture *[info.count]; - break; - case spv::DimBuffer: - info.baseType = UNIFORM_TEXELBUFFER; - info.buffers = new love::graphics::Buffer *[info.count]; - break; - default: - throw love::Exception("unknown dim"); - } + UniformInfo &u = *(uniformit->second); + u.active = true; + u.location = bindingMapper(comp, spirv, name, u.count, r.id); - if (info.baseType == UNIFORM_TEXELBUFFER) - { - for (int i = 0; i < info.count; i++) - info.buffers[i] = nullptr; - } - else - { - for (int i = 0; i < info.count; i++) - { - info.textures[i] = nullptr; - } - } - - uniformInfos[r.name] = info; BuiltinUniform builtin; - if (getConstant(r.name.c_str(), builtin)) - builtinUniformInfo[builtin] = &uniformInfos[info.name]; + if (getConstant(name.c_str(), builtin)) + builtinUniformInfo[builtin] = &u; } for (const auto &r : shaderResources.storage_buffers) { - const auto &type = comp.get_type(r.type_id); - - UniformInfo u{}; - u.baseType = UNIFORM_STORAGEBUFFER; - u.components = 1; - u.name = r.name; - u.count = type.array.empty() ? 1 : type.array[0]; - - if (!fillUniformReflectionData(u)) + // TODO: Do something smarter here. + if (active.find(r.id) == active.end()) continue; - u.location = bindingMapper(comp, spirv, r.name, r.id); - u.buffers = new love::graphics::Buffer *[u.count]; + std::string name = canonicaliizeUniformName(r.name); + const auto &uniformit = reflection.storageBuffers.find(name); + if (uniformit == reflection.storageBuffers.end()) + { + handleUnknownUniformName(name.c_str()); + continue; + } - for (int i = 0; i < u.count; i++) - u.buffers[i] = nullptr; - - uniformInfos[u.name] = u; + UniformInfo &u = uniformit->second; + u.active = true; + u.location = bindingMapper(comp, spirv, name, u.count, r.id); } for (const auto &r : shaderResources.storage_images) { - const auto &type = comp.get_type(r.type_id); - - UniformInfo u{}; - u.baseType = UNIFORM_STORAGETEXTURE; - u.components = 1; - u.name = r.name; - u.count = type.array.empty() ? 1 : type.array[0]; - - if (!fillUniformReflectionData(u)) + // TODO: Do something smarter here. + if (active.find(r.id) == active.end()) continue; - u.textures = new love::graphics::Texture *[u.count]; - u.location = bindingMapper(comp, spirv, r.name, r.id); + std::string name = canonicaliizeUniformName(r.name); + const auto &uniformit = reflection.storageTextures.find(name); + if (uniformit == reflection.storageTextures.end()) + { + handleUnknownUniformName(name.c_str()); + continue; + } - for (int i = 0; i < u.count; i++) - u.textures[i] = nullptr; - - uniformInfos[u.name] = u; + UniformInfo &u = uniformit->second; + u.active = true; + u.location = bindingMapper(comp, spirv, name, u.count, r.id); } if (shaderStage == SHADERSTAGE_VERTEX) { int nextAttributeIndex = ATTRIB_MAX_ENUM; + // Don't skip unused inputs, vulkan still needs to have valid + // bindings for them. for (const auto &r : shaderResources.stage_inputs) { int index; @@ -927,11 +683,47 @@ void Shader::compileShaders() uint32_t locationOffset; if (!comp.get_binary_offset_for_decoration(r.id, spv::DecorationLocation, locationOffset)) - throw love::Exception("could not get binary offset for location"); + throw love::Exception("could not get binary offset for vertex attribute %s location", r.name.c_str()); spirv[locationOffset] = (uint32_t)index; - attributes[r.name] = index; + DataBaseType basetype = DATA_BASETYPE_FLOAT; + + switch (comp.get_type(r.base_type_id).basetype) + { + case spirv_cross::SPIRType::Int: + basetype = DATA_BASETYPE_INT; + break; + case spirv_cross::SPIRType::UInt: + basetype = DATA_BASETYPE_UINT; + break; + default: + break; + } + + attributes[r.name] = { index, basetype }; + } + + for (const auto &r : shaderResources.stage_outputs) + { + const auto &type = comp.get_type(r.base_type_id); + int count = type.array.empty() ? 1 : type.array[0]; + if (type.op == spv::OpTypeMatrix) + count *= type.columns; + + ioLocationMapper(comp, spirv, r.name, count, r.id); + } + } + else if (shaderStage == SHADERSTAGE_PIXEL) + { + for (const auto &r : shaderResources.stage_inputs) + { + const auto &type = comp.get_type(r.base_type_id); + int count = type.array.empty() ? 1 : type.array[0]; + if (type.op == spv::OpTypeMatrix) + count *= type.columns; + + ioLocationMapper(comp, spirv, r.name, count, r.id); } } @@ -945,6 +737,19 @@ void Shader::compileShaders() if (vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule) != VK_SUCCESS) throw love::Exception("failed to create shader module"); + std::string debugname = getShaderStageDebugName(shaderStage); + if (!debugname.empty() && vgfx->getEnabledOptionalInstanceExtensions().debugInfo) + { + auto device = vgfx->getDevice(); + + VkDebugUtilsObjectNameInfoEXT nameInfo{}; + nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + nameInfo.objectType = VK_OBJECT_TYPE_SHADER_MODULE; + nameInfo.objectHandle = (uint64_t)shaderModule; + nameInfo.pObjectName = debugname.c_str(); + vkSetDebugUtilsObjectNameEXT(device, &nameInfo); + } + shaderModules.push_back(shaderModule); VkPipelineShaderStageCreateInfo shaderStageInfo{}; @@ -956,54 +761,199 @@ void Shader::compileShaders() shaderStages.push_back(shaderStageInfo); } - numBuffers = 0; - numTextures = 0; - numBufferViews = 0; + int numBuffers = 0; + int numTextures = 0; + int numBufferViews = 0; if (localUniformData.size() > 0) numBuffers++; - for (const auto &u : uniformInfos) + for (const auto &kvp : reflection.allUniforms) { - switch (u.second.baseType) + if (!kvp.second->active) + continue; + + switch (kvp.second->baseType) { case UNIFORM_SAMPLER: case UNIFORM_STORAGETEXTURE: - numTextures++; + numTextures += kvp.second->count; break; case UNIFORM_STORAGEBUFFER: - numBuffers++; + numBuffers += kvp.second->count; break; case UNIFORM_TEXELBUFFER: - numBufferViews++; + numBufferViews += kvp.second->count; break; default: continue; } } + + descriptorWrites.clear(); + + descriptorBuffers.clear(); + descriptorBuffers.reserve(numBuffers); + + descriptorImages.clear(); + descriptorImages.reserve(numTextures); + + descriptorBufferViews.clear(); + descriptorBufferViews.reserve(numBufferViews); + + if (localUniformData.size() > 0) + { + VkDescriptorBufferInfo bufferInfo{}; + bufferInfo.range = localUniformData.size(); + + descriptorBuffers.push_back(bufferInfo); + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstBinding = localUniformLocation; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + write.descriptorCount = 1; + write.pBufferInfo = &descriptorBuffers.back(); + descriptorWrites.push_back(write); + } + + for (auto &u : reflection.sampledTextures) + { + UniformInfo &info = u.second; + if (!info.active) + continue; + + info.bindingStartIndex = (int)descriptorImages.size(); + + for (int i = 0; i < info.count; i++) + { + VkDescriptorImageInfo imageInfo{}; + descriptorImages.push_back(imageInfo); + + auto texture = activeTextures[info.resourceIndex + i]; + if (texture != nullptr) + setTextureDescriptor(&info, texture, i); + } + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + write.descriptorCount = static_cast(info.count); + write.pImageInfo = &descriptorImages[info.bindingStartIndex]; + + descriptorWrites.push_back(write); + } + + for (auto &u : reflection.storageTextures) + { + UniformInfo &info = u.second; + if (!info.active) + continue; + + info.bindingStartIndex = (int)descriptorImages.size(); + + for (int i = 0; i < info.count; i++) + { + VkDescriptorImageInfo imageInfo{}; + descriptorImages.push_back(imageInfo); + + auto texture = activeTextures[info.resourceIndex + i]; + if (texture != nullptr) + setTextureDescriptor(&info, texture, i); + } + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + write.descriptorCount = static_cast(info.count); + write.pImageInfo = &descriptorImages[info.bindingStartIndex]; + + descriptorWrites.push_back(write); + } + + for (auto &u : reflection.texelBuffers) + { + UniformInfo &info = u.second; + if (!info.active) + continue; + + info.bindingStartIndex = (int)descriptorBufferViews.size(); + + for (int i = 0; i < info.count; i++) + { + descriptorBufferViews.push_back(VK_NULL_HANDLE); + + auto buffer = activeBuffers[info.resourceIndex + i]; + if (buffer != nullptr) + setBufferDescriptor(&info, buffer, i); + } + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER; + write.descriptorCount = info.count; + write.pTexelBufferView = &descriptorBufferViews[info.bindingStartIndex]; + + descriptorWrites.push_back(write); + } + + for (auto &u : reflection.storageBuffers) + { + UniformInfo &info = u.second; + if (!info.active) + continue; + + info.bindingStartIndex = (int)descriptorBuffers.size(); + + for (int i = 0; i < info.count; i++) + { + VkDescriptorBufferInfo bufferInfo{}; + descriptorBuffers.push_back(bufferInfo); + + auto buffer = activeBuffers[info.resourceIndex + i]; + if (buffer != nullptr) + setBufferDescriptor(&info, buffer, i); + } + + VkWriteDescriptorSet write{}; + write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + write.dstBinding = info.location; + write.dstArrayElement = 0; + write.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + write.descriptorCount = info.count; + write.pBufferInfo = &descriptorBuffers[info.bindingStartIndex]; + + descriptorWrites.push_back(write); + } + + resourceDescriptorsDirty = true; } void Shader::createDescriptorSetLayout() { std::vector bindings; - VkShaderStageFlags stageFlags; - if (isCompute) - stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; - else - stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - - for (auto const &entry : uniformInfos) + for (auto const &entry : reflection.allUniforms) { - auto type = Vulkan::getDescriptorType(entry.second.baseType); - if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + if (!entry.second->active) + continue; + + auto type = Vulkan::getDescriptorType(entry.second->baseType); + if (type != VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) { VkDescriptorSetLayoutBinding layoutBinding{}; - layoutBinding.binding = entry.second.location; + layoutBinding.binding = entry.second->location; layoutBinding.descriptorType = type; - layoutBinding.descriptorCount = entry.second.count; - layoutBinding.stageFlags = stageFlags; + layoutBinding.descriptorCount = entry.second->count; + layoutBinding.stageFlags = getStageFlags((ShaderStageMask)entry.second->stageMask); bindings.push_back(layoutBinding); } @@ -1013,9 +963,12 @@ void Shader::createDescriptorSetLayout() { VkDescriptorSetLayoutBinding uniformBinding{}; uniformBinding.binding = localUniformLocation; - uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + uniformBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; uniformBinding.descriptorCount = 1; - uniformBinding.stageFlags = stageFlags; + if (isCompute) + uniformBinding.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + else + uniformBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; bindings.push_back(uniformBinding); } @@ -1058,17 +1011,20 @@ void Shader::createDescriptorPoolSizes() if (!localUniformData.empty()) { VkDescriptorPoolSize size{}; - size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; size.descriptorCount = 1; descriptorPoolSizes.push_back(size); } - for (const auto &entry : uniformInfos) + for (const auto &entry : reflection.allUniforms) { + if (!entry.second->active) + continue; + VkDescriptorPoolSize size{}; - auto type = Vulkan::getDescriptorType(entry.second.baseType); - if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER) + auto type = Vulkan::getDescriptorType(entry.second->baseType); + if (type == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC) continue; size.type = type; @@ -1077,13 +1033,6 @@ void Shader::createDescriptorPoolSizes() } } -void Shader::createStreamBuffers() -{ - size_t size = STREAMBUFFER_DEFAULT_SIZE * uniformBufferSizeAligned; - if (size > 0) - streamBuffers.push_back(new StreamBuffer(vgfx, BUFFERUSAGE_UNIFORM, size)); -} - void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) { std::array textures = { @@ -1100,32 +1049,68 @@ void Shader::setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cb for (size_t i = 0; i < textures.size(); i++) { - if (builtinUniformInfo[builtIns[i]] != nullptr) + const UniformInfo *u = builtinUniformInfo[builtIns[i]]; + if (u != nullptr) { + auto prevtexture = activeTextures[u->resourceIndex]; textures[i]->retain(); - if (builtinUniformInfo[builtIns[i]]->textures[0]) - builtinUniformInfo[builtIns[i]]->textures[0]->release(); - builtinUniformInfo[builtIns[i]]->textures[0] = textures[i]; + if (prevtexture) + prevtexture->release(); + activeTextures[u->resourceIndex] = textures[i]; + + if (textures[i] != prevtexture) + setTextureDescriptor(u, textures[i], 0); } } } -bool Shader::hasUniform(const std::string &name) const -{ - return uniformInfos.find(name) != uniformInfos.end(); -} - void Shader::setMainTex(graphics::Texture *texture) { - if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN] != nullptr) + const UniformInfo *u = builtinUniformInfo[BUILTIN_TEXTURE_MAIN]; + if (u != nullptr) { + auto prevtexture = activeTextures[u->resourceIndex]; texture->retain(); - if (builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]) - builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0]->release(); - builtinUniformInfo[BUILTIN_TEXTURE_MAIN]->textures[0] = texture; + if (prevtexture) + prevtexture->release(); + activeTextures[u->resourceIndex] = texture; + + if (texture != prevtexture) + setTextureDescriptor(u, texture, 0); } } +void Shader::setTextureDescriptor(const UniformInfo *info, love::graphics::Texture *texture, int index) +{ + auto vkTexture = dynamic_cast(texture); + + VkDescriptorImageInfo &imageInfo = descriptorImages[info->bindingStartIndex + index]; + + // Samplers may change after this call, so they're set just before the + // descriptor set is used instead of here. + imageInfo.imageLayout = vkTexture->getImageLayout(); + imageInfo.imageView = (VkImageView)vkTexture->getRenderTargetHandle(); + + resourceDescriptorsDirty = true; +} + +void Shader::setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index) +{ + if (info->baseType == UNIFORM_STORAGEBUFFER) + { + VkDescriptorBufferInfo &bufferInfo = descriptorBuffers[info->bindingStartIndex + index]; + bufferInfo.buffer = (VkBuffer)buffer->getHandle(); + bufferInfo.offset = 0; + bufferInfo.range = buffer->getSize(); + } + else if (info->baseType == UNIFORM_TEXELBUFFER) + { + descriptorBufferViews[info->bindingStartIndex + index] = (VkBufferView)buffer->getTexelBufferHandle(); + } + + resourceDescriptorsDirty = true; +} + void Shader::createDescriptorPool() { VkDescriptorPoolCreateInfo createInfo{}; diff --git a/src/modules/graphics/vulkan/Shader.h b/src/modules/graphics/vulkan/Shader.h index af997b408..3e4fe7edb 100644 --- a/src/modules/graphics/vulkan/Shader.h +++ b/src/modules/graphics/vulkan/Shader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -52,7 +52,14 @@ class Shader final , public Volatile { public: - Shader(StrongRef stages[]); + + struct AttributeInfo + { + int index; + DataBaseType baseType; + }; + + Shader(StrongRef stages[], const CompileOptions &options); virtual ~Shader(); bool loadVolatile() override; @@ -75,8 +82,8 @@ public: std::string getWarnings() const override { return ""; } int getVertexAttributeIndex(const std::string &name) override; + const std::unordered_map getVertexAttributeIndices() const { return attributes; } - const UniformInfo *getUniformInfo(const std::string &name) const override; const UniformInfo *getUniformInfo(BuiltinUniform builtin) const override; void updateUniform(const UniformInfo *info, int count) override; @@ -84,40 +91,35 @@ public: void sendTextures(const UniformInfo *info, graphics::Texture **textures, int count) override; void sendBuffers(const UniformInfo *info, love::graphics::Buffer **buffers, int count) override; - bool hasUniform(const std::string &name) const override; - void setVideoTextures(graphics::Texture *ytexture, graphics::Texture *cbtexture, graphics::Texture *crtexture) override; void setMainTex(graphics::Texture *texture); private: - void calculateUniformBufferSizeAligned(); void compileShaders(); void createDescriptorSetLayout(); void createPipelineLayout(); void createDescriptorPoolSizes(); - void createStreamBuffers(); void buildLocalUniforms(spirv_cross::Compiler &comp, const spirv_cross::SPIRType &type, size_t baseoff, const std::string &basename); void createDescriptorPool(); VkDescriptorSet allocateDescriptorSet(); - VkDeviceSize uniformBufferSizeAligned; + void setTextureDescriptor(const UniformInfo *info, love::graphics::Texture *texture, int index); + void setBufferDescriptor(const UniformInfo *info, love::graphics::Buffer *buffer, int index); VkPipeline computePipeline; - uint32_t numTextures; - uint32_t numBuffers; - uint32_t numBufferViews; - VkDescriptorSetLayout descriptorSetLayout; VkPipelineLayout pipelineLayout; std::vector descriptorPoolSizes; - // we don't know how much memory we need per frame for the uniform buffer descriptors - // we keep a vector of stream buffers that gets dynamically increased if more memory is needed - std::vector streamBuffers; std::vector> descriptorPools; + std::vector descriptorBuffers; + std::vector descriptorImages; + std::vector descriptorBufferViews; + std::vector descriptorWrites; + std::vector shaderStages; std::vector shaderModules; @@ -125,8 +127,9 @@ private: VkDevice device; bool isCompute = false; + bool resourceDescriptorsDirty = false; + VkDescriptorSet currentDescriptorSet = VK_NULL_HANDLE; - std::unordered_map uniformInfos; UniformInfo *builtinUniformInfo[BUILTIN_MAX_ENUM]; std::unique_ptr uniformBufferObjectBuffer; @@ -135,10 +138,9 @@ private: uint32_t localUniformLocation; OptionalInt builtinUniformDataOffset; - std::unordered_map attributes; + std::unordered_map attributes; uint32_t currentFrame; - uint32_t currentUsedUniformStreamBuffersCount; uint32_t currentDescriptorPool; }; diff --git a/src/modules/graphics/vulkan/ShaderStage.cpp b/src/modules/graphics/vulkan/ShaderStage.cpp index 2e3b70c5d..e7657affd 100644 --- a/src/modules/graphics/vulkan/ShaderStage.cpp +++ b/src/modules/graphics/vulkan/ShaderStage.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/vulkan/ShaderStage.h b/src/modules/graphics/vulkan/ShaderStage.h index f3c015f15..a084e2b81 100644 --- a/src/modules/graphics/vulkan/ShaderStage.h +++ b/src/modules/graphics/vulkan/ShaderStage.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/vulkan/StreamBuffer.cpp b/src/modules/graphics/vulkan/StreamBuffer.cpp index eba9e9681..517a69eaa 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.cpp +++ b/src/modules/graphics/vulkan/StreamBuffer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -96,6 +96,11 @@ ptrdiff_t StreamBuffer::getHandle() const return (ptrdiff_t) buffer; } +size_t StreamBuffer::getGPUReadOffset() const +{ + return (frameIndex * bufferSize) + frameGPUReadOffset; +} + love::graphics::StreamBuffer::MapInfo StreamBuffer::map(size_t /*minsize*/) { // TODO: do we also need to wait until a fence is complete, here? diff --git a/src/modules/graphics/vulkan/StreamBuffer.h b/src/modules/graphics/vulkan/StreamBuffer.h index 98cc86b14..c32533d13 100644 --- a/src/modules/graphics/vulkan/StreamBuffer.h +++ b/src/modules/graphics/vulkan/StreamBuffer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -47,6 +47,7 @@ public: virtual void unloadVolatile() override; + size_t getGPUReadOffset() const override; MapInfo map(size_t minsize) override; size_t unmap(size_t usedSize) override; void markUsed(size_t usedSize) override; diff --git a/src/modules/graphics/vulkan/Texture.cpp b/src/modules/graphics/vulkan/Texture.cpp index 60c55b9a8..ff51a4e49 100644 --- a/src/modules/graphics/vulkan/Texture.cpp +++ b/src/modules/graphics/vulkan/Texture.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -41,6 +41,19 @@ Texture::Texture(love::graphics::Graphics *gfx, const Settings &settings, const slices = *data; loadVolatile(); + + // ImageData is referenced by the first loadVolatile call, but we don't + // hang on to it after that so we can save memory. + slices.clear(); +} + +Texture::Texture(love::graphics::Graphics *gfx, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings) + : love::graphics::Texture(gfx, base, viewsettings) + , vgfx(dynamic_cast(gfx)) + , slices(viewsettings.type.get(base->getTextureType())) + , imageAspect(0) +{ + loadVolatile(); } bool Texture::loadVolatile() @@ -48,6 +61,8 @@ bool Texture::loadVolatile() allocator = vgfx->getVmaAllocator(); device = vgfx->getDevice(); + bool root = rootView.texture == this; + if (isPixelFormatDepth(format)) imageAspect |= VK_IMAGE_ASPECT_DEPTH_BIT; if (isPixelFormatStencil(format)) @@ -55,7 +70,7 @@ bool Texture::loadVolatile() if (isPixelFormatColor(format)) imageAspect |= VK_IMAGE_ASPECT_COLOR_BIT; - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + auto vulkanFormat = Vulkan::getTextureFormat(format); VkImageUsageFlags usageFlags = VK_IMAGE_USAGE_TRANSFER_SRC_BIT | @@ -75,82 +90,119 @@ bool Texture::loadVolatile() usageFlags |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; } - VkImageCreateFlags createFlags = 0; - layerCount = 1; if (texType == TEXTURE_2D_ARRAY) layerCount = getLayerCount(); else if (texType == TEXTURE_CUBE) - { layerCount = 6; - createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - } - msaaSamples = vgfx->getMsaaCount(requestedMSAA); - - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.flags = createFlags; - imageInfo.imageType = Vulkan::getImageType(getTextureType()); - imageInfo.extent.width = static_cast(pixelWidth); - imageInfo.extent.height = static_cast(pixelHeight); - imageInfo.extent.depth = static_cast(depth); - imageInfo.arrayLayers = static_cast(layerCount); - imageInfo.mipLevels = static_cast(mipmapCount); - imageInfo.format = vulkanFormat.internalFormat; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = usageFlags; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = msaaSamples; - - VmaAllocationCreateInfo imageAllocationCreateInfo{}; - - if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) - throw love::Exception("failed to create image"); - - auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); - - if (isPixelFormatDepthStencil(format)) - imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - else if (computeWrite) - imageLayout = VK_IMAGE_LAYOUT_GENERAL; - else - imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_UNDEFINED, imageLayout, - 0, VK_REMAINING_MIP_LEVELS, - 0, VK_REMAINING_ARRAY_LAYERS); - - bool hasdata = slices.get(0, 0) != nullptr; - - if (hasdata) + if (root) { - for (int mip = 0; mip < getMipmapCount(); mip++) - { - int sliceCount; - if (texType == TEXTURE_CUBE) - sliceCount = 6; - else - sliceCount = slices.getSliceCount(); + VkImageCreateFlags createFlags = 0; + std::vector vkviewformats; - for (int slice = 0; slice < sliceCount; slice++) + for (PixelFormat viewformat : viewFormats) + { + if (viewformat != format) { - auto id = slices.get(slice, mip); - if (id != nullptr) - uploadImageData(id, mip, slice, 0, 0); + createFlags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT; + TextureFormat f = Vulkan::getTextureFormat(viewformat); + vkviewformats.push_back(f.internalFormat); } } + + if (texType == TEXTURE_CUBE || (texType == TEXTURE_2D_ARRAY && layerCount >= 6 && pixelWidth == pixelHeight)) + createFlags |= VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; + + msaaSamples = vgfx->getMsaaCount(requestedMSAA); + + VkImageCreateInfo imageInfo{}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.flags = createFlags; + imageInfo.imageType = Vulkan::getImageType(getTextureType()); + imageInfo.extent.width = static_cast(pixelWidth); + imageInfo.extent.height = static_cast(pixelHeight); + imageInfo.extent.depth = static_cast(depth); + imageInfo.arrayLayers = static_cast(layerCount); + imageInfo.mipLevels = static_cast(mipmapCount); + imageInfo.format = vulkanFormat.internalFormat; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = usageFlags; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = msaaSamples; + + VkImageFormatListCreateInfo viewFormatsInfo{}; + viewFormatsInfo.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO; + + if (!vkviewformats.empty() && vgfx->getDeviceApiVersion() >= VK_API_VERSION_1_2) + { + viewFormatsInfo.viewFormatCount = (uint32)vkviewformats.size(); + viewFormatsInfo.pViewFormats = vkviewformats.data(); + + imageInfo.pNext = &viewFormatsInfo; + } + + VmaAllocationCreateInfo imageAllocationCreateInfo{}; + + if (vmaCreateImage(allocator, &imageInfo, &imageAllocationCreateInfo, &textureImage, &textureImageAllocation, nullptr) != VK_SUCCESS) + throw love::Exception("failed to create image"); + + auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); + + if (computeWrite) + imageLayout = VK_IMAGE_LAYOUT_GENERAL; + else if (readable) + imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + else if (renderTarget && isPixelFormatDepthStencil(format)) + imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + else if (renderTarget) + imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + else // TODO: is there a better layout for this situation? + imageLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + VK_IMAGE_LAYOUT_UNDEFINED, imageLayout, + 0, VK_REMAINING_MIP_LEVELS, + 0, VK_REMAINING_ARRAY_LAYERS); + + bool hasdata = slices.get(0, 0) != nullptr; + + if (hasdata) + { + for (int mip = 0; mip < getMipmapCount(); mip++) + { + int sliceCount; + if (texType == TEXTURE_CUBE) + sliceCount = 6; + else + sliceCount = slices.getSliceCount(); + + for (int slice = 0; slice < sliceCount; slice++) + { + auto id = slices.get(slice, mip); + if (id != nullptr) + uploadImageData(id, mip, slice, 0, 0); + } + } + } + else + clear(); } else - clear(); + { + Texture *roottex = (Texture *) rootView.texture; + textureImage = roottex->textureImage; + textureImageAllocation = VK_NULL_HANDLE; + imageLayout = roottex->imageLayout; + msaaSamples = roottex->msaaSamples; + } createTextureImageView(); - textureSampler = vgfx->getCachedSampler(samplerState); + setSamplerState(samplerState); - if (!isPixelFormatDepthStencil(format) && mipmapCount > 1 && getMipmapsMode() != MIPMAPS_NONE) + if (root && !isPixelFormatDepthStencil(format) && slices.getMipmapCount() <= 1 && getMipmapsMode() != MIPMAPS_NONE) generateMipmaps(); if (renderTarget) @@ -166,11 +218,13 @@ bool Texture::loadVolatile() viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = textureImage; viewInfo.viewType = Vulkan::getImageViewType(getTextureType()); + if (viewInfo.viewType == VK_IMAGE_VIEW_TYPE_CUBE) + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = vulkanFormat.internalFormat; viewInfo.subresourceRange.aspectMask = imageAspect; - viewInfo.subresourceRange.baseMipLevel = mip; + viewInfo.subresourceRange.baseMipLevel = mip + rootView.startMipmap; viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = slice; + viewInfo.subresourceRange.baseArrayLayer = slice + rootView.startLayer; viewInfo.subresourceRange.layerCount = 1; viewInfo.components.r = vulkanFormat.swizzleR; viewInfo.components.g = vulkanFormat.swizzleG; @@ -185,18 +239,42 @@ bool Texture::loadVolatile() int64 memsize = 0; - for (int mip = 0; mip < getMipmapCount(); mip++) + if (root) { - int w = getPixelWidth(mip); - int h = getPixelHeight(mip); - int slices = getDepth(mip) * layerCount; - memsize += getPixelFormatSliceSize(format, w, h) * slices; + for (int mip = 0; mip < getMipmapCount(); mip++) + { + int w = getPixelWidth(mip); + int h = getPixelHeight(mip); + int slices = getDepth(mip) * layerCount; + memsize += getPixelFormatSliceSize(format, w, h) * slices; + } + + memsize *= static_cast(msaaSamples); } - memsize *= static_cast(msaaSamples); - setGraphicsMemorySize(memsize); + if (!debugName.empty()) + { + if (vgfx->getEnabledOptionalInstanceExtensions().debugInfo) + { + VkDebugUtilsObjectNameInfoEXT nameInfo{}; + nameInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_OBJECT_NAME_INFO_EXT; + if (root) + { + nameInfo.objectType = VK_OBJECT_TYPE_IMAGE; + nameInfo.objectHandle = (uint64_t)textureImage; + } + else + { + nameInfo.objectType = VK_OBJECT_TYPE_IMAGE_VIEW; + nameInfo.objectHandle = (uint64_t)textureImageView; + } + nameInfo.pObjectName = debugName.c_str(); + vkSetDebugUtilsObjectNameEXT(device, &nameInfo); + } + } + return true; } @@ -213,13 +291,15 @@ void Texture::unloadVolatile() textureImageAllocation = textureImageAllocation, textureImageViews = std::move(renderTargetImageViews)] () { vkDestroyImageView(device, textureImageView, nullptr); - vmaDestroyImage(allocator, textureImage, textureImageAllocation); + if (textureImageAllocation) + vmaDestroyImage(allocator, textureImage, textureImageAllocation); for (const auto &views : textureImageViews) for (const auto &view : views) vkDestroyImageView(device, view, nullptr); }); textureImage = VK_NULL_HANDLE; + textureImageAllocation = VK_NULL_HANDLE; setGraphicsMemorySize(0); } @@ -261,9 +341,8 @@ ptrdiff_t Texture::getHandle() const void Texture::setSamplerState(const SamplerState &s) { - love::graphics::Texture::setSamplerState(s); - - textureSampler = vgfx->getCachedSampler(s); + samplerState = validateSamplerState(s); + textureSampler = vgfx->getCachedSampler(samplerState); } VkImageLayout Texture::getImageLayout() const @@ -273,17 +352,20 @@ VkImageLayout Texture::getImageLayout() const void Texture::createTextureImageView() { - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); - + auto vulkanFormat = Vulkan::getTextureFormat(format); VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; viewInfo.image = textureImage; viewInfo.viewType = Vulkan::getImageViewType(getTextureType()); viewInfo.format = vulkanFormat.internalFormat; viewInfo.subresourceRange.aspectMask = imageAspect; - viewInfo.subresourceRange.baseMipLevel = 0; + // This view is used in descriptor sets, where having both depth and + // stencil aspects in the same view isn't allowed. + if (imageAspect & VK_IMAGE_ASPECT_DEPTH_BIT) + viewInfo.subresourceRange.aspectMask &= ~VK_IMAGE_ASPECT_STENCIL_BIT; + viewInfo.subresourceRange.baseMipLevel = rootView.startMipmap; viewInfo.subresourceRange.levelCount = getMipmapCount(); - viewInfo.subresourceRange.baseArrayLayer = 0; + viewInfo.subresourceRange.baseArrayLayer = rootView.startLayer; viewInfo.subresourceRange.layerCount = layerCount; viewInfo.components.r = vulkanFormat.swizzleR; viewInfo.components.g = vulkanFormat.swizzleG; @@ -305,71 +387,71 @@ void Texture::clear() range.baseArrayLayer = 0; range.layerCount = VK_REMAINING_ARRAY_LAYERS; - if (imageLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) + VkImageLayout clearLayout = imageLayout == VK_IMAGE_LAYOUT_GENERAL ? imageLayout : VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + + if (clearLayout != imageLayout) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); - - auto clearColor = getClearValue(); - - vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clearColor, 1, &range); - - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + imageLayout, clearLayout, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); } - else if (imageLayout == VK_IMAGE_LAYOUT_GENERAL) - { - auto clearColor = getClearValue(); - vkCmdClearColorImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, &clearColor, 1, &range); - } - else + if (isPixelFormatDepthStencil(format)) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); - VkClearDepthStencilValue depthStencilColor{}; depthStencilColor.depth = 0.0f; depthStencilColor.stencil = 0; + vkCmdClearDepthStencilImage(commandBuffer, textureImage, clearLayout, &depthStencilColor, 1, &range); + } + else + { + auto clearColor = getClearColor(this, ColorD(0, 0, 0, 0)); + vkCmdClearColorImage(commandBuffer, textureImage, clearLayout, &clearColor, 1, &range); + } - vkCmdClearDepthStencilImage(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &depthStencilColor, 1, &range); - - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, + if (clearLayout != imageLayout) + { + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + clearLayout, imageLayout, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS); } } -VkClearColorValue Texture::getClearValue() +VkClearColorValue Texture::getClearColor(love::graphics::Texture *texture, const ColorD &color) { - auto vulkanFormat = Vulkan::getTextureFormat(format, sRGB); + PixelFormatType formattype = PIXELFORMATTYPE_SFLOAT; + if (texture != nullptr) + formattype = getPixelFormatInfo(texture->getPixelFormat()).dataType; - VkClearColorValue clearColor{}; - switch (vulkanFormat.internalFormatRepresentation) + VkClearColorValue c{}; + + switch (formattype) { - case FORMATREPRESENTATION_FLOAT: - clearColor.float32[0] = 0.0f; - clearColor.float32[1] = 0.0f; - clearColor.float32[2] = 0.0f; - clearColor.float32[3] = 0.0f; + case PIXELFORMATTYPE_SINT: + c.int32[0] = (int32)color.r; + c.int32[1] = (int32)color.g; + c.int32[2] = (int32)color.b; + c.int32[3] = (int32)color.a; break; - case FORMATREPRESENTATION_SINT: - clearColor.int32[0] = 0; - clearColor.int32[1] = 0; - clearColor.int32[2] = 0; - clearColor.int32[3] = 0; + case PIXELFORMATTYPE_UINT: + c.uint32[0] = (uint32)color.r; + c.uint32[1] = (uint32)color.g; + c.uint32[2] = (uint32)color.b; + c.uint32[3] = (uint32)color.a; break; - case FORMATREPRESENTATION_UINT: - clearColor.uint32[0] = 0; - clearColor.uint32[1] = 0; - clearColor.uint32[2] = 0; - clearColor.uint32[3] = 0; + default: + { + Colorf cf((float)color.r, (float)color.g, (float)color.b, (float)color.a); + gammaCorrectColor(cf); + c.float32[0] = cf.r; + c.float32[1] = cf.g; + c.float32[2] = cf.b; + c.float32[3] = cf.a; + } break; } - return clearColor; + + return c; } void Texture::generateMipmapsInternal() @@ -377,8 +459,8 @@ void Texture::generateMipmapsInternal() auto commandBuffer = vgfx->getCommandBufferForDataTransfer(); if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, + imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 0, static_cast(getMipmapCount()), 0, static_cast(layerCount)); VkImageMemoryBarrier barrier{}; @@ -387,16 +469,16 @@ void Texture::generateMipmapsInternal() barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.baseArrayLayer = rootView.startLayer; barrier.subresourceRange.layerCount = static_cast(layerCount); - barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.baseMipLevel = rootView.startMipmap; barrier.subresourceRange.levelCount = 1u; uint32_t mipLevels = static_cast(getMipmapCount()); for (uint32_t i = 1; i < mipLevels; i++) { - barrier.subresourceRange.baseMipLevel = i - 1; + barrier.subresourceRange.baseMipLevel = rootView.startMipmap + i - 1; barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; @@ -412,15 +494,15 @@ void Texture::generateMipmapsInternal() blit.srcOffsets[0] = { 0, 0, 0 }; blit.srcOffsets[1] = { getPixelWidth(i - 1), getPixelHeight(i - 1), 1 }; blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.mipLevel = rootView.startMipmap + i - 1; + blit.srcSubresource.baseArrayLayer = rootView.startLayer; blit.srcSubresource.layerCount = static_cast(layerCount); blit.dstOffsets[0] = { 0, 0, 0 }; blit.dstOffsets[1] = { getPixelWidth(i), getPixelHeight(i), 1 }; blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.mipLevel = rootView.startMipmap + i; + blit.dstSubresource.baseArrayLayer = rootView.startLayer; blit.dstSubresource.layerCount = static_cast(layerCount); vkCmdBlitImage(commandBuffer, @@ -430,7 +512,7 @@ void Texture::generateMipmapsInternal() VK_FILTER_LINEAR); barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.newLayout = imageLayout; barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; @@ -441,9 +523,9 @@ void Texture::generateMipmapsInternal() 1, &barrier); } - barrier.subresourceRange.baseMipLevel = mipLevels - 1; + barrier.subresourceRange.baseMipLevel = rootView.startMipmap + mipLevels - 1; barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.newLayout = imageLayout; barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; @@ -455,7 +537,7 @@ void Texture::generateMipmapsInternal() 1, &barrier); } -void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) +void Texture::uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) { VkBuffer stagingBuffer; VmaAllocation vmaAllocation; @@ -479,11 +561,11 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s region.bufferRowLength = 0; region.bufferImageHeight = 0; - uint32_t baseLayer; - if (getTextureType() == TEXTURE_VOLUME) - baseLayer = 0; - else - baseLayer = slice; + uint32_t baseLayer = rootView.startLayer; + if (getTextureType() != TEXTURE_VOLUME) + baseLayer += slice; + + level += rootView.startMipmap; region.imageSubresource.aspectMask = imageAspect; region.imageSubresource.mipLevel = level; @@ -503,7 +585,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, level, 1, baseLayer, 1); @@ -516,7 +598,7 @@ void Texture::uploadByteData(PixelFormat pixelformat, const void *data, size_t s ®ion ); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout, level, 1, baseLayer, 1); } @@ -541,8 +623,8 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int VkImageSubresourceLayers layers{}; layers.aspectMask = imageAspect; - layers.mipLevel = mipmap; - layers.baseArrayLayer = slice; + layers.mipLevel = mipmap + rootView.startMipmap; + layers.baseArrayLayer = slice + rootView.startLayer; layers.layerCount = 1; VkBufferImageCopy region{}; @@ -555,11 +637,11 @@ void Texture::copyFromBuffer(graphics::Buffer *source, size_t sourceoffset, int if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, imageLayout); } else vkCmdCopyBufferToImage(commandBuffer, (VkBuffer)source->getHandle(), textureImage, VK_IMAGE_LAYOUT_GENERAL, 1, ®ion); @@ -571,8 +653,8 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const VkImageSubresourceLayers layers{}; layers.aspectMask = imageAspect; - layers.mipLevel = mipmap; - layers.baseArrayLayer = slice; + layers.mipLevel = mipmap + rootView.startMipmap; + layers.baseArrayLayer = slice + rootView.startLayer; layers.layerCount = 1; VkBufferImageCopy region{}; @@ -586,11 +668,11 @@ void Texture::copyToBuffer(graphics::Buffer *dest, int slice, int mipmap, const if (imageLayout != VK_IMAGE_LAYOUT_GENERAL) { - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, imageLayout, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, (VkBuffer) dest->getHandle(), 1, ®ion); - Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout); + Vulkan::cmdTransitionImageLayout(commandBuffer, textureImage, format, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, imageLayout); } else vkCmdCopyImageToBuffer(commandBuffer, textureImage, VK_IMAGE_LAYOUT_GENERAL, (VkBuffer)dest->getHandle(), 1, ®ion); diff --git a/src/modules/graphics/vulkan/Texture.h b/src/modules/graphics/vulkan/Texture.h index 571621a05..e9dac8be7 100644 --- a/src/modules/graphics/vulkan/Texture.h +++ b/src/modules/graphics/vulkan/Texture.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -40,11 +40,13 @@ class Texture final , public Volatile { public: - Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data); - ~Texture(); - virtual bool loadVolatile() override; - virtual void unloadVolatile() override; + Texture(love::graphics::Graphics *gfx, const Settings &settings, const Slices *data); + Texture(love::graphics::Graphics *gfx, love::graphics::Texture *base, const Texture::ViewSettings &viewsettings); + virtual ~Texture(); + + bool loadVolatile() override; + void unloadVolatile() override; void setSamplerState(const SamplerState &s) override; @@ -59,19 +61,19 @@ public: VkImageView getRenderTargetView(int mip, int layer); VkSampleCountFlagBits getMsaaSamples() const; - void uploadByteData(PixelFormat pixelformat, const void *data, size_t size, int level, int slice, const Rect &r) override; + void uploadByteData(const void *data, size_t size, int level, int slice, const Rect &r) override; - void generateMipmapsInternal() override; + void generateMipmapsInternal() override; int getMSAA() const override; ptrdiff_t getHandle() const override; + static VkClearColorValue getClearColor(love::graphics::Texture *texture, const ColorD &color); + private: void createTextureImageView(); void clear(); - VkClearColorValue getClearValue(); - Graphics *vgfx = nullptr; VkDevice device = VK_NULL_HANDLE; VkImageAspectFlags imageAspect; diff --git a/src/modules/graphics/vulkan/Vulkan.cpp b/src/modules/graphics/vulkan/Vulkan.cpp index 817f6fdb7..dea2523a7 100644 --- a/src/modules/graphics/vulkan/Vulkan.cpp +++ b/src/modules/graphics/vulkan/Vulkan.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -130,16 +130,10 @@ VkFormat Vulkan::getVulkanVertexFormat(DataFormat format) } } -TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) +TextureFormat Vulkan::getTextureFormat(PixelFormat format) { TextureFormat textureFormat{}; - if (sRGB) - format = getSRGBPixelFormat(format); - - if (!isPixelFormatCompressed(format) && !isPixelFormatSRGB(format)) - sRGB = false; - switch (format) { case PIXELFORMAT_UNKNOWN: @@ -231,13 +225,13 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) case PIXELFORMAT_RGBA8_UNORM: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_UNORM; break; - case PIXELFORMAT_RGBA8_UNORM_sRGB: + case PIXELFORMAT_RGBA8_sRGB: textureFormat.internalFormat = VK_FORMAT_R8G8B8A8_SRGB; break; case PIXELFORMAT_BGRA8_UNORM: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_UNORM; break; - case PIXELFORMAT_BGRA8_UNORM_sRGB: + case PIXELFORMAT_BGRA8_sRGB: textureFormat.internalFormat = VK_FORMAT_B8G8R8A8_SRGB; break; case PIXELFORMAT_RGBA8_INT: @@ -297,6 +291,9 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; break; case PIXELFORMAT_DEPTH24_UNORM: + textureFormat.internalFormat = VK_FORMAT_X8_D24_UNORM_PACK32; + textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; + break; case PIXELFORMAT_DEPTH24_UNORM_STENCIL8: textureFormat.internalFormat = VK_FORMAT_D24_UNORM_S8_UINT; textureFormat.internalFormatRepresentation = FORMATREPRESENTATION_UINT; @@ -308,13 +305,22 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) textureFormat.internalFormat = VK_FORMAT_D32_SFLOAT_S8_UINT; break; case PIXELFORMAT_DXT1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC1_RGBA_SRGB_BLOCK : VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC1_RGBA_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT1_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC1_RGBA_SRGB_BLOCK; break; case PIXELFORMAT_DXT3_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC2_SRGB_BLOCK : VK_FORMAT_BC2_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC2_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT3_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC2_SRGB_BLOCK; break; case PIXELFORMAT_DXT5_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC3_SRGB_BLOCK : VK_FORMAT_BC3_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC3_UNORM_BLOCK; + break; + case PIXELFORMAT_DXT5_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC3_SRGB_BLOCK; break; case PIXELFORMAT_BC4_UNORM: textureFormat.internalFormat = VK_FORMAT_BC4_UNORM_BLOCK; @@ -335,31 +341,55 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) textureFormat.internalFormat = VK_FORMAT_BC6H_SFLOAT_BLOCK; break; case PIXELFORMAT_BC7_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_BC7_SRGB_BLOCK : VK_FORMAT_BC7_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_BC7_UNORM_BLOCK; + break; + case PIXELFORMAT_BC7_sRGB: + textureFormat.internalFormat = VK_FORMAT_BC7_SRGB_BLOCK; break; case PIXELFORMAT_PVR1_RGB2_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGB2_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGB4_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGB4_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGBA2_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGBA2_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_PVR1_RGBA4_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG : VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG; + break; + case PIXELFORMAT_PVR1_RGBA4_sRGB: + textureFormat.internalFormat = VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG; break; case PIXELFORMAT_ETC1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; break; case PIXELFORMAT_ETC2_RGB_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGB_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK; break; case PIXELFORMAT_ETC2_RGBA_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGBA_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK; break; case PIXELFORMAT_ETC2_RGBA1_UNORM: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK : VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK; + break; + case PIXELFORMAT_ETC2_RGBA1_sRGB: + textureFormat.internalFormat = VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK; break; case PIXELFORMAT_EAC_R_UNORM: textureFormat.internalFormat = VK_FORMAT_EAC_R11_UNORM_BLOCK; @@ -373,47 +403,89 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) case PIXELFORMAT_EAC_RG_SNORM: textureFormat.internalFormat = VK_FORMAT_EAC_R11G11_SNORM_BLOCK; break; - case PIXELFORMAT_ASTC_4x4: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_4x4_SRGB_BLOCK : VK_FORMAT_ASTC_4x4_UNORM_BLOCK; + case PIXELFORMAT_ASTC_4x4_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_4x4_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_5x4: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_5x4_SRGB_BLOCK : VK_FORMAT_ASTC_5x4_UNORM_BLOCK; + case PIXELFORMAT_ASTC_5x4_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x4_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_5x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_5x5_SRGB_BLOCK : VK_FORMAT_ASTC_5x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_5x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_6x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_6x5_SRGB_BLOCK : VK_FORMAT_ASTC_6x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_6x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_6x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_6x6_SRGB_BLOCK : VK_FORMAT_ASTC_6x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_6x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x5_SRGB_BLOCK : VK_FORMAT_ASTC_8x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x6_SRGB_BLOCK : VK_FORMAT_ASTC_8x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_8x8: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_8x8_SRGB_BLOCK : VK_FORMAT_ASTC_8x8_UNORM_BLOCK; + case PIXELFORMAT_ASTC_8x8_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x8_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x5: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x5_SRGB_BLOCK : VK_FORMAT_ASTC_10x5_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x5_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x5_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x6: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x6_SRGB_BLOCK : VK_FORMAT_ASTC_10x6_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x6_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x6_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x8: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x8_SRGB_BLOCK : VK_FORMAT_ASTC_10x8_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x8_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x8_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_10x10: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_10x10_SRGB_BLOCK : VK_FORMAT_ASTC_10x10_UNORM_BLOCK; + case PIXELFORMAT_ASTC_10x10_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x10_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_12x10: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_12x10_SRGB_BLOCK : VK_FORMAT_ASTC_12x10_UNORM_BLOCK; + case PIXELFORMAT_ASTC_12x10_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x10_UNORM_BLOCK; break; - case PIXELFORMAT_ASTC_12x12: - textureFormat.internalFormat = sRGB ? VK_FORMAT_ASTC_12x12_SRGB_BLOCK : VK_FORMAT_ASTC_12x12_UNORM_BLOCK; + case PIXELFORMAT_ASTC_12x12_UNORM: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x12_UNORM_BLOCK; + break; + case PIXELFORMAT_ASTC_4x4_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_4x4_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_5x4_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x4_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_5x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_5x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_6x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_6x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_6x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_8x8_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_8x8_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x5_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x5_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x6_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x6_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x8_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x8_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_10x10_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_10x10_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_12x10_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x10_SRGB_BLOCK; + break; + case PIXELFORMAT_ASTC_12x12_sRGB: + textureFormat.internalFormat = VK_FORMAT_ASTC_12x12_SRGB_BLOCK; break; default: throw love::Exception("unknown pixel format"); @@ -422,13 +494,14 @@ TextureFormat Vulkan::getTextureFormat(PixelFormat format, bool sRGB) return textureFormat; } -// values taken from https://pcisig.com/membership/member-companies +// values taken from https://pcisig.com/membership/member-companies and https://vulkan.gpuinfo.org/displaycoreproperty.php?name=vendorid&platform=all // as specified at https://www.khronos.org/registry/vulkan/specs/1.3-extensions/man/html/VkPhysicalDeviceProperties.html std::string Vulkan::getVendorName(uint32_t vendorId) { switch (vendorId) { case 4130: + case 4098: return "AMD"; case 4318: return "Nvidia"; @@ -444,6 +517,8 @@ std::string Vulkan::getVendorName(uint32_t vendorId) return "Qualcomm"; case 5348: return "Broadcom"; + case 65541: + return "Mesa"; default: return "unknown"; } @@ -747,7 +822,7 @@ VkIndexType Vulkan::getVulkanIndexBufferType(IndexDataType type) } } -static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags, bool &depthStencil) +static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, VkAccessFlags &accessMask, VkPipelineStageFlags &stageFlags) { switch (layout) { @@ -769,7 +844,6 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, stageFlags = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; break; case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL: - depthStencil = true; accessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT; stageFlags = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT; break; @@ -794,7 +868,7 @@ static void setImageLayoutTransitionOptions(bool previous, VkImageLayout layout, } } -void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) +void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel, uint32_t levelCount, uint32_t baseLayer, uint32_t layerCount) { VkImageMemoryBarrier barrier{}; barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; @@ -808,17 +882,19 @@ void Vulkan::cmdTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage ima barrier.subresourceRange.baseArrayLayer = baseLayer; barrier.subresourceRange.layerCount = layerCount; - bool depthStencil = false; VkPipelineStageFlags sourceStage; VkPipelineStageFlags destinationStage; - setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage, depthStencil); - setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage, depthStencil); + setImageLayoutTransitionOptions(true, oldLayout, barrier.srcAccessMask, sourceStage); + setImageLayoutTransitionOptions(false, newLayout, barrier.dstAccessMask, destinationStage); - if (depthStencil) - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT; - else - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + const PixelFormatInfo &info = getPixelFormatInfo(format); + if (info.color) + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_COLOR_BIT; + if (info.depth) + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; + if (info.stencil) + barrier.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; vkCmdPipelineBarrier( commandBuffer, diff --git a/src/modules/graphics/vulkan/Vulkan.h b/src/modules/graphics/vulkan/Vulkan.h index 2e512ab9d..7e4db7c70 100644 --- a/src/modules/graphics/vulkan/Vulkan.h +++ b/src/modules/graphics/vulkan/Vulkan.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -59,7 +59,7 @@ public: static void resetShaderSwitches(); static VkFormat getVulkanVertexFormat(DataFormat format); - static TextureFormat getTextureFormat(PixelFormat, bool sRGB); + static TextureFormat getTextureFormat(PixelFormat format); static std::string getVendorName(uint32_t vendorId); static std::string getVulkanApiVersion(uint32_t apiVersion); static VkPrimitiveTopology getPrimitiveTypeTopology(graphics::PrimitiveType); @@ -81,7 +81,7 @@ public: static VkIndexType getVulkanIndexBufferType(IndexDataType type); static void cmdTransitionImageLayout( - VkCommandBuffer, VkImage, VkImageLayout oldLayout, VkImageLayout newLayout, + VkCommandBuffer, VkImage, PixelFormat format, VkImageLayout oldLayout, VkImageLayout newLayout, uint32_t baseLevel = 0, uint32_t levelCount = VK_REMAINING_MIP_LEVELS, uint32_t baseLayer = 0, uint32_t layerCount = VK_REMAINING_ARRAY_LAYERS); }; diff --git a/src/modules/graphics/vulkan/VulkanWrapper.h b/src/modules/graphics/vulkan/VulkanWrapper.h index c09617163..6ac7c6da5 100644 --- a/src/modules/graphics/vulkan/VulkanWrapper.h +++ b/src/modules/graphics/vulkan/VulkanWrapper.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Buffer.cpp b/src/modules/graphics/wrap_Buffer.cpp index c9bb30d4d..3f6d4960a 100644 --- a/src/modules/graphics/wrap_Buffer.cpp +++ b/src/modules/graphics/wrap_Buffer.cpp @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,7 +46,7 @@ template static inline size_t writeSNormData(lua_State *L, int startidx, int components, char *data) { auto componentdata = (T *) data; - const auto maxval = std::numeric_limits::max(); + constexpr auto maxval = std::numeric_limits::max(); for (int i = 0; i < components; i++) componentdata[i] = (T) (luax_optnumberclamped(L, startidx + i, -1.0, 1.0, defaultComponents[i]) * maxval); @@ -58,7 +58,7 @@ template static inline size_t writeUNormData(lua_State *L, int startidx, int components, char *data) { auto componentdata = (T *) data; - const auto maxval = std::numeric_limits::max(); + constexpr auto maxval = std::numeric_limits::max(); for (int i = 0; i < components; i++) componentdata[i] = (T) (luax_optnumberclamped01(L, startidx + i, 1.0) * maxval); @@ -66,6 +66,17 @@ static inline size_t writeUNormData(lua_State *L, int startidx, int components, return sizeof(T) * components; } +template +static inline size_t writeDataRequired(lua_State *L, int startidx, int components, char *data) +{ + auto componentdata = (T*)data; + + for (int i = 0; i < components; i++) + componentdata[i] = (T)(luaL_checknumber(L, startidx + i)); + + return sizeof(T) * components; +} + void luax_writebufferdata(lua_State *L, int startidx, DataFormat format, char *data) { switch (format) @@ -75,6 +86,18 @@ void luax_writebufferdata(lua_State *L, int startidx, DataFormat format, char *d case DATAFORMAT_FLOAT_VEC3: writeData(L, startidx, 3, data); break; case DATAFORMAT_FLOAT_VEC4: writeData(L, startidx, 4, data); break; + case DATAFORMAT_FLOAT_MAT2X2: writeDataRequired(L, startidx, 4, data); break; + case DATAFORMAT_FLOAT_MAT2X3: writeDataRequired(L, startidx, 6, data); break; + case DATAFORMAT_FLOAT_MAT2X4: writeDataRequired(L, startidx, 8, data); break; + + case DATAFORMAT_FLOAT_MAT3X2: writeDataRequired(L, startidx, 6, data); break; + case DATAFORMAT_FLOAT_MAT3X3: writeDataRequired(L, startidx, 9, data); break; + case DATAFORMAT_FLOAT_MAT3X4: writeDataRequired(L, startidx, 12, data); break; + + case DATAFORMAT_FLOAT_MAT4X2: writeDataRequired(L, startidx, 8, data); break; + case DATAFORMAT_FLOAT_MAT4X3: writeDataRequired(L, startidx, 12, data); break; + case DATAFORMAT_FLOAT_MAT4X4: writeDataRequired(L, startidx, 16, data); break; + case DATAFORMAT_INT32: writeData(L, startidx, 1, data); break; case DATAFORMAT_INT32_VEC2: writeData(L, startidx, 2, data); break; case DATAFORMAT_INT32_VEC3: writeData(L, startidx, 3, data); break; @@ -122,7 +145,7 @@ template static inline size_t readSNormData(lua_State *L, int components, const char *data) { const auto componentdata = (const T *) data; - const auto maxval = std::numeric_limits::max(); + constexpr auto maxval = std::numeric_limits::max(); for (int i = 0; i < components; i++) lua_pushnumber(L, std::max(-1.0, (lua_Number) componentdata[i] / (lua_Number)maxval)); @@ -134,7 +157,7 @@ template static inline size_t readUNormData(lua_State *L, int components, const char *data) { const auto componentdata = (const T *) data; - const auto maxval = std::numeric_limits::max(); + constexpr auto maxval = std::numeric_limits::max(); for (int i = 0; i < components; i++) lua_pushnumber(L, (lua_Number) componentdata[i] / (lua_Number)maxval); @@ -401,6 +424,17 @@ static int w_Buffer_isBufferType(lua_State *L) return 1; } +static int w_Buffer_getDebugName(lua_State *L) +{ + Buffer *t = luax_checkbuffer(L, 1); + const std::string &debugName = t->getDebugName(); + if (debugName.empty()) + lua_pushnil(L); + else + luax_pushstring(L, debugName); + return 1; +} + static const luaL_Reg w_Buffer_functions[] = { { "setArrayData", w_Buffer_setArrayData }, @@ -410,6 +444,7 @@ static const luaL_Reg w_Buffer_functions[] = { "getSize", w_Buffer_getSize }, { "getFormat", w_Buffer_getFormat }, { "isBufferType", w_Buffer_isBufferType }, + { "getDebugName", w_Buffer_getDebugName }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Buffer.h b/src/modules/graphics/wrap_Buffer.h index 35a5742a7..9676b99bb 100644 --- a/src/modules/graphics/wrap_Buffer.h +++ b/src/modules/graphics/wrap_Buffer.h @@ -1,5 +1,5 @@ /** -* Copyright (c) 2006-2023 LOVE Development Team +* Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Font.cpp b/src/modules/graphics/wrap_Font.cpp index 807feefbd..1982daa84 100644 --- a/src/modules/graphics/wrap_Font.cpp +++ b/src/modules/graphics/wrap_Font.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Font.h b/src/modules/graphics/wrap_Font.h index 69ff068d6..404b215af 100644 --- a/src/modules/graphics/wrap_Font.h +++ b/src/modules/graphics/wrap_Font.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 097c0534d..ba8faff05 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -608,52 +608,78 @@ int w_setStencilMode(lua_State *L) { if (lua_gettop(L) <= 1 && lua_isnoneornil(L, 1)) { - luax_catchexcept(L, [&](){ instance()->setStencilMode(); }); + luax_catchexcept(L, [&]() { instance()->setStencilMode(); }); return 0; } - StencilAction action = STENCIL_KEEP; - const char *actionstr = luaL_checkstring(L, 1); - if (!getConstant(actionstr, action)) - return luax_enumerror(L, "stencil draw action", getConstants(action), actionstr); + StencilMode mode = STENCIL_MODE_OFF; + const char *modestr = luaL_checkstring(L, 1); + if (!getConstant(modestr, mode)) + return luax_enumerror(L, "stencil mode", getConstants(mode), modestr); - CompareMode compare = COMPARE_ALWAYS; - const char *comparestr = luaL_checkstring(L, 2); - if (!getConstant(comparestr, compare)) - return luax_enumerror(L, "compare mode", getConstants(compare), comparestr); + int value = (int) luaL_optinteger(L, 3, 1); - int value = (int) luaL_optinteger(L, 3, 0); - - uint32 readmask = (uint32) luaL_optnumber(L, 4, LOVE_UINT32_MAX); - uint32 writemask = (uint32) luaL_optnumber(L, 5, LOVE_UINT32_MAX); - - luax_catchexcept(L, [&](){ instance()->setStencilMode(action, compare, value, readmask, writemask); }); + luax_catchexcept(L, [&]() { instance()->setStencilMode(mode, value); }); return 0; } int w_getStencilMode(lua_State *L) { - StencilAction action = STENCIL_KEEP; - CompareMode compare = COMPARE_ALWAYS; - int value = 1; - uint32 readmask = LOVE_UINT32_MAX; - uint32 writemask = LOVE_UINT32_MAX; + int value = 0; + StencilMode mode = instance()->getStencilMode(value); - instance()->getStencilMode(action, compare, value, readmask, writemask); + const char *modestr; + if (!getConstant(mode, modestr)) + return luaL_error(L, "Unknown stencil mode."); + + lua_pushstring(L, modestr); + lua_pushinteger(L, value); + return 2; +} + +int w_setStencilState(lua_State *L) +{ + if (lua_gettop(L) <= 1 && lua_isnoneornil(L, 1)) + { + luax_catchexcept(L, [&](){ instance()->setStencilState(); }); + return 0; + } + + StencilState s; + + const char *actionstr = luaL_checkstring(L, 1); + if (!getConstant(actionstr, s.action)) + return luax_enumerror(L, "stencil draw action", getConstants(s.action), actionstr); + + const char *comparestr = luaL_checkstring(L, 2); + if (!getConstant(comparestr, s.compare)) + return luax_enumerror(L, "compare mode", getConstants(s.compare), comparestr); + + s.value = (int) luaL_optinteger(L, 3, 0); + s.readMask = (uint32) luaL_optnumber(L, 4, LOVE_UINT32_MAX); + s.writeMask = (uint32) luaL_optnumber(L, 5, LOVE_UINT32_MAX); + + luax_catchexcept(L, [&](){ instance()->setStencilState(s); }); + return 0; +} + +int w_getStencilState(lua_State *L) +{ + const StencilState &s = instance()->getStencilState(); const char *actionstr; - if (!getConstant(action, actionstr)) + if (!getConstant(s.action, actionstr)) return luaL_error(L, "Unknown stencil draw action."); const char *comparestr; - if (!getConstant(compare, comparestr)) + if (!getConstant(s.compare, comparestr)) return luaL_error(L, "Unknown compare mode."); lua_pushstring(L, actionstr); lua_pushstring(L, comparestr); - lua_pushnumber(L, value); - lua_pushnumber(L, readmask); - lua_pushnumber(L, writemask); + lua_pushinteger(L, s.value); + lua_pushnumber(L, s.readMask); + lua_pushnumber(L, s.writeMask); return 5; } @@ -738,6 +764,13 @@ static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool chec if (!forceRenderTarget.hasValue) s.renderTarget = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_RENDER_TARGET), s.renderTarget); + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_DEBUGNAME)); + if (!lua_isnoneornil(L, -1)) + { + s.debugName = luaL_checkstring(L, -1); + } + lua_pop(L, 1); + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_FORMAT)); if (!lua_isnoneornil(L, -1)) { @@ -766,6 +799,13 @@ static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool chec if (s.type == TEXTURE_2D_ARRAY || s.type == TEXTURE_VOLUME) s.layers = luax_checkintflag(L, idx, Texture::getConstant(Texture::SETTING_LAYERS)); } + else + { + s.width = luax_intflag(L, idx, Texture::getConstant(Texture::SETTING_WIDTH), s.width); + s.height = luax_intflag(L, idx, Texture::getConstant(Texture::SETTING_HEIGHT), s.height); + if (s.type == TEXTURE_2D_ARRAY || s.type == TEXTURE_VOLUME) + s.layers = luax_intflag(L, idx, Texture::getConstant(Texture::SETTING_LAYERS), s.layers); + } lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_MIPMAPS)); if (!lua_isnoneornil(L, -1)) @@ -791,6 +831,25 @@ static void luax_checktexturesettings(lua_State *L, int idx, bool opt, bool chec s.computeWrite = luax_boolflag(L, idx, Texture::getConstant(Texture::SETTING_COMPUTE_WRITE), s.computeWrite); + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_VIEW_FORMATS)); + if (!lua_isnoneornil(L, -1)) + { + if (lua_type(L, -1) != LUA_TTABLE) + luaL_argerror(L, idx, "expected field 'viewformats' to be a table type"); + + for (int i = 1; i <= luax_objlen(L, -1); i++) + { + lua_rawgeti(L, -1, i); + const char *str = luaL_checkstring(L, -1); + PixelFormat viewformat = PIXELFORMAT_UNKNOWN; + if (!getConstant(str, viewformat)) + luax_enumerror(L, "pixel format", str); + s.viewFormats.push_back(viewformat); + lua_pop(L, 1); + } + } + lua_pop(L, 1); + lua_getfield(L, idx, Texture::getConstant(Texture::SETTING_READABLE)); if (!lua_isnoneornil(L, -1)) s.readable.set(luax_checkboolean(L, -1)); @@ -1207,6 +1266,66 @@ int w_newVolumeImage(lua_State *L) return w_newVolumeTexture(L); } +int w_newTextureView(lua_State *L) +{ + Texture *base = luax_checktexture(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + + Texture::ViewSettings settings; + + lua_getfield(L, 2, "format"); + if (!lua_isnoneornil(L, -1)) + { + const char *str = luaL_checkstring(L, -1); + if (!getConstant(str, settings.format.value)) + luax_enumerror(L, "pixel format", str); + settings.format.hasValue = true; + } + lua_pop(L, 1); + + lua_getfield(L, 2, "type"); + if (!lua_isnoneornil(L, -1)) + { + const char *str = luaL_checkstring(L, -1); + if (!Texture::getConstant(str, settings.type.value)) + luax_enumerror(L, "texture type", Texture::getConstants(settings.type.value), str); + settings.type.hasValue = true; + } + lua_pop(L, 1); + + lua_getfield(L, 2, "mipmapstart"); + if (!lua_isnoneornil(L, -1)) + settings.mipmapStart.set(luaL_checkint(L, -1) - 1); + lua_pop(L, 1); + + lua_getfield(L, 2, "mipmapcount"); + if (!lua_isnoneornil(L, -1)) + settings.mipmapCount.set(luaL_checkint(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, 2, "layerstart"); + if (!lua_isnoneornil(L, -1)) + settings.layerStart.set(luaL_checkint(L, -1) - 1); + lua_pop(L, 1); + + lua_getfield(L, 2, "layers"); + if (!lua_isnoneornil(L, -1)) + settings.layerCount.set(luaL_checkint(L, -1)); + lua_pop(L, 1); + + lua_getfield(L, 2, "debugname"); + if (!lua_isnoneornil(L, -1)) + settings.debugName = luaL_checkstring(L, -1); + lua_pop(L, 1); + + Texture *t = nullptr; + luax_catchexcept(L, [&]() { t = instance()->newTextureView(base, settings); }); + + luax_pushtype(L, t); + t->release(); + return 1; +} + int w_newQuad(lua_State *L) { luax_checkgraphicscreated(L); @@ -1456,6 +1575,11 @@ static int w_getShaderSource(lua_State *L, int startidx, std::vectornewShader(stages, options); + if (shader->isUsingDeprecatedTextureFunctions()) + luax_markdeprecated(L, 1, "texture2D() or textureCube() function calls in shader code", API_CUSTOM, DEPRECATED_REPLACED, "texture() function calls"); + if (shader->isUsingDeprecatedTextureUniform()) + luax_markdeprecated(L, 1, "'texture' uniform variable name in shader code", API_CUSTOM, DEPRECATED_NO_REPLACEMENT, ""); luax_pushtype(L, shader); shader->release(); } @@ -1500,6 +1628,10 @@ int w_newComputeShader(lua_State* L) try { Shader *shader = instance()->newComputeShader(stages[0], options); + if (shader->isUsingDeprecatedTextureFunctions()) + luax_markdeprecated(L, 1, "texture2D() or textureCube() function calls in shader code", API_CUSTOM, DEPRECATED_REPLACED, "texture() function calls"); + if (shader->isUsingDeprecatedTextureUniform()) + luax_markdeprecated(L, 1, "'texture' uniform variable name in shader code", API_CUSTOM, DEPRECATED_NO_REPLACEMENT, ""); luax_pushtype(L, shader); shader->release(); } @@ -1570,6 +1702,11 @@ static void luax_optbuffersettings(lua_State *L, int idx, Buffer::Settings &sett lua_getfield(L, idx, "usage"); settings.dataUsage = luax_optdatausage(L, -1, settings.dataUsage); lua_pop(L, 1); + + lua_getfield(L, idx, "debugname"); + if (!lua_isnoneornil(L, -1)) + settings.debugName = luax_checkstring(L, -1); + lua_pop(L, 1); } static Buffer::DataDeclaration luax_checkdatadeclaration(lua_State* L, int formattableidx, int arrayindex, int declindex, bool requirename) @@ -1912,7 +2049,7 @@ static Mesh *newCustomMesh(lua_State *L) } if (decl.format == DATAFORMAT_MAX_ENUM) - luax_enumerror(L, "vertex data format", getConstants(decl.format), tname); + luax_enumerror(L, "vertex data type", {"float", "byte", "unorm8", "unorm16"}, tname); lua_pop(L, 3); @@ -1990,6 +2127,79 @@ static Mesh *newCustomMesh(lua_State *L) return t; } +static bool luax_isbufferattributetable(lua_State* L, int idx) +{ + if (lua_type(L, idx) != LUA_TTABLE) + return false; + + lua_rawgeti(L, idx, 1); + if (lua_type(L, -1) != LUA_TTABLE) + { + lua_pop(L, 1); + return false; + } + + lua_getfield(L, -1, "buffer"); + bool isbuffer = luax_istype(L, -1, Buffer::type); + lua_pop(L, 2); + return isbuffer; +} + +static Mesh::BufferAttribute luax_checkbufferattributetable(lua_State *L, int idx) +{ + Mesh::BufferAttribute attrib = {}; + + attrib.step = STEP_PER_VERTEX; + attrib.enabled = true; + + lua_getfield(L, idx, "buffer"); + attrib.buffer = luax_checkbuffer(L, -1); + lua_pop(L, 1); + + lua_getfield(L, idx, "name"); + attrib.name = luax_checkstring(L, -1); + lua_pop(L, 1); + + lua_getfield(L, idx, "step"); + if (!lua_isnoneornil(L, -1)) + { + const char *stepstr = luaL_checkstring(L, -1); + if (!getConstant(stepstr, attrib.step)) + luax_enumerror(L, "vertex attribute step", getConstants(attrib.step), stepstr); + } + lua_pop(L, 1); + + lua_getfield(L, idx, "nameinbuffer"); + if (!lua_isnoneornil(L, -1)) + attrib.nameInBuffer = luax_checkstring(L, -1); + else + attrib.nameInBuffer = attrib.name; + lua_pop(L, 1); + + lua_getfield(L, idx, "startindex"); + attrib.startArrayIndex = (int) luaL_optinteger(L, -1, 1) - 1; + lua_pop(L, 1); + + return attrib; +} + +static Mesh* newMeshFromBuffers(lua_State *L) +{ + std::vector attributes; + for (size_t i = 1; i <= luax_objlen(L, 1); i++) + { + lua_rawgeti(L, 1, i); + attributes.push_back(luax_checkbufferattributetable(L, -1)); + lua_pop(L, 1); + } + + PrimitiveType drawmode = luax_checkmeshdrawmode(L, 2); + + Mesh *t = nullptr; + luax_catchexcept(L, [&]() { t = instance()->newMesh(attributes, drawmode); }); + return t; +} + int w_newMesh(lua_State *L) { luax_checkgraphicscreated(L); @@ -2002,7 +2212,9 @@ int w_newMesh(lua_State *L) Mesh *t = nullptr; int arg2type = lua_type(L, 2); - if (arg1type == LUA_TTABLE && (arg2type == LUA_TTABLE || arg2type == LUA_TNUMBER || arg2type == LUA_TUSERDATA)) + if (luax_isbufferattributetable(L, 1)) + t = newMeshFromBuffers(L); + else if (arg1type == LUA_TTABLE && (arg2type == LUA_TTABLE || arg2type == LUA_TNUMBER || arg2type == LUA_TUSERDATA)) t = newCustomMesh(L); else t = newStandardMesh(L); @@ -2280,7 +2492,11 @@ int w_setColorMask(lua_State *L) { ColorChannelMask mask; - if (lua_gettop(L) <= 1) + if (lua_isnoneornil(L, 1)) + { + mask.r = mask.g = mask.b = mask.a = true; + } + else if (lua_gettop(L) <= 1) { // Set all color components if a single argument is given. mask.r = mask.g = mask.b = mask.a = luax_checkboolean(L, 1); @@ -2708,7 +2924,6 @@ int w_getTextureFormats(lua_State *L) luaL_checktype(L, 1, LUA_TTABLE); bool rt = luax_checkboolflag(L, 1, Texture::getConstant(Texture::SETTING_RENDER_TARGET)); - bool linear = luax_boolflag(L, 1, Texture::getConstant(Texture::SETTING_LINEAR), false); bool computewrite = luax_boolflag(L, 1, Texture::getConstant(Texture::SETTING_COMPUTE_WRITE), false); OptionalBool readable; @@ -2730,11 +2945,6 @@ int w_getTextureFormats(lua_State *L) if (format == PIXELFORMAT_UNKNOWN || !love::getConstant(format, name)) continue; - if (rt && isPixelFormatDepth(format)) - continue; - - bool sRGB = isGammaCorrect() && !linear; - uint32 usage = PIXELFORMATUSAGEFLAGS_NONE; if (rt) usage |= PIXELFORMATUSAGEFLAGS_RENDERTARGET; @@ -2743,7 +2953,7 @@ int w_getTextureFormats(lua_State *L) if (computewrite) usage |= PIXELFORMATUSAGEFLAGS_COMPUTEWRITE; - luax_pushboolean(L, instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, sRGB)); + luax_pushboolean(L, instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage)); lua_setfield(L, -2, name); } @@ -2787,14 +2997,14 @@ int w_getCanvasFormats(lua_State *L) supported = [](PixelFormat format) -> bool { const uint32 usage = PIXELFORMATUSAGEFLAGS_SAMPLE | PIXELFORMATUSAGEFLAGS_RENDERTARGET; - return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, false); + return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage); }; } else { supported = [](PixelFormat format) -> bool { - return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_RENDERTARGET, false); + return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_RENDERTARGET); }; } } @@ -2806,7 +3016,7 @@ int w_getCanvasFormats(lua_State *L) uint32 usage = PIXELFORMATUSAGEFLAGS_RENDERTARGET; if (readable) usage |= PIXELFORMATUSAGEFLAGS_SAMPLE; - return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage, false); + return instance()->isPixelFormatSupported(format, (PixelFormatUsageFlags) usage); }; } @@ -2819,7 +3029,7 @@ int w_getImageFormats(lua_State *L) const auto supported = [](PixelFormat format) -> bool { - return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_SAMPLE, false); + return instance()->isPixelFormatSupported(format, PIXELFORMATUSAGEFLAGS_SAMPLE); }; const auto ignore = [](PixelFormat format) -> bool @@ -2917,9 +3127,15 @@ int w_getStats(lua_State *L) lua_pushinteger(L, stats.fonts); lua_setfield(L, -2, "fonts"); - lua_pushinteger(L, stats.textureMemory); + lua_pushinteger(L, stats.buffers); + lua_setfield(L, -2, "buffers"); + + lua_pushnumber(L, (lua_Number) stats.textureMemory); lua_setfield(L, -2, "texturememory"); + lua_pushnumber(L, (lua_Number) stats.bufferMemory); + lua_setfield(L, -2, "buffermemory"); + return 1; } @@ -2927,13 +3143,12 @@ int w_draw(lua_State *L) { Drawable *drawable = nullptr; Texture *texture = nullptr; - Quad *quad = nullptr; + Quad *quad = luax_totype(L, 2); int startidx = 2; - if (luax_istype(L, 2, Quad::type)) + if (quad != nullptr) { texture = luax_checktexture(L, 1); - quad = luax_totype(L, 2); startidx = 3; } else if (lua_isnil(L, 2) && !lua_isnoneornil(L, 3)) @@ -2963,14 +3178,14 @@ int w_draw(lua_State *L) int w_drawLayer(lua_State *L) { Texture *texture = luax_checktexture(L, 1); - Quad *quad = nullptr; int layer = (int) luaL_checkinteger(L, 2) - 1; - int startidx = 3; - if (luax_istype(L, startidx, Quad::type)) + int startidx = 3; + Quad *quad = luax_totype(L, startidx); + + if (quad != nullptr) { texture = luax_checktexture(L, 1); - quad = luax_totype(L, startidx); startidx++; } else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) @@ -3690,25 +3905,31 @@ int w_inverseTransformPoint(lua_State *L) return 2; } -int w_setOrthoProjection(lua_State *L) +int w_setProjection(lua_State *L) { - float w = (float) luaL_checknumber(L, 1); - float h = (float) luaL_checknumber(L, 2); - float near = (float) luaL_optnumber(L, 3, -10.0); - float far = (float) luaL_optnumber(L, 4, 10.0); + math::Transform *transform = luax_totype(L, 1); + if (transform != nullptr) + { + instance()->setProjection(transform->getMatrix()); + return 0; + } - luax_catchexcept(L, [&]() { instance()->setOrthoProjection(w, h, near, far); }); - return 0; -} + math::Transform::MatrixLayout layout = math::Transform::MATRIX_ROW_MAJOR; -int w_setPerspectiveProjection(lua_State *L) -{ - float verticalfov = (float) luaL_checknumber(L, 1); - float aspect = (float) luaL_checknumber(L, 2); - float near = (float) luaL_checknumber(L, 3); - float far = (float) luaL_checknumber(L, 4); + int idx = 1; + if (lua_type(L, idx) == LUA_TSTRING) + { + const char* layoutstr = lua_tostring(L, idx); + if (!math::Transform::getConstant(layoutstr, layout)) + return luax_enumerror(L, "matrix layout", math::Transform::getConstants(layout), layoutstr); - luax_catchexcept(L, [&]() { instance()->setPerspectiveProjection(verticalfov, aspect, near, far); }); + idx++; + } + + float elements[16]; + love::math::luax_checkmatrix(L, idx, layout, elements); + + instance()->setProjection(Matrix4(elements)); return 0; } @@ -3732,6 +3953,7 @@ static const luaL_Reg functions[] = { "newCubeTexture", w_newCubeTexture }, { "newArrayTexture", w_newArrayTexture }, { "newVolumeTexture", w_newVolumeTexture }, + { "newTextureView", w_newTextureView }, { "newQuad", w_newQuad }, { "newFont", w_newFont }, { "newImageFont", w_newImageFont }, @@ -3837,6 +4059,8 @@ static const luaL_Reg functions[] = { "setStencilMode", w_setStencilMode }, { "getStencilMode", w_getStencilMode }, + { "setStencilState", w_setStencilState }, + { "getStencilState", w_getStencilState }, { "points", w_points }, { "line", w_line }, @@ -3861,8 +4085,7 @@ static const luaL_Reg functions[] = { "transformPoint", w_transformPoint }, { "inverseTransformPoint", w_inverseTransformPoint }, - { "setOrthoProjection", w_setOrthoProjection }, - { "setPerspectiveProjection", w_setPerspectiveProjection }, + { "setProjection", w_setProjection }, { "resetProjection", w_resetProjection }, // Deprecated diff --git a/src/modules/graphics/wrap_Graphics.h b/src/modules/graphics/wrap_Graphics.h index b1a1c2f00..9946f161f 100644 --- a/src/modules/graphics/wrap_Graphics.h +++ b/src/modules/graphics/wrap_Graphics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Graphics.lua b/src/modules/graphics/wrap_Graphics.lua index 7815edebf..3f1b3879c 100644 --- a/src/modules/graphics/wrap_Graphics.lua +++ b/src/modules/graphics/wrap_Graphics.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -53,7 +53,7 @@ function graphics.newVideo(file, settings) end function graphics.stencil(func, action, value, keepvalues) - love.markDeprecated(2, "love.graphics.stencil", "function", "replaced", "love.graphics.setStencilMode") + love.markDeprecated(2, "love.graphics.stencil", "function", "replaced", "love.graphics.setStencilMode or setStencilState") if not keepvalues then graphics.clear(false, true, false) @@ -61,15 +61,16 @@ function graphics.stencil(func, action, value, keepvalues) if value == nil then value = 1 end - graphics.setStencilMode(action, "always", value) - + local action2, mode2, value2, readmask2, writemask2 = graphics.getStencilState() local mr, mg, mb, ma = graphics.getColorMask() + + graphics.setStencilState(action, "always", value) graphics.setColorMask(false) local success, err = pcall(func) + graphics.setStencilState(action2, mode2, value2, readmask2, writemask2) graphics.setColorMask(mr, mg, mb, ma) - graphics.setStencilMode() if not success then error(err, 2) @@ -77,19 +78,19 @@ function graphics.stencil(func, action, value, keepvalues) end function graphics.setStencilTest(mode, value) - love.markDeprecated(2, "love.graphics.setStencilTest", "function", "replaced", "love.graphics.setStencilMode") + love.markDeprecated(2, "love.graphics.setStencilTest", "function", "replaced", "love.graphics.setStencilMode or setStencilState") if mode ~= nil then - graphics.setStencilMode("keep", mode, value) + graphics.setStencilState("keep", mode, value) else - graphics.setStencilMode() + graphics.setStencilState() end end function graphics.getStencilTest() - love.markDeprecated(2, "love.graphics.getStencilTest", "function", "replaced", "love.graphics.getStencilMode") + love.markDeprecated(2, "love.graphics.getStencilTest", "function", "replaced", "love.graphics.getStencilMode or getStencilState") - local action, mode, value = graphics.getStencilMode() + local action, mode, value = graphics.getStencilState() return mode, value end diff --git a/src/modules/graphics/wrap_GraphicsReadback.cpp b/src/modules/graphics/wrap_GraphicsReadback.cpp index 262e3faa1..18e1ecc1b 100644 --- a/src/modules/graphics/wrap_GraphicsReadback.cpp +++ b/src/modules/graphics/wrap_GraphicsReadback.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_GraphicsReadback.h b/src/modules/graphics/wrap_GraphicsReadback.h index 9b9197199..c4e2ba2e2 100644 --- a/src/modules/graphics/wrap_GraphicsReadback.h +++ b/src/modules/graphics/wrap_GraphicsReadback.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index 7c4072ef5..e36e7a453 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -250,21 +250,28 @@ int w_Mesh_getVertexFormat(lua_State *L) for (size_t i = 0; i < vertexformat.size(); i++) { - const auto &decl = vertexformat[i].decl; + const auto &member = vertexformat[i]; - if (!getConstant(decl.format, tname)) - return luax_enumerror(L, "vertex attribute data type", getConstants(decl.format), tname); + if (!getConstant(member.decl.format, tname)) + return luax_enumerror(L, "vertex attribute data type", getConstants(member.decl.format), tname); - lua_createtable(L, 3, 0); + lua_createtable(L, 0, 4); - lua_pushstring(L, decl.name.c_str()); - lua_rawseti(L, -2, 1); + lua_pushstring(L, member.decl.name.c_str()); + lua_setfield(L, -2, "name"); - lua_pushstring(L, tname); - lua_rawseti(L, -2, 2); + const char *formatstr = "unknown"; + getConstant(member.decl.format, formatstr); + lua_pushstring(L, formatstr); + lua_setfield(L, -2, "format"); - // format[i] = {name, type} - lua_rawseti(L, -2, (int) i + 1); + lua_pushinteger(L, member.decl.arrayLength); + lua_setfield(L, -2, "arraylength"); + + lua_pushinteger(L, member.offset); + lua_setfield(L, -2, "offset"); + + lua_rawseti(L, -2, i + 1); } return 1; diff --git a/src/modules/graphics/wrap_Mesh.h b/src/modules/graphics/wrap_Mesh.h index 3d00c58de..fdd65739b 100644 --- a/src/modules/graphics/wrap_Mesh.h +++ b/src/modules/graphics/wrap_Mesh.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_ParticleSystem.cpp b/src/modules/graphics/wrap_ParticleSystem.cpp index c6fc1b878..57b2d0634 100644 --- a/src/modules/graphics/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/wrap_ParticleSystem.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_ParticleSystem.h b/src/modules/graphics/wrap_ParticleSystem.h index dff5c5024..c828e9e0d 100644 --- a/src/modules/graphics/wrap_ParticleSystem.h +++ b/src/modules/graphics/wrap_ParticleSystem.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Quad.cpp b/src/modules/graphics/wrap_Quad.cpp index 6d65f247a..9328123b4 100644 --- a/src/modules/graphics/wrap_Quad.cpp +++ b/src/modules/graphics/wrap_Quad.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Quad.h b/src/modules/graphics/wrap_Quad.h index bf8e401e1..02cf333fa 100644 --- a/src/modules/graphics/wrap_Quad.h +++ b/src/modules/graphics/wrap_Quad.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Shader.cpp b/src/modules/graphics/wrap_Shader.cpp index cdaad13a6..5902640ea 100644 --- a/src/modules/graphics/wrap_Shader.cpp +++ b/src/modules/graphics/wrap_Shader.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -446,7 +446,7 @@ int w_Shader_send(lua_State *L) const char *name = luaL_checkstring(L, 2); const Shader::UniformInfo *info = shader->getUniformInfo(name); - if (info == nullptr) + if (info == nullptr || !info->active) return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name); if (luax_istype(L, 3, Data::type) || (info->baseType == Shader::UNIFORM_MATRIX && luax_istype(L, 4, Data::type))) @@ -461,14 +461,11 @@ int w_Shader_sendColors(lua_State *L) const char *name = luaL_checkstring(L, 2); const Shader::UniformInfo *info = shader->getUniformInfo(name); - if (info == nullptr) - { - luax_pushboolean(L, false); - return 1; - } + if (info == nullptr || !info->active) + return luaL_error(L, "Shader uniform '%s' does not exist.\nA common error is to define but not use the variable.", name); if (info->baseType != Shader::UNIFORM_FLOAT || info->components < 3) - return luaL_error(L, "sendColor can only be used on vec3 or vec4 uniforms."); + return luaL_error(L, "Shader:sendColor can only be used with vec3 or vec4 uniforms."); if (luax_istype(L, 3, Data::type)) w_Shader_sendData(L, 3, shader, info, true); @@ -517,6 +514,52 @@ int w_Shader_getLocalThreadgroupSize(lua_State* L) return 3; } +int w_Shader_getBufferFormat(lua_State *L) +{ + Shader *shader = luax_checkshader(L, 1); + const char *name = luaL_checkstring(L, 2); + const std::vector *format = shader->getBufferFormat(name); + if (name != nullptr) + { + lua_createtable(L, (int)format->size(), 0); + + for (size_t i = 0; i < format->size(); i++) + { + const Buffer::DataDeclaration &member = (*format)[i]; + + lua_createtable(L, 0, 3); + + lua_pushstring(L, member.name.c_str()); + lua_setfield(L, -2, "name"); + + const char* formatstr = "unknown"; + getConstant(member.format, formatstr); + lua_pushstring(L, formatstr); + lua_setfield(L, -2, "format"); + + lua_pushinteger(L, member.arrayLength); + lua_setfield(L, -2, "arraylength"); + + lua_rawseti(L, -2, i + 1); + } + + return 1; + } + + return luaL_error(L, "Buffer '%s' does not exist in the Shader.", name); +} + +int w_Shader_getDebugName(lua_State *L) +{ + Shader *shader = luax_checkshader(L, 1); + const std::string &debugName = shader->getDebugName(); + if (debugName.empty()) + lua_pushnil(L); + else + luax_pushstring(L, debugName); + return 1; +} + static const luaL_Reg w_Shader_functions[] = { { "getWarnings", w_Shader_getWarnings }, @@ -525,6 +568,8 @@ static const luaL_Reg w_Shader_functions[] = { "hasUniform", w_Shader_hasUniform }, { "hasStage", w_Shader_hasStage }, { "getLocalThreadgroupSize", w_Shader_getLocalThreadgroupSize }, + { "getBufferFormat", w_Shader_getBufferFormat }, + { "getDebugName", w_Shader_getDebugName }, { 0, 0 } }; diff --git a/src/modules/graphics/wrap_Shader.h b/src/modules/graphics/wrap_Shader.h index d71ad141f..ca6d2f2e5 100644 --- a/src/modules/graphics/wrap_Shader.h +++ b/src/modules/graphics/wrap_Shader.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_SpriteBatch.cpp b/src/modules/graphics/wrap_SpriteBatch.cpp index 1ef99e259..47168093b 100644 --- a/src/modules/graphics/wrap_SpriteBatch.cpp +++ b/src/modules/graphics/wrap_SpriteBatch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,13 +35,10 @@ SpriteBatch *luax_checkspritebatch(lua_State *L, int idx) static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int startidx, int index) { - Quad *quad = nullptr; + Quad *quad = luax_totype(L, startidx); - if (luax_istype(L, startidx, Quad::type)) - { - quad = luax_totype(L, startidx); + if (quad != nullptr) startidx++; - } else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) return luax_typerror(L, startidx, "Quad"); @@ -61,15 +58,13 @@ static inline int w_SpriteBatch_add_or_set(lua_State *L, SpriteBatch *t, int sta static int w_SpriteBatch_addLayer_or_setLayer(lua_State *L, SpriteBatch *t, int startidx, int index) { - Quad *quad = nullptr; int layer = (int) luaL_checkinteger(L, startidx) - 1; startidx++; - if (luax_istype(L, startidx, Quad::type)) - { - quad = luax_totype(L, startidx); + Quad *quad = luax_totype(L, startidx); + + if (quad != nullptr) startidx++; - } else if (lua_isnil(L, startidx) && !lua_isnoneornil(L, startidx + 1)) return luax_typerror(L, startidx, "Quad"); diff --git a/src/modules/graphics/wrap_SpriteBatch.h b/src/modules/graphics/wrap_SpriteBatch.h index d7f0c09a2..1e0894831 100644 --- a/src/modules/graphics/wrap_SpriteBatch.h +++ b/src/modules/graphics/wrap_SpriteBatch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -32,22 +32,33 @@ namespace graphics template static void luax_checkstandardtransform(lua_State *L, int idx, const T &func) { - if (luax_istype(L, idx, math::Transform::type)) + math::Transform *tf = luax_totype(L, idx); + if (tf != nullptr) { - math::Transform *tf = luax_totype(L, idx); func(tf->getMatrix()); } else { + int nargs = lua_gettop(L); float x = (float) luaL_optnumber(L, idx + 0, 0.0); float y = (float) luaL_optnumber(L, idx + 1, 0.0); float a = (float) luaL_optnumber(L, idx + 2, 0.0); float sx = (float) luaL_optnumber(L, idx + 3, 1.0); float sy = (float) luaL_optnumber(L, idx + 4, sx); - float ox = (float) luaL_optnumber(L, idx + 5, 0.0); - float oy = (float) luaL_optnumber(L, idx + 6, 0.0); - float kx = (float) luaL_optnumber(L, idx + 7, 0.0); - float ky = (float) luaL_optnumber(L, idx + 8, 0.0); + float ox = 0.0f; + float oy = 0.0f; + if (nargs >= idx + 5) + { + ox = (float) luaL_optnumber(L, idx + 5, 0.0); + oy = (float) luaL_optnumber(L, idx + 6, 0.0); + } + float kx = 0.0f; + float ky = 0.0f; + if (nargs >= idx + 7) + { + kx = (float) luaL_optnumber(L, idx + 7, 0.0); + ky = (float) luaL_optnumber(L, idx + 8, 0.0); + } func(Matrix4(x, y, a, sx, sy, ox, oy, kx, ky)); } } diff --git a/src/modules/graphics/wrap_TextBatch.cpp b/src/modules/graphics/wrap_TextBatch.cpp index 6a21da769..ffe0867f1 100644 --- a/src/modules/graphics/wrap_TextBatch.cpp +++ b/src/modules/graphics/wrap_TextBatch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_TextBatch.h b/src/modules/graphics/wrap_TextBatch.h index 933626d28..272f1364d 100644 --- a/src/modules/graphics/wrap_TextBatch.h +++ b/src/modules/graphics/wrap_TextBatch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index 00f6058af..b667c48b3 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -300,6 +300,24 @@ int w_Texture_isReadable(lua_State *L) return 1; } +int w_Texture_getViewFormats(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + const std::vector &viewformats = t->getViewFormats(); + + lua_createtable(L, (int) viewformats.size(), 0); + for (int i = 0; i < (int) viewformats.size(); i++) + { + const char *str = nullptr; + if (!getConstant(viewformats[i], str)) + return luaL_error(L, "Unknown pixel format."); + lua_pushstring(L, str); + lua_rawseti(L, -2, i + 1); + } + + return 1; +} + int w_Texture_setDepthSampleMode(lua_State *L) { Texture *t = luax_checktexture(L, 1); @@ -474,6 +492,17 @@ int w_Texture_renderTo(lua_State *L) return 0; } +static int w_Texture_getDebugName(lua_State *L) +{ + Texture *t = luax_checktexture(L, 1); + const std::string &debugName = t->getDebugName(); + if (debugName.empty()) + lua_pushnil(L); + else + luax_pushstring(L, debugName); + return 1; +} + const luaL_Reg w_Texture_functions[] = { { "getTextureType", w_Texture_getTextureType }, @@ -500,12 +529,14 @@ const luaL_Reg w_Texture_functions[] = { "isCanvas", w_Texture_isCanvas }, { "isComputeWritable", w_Texture_isComputeWritable }, { "isReadable", w_Texture_isReadable }, + { "getViewFormats", w_Texture_getViewFormats }, { "getMipmapMode", w_Texture_getMipmapMode }, { "getDepthSampleMode", w_Texture_getDepthSampleMode }, { "setDepthSampleMode", w_Texture_setDepthSampleMode }, { "generateMipmaps", w_Texture_generateMipmaps }, { "replacePixels", w_Texture_replacePixels }, { "renderTo", w_Texture_renderTo }, + { "getDebugName", w_Texture_getDebugName }, // Deprecated { "newImageData", w_Texture_newImageData }, diff --git a/src/modules/graphics/wrap_Texture.h b/src/modules/graphics/wrap_Texture.h index 94c62dfb0..aae3f97dd 100644 --- a/src/modules/graphics/wrap_Texture.h +++ b/src/modules/graphics/wrap_Texture.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 4004c61d8..1463d0899 100644 --- a/src/modules/graphics/wrap_Video.cpp +++ b/src/modules/graphics/wrap_Video.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Video.h b/src/modules/graphics/wrap_Video.h index 39f6e5e45..700a4bba1 100644 --- a/src/modules/graphics/wrap_Video.h +++ b/src/modules/graphics/wrap_Video.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/graphics/wrap_Video.lua b/src/modules/graphics/wrap_Video.lua index ae8097b95..eaf7a0631 100644 --- a/src/modules/graphics/wrap_Video.lua +++ b/src/modules/graphics/wrap_Video.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/CompressedImageData.cpp b/src/modules/image/CompressedImageData.cpp index 0ff04cb5d..6ec15b927 100644 --- a/src/modules/image/CompressedImageData.cpp +++ b/src/modules/image/CompressedImageData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -30,7 +30,6 @@ love::Type CompressedImageData::type("CompressedImageData", &Data::type); CompressedImageData::CompressedImageData(const std::list &formats, Data *filedata) : format(PIXELFORMAT_UNKNOWN) - , sRGB(false) { FormatHandler *parser = nullptr; @@ -46,7 +45,7 @@ CompressedImageData::CompressedImageData(const std::list &forma if (parser == nullptr) throw love::Exception("Could not parse compressed data: Unknown format."); - memory = parser->parseCompressed(filedata, dataImages, format, sRGB); + memory = parser->parseCompressed(filedata, dataImages, format); if (memory == nullptr) throw love::Exception("Could not parse compressed data."); @@ -56,11 +55,14 @@ CompressedImageData::CompressedImageData(const std::list &forma if (dataImages.size() == 0 || memory->getSize() == 0) throw love::Exception("Could not parse compressed data: No valid data?"); + + // This throws away some information the decoder could give us, but we + // can't really rely on it I think... + format = getLinearPixelFormat(format); } CompressedImageData::CompressedImageData(const CompressedImageData &c) : format(c.format) - , sRGB(c.sRGB) { memory.set(c.memory->clone(), Acquire::NORETAIN); @@ -134,9 +136,15 @@ PixelFormat CompressedImageData::getFormat() const return format; } -bool CompressedImageData::isSRGB() const +void CompressedImageData::setLinear(bool linear) { - return sRGB; + for (auto &slice : dataImages) + slice->setLinear(linear); +} + +bool CompressedImageData::isLinear() const +{ + return dataImages.empty() ? false : dataImages[0]->isLinear(); } CompressedSlice *CompressedImageData::getSlice(int slice, int miplevel) const diff --git a/src/modules/image/CompressedImageData.h b/src/modules/image/CompressedImageData.h index e834935b1..743d3bd0d 100644 --- a/src/modules/image/CompressedImageData.h +++ b/src/modules/image/CompressedImageData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -93,14 +93,14 @@ public: **/ PixelFormat getFormat() const; - bool isSRGB() const; + void setLinear(bool linear); + bool isLinear() const; CompressedSlice *getSlice(int slice, int miplevel) const; protected: PixelFormat format; - bool sRGB; // Single block of memory containing all of the sub-images. StrongRef memory; diff --git a/src/modules/image/CompressedSlice.cpp b/src/modules/image/CompressedSlice.cpp index a4ab37d6f..34d79621c 100644 --- a/src/modules/image/CompressedSlice.cpp +++ b/src/modules/image/CompressedSlice.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -31,7 +31,6 @@ CompressedSlice::CompressedSlice(PixelFormat format, int width, int height, Byte , memory(memory) , offset(offset) , dataSize(size) - , sRGB(false) { } @@ -40,7 +39,6 @@ CompressedSlice::CompressedSlice(const CompressedSlice &s) , memory(s.memory) , offset(s.offset) , dataSize(s.dataSize) - , sRGB(s.sRGB) { } diff --git a/src/modules/image/CompressedSlice.h b/src/modules/image/CompressedSlice.h index 581641b9c..cffdf57f1 100644 --- a/src/modules/image/CompressedSlice.h +++ b/src/modules/image/CompressedSlice.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,7 +46,6 @@ public: CompressedSlice *clone() const override; void *getData() const override { return (uint8 *) memory->getData() + offset; } size_t getSize() const override { return dataSize; } - bool isSRGB() const override { return sRGB; } size_t getOffset() const { return offset; } private: @@ -54,7 +53,6 @@ private: StrongRef memory; size_t offset; size_t dataSize; - bool sRGB; }; // CompressedSlice diff --git a/src/modules/image/FormatHandler.cpp b/src/modules/image/FormatHandler.cpp index b75b9a226..f1a1edff3 100644 --- a/src/modules/image/FormatHandler.cpp +++ b/src/modules/image/FormatHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -60,7 +60,7 @@ bool FormatHandler::canParseCompressed(Data* /*data*/) return false; } -StrongRef FormatHandler::parseCompressed(Data* /*filedata*/, std::vector>& /*images*/, PixelFormat& /*format*/, bool& /*sRGB*/) +StrongRef FormatHandler::parseCompressed(Data* /*filedata*/, std::vector>& /*images*/, PixelFormat& /*format*/) { throw love::Exception("Compressed image parsing is not implemented for this format backend."); } diff --git a/src/modules/image/FormatHandler.h b/src/modules/image/FormatHandler.h index 9fc6cab16..aa5f8db4b 100644 --- a/src/modules/image/FormatHandler.h +++ b/src/modules/image/FormatHandler.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -106,13 +106,12 @@ public: * @param[out] images The list of sub-images generated. Byte data is a * pointer to the returned data. * @param[out] format The format of the Compressed Data. - * @param[out] sRGB Whether the texture is sRGB-encoded. * * @return The single block of memory containing the parsed images. **/ virtual StrongRef parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB); + PixelFormat &format); /** * Frees raw pixel memory allocated by the format handler. diff --git a/src/modules/image/Image.cpp b/src/modules/image/Image.cpp index d5f58e997..8bf46a619 100644 --- a/src/modules/image/Image.cpp +++ b/src/modules/image/Image.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -40,6 +40,7 @@ namespace image love::Type Image::type("image", &Module::type); Image::Image() + : Module(M_IMAGE, "love.image.magpie") { using namespace magpie; @@ -65,11 +66,6 @@ Image::~Image() handler->release(); } -const char *Image::getName() const -{ - return "love.image.magpie"; -} - love::image::ImageData *Image::newImageData(Data *data) { return new ImageData(data); diff --git a/src/modules/image/Image.h b/src/modules/image/Image.h index 9ac76ee6c..cac95f5d1 100644 --- a/src/modules/image/Image.h +++ b/src/modules/image/Image.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -52,10 +52,6 @@ public: Image(); virtual ~Image(); - // Implements Module. - ModuleType getModuleType() const override { return M_IMAGE; } - const char *getName() const override; - /** * Creates new ImageData from FileData. * @param data The FileData containing the encoded image data. diff --git a/src/modules/image/ImageData.cpp b/src/modules/image/ImageData.cpp index 108a945ae..7c2c5205c 100644 --- a/src/modules/image/ImageData.cpp +++ b/src/modules/image/ImageData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -152,6 +152,10 @@ void ImageData::decode(Data *data) else delete[] this->data; + // This throws away some information the decoder could give us, but we + // can't really rely on it I think... + decodedimage.format = getLinearPixelFormat(decodedimage.format); + this->width = decodedimage.width; this->height = decodedimage.height; this->data = decodedimage.data; @@ -190,10 +194,7 @@ love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encod } if (encoder != nullptr) - { - thread::Lock lock(mutex); encodedimage = encoder->encode(rawimage, encodedFormat); - } if (encoder == nullptr || encodedimage.data == nullptr) throw love::Exception("No suitable image encoder for the %s pixel format.", getPixelFormatName(format)); @@ -247,11 +248,6 @@ void *ImageData::getData() const return data; } -bool ImageData::isSRGB() const -{ - return false; -} - bool ImageData::inside(int x, int y) const { return x >= 0 && x < getWidth() && y >= 0 && y < getHeight(); @@ -538,8 +534,6 @@ void ImageData::setPixel(int x, int y, const Colorf &c) if (pixelSetFunction == nullptr) throw love::Exception("ImageData:setPixel does not currently support the %s pixel format.", getPixelFormatName(format)); - Lock lock(mutex); - pixelSetFunction(c, p); } @@ -554,8 +548,6 @@ void ImageData::getPixel(int x, int y, Colorf &c) const if (pixelGetFunction == nullptr) throw love::Exception("ImageData:getPixel does not currently support the %s pixel format.", getPixelFormatName(format)); - Lock lock(mutex); - pixelGetFunction(p, c); } @@ -702,9 +694,6 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in if (sy + sh > srcH) sh = srcH - sy; - Lock lock2(src->mutex); - Lock lock1(mutex); - uint8 *s = (uint8 *) src->getData(); uint8 *d = (uint8 *) getData(); @@ -775,11 +764,6 @@ void ImageData::paste(ImageData *src, int dx, int dy, int sx, int sy, int sw, in } } -love::thread::Mutex *ImageData::getMutex() const -{ - return mutex; -} - size_t ImageData::getPixelSize() const { return getPixelFormatBlockSize(format); diff --git a/src/modules/image/ImageData.h b/src/modules/image/ImageData.h index fa43a848c..5eb800f4d 100644 --- a/src/modules/image/ImageData.h +++ b/src/modules/image/ImageData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -62,7 +62,7 @@ public: static love::Type type; ImageData(Data *data); - ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8_UNORM); + ImageData(int width, int height, PixelFormat format); ImageData(int width, int height, PixelFormat format, void *data, bool own); ImageData(const ImageData &c); virtual ~ImageData(); @@ -110,13 +110,10 @@ public: **/ love::filesystem::FileData *encode(FormatHandler::EncodedFormat format, const char *filename, bool writefile) const; - love::thread::Mutex *getMutex() const; - // Implements ImageDataBase. ImageData *clone() const override; void *getData() const override; size_t getSize() const override; - bool isSRGB() const override; size_t getPixelSize() const; @@ -143,8 +140,6 @@ private: // The actual data. unsigned char *data = nullptr; - love::thread::MutexRef mutex; - // The format handler that was used to decode the ImageData. We need to know // this so we can properly delete memory allocated by the decoder. StrongRef decodeHandler; diff --git a/src/modules/image/ImageDataBase.cpp b/src/modules/image/ImageDataBase.cpp index 1e7248c9c..27ac610f1 100644 --- a/src/modules/image/ImageDataBase.cpp +++ b/src/modules/image/ImageDataBase.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -29,6 +29,7 @@ ImageDataBase::ImageDataBase(PixelFormat format, int width, int height) : format(format) , width(width) , height(height) + , linear(false) { } @@ -47,5 +48,15 @@ int ImageDataBase::getHeight() const return height; } +void ImageDataBase::setLinear(bool linear) +{ + this->linear = linear; +} + +bool ImageDataBase::isLinear() const +{ + return linear; +} + } // image } // love diff --git a/src/modules/image/ImageDataBase.h b/src/modules/image/ImageDataBase.h index 0f4f523ee..d57010109 100644 --- a/src/modules/image/ImageDataBase.h +++ b/src/modules/image/ImageDataBase.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -40,7 +40,8 @@ public: int getWidth() const; int getHeight() const; - virtual bool isSRGB() const = 0; + void setLinear(bool linear); + bool isLinear() const; protected: @@ -50,6 +51,8 @@ protected: int width; int height; + bool linear; + }; // ImageDataBase } // image diff --git a/src/modules/image/magpie/ASTCHandler.cpp b/src/modules/image/magpie/ASTCHandler.cpp index 8f2fb569f..e0917d336 100644 --- a/src/modules/image/magpie/ASTCHandler.cpp +++ b/src/modules/image/magpie/ASTCHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -54,33 +54,33 @@ static PixelFormat convertFormat(uint32 blockX, uint32 blockY, uint32 blockZ) return PIXELFORMAT_UNKNOWN; if (blockX == 4 && blockY == 4) - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; else if (blockX == 5 && blockY == 4) - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; else if (blockX == 5 && blockY == 5) - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; else if (blockX == 6 && blockY == 5) - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; else if (blockX == 6 && blockY == 6) - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; else if (blockX == 8 && blockY == 5) - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; else if (blockX == 8 && blockY == 6) - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; else if (blockX == 8 && blockY == 8) - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; else if (blockX == 10 && blockY == 5) - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; else if (blockX == 10 && blockY == 6) - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; else if (blockX == 10 && blockY == 8) - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; else if (blockX == 10 && blockY == 10) - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; else if (blockX == 12 && blockY == 10) - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; else if (blockX == 12 && blockY == 12) - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; return PIXELFORMAT_UNKNOWN; } @@ -105,7 +105,7 @@ bool ASTCHandler::canParseCompressed(Data *data) return true; } -StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not an .astc file?)"); @@ -138,8 +138,6 @@ StrongRef ASTCHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // ASTCHandler diff --git a/src/modules/image/magpie/EXRHandler.cpp b/src/modules/image/magpie/EXRHandler.cpp index f986e4e38..e35df2336 100644 --- a/src/modules/image/magpie/EXRHandler.cpp +++ b/src/modules/image/magpie/EXRHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/EXRHandler.h b/src/modules/image/magpie/EXRHandler.h index 7aabdc236..c6a2a7b53 100644 --- a/src/modules/image/magpie/EXRHandler.h +++ b/src/modules/image/magpie/EXRHandler.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/KTXHandler.cpp b/src/modules/image/magpie/KTXHandler.cpp index ac7f7ef03..39af852ca 100644 --- a/src/modules/image/magpie/KTXHandler.cpp +++ b/src/modules/image/magpie/KTXHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -137,10 +137,8 @@ enum KTXGLInternalFormat KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD }; -PixelFormat convertFormat(uint32 glformat, bool &sRGB) +PixelFormat convertFormat(uint32 glformat) { - sRGB = false; - // hnnngg ASTC... switch (glformat) @@ -160,18 +158,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) case KTX_GL_COMPRESSED_RGB8_ETC2: return PIXELFORMAT_ETC2_RGB_UNORM; case KTX_GL_COMPRESSED_SRGB8_ETC2: - sRGB = true; - return PIXELFORMAT_ETC2_RGB_UNORM; + return PIXELFORMAT_ETC2_RGB_sRGB; case KTX_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: return PIXELFORMAT_ETC2_RGBA1_UNORM; case KTX_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: - sRGB = true; - return PIXELFORMAT_ETC2_RGBA1_UNORM; + return PIXELFORMAT_ETC2_RGBA1_sRGB; case KTX_GL_COMPRESSED_RGBA8_ETC2_EAC: return PIXELFORMAT_ETC2_RGBA_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: - sRGB = true; - return PIXELFORMAT_ETC2_RGBA_UNORM; + return PIXELFORMAT_ETC2_RGBA_sRGB; // PVRTC. case KTX_GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG: @@ -185,15 +180,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // DXT. case KTX_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: - sRGB = true; + return PIXELFORMAT_DXT1_sRGB; case KTX_GL_COMPRESSED_RGB_S3TC_DXT1_EXT: return PIXELFORMAT_DXT1_UNORM; case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: - sRGB = true; + return PIXELFORMAT_DXT3_sRGB; case KTX_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: return PIXELFORMAT_DXT3_UNORM; case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - sRGB = true; + return PIXELFORMAT_DXT5_sRGB; case KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: return PIXELFORMAT_DXT5_UNORM; @@ -209,7 +204,7 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // BC6 and BC7. case KTX_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: - sRGB = true; + return PIXELFORMAT_BC7_sRGB; case KTX_GL_COMPRESSED_RGBA_BPTC_UNORM: return PIXELFORMAT_BC7_UNORM; case KTX_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: @@ -219,61 +214,61 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB) // ASTC. case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_4x4_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR: - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_5x4_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR: - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_5x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR: - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_6x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR: - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_6x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR: - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR: - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR: - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_8x8_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR: - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x5_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR: - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x6_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR: - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x8_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR: - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_10x10_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR: - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_12x10_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR: - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: - sRGB = true; + return PIXELFORMAT_ASTC_12x12_sRGB; case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR: - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; default: return PIXELFORMAT_UNKNOWN; } @@ -298,7 +293,7 @@ bool KTXHandler::canParseCompressed(Data *data) return true; } -StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a KTX file?)"); @@ -314,8 +309,7 @@ StrongRef KTXHandler::parseCompressed(Data *filedata, std::vector KTXHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // KTXHandler diff --git a/src/modules/image/magpie/PKMHandler.cpp b/src/modules/image/magpie/PKMHandler.cpp index 1fa13283f..8b316fbd5 100644 --- a/src/modules/image/magpie/PKMHandler.cpp +++ b/src/modules/image/magpie/PKMHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -114,7 +114,7 @@ bool PKMHandler::canParseCompressed(Data *data) return true; } -StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a PKM file?)"); @@ -148,8 +148,6 @@ StrongRef PKMHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // PKMHandler diff --git a/src/modules/image/magpie/PNGHandler.cpp b/src/modules/image/magpie/PNGHandler.cpp index 69dd3fb50..7c8b0c978 100644 --- a/src/modules/image/magpie/PNGHandler.cpp +++ b/src/modules/image/magpie/PNGHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/PNGHandler.h b/src/modules/image/magpie/PNGHandler.h index 13a0c7f4e..49d5c4848 100644 --- a/src/modules/image/magpie/PNGHandler.h +++ b/src/modules/image/magpie/PNGHandler.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/PVRHandler.cpp b/src/modules/image/magpie/PVRHandler.cpp index 21ebe6f0a..c66be4606 100644 --- a/src/modules/image/magpie/PVRHandler.cpp +++ b/src/modules/image/magpie/PVRHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -256,33 +256,33 @@ static PixelFormat convertFormat(PVRV3PixelFormat format, PVRV3ChannelType chann case ePVRTPF_EAC_RG: return snorm ? PIXELFORMAT_EAC_RG_SNORM : PIXELFORMAT_EAC_RG_UNORM; case ePVRTPF_ASTC_4x4: - return PIXELFORMAT_ASTC_4x4; + return PIXELFORMAT_ASTC_4x4_UNORM; case ePVRTPF_ASTC_5x4: - return PIXELFORMAT_ASTC_5x4; + return PIXELFORMAT_ASTC_5x4_UNORM; case ePVRTPF_ASTC_5x5: - return PIXELFORMAT_ASTC_5x5; + return PIXELFORMAT_ASTC_5x5_UNORM; case ePVRTPF_ASTC_6x5: - return PIXELFORMAT_ASTC_6x5; + return PIXELFORMAT_ASTC_6x5_UNORM; case ePVRTPF_ASTC_6x6: - return PIXELFORMAT_ASTC_6x6; + return PIXELFORMAT_ASTC_6x6_UNORM; case ePVRTPF_ASTC_8x5: - return PIXELFORMAT_ASTC_8x5; + return PIXELFORMAT_ASTC_8x5_UNORM; case ePVRTPF_ASTC_8x6: - return PIXELFORMAT_ASTC_8x6; + return PIXELFORMAT_ASTC_8x6_UNORM; case ePVRTPF_ASTC_8x8: - return PIXELFORMAT_ASTC_8x8; + return PIXELFORMAT_ASTC_8x8_UNORM; case ePVRTPF_ASTC_10x5: - return PIXELFORMAT_ASTC_10x5; + return PIXELFORMAT_ASTC_10x5_UNORM; case ePVRTPF_ASTC_10x6: - return PIXELFORMAT_ASTC_10x6; + return PIXELFORMAT_ASTC_10x6_UNORM; case ePVRTPF_ASTC_10x8: - return PIXELFORMAT_ASTC_10x8; + return PIXELFORMAT_ASTC_10x8_UNORM; case ePVRTPF_ASTC_10x10: - return PIXELFORMAT_ASTC_10x10; + return PIXELFORMAT_ASTC_10x10_UNORM; case ePVRTPF_ASTC_12x10: - return PIXELFORMAT_ASTC_12x10; + return PIXELFORMAT_ASTC_12x10_UNORM; case ePVRTPF_ASTC_12x12: - return PIXELFORMAT_ASTC_12x12; + return PIXELFORMAT_ASTC_12x12_UNORM; default: return PIXELFORMAT_UNKNOWN; } @@ -475,7 +475,7 @@ bool PVRHandler::canParseCompressed(Data *data) return false; } -StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!canParseCompressed(filedata)) throw love::Exception("Could not decode compressed data (not a PVR file?)"); @@ -510,6 +510,9 @@ StrongRef PVRHandler::parseCompressed(Data *filedata, std::vector PVRHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // PVRHandler diff --git a/src/modules/image/magpie/STBHandler.cpp b/src/modules/image/magpie/STBHandler.cpp index 24119faf2..768ed6dc5 100644 --- a/src/modules/image/magpie/STBHandler.cpp +++ b/src/modules/image/magpie/STBHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/STBHandler.h b/src/modules/image/magpie/STBHandler.h index 476563315..fd636f588 100644 --- a/src/modules/image/magpie/STBHandler.h +++ b/src/modules/image/magpie/STBHandler.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/magpie/ddsHandler.cpp b/src/modules/image/magpie/ddsHandler.cpp index 974dec24e..416c96cd9 100644 --- a/src/modules/image/magpie/ddsHandler.cpp +++ b/src/modules/image/magpie/ddsHandler.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -32,13 +32,10 @@ namespace image namespace magpie { -static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, bool &bgra) +static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat) { using namespace dds::dxinfo; - sRGB = false; - bgra = false; - switch (dxformat) { case DXGI_FORMAT_R32G32B32A32_TYPELESS: @@ -65,9 +62,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_R8G8B8A8_TYPELESS: case DXGI_FORMAT_R8G8B8A8_UNORM: - case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB); return PIXELFORMAT_RGBA8_UNORM; + case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: + return PIXELFORMAT_RGBA8_sRGB; case DXGI_FORMAT_R16G16_TYPELESS: case DXGI_FORMAT_R16G16_FLOAT: @@ -98,21 +95,21 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_BC1_TYPELESS: case DXGI_FORMAT_BC1_UNORM: - case DXGI_FORMAT_BC1_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC1_UNORM_SRGB); return PIXELFORMAT_DXT1_UNORM; + case DXGI_FORMAT_BC1_UNORM_SRGB: + return PIXELFORMAT_DXT1_sRGB; case DXGI_FORMAT_BC2_TYPELESS: case DXGI_FORMAT_BC2_UNORM: - case DXGI_FORMAT_BC2_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC2_UNORM_SRGB); return PIXELFORMAT_DXT3_UNORM; + case DXGI_FORMAT_BC2_UNORM_SRGB: + return PIXELFORMAT_DXT3_sRGB; case DXGI_FORMAT_BC3_TYPELESS: case DXGI_FORMAT_BC3_UNORM: - case DXGI_FORMAT_BC3_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC3_UNORM_SRGB); return PIXELFORMAT_DXT5_UNORM; + case DXGI_FORMAT_BC3_UNORM_SRGB: + return PIXELFORMAT_DXT5_sRGB; case DXGI_FORMAT_BC4_TYPELESS: case DXGI_FORMAT_BC4_UNORM: @@ -136,10 +133,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_B8G8R8A8_UNORM: case DXGI_FORMAT_B8G8R8A8_TYPELESS: + return PIXELFORMAT_BGRA8_UNORM; case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB); - bgra = true; - return PIXELFORMAT_RGBA8_UNORM; + return PIXELFORMAT_BGRA8_sRGB; case DXGI_FORMAT_BC6H_TYPELESS: case DXGI_FORMAT_BC6H_UF16: @@ -150,9 +146,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_UNORM: - case DXGI_FORMAT_BC7_UNORM_SRGB: - sRGB = (dxformat == DXGI_FORMAT_BC7_UNORM_SRGB); return PIXELFORMAT_BC7_UNORM; + case DXGI_FORMAT_BC7_UNORM_SRGB: + return PIXELFORMAT_BC7_sRGB; default: return PIXELFORMAT_UNKNOWN; @@ -164,9 +160,13 @@ bool DDSHandler::canDecode(Data *data) using namespace dds::dxinfo; DXGIFormat dxformat = dds::getDDSPixelFormat(data->getData(), data->getSize()); - bool isSRGB = false; - bool bgra = false; - PixelFormat format = convertFormat(dxformat, isSRGB, bgra); + PixelFormat format = convertFormat(dxformat); + + // We convert BGRA to RGBA + if (format == PIXELFORMAT_BGRA8_UNORM) + format = PIXELFORMAT_RGBA8_UNORM; + else if (format == PIXELFORMAT_BGRA8_sRGB) + format = PIXELFORMAT_RGBA8_sRGB; return ImageData::validPixelFormat(format); } @@ -177,9 +177,19 @@ FormatHandler::DecodedImage DDSHandler::decode(Data *data) dds::Parser parser(data->getData(), data->getSize()); - bool isSRGB = false; + img.format = convertFormat(parser.getFormat()); + bool bgra = false; - img.format = convertFormat(parser.getFormat(), isSRGB, bgra); + if (img.format == PIXELFORMAT_BGRA8_UNORM) + { + img.format = PIXELFORMAT_RGBA8_UNORM; + bgra = true; + } + else if (img.format == PIXELFORMAT_BGRA8_sRGB) + { + img.format = PIXELFORMAT_RGBA8_sRGB; + bgra = true; + } if (!ImageData::validPixelFormat(img.format)) throw love::Exception("Could not parse DDS pixel data: Unsupported format."); @@ -229,14 +239,12 @@ bool DDSHandler::canParseCompressed(Data *data) return dds::isCompressedDDS(data->getData(), data->getSize()); } -StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format, bool &sRGB) +StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector> &images, PixelFormat &format) { if (!dds::isCompressedDDS(filedata->getData(), filedata->getSize())) throw love::Exception("Could not decode compressed data (not a DDS file?)"); PixelFormat texformat = PIXELFORMAT_UNKNOWN; - bool isSRGB = false; - bool bgra = false; size_t dataSize = 0; @@ -245,7 +253,7 @@ StrongRef DDSHandler::parseCompressed(Data *filedata, std::vectorgetData(), filedata->getSize()); - texformat = convertFormat(parser.getFormat(), isSRGB, bgra); + texformat = convertFormat(parser.getFormat()); if (texformat == PIXELFORMAT_UNKNOWN) throw love::Exception("Could not parse compressed data: Unsupported format."); @@ -280,7 +288,6 @@ StrongRef DDSHandler::parseCompressed(Data *filedata, std::vector parseCompressed(Data *filedata, std::vector> &images, - PixelFormat &format, bool &sRGB) override; + PixelFormat &format) override; }; // DDSHandler diff --git a/src/modules/image/wrap_CompressedImageData.cpp b/src/modules/image/wrap_CompressedImageData.cpp index 15f8908e2..aa8fd0cce 100644 --- a/src/modules/image/wrap_CompressedImageData.cpp +++ b/src/modules/image/wrap_CompressedImageData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -103,6 +103,20 @@ int w_CompressedImageData_getFormat(lua_State *L) return 1; } +int w_CompressedImageData_setLinear(lua_State *L) +{ + CompressedImageData *t = luax_checkcompressedimagedata(L, 1); + t->setLinear(luax_checkboolean(L, 2)); + return 0; +} + +int w_CompressedImageData_isLinear(lua_State *L) +{ + CompressedImageData *t = luax_checkcompressedimagedata(L, 1); + luax_pushboolean(L, t->isLinear()); + return 1; +} + static const luaL_Reg w_CompressedImageData_functions[] = { { "clone", w_CompressedImageData_clone }, @@ -111,6 +125,8 @@ static const luaL_Reg w_CompressedImageData_functions[] = { "getDimensions", w_CompressedImageData_getDimensions }, { "getMipmapCount", w_CompressedImageData_getMipmapCount }, { "getFormat", w_CompressedImageData_getFormat }, + { "setLinear", w_CompressedImageData_setLinear }, + { "isLinear", w_CompressedImageData_isLinear }, { 0, 0 }, }; diff --git a/src/modules/image/wrap_CompressedImageData.h b/src/modules/image/wrap_CompressedImageData.h index 041511a71..473e99eb1 100644 --- a/src/modules/image/wrap_CompressedImageData.h +++ b/src/modules/image/wrap_CompressedImageData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/wrap_Image.cpp b/src/modules/image/wrap_Image.cpp index 2af0d7b20..7fbcba3fc 100644 --- a/src/modules/image/wrap_Image.cpp +++ b/src/modules/image/wrap_Image.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/wrap_Image.h b/src/modules/image/wrap_Image.h index 86daafd79..cd60f6741 100644 --- a/src/modules/image/wrap_Image.h +++ b/src/modules/image/wrap_Image.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index 754ad01c5..7b04e7c1d 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -66,6 +66,20 @@ int w_ImageData_getFormat(lua_State *L) return 1; } +int w_ImageData_setLinear(lua_State *L) +{ + ImageData *t = luax_checkimagedata(L, 1); + t->setLinear(luax_checkboolean(L, 2)); + return 0; +} + +int w_ImageData_isLinear(lua_State *L) +{ + ImageData *t = luax_checkimagedata(L, 1); + luax_pushboolean(L, t->isLinear()); + return 1; +} + int w_ImageData_getWidth(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); @@ -144,18 +158,15 @@ int w_ImageData_setPixel(lua_State *L) return 0; } -// ImageData:mapPixel. Not thread-safe! See wrap_ImageData.lua for the thread- -// safe wrapper function. -int w_ImageData__mapPixelUnsafe(lua_State *L) +int w_ImageData_mapPixel(lua_State *L) { ImageData *t = luax_checkimagedata(L, 1); luaL_checktype(L, 2, LUA_TFUNCTION); - // No optints because we assume they're done in the wrapper function. - int sx = (int) lua_tonumber(L, 3); - int sy = (int) lua_tonumber(L, 4); - int w = (int) lua_tonumber(L, 5); - int h = (int) lua_tonumber(L, 6); + int sx = luaL_optint(L, 3, 0); + int sy = luaL_optint(L, 4, 0); + int w = luaL_optint(L, 5, t->getWidth()); + int h = luaL_optint(L, 6, t->getHeight()); if (!(t->inside(sx, sy) && t->inside(sx+w-1, sy+h-1))) return luaL_error(L, "Invalid rectangle dimensions."); @@ -250,32 +261,9 @@ int w_ImageData_encode(lua_State *L) return 1; } -int w_ImageData__performAtomic(lua_State *L) -{ - ImageData *t = luax_checkimagedata(L, 1); - int err = 0; - - { - love::thread::Lock lock(t->getMutex()); - // call the function, passing any user-specified arguments. - err = lua_pcall(L, lua_gettop(L) - 2, LUA_MULTRET, 0); - } - - // Unfortunately, this eats the stack trace, too bad. - if (err != 0) - return lua_error(L); - - // The function and everything after it in the stack are eaten by the pcall, - // leaving only the ImageData object. Everything else is a return value. - return lua_gettop(L) - 1; -} - // C functions in a struct, necessary for the FFI versions of ImageData methods. struct FFI_ImageData { - void (*lockMutex)(Proxy *p); - void (*unlockMutex)(Proxy *p); - float (*float16to32)(float16 f); float16 (*float32to16)(float f); @@ -288,20 +276,6 @@ struct FFI_ImageData static FFI_ImageData ffifuncs = { - [](Proxy *p) // lockMutex - { - // We don't do any type-checking for the Proxy here since these functions - // are always called from code which has already done type checking. - ImageData *i = (ImageData *) p->object; - i->getMutex()->lock(); - }, - - [](Proxy *p) // unlockMutex - { - ImageData *i = (ImageData *) p->object; - i->getMutex()->unlock(); - }, - float16to32, float32to16, float11to32, @@ -314,18 +288,16 @@ static const luaL_Reg w_ImageData_functions[] = { { "clone", w_ImageData_clone }, { "getFormat", w_ImageData_getFormat }, + { "setLinear", w_ImageData_setLinear }, + { "isLinear", w_ImageData_isLinear }, { "getWidth", w_ImageData_getWidth }, { "getHeight", w_ImageData_getHeight }, { "getDimensions", w_ImageData_getDimensions }, { "getPixel", w_ImageData_getPixel }, { "setPixel", w_ImageData_setPixel }, { "paste", w_ImageData_paste }, + { "mapPixel", w_ImageData_mapPixel }, { "encode", w_ImageData_encode }, - - // Used in the Lua wrapper code. - { "_mapPixelUnsafe", w_ImageData__mapPixelUnsafe }, - { "_performAtomic", w_ImageData__performAtomic }, - { 0, 0 } }; diff --git a/src/modules/image/wrap_ImageData.h b/src/modules/image/wrap_ImageData.h index 6d797068b..bd5e1beba 100644 --- a/src/modules/image/wrap_ImageData.h +++ b/src/modules/image/wrap_ImageData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/image/wrap_ImageData.lua b/src/modules/image/wrap_ImageData.lua index 308272da6..26502afb0 100644 --- a/src/modules/image/wrap_ImageData.lua +++ b/src/modules/image/wrap_ImageData.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -38,29 +38,6 @@ local function clamp01(x) return min(max(x, 0), 1) end --- Implement thread-safe ImageData:mapPixel regardless of whether the FFI is --- used or not. -function ImageData:mapPixel(func, ix, iy, iw, ih) - local idw, idh = self:getDimensions() - - ix = ix or 0 - iy = iy or 0 - iw = iw or idw - ih = ih or idh - - if type(ix) ~= "number" then error("bad argument #2 to ImageData:mapPixel (expected number)", 2) end - if type(iy) ~= "number" then error("bad argument #3 to ImageData:mapPixel (expected number)", 2) end - if type(iw) ~= "number" then error("bad argument #4 to ImageData:mapPixel (expected number)", 2) end - if type(ih) ~= "number" then error("bad argument #5 to ImageData:mapPixel (expected number)", 2) end - - if type(func) ~= "function" then error("bad argument #1 to ImageData:mapPixel (expected function)", 2) end - if not (inside(ix, iy, idw, idh) and inside(ix+iw-1, iy+ih-1, idw, idh)) then error("Invalid rectangle dimensions", 2) end - - -- performAtomic and mapPixelUnsafe have Lua-C API and FFI versions. - self:_performAtomic(self._mapPixelUnsafe, self, func, ix, iy, iw, ih) -end - - -- Everything below this point is efficient FFI replacements for existing -- ImageData functionality. @@ -84,9 +61,6 @@ typedef uint16_t float10; typedef struct FFI_ImageData { - void (*lockMutex)(Proxy *p); - void (*unlockMutex)(Proxy *p); - float (*float16to32)(float16 f); float16 (*float32to16)(float f); @@ -368,9 +342,9 @@ local objectcache = setmetatable({}, { width = width, height = height, format = format, - pointer = conv == nil and nil or ffi.cast(conv.pointer, imagedata:getFFIPointer()), - tolua = conv == nil and nil or conv.tolua, - fromlua = conv == nil and nil or conv.fromlua, + pointer = conv ~= nil and ffi.cast(conv.pointer, imagedata:getFFIPointer()) or nil, + tolua = conv ~= nil and conv.tolua or nil, + fromlua = conv ~= nil and conv.fromlua or nil, } self[imagedata] = p @@ -381,20 +355,23 @@ local objectcache = setmetatable({}, { -- Overwrite existing functions with new FFI versions. -function ImageData:_performAtomic(...) - ffifuncs.lockMutex(self) - local success, err = pcall(...) - ffifuncs.unlockMutex(self) - - if not success then - error(err, 3) - end -end - -function ImageData:_mapPixelUnsafe(func, ix, iy, iw, ih) +function ImageData:mapPixel(func, ix, iy, iw, ih) local p = objectcache[self] local idw, idh = p.width, p.height + ix = ix or 0 + iy = iy or 0 + iw = iw or idw + ih = ih or idh + + if type(ix) ~= "number" then error("bad argument #2 to ImageData:mapPixel (expected number)", 2) end + if type(iy) ~= "number" then error("bad argument #3 to ImageData:mapPixel (expected number)", 2) end + if type(iw) ~= "number" then error("bad argument #4 to ImageData:mapPixel (expected number)", 2) end + if type(ih) ~= "number" then error("bad argument #5 to ImageData:mapPixel (expected number)", 2) end + + if type(func) ~= "function" then error("bad argument #1 to ImageData:mapPixel (expected function)", 2) end + if not (inside(ix, iy, idw, idh) and inside(ix+iw-1, iy+ih-1, idw, idh)) then error("Invalid rectangle dimensions", 2) end + if p.pointer == nil then error("ImageData:mapPixel does not currently support the "..p.format.." pixel format.", 2) end ix = floor(ix) @@ -427,12 +404,8 @@ function ImageData:getPixel(x, y) if p.pointer == nil then error("ImageData:getPixel does not currently support the "..p.format.." pixel format.", 2) end - ffifuncs.lockMutex(self) local pixel = p.pointer[y * p.width + x] - local r, g, b, a = p.tolua(pixel) - ffifuncs.unlockMutex(self) - - return r, g, b, a + return p.tolua(pixel) end function ImageData:setPixel(x, y, r, g, b, a) @@ -457,9 +430,7 @@ function ImageData:setPixel(x, y, r, g, b, a) if p.pointer == nil then error("ImageData:setPixel does not currently support the "..p.format.." pixel format.", 2) end - ffifuncs.lockMutex(self) p.fromlua(p.pointer[y * p.width + x], r, g, b, a) - ffifuncs.unlockMutex(self) end function ImageData:getWidth() diff --git a/src/modules/joystick/Joystick.cpp b/src/modules/joystick/Joystick.cpp index 34b2a29f3..5f955e18e 100644 --- a/src/modules/joystick/Joystick.cpp +++ b/src/modules/joystick/Joystick.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/joystick/Joystick.h b/src/modules/joystick/Joystick.h index 4727c594a..50c922c76 100644 --- a/src/modules/joystick/Joystick.h +++ b/src/modules/joystick/Joystick.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ // LOVE #include "common/Object.h" #include "common/StringMap.h" +#include "common/int.h" #include "sensor/Sensor.h" // stdlib @@ -172,7 +173,7 @@ public: virtual ~Joystick() {} - virtual bool open(int deviceindex) = 0; + virtual bool open(int64 deviceid) = 0; virtual void close() = 0; virtual bool isConnected() const = 0; @@ -194,7 +195,7 @@ public: virtual void setPlayerIndex(int index) = 0; virtual int getPlayerIndex() const = 0; - virtual bool openGamepad(int deviceindex) = 0; + virtual bool openGamepad(int64 deviceid) = 0; virtual bool isGamepad() const = 0; virtual GamepadType getGamepadType() const = 0; diff --git a/src/modules/joystick/JoystickModule.h b/src/modules/joystick/JoystickModule.h index dc890efa9..26b208bc6 100644 --- a/src/modules/joystick/JoystickModule.h +++ b/src/modules/joystick/JoystickModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -36,14 +36,11 @@ public: virtual ~JoystickModule() {} - // Implements Module. - ModuleType getModuleType() const override { return M_JOYSTICK; } - /** * Adds a connected Joystick device and opens it for use. * Returns NULL if the Joystick could not be added. **/ - virtual Joystick *addJoystick(int deviceindex) = 0; + virtual Joystick *addJoystick(int64 deviceid) = 0; /** * Removes a disconnected Joystick device. @@ -101,6 +98,12 @@ public: **/ virtual std::string getGamepadMappingString(const std::string &guid) const = 0; +protected: + + JoystickModule(const char *name) + : Module(M_JOYSTICK, name) + {} + }; // JoystickModule } // joystick diff --git a/src/modules/joystick/sdl/Joystick.cpp b/src/modules/joystick/sdl/Joystick.cpp index def324747..1ebe6f545 100644 --- a/src/modules/joystick/sdl/Joystick.cpp +++ b/src/modules/joystick/sdl/Joystick.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -31,6 +31,8 @@ #include #include +#if !SDL_VERSION_ATLEAST(3, 0, 0) + #ifndef SDL_TICKS_PASSED #define SDL_TICKS_PASSED(A, B) ((Sint32)((B) - (A)) <= 0) #endif @@ -69,8 +71,10 @@ Joystick::~Joystick() close(); } -bool Joystick::open(int deviceindex) +bool Joystick::open(int64 deviceid) { + int deviceindex = (int) deviceid; + close(); joyhandle = SDL_JoystickOpen(deviceindex); @@ -263,8 +267,10 @@ int Joystick::getPlayerIndex() const #endif } -bool Joystick::openGamepad(int deviceindex) +bool Joystick::openGamepad(int64 deviceid) { + int deviceindex = (int) deviceid; + if (!SDL_IsGameController(deviceindex)) return false; @@ -852,3 +858,5 @@ EnumMap +#if !SDL_VERSION_ATLEAST(3, 0, 0) + namespace love { namespace joystick @@ -44,7 +46,7 @@ public: virtual ~Joystick(); - bool open(int deviceindex) override; + bool open(int64 deviceid) override; void close() override; bool isConnected() const override; @@ -66,7 +68,7 @@ public: void setPlayerIndex(int index) override; int getPlayerIndex() const override; - bool openGamepad(int deviceindex) override; + bool openGamepad(int64 deviceid) override; bool isGamepad() const override; GamepadType getGamepadType() const override; @@ -155,4 +157,6 @@ private: } // joystick } // love +#endif // !SDL_VERSION_ATLEAST(3, 0, 0) + #endif // LOVE_JOYSTICK_SDL_JOYSTICK_H diff --git a/src/modules/joystick/sdl/JoystickModule.cpp b/src/modules/joystick/sdl/JoystickModule.cpp index de45fe0ff..9e4510ecd 100644 --- a/src/modules/joystick/sdl/JoystickModule.cpp +++ b/src/modules/joystick/sdl/JoystickModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -21,6 +21,7 @@ #include "common/config.h" #include "JoystickModule.h" #include "Joystick.h" +#include "JoystickSDL3.h" // SDL #include @@ -40,11 +41,28 @@ namespace sdl { JoystickModule::JoystickModule() + : love::joystick::JoystickModule("love.joystick.sdl") { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD) < 0) +#else if (SDL_InitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) +#endif throw love::Exception("Could not initialize SDL joystick subsystem (%s)", SDL_GetError()); // Initialize any joysticks which are already connected. +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + SDL_JoystickID *sticks = SDL_GetJoysticks(&count); + for (int i = 0; i < count; i++) + addJoystick((int64) sticks[i]); + SDL_free(sticks); + + // Start joystick event watching. Joysticks are automatically added and + // removed via love.event. + SDL_SetJoystickEventsEnabled(SDL_TRUE); + SDL_SetGamepadEventsEnabled(SDL_TRUE); +#else for (int i = 0; i < SDL_NumJoysticks(); i++) addJoystick(i); @@ -52,6 +70,7 @@ JoystickModule::JoystickModule() // removed via love.event. SDL_JoystickEventState(SDL_ENABLE); SDL_GameControllerEventState(SDL_ENABLE); +#endif } JoystickModule::~JoystickModule() @@ -66,12 +85,11 @@ JoystickModule::~JoystickModule() if (SDL_WasInit(SDL_INIT_HAPTIC) != 0) SDL_QuitSubSystem(SDL_INIT_HAPTIC); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD); +#else SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); -} - -const char *JoystickModule::getName() const -{ - return "love.joystick.sdl"; +#endif } love::joystick::Joystick *JoystickModule::getJoystick(int joyindex) @@ -110,12 +128,16 @@ love::joystick::Joystick *JoystickModule::getJoystickFromID(int instanceid) return nullptr; } -love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex) +love::joystick::Joystick *JoystickModule::addJoystick(int64 deviceid) { - if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (deviceid == 0) +#else + if (deviceid < 0 || (int) deviceid >= SDL_NumJoysticks()) +#endif return nullptr; - std::string guidstr = getDeviceGUID(deviceindex); + std::string guidstr = getDeviceGUID(deviceid); joystick::Joystick *joystick = 0; bool reused = false; @@ -132,14 +154,18 @@ love::joystick::Joystick *JoystickModule::addJoystick(int deviceindex) if (!joystick) { +#if SDL_VERSION_ATLEAST(3, 0, 0) joystick = new Joystick((int) joysticks.size()); +#else + joystick = new Joystick((int) joysticks.size()); +#endif joysticks.push_back(joystick); } // Make sure the Joystick object isn't in the active list already. removeJoystick(joystick); - if (!joystick->open(deviceindex)) + if (!joystick->open(deviceid)) return nullptr; // Make sure multiple instances of the same physical joystick aren't added @@ -188,10 +214,17 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa if (guid.length() != 32) throw love::Exception("Invalid joystick GUID: %s", guid.c_str()); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_JoystickGUID sdlguid = SDL_GetJoystickGUIDFromString(guid.c_str()); + std::string mapstr; + + char *sdlmapstr = SDL_GetGamepadMappingForGUID(sdlguid); +#else SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str()); std::string mapstr; char *sdlmapstr = SDL_GameControllerMappingForGUID(sdlguid); +#endif if (sdlmapstr) { mapstr = sdlmapstr; @@ -273,7 +306,11 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa } // 1 == added, 0 == updated, -1 == error. +#if SDL_VERSION_ATLEAST(3, 0, 0) + int status = SDL_AddGamepadMapping(mapstr.c_str()); +#else int status = SDL_GameControllerAddMapping(mapstr.c_str()); +#endif if (status != -1) recentGamepadGUIDs[guid] = true; @@ -288,8 +325,13 @@ bool JoystickModule::setGamepadMapping(const std::string &guid, Joystick::Gamepa std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinput) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_GamepadAxis sdlaxis; + SDL_GamepadButton sdlbutton; +#else SDL_GameControllerAxis sdlaxis; SDL_GameControllerButton sdlbutton; +#endif const char *gpinputname = nullptr; @@ -297,11 +339,19 @@ std::string JoystickModule::stringFromGamepadInput(Joystick::GamepadInput gpinpu { case Joystick::INPUT_TYPE_AXIS: if (Joystick::getConstant(gpinput.axis, sdlaxis)) +#if SDL_VERSION_ATLEAST(3, 0, 0) + gpinputname = SDL_GetGamepadStringForAxis(sdlaxis); +#else gpinputname = SDL_GameControllerGetStringForAxis(sdlaxis); +#endif break; case Joystick::INPUT_TYPE_BUTTON: if (Joystick::getConstant(gpinput.button, sdlbutton)) +#if SDL_VERSION_ATLEAST(3, 0, 0) + gpinputname = SDL_GetGamepadStringForButton(sdlbutton); +#else gpinputname = SDL_GameControllerGetStringForButton(sdlbutton); +#endif break; default: break; @@ -351,12 +401,25 @@ void JoystickModule::checkGamepads(const std::string &guid) const // Make sure all connected joysticks of a certain guid that are // gamepad-capable are opened as such. +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + SDL_JoystickID *sdlsticks = SDL_GetJoysticks(&count); + for (int d_index = 0; d_index < count; d_index++) + { + if (!SDL_IsGamepad(sdlsticks[d_index])) + continue; + + auto sdlid = sdlsticks[d_index]; +#else for (int d_index = 0; d_index < SDL_NumJoysticks(); d_index++) { if (!SDL_IsGameController(d_index)) continue; - if (guid.compare(getDeviceGUID(d_index)) != 0) + auto sdlid = d_index; +#endif + + if (guid.compare(getDeviceGUID(sdlid)) != 0) continue; for (auto stick : activeSticks) @@ -366,6 +429,17 @@ void JoystickModule::checkGamepads(const std::string &guid) const // Big hack time: open the index as a game controller and compare // the underlying joystick handle to the active stick's. +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Gamepad *controller = SDL_OpenGamepad(sdlid); + if (controller == nullptr) + continue; + + // GameController objects are reference-counted in SDL, so we don't want to + // have a joystick open when trying to re-initialize it + SDL_Joystick *sdlstick = SDL_GetGamepadJoystick(controller); + bool open_gamepad = (sdlstick == (SDL_Joystick *) stick->getHandle()); + SDL_CloseGamepad(controller); +#else SDL_GameController *controller = SDL_GameControllerOpen(d_index); if (controller == nullptr) continue; @@ -375,25 +449,36 @@ void JoystickModule::checkGamepads(const std::string &guid) const SDL_Joystick *sdlstick = SDL_GameControllerGetJoystick(controller); bool open_gamepad = (sdlstick == (SDL_Joystick *) stick->getHandle()); SDL_GameControllerClose(controller); +#endif // open as gamepad if necessary if (open_gamepad) - stick->openGamepad(d_index); + stick->openGamepad(sdlid); } } } -std::string JoystickModule::getDeviceGUID(int deviceindex) const +std::string JoystickModule::getDeviceGUID(int64 deviceid) const { - if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) - return std::string(""); - // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator. char guidstr[33] = {'\0'}; +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (deviceid <= 0) + return std::string(""); + + // SDL's GUIDs identify *classes* of devices, instead of unique devices. + SDL_JoystickGUID guid = SDL_GetJoystickInstanceGUID((SDL_JoystickID)deviceid); + SDL_GetJoystickGUIDString(guid, guidstr, sizeof(guidstr)); +#else + int deviceindex = (int) deviceid; + if (deviceindex < 0 || deviceindex >= SDL_NumJoysticks()) + return std::string(""); + // SDL2's GUIDs identify *classes* of devices, instead of unique devices. SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(deviceindex); SDL_JoystickGetGUIDString(guid, guidstr, sizeof(guidstr)); +#endif return std::string(guidstr); } @@ -438,7 +523,11 @@ void JoystickModule::loadGamepadMappings(const std::string &mappings) mapping.erase(pstartpos, pendpos - pstartpos + 1); } +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_AddGamepadMapping(mapping.c_str()) != -1) +#else if (SDL_GameControllerAddMapping(mapping.c_str()) != -1) +#endif { success = true; std::string guid = mapping.substr(0, mapping.find_first_of(',')); @@ -458,9 +547,13 @@ void JoystickModule::loadGamepadMappings(const std::string &mappings) std::string JoystickModule::getGamepadMappingString(const std::string &guid) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_JoystickGUID sdlguid = SDL_GetJoystickGUIDFromString(guid.c_str()); + char *sdlmapping = SDL_GetGamepadMappingForGUID(sdlguid); +#else SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(guid.c_str()); - char *sdlmapping = SDL_GameControllerMappingForGUID(sdlguid); +#endif if (sdlmapping == nullptr) return ""; @@ -483,9 +576,13 @@ std::string JoystickModule::saveGamepadMappings() for (const auto &g : recentGamepadGUIDs) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_JoystickGUID sdlguid = SDL_GetJoystickGUIDFromString(g.first.c_str()); + char *sdlmapping = SDL_GetGamepadMappingForGUID(sdlguid); +#else SDL_JoystickGUID sdlguid = SDL_JoystickGetGUIDFromString(g.first.c_str()); - char *sdlmapping = SDL_GameControllerMappingForGUID(sdlguid); +#endif if (sdlmapping == nullptr) continue; diff --git a/src/modules/joystick/sdl/JoystickModule.h b/src/modules/joystick/sdl/JoystickModule.h index 39b9548df..5afdc133a 100644 --- a/src/modules/joystick/sdl/JoystickModule.h +++ b/src/modules/joystick/sdl/JoystickModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -44,11 +44,8 @@ public: JoystickModule(); virtual ~JoystickModule(); - // Implements Module. - const char *getName() const override; - // Implements JoystickModule. - love::joystick::Joystick *addJoystick(int deviceindex) override; + love::joystick::Joystick *addJoystick(int64 deviceid) override; void removeJoystick(love::joystick::Joystick *joystick) override; love::joystick::Joystick *getJoystickFromID(int instanceid) override; love::joystick::Joystick *getJoystick(int joyindex) override; @@ -69,7 +66,7 @@ private: void checkGamepads(const std::string &guid) const; // SDL2's GUIDs identify *classes* of devices, instead of unique devices. - std::string getDeviceGUID(int deviceindex) const; + std::string getDeviceGUID(int64 deviceid) const; // Lists of currently connected Joysticks. std::vector activeSticks; diff --git a/src/modules/joystick/sdl/JoystickSDL3.cpp b/src/modules/joystick/sdl/JoystickSDL3.cpp new file mode 100644 index 000000000..6ba7b2ae8 --- /dev/null +++ b/src/modules/joystick/sdl/JoystickSDL3.cpp @@ -0,0 +1,652 @@ +/** + * Copyright (c) 2006-2023 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +// LOVE +#include "common/config.h" +#include "JoystickSDL3.h" +#include "common/int.h" +#include "sensor/sdl/Sensor.h" + +// SDL +#include + +#if SDL_VERSION_ATLEAST(3, 0, 0) + +// C++ +#include +#include + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +Joystick::Joystick(int id) + : joyhandle(nullptr) + , controller(nullptr) + , joystickType(JOYSTICK_TYPE_UNKNOWN) + , instanceid(-1) + , id(id) +{ +} + +Joystick::~Joystick() +{ + close(); +} + +bool Joystick::open(int64 deviceid) +{ + close(); + + joyhandle = SDL_OpenJoystick((SDL_JoystickID) deviceid); + + if (joyhandle) + { + instanceid = SDL_GetJoystickInstanceID(joyhandle); + + // SDL_JoystickGetGUIDString uses 32 bytes plus the null terminator. + char cstr[33]; + + SDL_JoystickGUID sdlguid = SDL_GetJoystickGUID(joyhandle); + SDL_GetJoystickGUIDString(sdlguid, cstr, (int) sizeof(cstr)); + + pguid = std::string(cstr); + + // See if SDL thinks this is a Game Controller. + openGamepad(deviceid); + + // Prefer the Joystick name for consistency. + const char *joyname = SDL_GetJoystickName(joyhandle); + if (!joyname && controller) + joyname = SDL_GetGamepadName(controller); + + if (joyname) + name = joyname; + + switch (SDL_GetJoystickType(joyhandle)) + { + case SDL_JOYSTICK_TYPE_GAMEPAD: + joystickType = JOYSTICK_TYPE_GAMEPAD; + break; + case SDL_JOYSTICK_TYPE_WHEEL: + joystickType = JOYSTICK_TYPE_WHEEL; + break; + case SDL_JOYSTICK_TYPE_ARCADE_STICK: + joystickType = JOYSTICK_TYPE_ARCADE_STICK; + break; + case SDL_JOYSTICK_TYPE_FLIGHT_STICK: + joystickType = JOYSTICK_TYPE_FLIGHT_STICK; + break; + case SDL_JOYSTICK_TYPE_DANCE_PAD: + joystickType = JOYSTICK_TYPE_DANCE_PAD; + break; + case SDL_JOYSTICK_TYPE_GUITAR: + joystickType = JOYSTICK_TYPE_GUITAR; + break; + case SDL_JOYSTICK_TYPE_DRUM_KIT: + joystickType = JOYSTICK_TYPE_DRUM_KIT; + break; + case SDL_JOYSTICK_TYPE_ARCADE_PAD: + joystickType = JOYSTICK_TYPE_ARCADE_PAD; + break; + case SDL_JOYSTICK_TYPE_THROTTLE: + joystickType = JOYSTICK_TYPE_THROTTLE; + break; + default: + joystickType = JOYSTICK_TYPE_UNKNOWN; + break; + } + } + + return isConnected(); +} + +void Joystick::close() +{ + if (controller) + SDL_CloseGamepad(controller); + + if (joyhandle) + SDL_CloseJoystick(joyhandle); + + joyhandle = nullptr; + controller = nullptr; + instanceid = -1; +} + +bool Joystick::isConnected() const +{ + return joyhandle != nullptr && SDL_JoystickConnected(joyhandle); +} + +const char *Joystick::getName() const +{ + return name.c_str(); +} + +Joystick::JoystickType Joystick::getJoystickType() const +{ + return joystickType; +} + +int Joystick::getAxisCount() const +{ + return isConnected() ? SDL_GetNumJoystickAxes(joyhandle) : 0; +} + +int Joystick::getButtonCount() const +{ + return isConnected() ? SDL_GetNumJoystickButtons(joyhandle) : 0; +} + +int Joystick::getHatCount() const +{ + return isConnected() ? SDL_GetNumJoystickHats(joyhandle) : 0; +} + +float Joystick::getAxis(int axisindex) const +{ + if (!isConnected() || axisindex < 0 || axisindex >= getAxisCount()) + return 0; + + return clampval(((float) SDL_GetJoystickAxis(joyhandle, axisindex))/32768.0f); +} + +std::vector Joystick::getAxes() const +{ + std::vector axes; + int count = getAxisCount(); + + if (!isConnected() || count <= 0) + return axes; + + axes.reserve(count); + + for (int i = 0; i < count; i++) + axes.push_back(clampval(((float) SDL_GetJoystickAxis(joyhandle, i))/32768.0f)); + + return axes; +} + +Joystick::Hat Joystick::getHat(int hatindex) const +{ + Hat h = HAT_INVALID; + + if (!isConnected() || hatindex < 0 || hatindex >= getHatCount()) + return h; + + getConstant(SDL_GetJoystickHat(joyhandle, hatindex), h); + + return h; +} + +bool Joystick::isDown(const std::vector &buttonlist) const +{ + if (!isConnected()) + return false; + + int numbuttons = getButtonCount(); + + for (int button : buttonlist) + { + if (button < 0 || button >= numbuttons) + continue; + + if (SDL_GetJoystickButton(joyhandle, button) == 1) + return true; + } + + return false; +} + +void Joystick::setPlayerIndex(int index) +{ + if (!isConnected()) + return; + + SDL_SetJoystickPlayerIndex(joyhandle, index); +} + +int Joystick::getPlayerIndex() const +{ + if (!isConnected()) + return -1; + + return SDL_GetJoystickPlayerIndex(joyhandle); +} + +bool Joystick::openGamepad(int64 deviceid) +{ + if (!SDL_IsGamepad((SDL_JoystickID)deviceid)) + return false; + + if (isGamepad()) + { + SDL_CloseGamepad(controller); + controller = nullptr; + } + + controller = SDL_OpenGamepad((SDL_JoystickID)deviceid); + return isGamepad(); +} + +bool Joystick::isGamepad() const +{ + return controller != nullptr; +} + +Joystick::GamepadType Joystick::getGamepadType() const +{ + if (controller == nullptr) + return GAMEPAD_TYPE_UNKNOWN; + + switch (SDL_GetGamepadType(controller)) + { + case SDL_GAMEPAD_TYPE_UNKNOWN: return GAMEPAD_TYPE_UNKNOWN; + case SDL_GAMEPAD_TYPE_XBOX360: return GAMEPAD_TYPE_XBOX360; + case SDL_GAMEPAD_TYPE_XBOXONE: return GAMEPAD_TYPE_XBOXONE; + case SDL_GAMEPAD_TYPE_PS3: return GAMEPAD_TYPE_PS3; + case SDL_GAMEPAD_TYPE_PS4: return GAMEPAD_TYPE_PS4; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: return GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; + case SDL_GAMEPAD_TYPE_PS5: return GAMEPAD_TYPE_PS5; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: return GAMEPAD_TYPE_JOYCON_LEFT; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: return GAMEPAD_TYPE_JOYCON_RIGHT; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: return GAMEPAD_TYPE_JOYCON_PAIR; + default: return GAMEPAD_TYPE_UNKNOWN; + } + + return GAMEPAD_TYPE_UNKNOWN; +} + +float Joystick::getGamepadAxis(love::joystick::Joystick::GamepadAxis axis) const +{ + if (!isConnected() || !isGamepad()) + return 0.f; + + SDL_GamepadAxis sdlaxis; + if (!getConstant(axis, sdlaxis)) + return 0.f; + + Sint16 value = SDL_GetGamepadAxis(controller, sdlaxis); + + return clampval((float) value / 32768.0f); +} + +bool Joystick::isGamepadDown(const std::vector &blist) const +{ + if (!isConnected() || !isGamepad()) + return false; + + SDL_GamepadButton sdlbutton; + + for (GamepadButton button : blist) + { + if (!getConstant(button, sdlbutton)) + continue; + + if (SDL_GetGamepadButton(controller, sdlbutton) == 1) + return true; + } + + return false; +} + +Joystick::JoystickInput Joystick::getGamepadMapping(const GamepadInput &input) const +{ + Joystick::JoystickInput jinput; + jinput.type = INPUT_TYPE_MAX_ENUM; + + if (!isGamepad()) + return jinput; + + SDL_GamepadButton sdlbutton = SDL_GAMEPAD_BUTTON_INVALID; + SDL_GamepadAxis sdlaxis = SDL_GAMEPAD_AXIS_INVALID; + + switch (input.type) + { + case INPUT_TYPE_BUTTON: + getConstant(input.button, sdlbutton); + break; + case INPUT_TYPE_AXIS: + getConstant(input.axis, sdlaxis); + break; + default: + break; + } + + int bindcount = 0; + SDL_GamepadBinding **sdlbindings = SDL_GetGamepadBindings(controller, &bindcount); + for (int i = 0; i < bindcount; i++) + { + const SDL_GamepadBinding *b = sdlbindings[i]; + if ((input.type == INPUT_TYPE_BUTTON && b->output_type == SDL_GAMEPAD_BINDTYPE_BUTTON && b->output.button == sdlbutton) + || (input.type == INPUT_TYPE_AXIS && b->output_type == SDL_GAMEPAD_BINDTYPE_AXIS && b->output.axis.axis == sdlaxis)) + { + switch (b->input_type) + { + case SDL_GAMEPAD_BINDTYPE_BUTTON: + jinput.type = INPUT_TYPE_BUTTON; + jinput.button = b->input.button; + break; + case SDL_GAMEPAD_BINDTYPE_AXIS: + jinput.type = INPUT_TYPE_AXIS; + jinput.axis = b->input.axis.axis; + break; + case SDL_GAMEPAD_BINDTYPE_HAT: + if (getConstant(b->input.hat.hat_mask, jinput.hat.value)) + { + jinput.type = INPUT_TYPE_HAT; + jinput.hat.index = b->input.hat.hat; + } + break; + case SDL_GAMEPAD_BINDTYPE_NONE: + default: + break; + } + + break; + } + } + + SDL_free(sdlbindings); + + return jinput; +} + +std::string Joystick::getGamepadMappingString() const +{ + char *sdlmapping = nullptr; + + if (controller != nullptr) + sdlmapping = SDL_GetGamepadMapping(controller); + + if (sdlmapping == nullptr) + { + SDL_JoystickGUID sdlguid = SDL_GetJoystickGUIDFromString(pguid.c_str()); + sdlmapping = SDL_GetGamepadMappingForGUID(sdlguid); + } + + if (sdlmapping == nullptr) + return ""; + + std::string mappingstr(sdlmapping); + SDL_free(sdlmapping); + + // Matches SDL_GameControllerAddMappingsFromRW. + if (mappingstr.find_last_of(',') != mappingstr.length() - 1) + mappingstr += ","; + + if (mappingstr.find("platform:") == std::string::npos) + mappingstr += "platform:" + std::string(SDL_GetPlatform()); + + return mappingstr; +} + +void *Joystick::getHandle() const +{ + return joyhandle; +} + +std::string Joystick::getGUID() const +{ + // SDL2's GUIDs identify *classes* of devices, instead of unique devices. + return pguid; +} + +int Joystick::getInstanceID() const +{ + return instanceid; +} + +int Joystick::getID() const +{ + return id; +} + +void Joystick::getDeviceInfo(int &vendorID, int &productID, int &productVersion) const +{ + if (joyhandle != nullptr) + { + vendorID = SDL_GetJoystickVendor(joyhandle); + productID = SDL_GetJoystickProduct(joyhandle); + productVersion = SDL_GetJoystickProductVersion(joyhandle); + } + else + { + vendorID = 0; + productID = 0; + productVersion = 0; + } +} + +bool Joystick::isVibrationSupported() +{ + if (!isConnected()) + return false; + + SDL_PropertiesID props = SDL_GetJoystickProperties(joyhandle); + return SDL_GetBooleanProperty(props, SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, SDL_FALSE); +} + +bool Joystick::setVibration(float left, float right, float duration) +{ + left = std::min(std::max(left, 0.0f), 1.0f); + right = std::min(std::max(right, 0.0f), 1.0f); + + if (left == 0.0f && right == 0.0f) + return setVibration(); + + if (!isConnected()) + return false; + + Uint32 length = LOVE_UINT32_MAX; + if (duration >= 0.0f) + { + float maxduration = (float) (std::numeric_limits::max() / 1000.0); + length = Uint32(std::min(duration, maxduration) * 1000); + } + + return SDL_RumbleJoystick(joyhandle, (Uint16)(left * LOVE_UINT16_MAX), (Uint16)(right * LOVE_UINT16_MAX), length) == 0; +} + +bool Joystick::setVibration() +{ + return isConnected() && SDL_RumbleJoystick(joyhandle, 0, 0, 0) == 0; +} + +void Joystick::getVibration(float &left, float &right) +{ + // Deprecated. + left = 0.0f; + right = 0.0f; +} + +bool Joystick::hasSensor(Sensor::SensorType type) const +{ +#if defined(LOVE_ENABLE_SENSOR) + using SDLSensor = love::sensor::sdl::Sensor; + + if (!isGamepad()) + return false; + + return SDL_GamepadHasSensor(controller, SDLSensor::convert(type)) == SDL_TRUE; +#else + return false; +#endif +} + +bool Joystick::isSensorEnabled(Sensor::SensorType type) const +{ +#if defined(LOVE_ENABLE_SENSOR) + using SDLSensor = love::sensor::sdl::Sensor; + + if (!isGamepad()) + return false; + + return SDL_GamepadSensorEnabled(controller, SDLSensor::convert(type)) == SDL_TRUE; +#else + return false; +#endif +} + +void Joystick::setSensorEnabled(Sensor::SensorType type, bool enabled) +{ +#if defined(LOVE_ENABLE_SENSOR) + using SDLSensor = love::sensor::sdl::Sensor; + + if (!isGamepad()) + throw love::Exception("Sensor is only supported on gamepad"); + + if (SDL_SetGamepadSensorEnabled(controller, SDLSensor::convert(type), enabled ? SDL_TRUE : SDL_FALSE) != 0) + { + const char *name = nullptr; + SDLSensor::getConstant(type, name); + + throw love::Exception("Could not open \"%s\" SDL gamepad sensor (%s)", name, SDL_GetError()); + } +#else + throw love::Exception("Compiled version of LOVE does not support gamepad sensor"); +#endif +} + +std::vector Joystick::getSensorData(Sensor::SensorType type) const +{ +#if defined(LOVE_ENABLE_SENSOR) + using SDLSensor = love::sensor::sdl::Sensor; + + if (!isGamepad()) + throw love::Exception("Sensor is only supported on gamepad"); + + std::vector data(3); + + if (!isSensorEnabled(type)) + { + const char *name = nullptr; + SDLSensor::getConstant(type, name); + + throw love::Exception("\"%s\" gamepad sensor is not enabled", name); + } + + if (SDL_GetGamepadSensorData(controller, SDLSensor::convert(type), data.data(), (int) data.size()) != 0) + { + const char *name = nullptr; + SDLSensor::getConstant(type, name); + + throw love::Exception("Could not get \"%s\" SDL gamepad sensor data (%s)", name, SDL_GetError()); + } + + return data; +#else + throw love::Exception("Compiled version of LOVE does not support gamepad sensor"); +#endif +} + +bool Joystick::getConstant(Uint8 in, Joystick::Hat &out) +{ + return hats.find(in, out); +} + +bool Joystick::getConstant(Joystick::Hat in, Uint8 &out) +{ + return hats.find(in, out); +} + +bool Joystick::getConstant(SDL_GamepadAxis in, Joystick::GamepadAxis &out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadAxis in, SDL_GamepadAxis &out) +{ + return gpAxes.find(in, out); +} + +bool Joystick::getConstant(SDL_GamepadButton in, Joystick::GamepadButton &out) +{ + return gpButtons.find(in, out); +} + +bool Joystick::getConstant(Joystick::GamepadButton in, SDL_GamepadButton &out) +{ + return gpButtons.find(in, out); +} + +EnumMap::Entry Joystick::hatEntries[] = +{ + {Joystick::HAT_CENTERED, SDL_HAT_CENTERED}, + {Joystick::HAT_UP, SDL_HAT_UP}, + {Joystick::HAT_RIGHT, SDL_HAT_RIGHT}, + {Joystick::HAT_DOWN, SDL_HAT_DOWN}, + {Joystick::HAT_LEFT, SDL_HAT_LEFT}, + {Joystick::HAT_RIGHTUP, SDL_HAT_RIGHTUP}, + {Joystick::HAT_RIGHTDOWN, SDL_HAT_RIGHTDOWN}, + {Joystick::HAT_LEFTUP, SDL_HAT_LEFTUP}, + {Joystick::HAT_LEFTDOWN, SDL_HAT_LEFTDOWN}, +}; + +EnumMap Joystick::hats(Joystick::hatEntries, sizeof(Joystick::hatEntries)); + +EnumMap::Entry Joystick::gpAxisEntries[] = +{ + {Joystick::GAMEPAD_AXIS_LEFTX, SDL_GAMEPAD_AXIS_LEFTX}, + {Joystick::GAMEPAD_AXIS_LEFTY, SDL_GAMEPAD_AXIS_LEFTY}, + {Joystick::GAMEPAD_AXIS_RIGHTX, SDL_GAMEPAD_AXIS_RIGHTX}, + {Joystick::GAMEPAD_AXIS_RIGHTY, SDL_GAMEPAD_AXIS_RIGHTY}, + {Joystick::GAMEPAD_AXIS_TRIGGERLEFT, SDL_GAMEPAD_AXIS_LEFT_TRIGGER}, + {Joystick::GAMEPAD_AXIS_TRIGGERRIGHT, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER}, +}; + +EnumMap Joystick::gpAxes(Joystick::gpAxisEntries, sizeof(Joystick::gpAxisEntries)); + +EnumMap::Entry Joystick::gpButtonEntries[] = +{ + {Joystick::GAMEPAD_BUTTON_A, SDL_GAMEPAD_BUTTON_SOUTH}, + {Joystick::GAMEPAD_BUTTON_B, SDL_GAMEPAD_BUTTON_EAST}, + {Joystick::GAMEPAD_BUTTON_X, SDL_GAMEPAD_BUTTON_WEST}, + {Joystick::GAMEPAD_BUTTON_Y, SDL_GAMEPAD_BUTTON_NORTH}, + {Joystick::GAMEPAD_BUTTON_BACK, SDL_GAMEPAD_BUTTON_BACK}, + {Joystick::GAMEPAD_BUTTON_GUIDE, SDL_GAMEPAD_BUTTON_GUIDE}, + {Joystick::GAMEPAD_BUTTON_START, SDL_GAMEPAD_BUTTON_START}, + {Joystick::GAMEPAD_BUTTON_LEFTSTICK, SDL_GAMEPAD_BUTTON_LEFT_STICK}, + {Joystick::GAMEPAD_BUTTON_RIGHTSTICK, SDL_GAMEPAD_BUTTON_RIGHT_STICK}, + {Joystick::GAMEPAD_BUTTON_LEFTSHOULDER, SDL_GAMEPAD_BUTTON_LEFT_SHOULDER}, + {Joystick::GAMEPAD_BUTTON_RIGHTSHOULDER, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER}, + {Joystick::GAMEPAD_BUTTON_DPAD_UP, SDL_GAMEPAD_BUTTON_DPAD_UP}, + {Joystick::GAMEPAD_BUTTON_DPAD_DOWN, SDL_GAMEPAD_BUTTON_DPAD_DOWN}, + {Joystick::GAMEPAD_BUTTON_DPAD_LEFT, SDL_GAMEPAD_BUTTON_DPAD_LEFT}, + {Joystick::GAMEPAD_BUTTON_DPAD_RIGHT, SDL_GAMEPAD_BUTTON_DPAD_RIGHT}, + {Joystick::GAMEPAD_BUTTON_MISC1, SDL_GAMEPAD_BUTTON_MISC1}, + {Joystick::GAMEPAD_BUTTON_PADDLE1, SDL_GAMEPAD_BUTTON_LEFT_PADDLE1}, + {Joystick::GAMEPAD_BUTTON_PADDLE2, SDL_GAMEPAD_BUTTON_LEFT_PADDLE2}, + {Joystick::GAMEPAD_BUTTON_PADDLE3, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1}, + {Joystick::GAMEPAD_BUTTON_PADDLE4, SDL_GAMEPAD_BUTTON_RIGHT_PADDLE2}, + {Joystick::GAMEPAD_BUTTON_TOUCHPAD, SDL_GAMEPAD_BUTTON_TOUCHPAD}, +}; + +EnumMap Joystick::gpButtons(Joystick::gpButtonEntries, sizeof(Joystick::gpButtonEntries)); + +} // sdl +} // joystick +} // love + +#endif // SDL_VERSION_ATLEAST(3, 0, 0) diff --git a/src/modules/joystick/sdl/JoystickSDL3.h b/src/modules/joystick/sdl/JoystickSDL3.h new file mode 100644 index 000000000..62992c39b --- /dev/null +++ b/src/modules/joystick/sdl/JoystickSDL3.h @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2006-2023 LOVE Development Team + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + **/ + +#ifndef LOVE_JOYSTICK_SDL_JOYSTICK_SDL3_H +#define LOVE_JOYSTICK_SDL_JOYSTICK_SDL3_H + +// LOVE +#include "joystick/Joystick.h" +#include "common/EnumMap.h" +#include "common/int.h" + +// SDL +#include + +#if SDL_VERSION_ATLEAST(3, 0, 0) + +namespace love +{ +namespace joystick +{ +namespace sdl +{ + +class Joystick : public love::joystick::Joystick +{ +public: + + Joystick(int id); + + virtual ~Joystick(); + + bool open(int64 deviceid) override; + void close() override; + + bool isConnected() const override; + + const char *getName() const override; + + JoystickType getJoystickType() const override; + + int getAxisCount() const override; + int getButtonCount() const override; + int getHatCount() const override; + + float getAxis(int axisindex) const override; + std::vector getAxes() const override; + Hat getHat(int hatindex) const override; + + bool isDown(const std::vector &buttonlist) const override; + + void setPlayerIndex(int index) override; + int getPlayerIndex() const override; + + bool openGamepad(int64 deviceid) override; + bool isGamepad() const override; + + GamepadType getGamepadType() const override; + + float getGamepadAxis(GamepadAxis axis) const override; + bool isGamepadDown(const std::vector &blist) const override; + + JoystickInput getGamepadMapping(const GamepadInput &input) const override; + std::string getGamepadMappingString() const override; + + void *getHandle() const override; + + std::string getGUID() const override; + int getInstanceID() const override; + int getID() const override; + + void getDeviceInfo(int &vendorID, int &productID, int &productVersion) const override; + + bool isVibrationSupported() override; + bool setVibration(float left, float right, float duration = -1.0f) override; + bool setVibration() override; + void getVibration(float &left, float &right) override; + + bool hasSensor(Sensor::SensorType type) const override; + bool isSensorEnabled(Sensor::SensorType type) const override; + void setSensorEnabled(Sensor::SensorType type, bool enabled) override; + std::vector getSensorData(Sensor::SensorType type) const override; + + static bool getConstant(Hat in, Uint8 &out); + static bool getConstant(Uint8 in, Hat &out); + + static bool getConstant(SDL_GamepadAxis in, GamepadAxis &out); + static bool getConstant(GamepadAxis in, SDL_GamepadAxis &out); + + static bool getConstant(SDL_GamepadButton in, GamepadButton &out); + static bool getConstant(GamepadButton in, SDL_GamepadButton &out); + +private: + + Joystick() {} + + SDL_Joystick *joyhandle; + SDL_Gamepad *controller; + + JoystickType joystickType; + + SDL_JoystickID instanceid; + std::string pguid; + int id; + + std::string name; + + static EnumMap::Entry hatEntries[]; + static EnumMap hats; + + static EnumMap::Entry gpAxisEntries[]; + static EnumMap gpAxes; + + static EnumMap::Entry gpButtonEntries[]; + static EnumMap gpButtons; + +}; + +} // sdl +} // joystick +} // love + +#endif // SDL_VERSION_ATLEAST(3, 0, 0) + +#endif // LOVE_JOYSTICK_SDL_JOYSTICK_SDL3_H diff --git a/src/modules/joystick/wrap_Joystick.cpp b/src/modules/joystick/wrap_Joystick.cpp index 73386f1b1..4e08826a1 100644 --- a/src/modules/joystick/wrap_Joystick.cpp +++ b/src/modules/joystick/wrap_Joystick.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/joystick/wrap_Joystick.h b/src/modules/joystick/wrap_Joystick.h index b80dcd71a..2f3bdc96a 100644 --- a/src/modules/joystick/wrap_Joystick.h +++ b/src/modules/joystick/wrap_Joystick.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/joystick/wrap_JoystickModule.cpp b/src/modules/joystick/wrap_JoystickModule.cpp index 5a98f6d0a..b0c6e8289 100644 --- a/src/modules/joystick/wrap_JoystickModule.cpp +++ b/src/modules/joystick/wrap_JoystickModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/joystick/wrap_JoystickModule.h b/src/modules/joystick/wrap_JoystickModule.h index c84d05915..1344fb0a5 100644 --- a/src/modules/joystick/wrap_JoystickModule.h +++ b/src/modules/joystick/wrap_JoystickModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/keyboard/Keyboard.cpp b/src/modules/keyboard/Keyboard.cpp index 666957a2b..00ad69ad1 100644 --- a/src/modules/keyboard/Keyboard.cpp +++ b/src/modules/keyboard/Keyboard.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -19,6 +19,7 @@ **/ #include "common/config.h" +#include "libraries/utf8/utf8.h" #include "Keyboard.h" @@ -27,14 +28,77 @@ namespace love namespace keyboard { +Keyboard::Keyboard(const char *name) + : Module(M_KEYBOARD, name) +{ +} + bool Keyboard::getConstant(const char *in, Key &out) { - return keys.find(in, out); + auto it = stringToKey.find(in); + if (it != stringToKey.end()) + { + out = (Key)it->second; + return true; + } + + std::string text(in); + uint32 codepoint = 0; + + try + { + codepoint = utf8::peek_next(text.begin(), text.end()); + } + catch (utf8::exception &) + { + return false; + } + + if (codepoint > 0) + { + stringToKey[text] = codepoint; + out = (Key)codepoint; + } + + return false; } bool Keyboard::getConstant(Key in, const char *&out) { - return keys.find(in, out); + if (keyToString.empty()) + { + for (const auto &kvp : stringToKey) + keyToString[kvp.second] = kvp.first; + } + + auto it = keyToString.find(in); + if (it != keyToString.end()) + { + out = it->second.c_str(); + return true; + } + + char u[5] = { 0, 0, 0, 0, 0 }; + ptrdiff_t length = 0; + + try + { + char *end = utf8::unchecked::append(in, u); + length = end - u; + } + catch (utf8::exception &) + { + return false; + } + + if (length > 0) + { + keyToString[in] = std::string(u, length); + out = keyToString[in].c_str(); + return true; + } + + return false; } bool Keyboard::getConstant(const char *in, Scancode &out) @@ -57,7 +121,7 @@ bool Keyboard::getConstant(ModifierKey in, const char *&out) return modifiers.find(in, out); } -StringMap::Entry Keyboard::keyEntries[] = +std::map Keyboard::stringToKey = { {"unknown", Keyboard::KEY_UNKNOWN}, @@ -265,7 +329,7 @@ StringMap::Entry Keyboard::keyEntries[] = {"sleep", Keyboard::KEY_SLEEP}, }; -StringMap Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries)); +std::map Keyboard::keyToString; StringMap::Entry Keyboard::scancodeEntries[] = { diff --git a/src/modules/keyboard/Keyboard.h b/src/modules/keyboard/Keyboard.h index 65c6e465b..fc59b3d54 100644 --- a/src/modules/keyboard/Keyboard.h +++ b/src/modules/keyboard/Keyboard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -27,6 +27,7 @@ // C++ #include +#include namespace love { @@ -37,219 +38,6 @@ class Keyboard : public Module { public: - /** - * Keyboard keys. They are dependent on the current layout of the keyboard. - **/ - enum Key - { - KEY_UNKNOWN, - - KEY_RETURN, - KEY_ESCAPE, - KEY_BACKSPACE, - KEY_TAB, - KEY_SPACE, - KEY_EXCLAIM, - KEY_QUOTEDBL, - KEY_HASH, - KEY_PERCENT, - KEY_DOLLAR, - KEY_AMPERSAND, - KEY_QUOTE, - KEY_LEFTPAREN, - KEY_RIGHTPAREN, - KEY_ASTERISK, - KEY_PLUS, - KEY_COMMA, - KEY_MINUS, - KEY_PERIOD, - KEY_SLASH, - KEY_0, - KEY_1, - KEY_2, - KEY_3, - KEY_4, - KEY_5, - KEY_6, - KEY_7, - KEY_8, - KEY_9, - KEY_COLON, - KEY_SEMICOLON, - KEY_LESS, - KEY_EQUALS, - KEY_GREATER, - KEY_QUESTION, - KEY_AT, - - KEY_LEFTBRACKET, - KEY_BACKSLASH, - KEY_RIGHTBRACKET, - KEY_CARET, - KEY_UNDERSCORE, - KEY_BACKQUOTE, - KEY_A, - KEY_B, - KEY_C, - KEY_D, - KEY_E, - KEY_F, - KEY_G, - KEY_H, - KEY_I, - KEY_J, - KEY_K, - KEY_L, - KEY_M, - KEY_N, - KEY_O, - KEY_P, - KEY_Q, - KEY_R, - KEY_S, - KEY_T, - KEY_U, - KEY_V, - KEY_W, - KEY_X, - KEY_Y, - KEY_Z, - - KEY_CAPSLOCK, - - KEY_F1, - KEY_F2, - KEY_F3, - KEY_F4, - KEY_F5, - KEY_F6, - KEY_F7, - KEY_F8, - KEY_F9, - KEY_F10, - KEY_F11, - KEY_F12, - - KEY_PRINTSCREEN, - KEY_SCROLLLOCK, - KEY_PAUSE, - KEY_INSERT, - KEY_HOME, - KEY_PAGEUP, - KEY_DELETE, - KEY_END, - KEY_PAGEDOWN, - KEY_RIGHT, - KEY_LEFT, - KEY_DOWN, - KEY_UP, - - KEY_NUMLOCKCLEAR, - KEY_KP_DIVIDE, - KEY_KP_MULTIPLY, - KEY_KP_MINUS, - KEY_KP_PLUS, - KEY_KP_ENTER, - KEY_KP_1, - KEY_KP_2, - KEY_KP_3, - KEY_KP_4, - KEY_KP_5, - KEY_KP_6, - KEY_KP_7, - KEY_KP_8, - KEY_KP_9, - KEY_KP_0, - KEY_KP_PERIOD, - KEY_KP_COMMA, - KEY_KP_EQUALS, - - KEY_APPLICATION, - KEY_POWER, - KEY_F13, - KEY_F14, - KEY_F15, - KEY_F16, - KEY_F17, - KEY_F18, - KEY_F19, - KEY_F20, - KEY_F21, - KEY_F22, - KEY_F23, - KEY_F24, - KEY_EXECUTE, - KEY_HELP, - KEY_MENU, - KEY_SELECT, - KEY_STOP, - KEY_AGAIN, - KEY_UNDO, - KEY_CUT, - KEY_COPY, - KEY_PASTE, - KEY_FIND, - KEY_MUTE, - KEY_VOLUMEUP, - KEY_VOLUMEDOWN, - - KEY_ALTERASE, - KEY_SYSREQ, - KEY_CANCEL, - KEY_CLEAR, - KEY_PRIOR, - KEY_RETURN2, - KEY_SEPARATOR, - KEY_OUT, - KEY_OPER, - KEY_CLEARAGAIN, - - KEY_THOUSANDSSEPARATOR, - KEY_DECIMALSEPARATOR, - KEY_CURRENCYUNIT, - KEY_CURRENCYSUBUNIT, - - KEY_LCTRL, - KEY_LSHIFT, - KEY_LALT, - KEY_LGUI, - KEY_RCTRL, - KEY_RSHIFT, - KEY_RALT, - KEY_RGUI, - - KEY_MODE, - - KEY_AUDIONEXT, - KEY_AUDIOPREV, - KEY_AUDIOSTOP, - KEY_AUDIOPLAY, - KEY_AUDIOMUTE, - KEY_MEDIASELECT, - KEY_WWW, - KEY_MAIL, - KEY_CALCULATOR, - KEY_COMPUTER, - KEY_APP_SEARCH, - KEY_APP_HOME, - KEY_APP_BACK, - KEY_APP_FORWARD, - KEY_APP_STOP, - KEY_APP_REFRESH, - KEY_APP_BOOKMARKS, - - KEY_BRIGHTNESSDOWN, - KEY_BRIGHTNESSUP, - KEY_DISPLAYSWITCH, - KEY_KBDILLUMTOGGLE, - KEY_KBDILLUMDOWN, - KEY_KBDILLUMUP, - KEY_EJECT, - KEY_SLEEP, - - KEY_MAX_ENUM - }; - /** * Scancodes represent physical keys independent of the current layout. * Their names may not match the names of the keys printed on the keyboard. @@ -520,21 +308,238 @@ public: }; /** - * Modifier keys. These are special keys that temporarily modifies the normal function of a button when active. + * Modifier keys. These are special keys that temporarily modify the normal function of a button when active. **/ - enum ModifierKey { + enum ModifierKey + { MODKEY_NUMLOCK, MODKEY_CAPSLOCK, MODKEY_SCROLLLOCK, MODKEY_MODE, - MODKEY_MAX_ENUM }; - virtual ~Keyboard() {} + static constexpr uint32 KEY_SCANCODE_MASK = 1u << 30; - // Implements Module. - virtual ModuleType getModuleType() const { return M_KEYBOARD; } + #define LOVE_KEY(scancode) (scancode | KEY_SCANCODE_MASK) + + /** + * Keyboard keys. They are dependent on the current layout of the keyboard. + * This is not a full list of all keys - any unicode character can be a key, + * which is why the ASCII keys in this list use their ASCII value directly. + **/ + enum Key + { + KEY_UNKNOWN = 0, + + KEY_RETURN = '\r', + KEY_ESCAPE = '\x1B', + KEY_BACKSPACE = '\b', + KEY_TAB = '\t', + KEY_SPACE = ' ', + KEY_EXCLAIM = '!', + KEY_QUOTEDBL = '"', + KEY_HASH = '#', + KEY_PERCENT = '%', + KEY_DOLLAR = '$', + KEY_AMPERSAND = '&', + KEY_QUOTE = '\'', + KEY_LEFTPAREN = '(', + KEY_RIGHTPAREN = ')', + KEY_ASTERISK = '*', + KEY_PLUS = '+', + KEY_COMMA = ',', + KEY_MINUS = '-', + KEY_PERIOD = '.', + KEY_SLASH = '/', + KEY_0 = '0', + KEY_1 = '1', + KEY_2 = '2', + KEY_3 = '3', + KEY_4 = '4', + KEY_5 = '5', + KEY_6 = '6', + KEY_7 = '7', + KEY_8 = '8', + KEY_9 = '9', + KEY_COLON = ':', + KEY_SEMICOLON = ';', + KEY_LESS = '<', + KEY_EQUALS = '=', + KEY_GREATER = '>', + KEY_QUESTION = '?', + KEY_AT = '@', + + KEY_LEFTBRACKET = '[', + KEY_BACKSLASH = '\\', + KEY_RIGHTBRACKET = ']', + KEY_CARET = '^', + KEY_UNDERSCORE = '_', + KEY_BACKQUOTE = '`', + KEY_A = 'a', + KEY_B = 'b', + KEY_C = 'c', + KEY_D = 'd', + KEY_E = 'e', + KEY_F = 'f', + KEY_G = 'g', + KEY_H = 'h', + KEY_I = 'i', + KEY_J = 'j', + KEY_K = 'k', + KEY_L = 'l', + KEY_M = 'm', + KEY_N = 'n', + KEY_O = 'o', + KEY_P = 'p', + KEY_Q = 'q', + KEY_R = 'r', + KEY_S = 's', + KEY_T = 't', + KEY_U = 'u', + KEY_V = 'v', + KEY_W = 'w', + KEY_X = 'x', + KEY_Y = 'y', + KEY_Z = 'z', + + KEY_DELETE = '\x7F', + + KEY_CAPSLOCK = LOVE_KEY(SCANCODE_CAPSLOCK), + + KEY_F1 = LOVE_KEY(SCANCODE_F1), + KEY_F2 = LOVE_KEY(SCANCODE_F2), + KEY_F3 = LOVE_KEY(SCANCODE_F3), + KEY_F4 = LOVE_KEY(SCANCODE_F4), + KEY_F5 = LOVE_KEY(SCANCODE_F5), + KEY_F6 = LOVE_KEY(SCANCODE_F6), + KEY_F7 = LOVE_KEY(SCANCODE_F7), + KEY_F8 = LOVE_KEY(SCANCODE_F8), + KEY_F9 = LOVE_KEY(SCANCODE_F9), + KEY_F10 = LOVE_KEY(SCANCODE_F10), + KEY_F11 = LOVE_KEY(SCANCODE_F11), + KEY_F12 = LOVE_KEY(SCANCODE_F12), + + KEY_PRINTSCREEN = LOVE_KEY(SCANCODE_PRINTSCREEN), + KEY_SCROLLLOCK = LOVE_KEY(SCANCODE_SCROLLLOCK), + KEY_PAUSE = LOVE_KEY(SCANCODE_PAUSE), + KEY_INSERT = LOVE_KEY(SCANCODE_INSERT), + KEY_HOME = LOVE_KEY(SCANCODE_HOME), + KEY_PAGEUP = LOVE_KEY(SCANCODE_PAGEUP), + KEY_END = LOVE_KEY(SCANCODE_END), + KEY_PAGEDOWN = LOVE_KEY(SCANCODE_PAGEDOWN), + KEY_RIGHT = LOVE_KEY(SCANCODE_RIGHT), + KEY_LEFT = LOVE_KEY(SCANCODE_LEFT), + KEY_DOWN = LOVE_KEY(SCANCODE_DOWN), + KEY_UP = LOVE_KEY(SCANCODE_UP), + + KEY_NUMLOCKCLEAR = LOVE_KEY(SCANCODE_NUMLOCKCLEAR), + KEY_KP_DIVIDE = LOVE_KEY(SCANCODE_KP_DIVIDE), + KEY_KP_MULTIPLY = LOVE_KEY(SCANCODE_KP_MULTIPLY), + KEY_KP_MINUS = LOVE_KEY(SCANCODE_KP_MINUS), + KEY_KP_PLUS = LOVE_KEY(SCANCODE_KP_PLUS), + KEY_KP_ENTER = LOVE_KEY(SCANCODE_KP_ENTER), + KEY_KP_1 = LOVE_KEY(SCANCODE_KP_1), + KEY_KP_2 = LOVE_KEY(SCANCODE_KP_2), + KEY_KP_3 = LOVE_KEY(SCANCODE_KP_3), + KEY_KP_4 = LOVE_KEY(SCANCODE_KP_4), + KEY_KP_5 = LOVE_KEY(SCANCODE_KP_5), + KEY_KP_6 = LOVE_KEY(SCANCODE_KP_6), + KEY_KP_7 = LOVE_KEY(SCANCODE_KP_7), + KEY_KP_8 = LOVE_KEY(SCANCODE_KP_8), + KEY_KP_9 = LOVE_KEY(SCANCODE_KP_9), + KEY_KP_0 = LOVE_KEY(SCANCODE_KP_0), + KEY_KP_PERIOD = LOVE_KEY(SCANCODE_KP_PERIOD), + KEY_KP_COMMA = LOVE_KEY(SCANCODE_KP_COMMA), + KEY_KP_EQUALS = LOVE_KEY(SCANCODE_KP_EQUALS), + + KEY_APPLICATION = LOVE_KEY(SCANCODE_APPLICATION), + KEY_POWER = LOVE_KEY(SCANCODE_POWER), + KEY_F13 = LOVE_KEY(SCANCODE_F13), + KEY_F14 = LOVE_KEY(SCANCODE_F14), + KEY_F15 = LOVE_KEY(SCANCODE_F15), + KEY_F16 = LOVE_KEY(SCANCODE_F16), + KEY_F17 = LOVE_KEY(SCANCODE_F17), + KEY_F18 = LOVE_KEY(SCANCODE_F18), + KEY_F19 = LOVE_KEY(SCANCODE_F19), + KEY_F20 = LOVE_KEY(SCANCODE_F20), + KEY_F21 = LOVE_KEY(SCANCODE_F21), + KEY_F22 = LOVE_KEY(SCANCODE_F22), + KEY_F23 = LOVE_KEY(SCANCODE_F23), + KEY_F24 = LOVE_KEY(SCANCODE_F24), + KEY_EXECUTE = LOVE_KEY(SCANCODE_EXECUTE), + KEY_HELP = LOVE_KEY(SCANCODE_HELP), + KEY_MENU = LOVE_KEY(SCANCODE_MENU), + KEY_SELECT = LOVE_KEY(SCANCODE_SELECT), + KEY_STOP = LOVE_KEY(SCANCODE_STOP), + KEY_AGAIN = LOVE_KEY(SCANCODE_AGAIN), + KEY_UNDO = LOVE_KEY(SCANCODE_UNDO), + KEY_CUT = LOVE_KEY(SCANCODE_CUT), + KEY_COPY = LOVE_KEY(SCANCODE_COPY), + KEY_PASTE = LOVE_KEY(SCANCODE_PASTE), + KEY_FIND = LOVE_KEY(SCANCODE_FIND), + KEY_MUTE = LOVE_KEY(SCANCODE_MUTE), + KEY_VOLUMEUP = LOVE_KEY(SCANCODE_VOLUMEUP), + KEY_VOLUMEDOWN = LOVE_KEY(SCANCODE_VOLUMEDOWN), + + KEY_ALTERASE = LOVE_KEY(SCANCODE_ALTERASE), + KEY_SYSREQ = LOVE_KEY(SCANCODE_SYSREQ), + KEY_CANCEL = LOVE_KEY(SCANCODE_CANCEL), + KEY_CLEAR = LOVE_KEY(SCANCODE_CLEAR), + KEY_PRIOR = LOVE_KEY(SCANCODE_PRIOR), + KEY_RETURN2 = LOVE_KEY(SCANCODE_RETURN2), + KEY_SEPARATOR = LOVE_KEY(SCANCODE_SEPARATOR), + KEY_OUT = LOVE_KEY(SCANCODE_OUT), + KEY_OPER = LOVE_KEY(SCANCODE_OPER), + KEY_CLEARAGAIN = LOVE_KEY(SCANCODE_CLEARAGAIN), + + KEY_THOUSANDSSEPARATOR = LOVE_KEY(SCANCODE_THOUSANDSSEPARATOR), + KEY_DECIMALSEPARATOR = LOVE_KEY(SCANCODE_DECIMALSEPARATOR), + KEY_CURRENCYUNIT = LOVE_KEY(SCANCODE_CURRENCYUNIT), + KEY_CURRENCYSUBUNIT = LOVE_KEY(SCANCODE_CURRENCYSUBUNIT), + + KEY_LCTRL = LOVE_KEY(SCANCODE_LCTRL), + KEY_LSHIFT = LOVE_KEY(SCANCODE_LSHIFT), + KEY_LALT = LOVE_KEY(SCANCODE_LALT), + KEY_LGUI = LOVE_KEY(SCANCODE_LGUI), + KEY_RCTRL = LOVE_KEY(SCANCODE_RCTRL), + KEY_RSHIFT = LOVE_KEY(SCANCODE_RSHIFT), + KEY_RALT = LOVE_KEY(SCANCODE_RALT), + KEY_RGUI = LOVE_KEY(SCANCODE_RGUI), + + KEY_MODE = LOVE_KEY(SCANCODE_MODE), + + KEY_AUDIONEXT = LOVE_KEY(SCANCODE_AUDIONEXT), + KEY_AUDIOPREV = LOVE_KEY(SCANCODE_AUDIOPREV), + KEY_AUDIOSTOP = LOVE_KEY(SCANCODE_AUDIOSTOP), + KEY_AUDIOPLAY = LOVE_KEY(SCANCODE_AUDIOPLAY), + KEY_AUDIOMUTE = LOVE_KEY(SCANCODE_AUDIOMUTE), + KEY_MEDIASELECT = LOVE_KEY(SCANCODE_MEDIASELECT), + KEY_WWW = LOVE_KEY(SCANCODE_WWW), + KEY_MAIL = LOVE_KEY(SCANCODE_MAIL), + KEY_CALCULATOR = LOVE_KEY(SCANCODE_CALCULATOR), + KEY_COMPUTER = LOVE_KEY(SCANCODE_COMPUTER), + KEY_APP_SEARCH = LOVE_KEY(SCANCODE_AC_SEARCH), + KEY_APP_HOME = LOVE_KEY(SCANCODE_AC_HOME), + KEY_APP_BACK = LOVE_KEY(SCANCODE_AC_BACK), + KEY_APP_FORWARD = LOVE_KEY(SCANCODE_AC_FORWARD), + KEY_APP_STOP = LOVE_KEY(SCANCODE_AC_STOP), + KEY_APP_REFRESH = LOVE_KEY(SCANCODE_AC_REFRESH), + KEY_APP_BOOKMARKS = LOVE_KEY(SCANCODE_AC_BOOKMARKS), + + KEY_BRIGHTNESSDOWN = LOVE_KEY(SCANCODE_BRIGHTNESSDOWN), + KEY_BRIGHTNESSUP = LOVE_KEY(SCANCODE_BRIGHTNESSUP), + KEY_DISPLAYSWITCH = LOVE_KEY(SCANCODE_DISPLAYSWITCH), + KEY_KBDILLUMTOGGLE = LOVE_KEY(SCANCODE_KBDILLUMTOGGLE), + KEY_KBDILLUMDOWN = LOVE_KEY(SCANCODE_KBDILLUMDOWN), + KEY_KBDILLUMUP = LOVE_KEY(SCANCODE_KBDILLUMUP), + KEY_EJECT = LOVE_KEY(SCANCODE_EJECT), + KEY_SLEEP = LOVE_KEY(SCANCODE_SLEEP), + }; + + #undef LOVE_KEY + + virtual ~Keyboard() {} /** * Sets whether repeat keypress events should be sent if a key is held down. @@ -614,10 +619,14 @@ public: static bool getConstant(const char *in, ModifierKey &out); static bool getConstant(ModifierKey in, const char *&out); +protected: + + Keyboard(const char *name); + private: - static StringMap::Entry keyEntries[]; - static StringMap keys; + static std::map keyToString; + static std::map stringToKey; static StringMap::Entry scancodeEntries[]; static StringMap scancodes; diff --git a/src/modules/keyboard/sdl/Keyboard.cpp b/src/modules/keyboard/sdl/Keyboard.cpp index fdf4713b1..42c369ca8 100644 --- a/src/modules/keyboard/sdl/Keyboard.cpp +++ b/src/modules/keyboard/sdl/Keyboard.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -22,6 +22,7 @@ #include "Keyboard.h" #include "window/Window.h" +#include "common/config.h" // SDL before 2.0.18 lack KMOD_SCROLL. Use KMOD_RESERVED instead. #if !SDL_VERSION_ATLEAST(2, 0, 18) @@ -36,15 +37,11 @@ namespace sdl { Keyboard::Keyboard() - : key_repeat(false) + : love::keyboard::Keyboard("love.keyboard.sdl") + , key_repeat(false) { } -const char *Keyboard::getName() const -{ - return "love.keyboard.sdl"; -} - void Keyboard::setKeyRepeat(bool enable) { key_repeat = enable; @@ -61,10 +58,13 @@ bool Keyboard::isDown(const std::vector &keylist) const for (Key key : keylist) { - SDL_Scancode scancode = SDL_GetScancodeFromKey(keymap[key]); - - if (state[scancode]) - return true; + SDL_Keycode sdlkey = SDLK_UNKNOWN; + if (getConstant(key, sdlkey)) + { + SDL_Scancode scancode = SDL_GetScancodeFromKey(sdlkey); + if (state[scancode]) + return true; + } } return false; @@ -91,6 +91,16 @@ bool Keyboard::isModifierActive(ModifierKey key) const switch (key) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + case MODKEY_NUMLOCK: + return (modstate & SDL_KMOD_NUM) != 0; + case MODKEY_CAPSLOCK: + return (modstate & SDL_KMOD_CAPS) != 0; + case MODKEY_SCROLLLOCK: + return (modstate & SDL_KMOD_SCROLL) != 0; + case MODKEY_MODE: + return (modstate & SDL_KMOD_MODE) != 0; +#else case MODKEY_NUMLOCK: return (modstate & KMOD_NUM) != 0; case MODKEY_CAPSLOCK: @@ -99,6 +109,7 @@ bool Keyboard::isModifierActive(ModifierKey key) const return (modstate & KMOD_SCROLL) != 0; case MODKEY_MODE: return (modstate & KMOD_MODE) != 0; +#endif default: break; } @@ -113,23 +124,18 @@ Keyboard::Key Keyboard::getKeyFromScancode(Scancode scancode) const SDL_Keycode sdlkey = SDL_GetKeyFromScancode(sdlscancode); - for (int i = 0; i < KEY_MAX_ENUM; i++) - { - if (keymap[i] == sdlkey) - return (Key) i; - } - - return KEY_UNKNOWN; + Key key = KEY_UNKNOWN; + getConstant(sdlkey, key); + return key; } Keyboard::Scancode Keyboard::getScancodeFromKey(Key key) const { Scancode scancode = SCANCODE_UNKNOWN; - if (key != KEY_MAX_ENUM) + SDL_Keycode sdlkey = SDLK_UNKNOWN; + if (getConstant(key, sdlkey)) { - SDL_Keycode sdlkey = keymap[key]; - SDL_Scancode sdlscancode = SDL_GetScancodeFromKey(sdlkey); scancodes.find(sdlscancode, scancode); } @@ -164,7 +170,11 @@ void Keyboard::setTextInput(bool enable, double x, double y, double w, double h) bool Keyboard::hasTextInput() const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + return SDL_TextInputActive(); +#else return SDL_IsTextInputActive() != SDL_FALSE; +#endif } bool Keyboard::hasScreenKeyboard() const @@ -172,6 +182,65 @@ bool Keyboard::hasScreenKeyboard() const return SDL_HasScreenKeyboardSupport() != SDL_FALSE; } +bool Keyboard::getConstant(Key in, SDL_Keycode &out) +{ + if (in & KEY_SCANCODE_MASK) + { + auto it = keyToSDLKey.find(in); + if (it != keyToSDLKey.end()) + { + out = it->second; + return true; + } + } + else + { + // All other keys use the same value as their ASCII character + // representation in SDL and in love. + out = (SDL_Keycode)in; + return true; + } + + return false; +} + +bool Keyboard::getConstant(SDL_Keycode in, Key &out) +{ +#ifdef LOVE_ANDROID + // TODO: Can this be done more cleanly? + if (in == SDLK_AC_BACK) + { + out = KEY_ESCAPE; + return true; + } +#endif + + if (in & SDLK_SCANCODE_MASK) + { + if (sdlKeyToKey.empty()) + { + for (const auto& kvp : keyToSDLKey) + sdlKeyToKey[kvp.second] = kvp.first; + } + + auto it = sdlKeyToKey.find(in); + if (it != sdlKeyToKey.end()) + { + out = it->second; + return true; + } + } + else + { + // All other keys use the same value as their ASCII character + // representation in SDL and in love. + out = (Key)in; + return true; + } + + return false; +} + bool Keyboard::getConstant(Scancode in, SDL_Scancode &out) { return scancodes.find(in, out); @@ -182,220 +251,147 @@ bool Keyboard::getConstant(SDL_Scancode in, Scancode &out) return scancodes.find(in, out); } -const SDL_Keycode *Keyboard::createKeyMap() +std::map Keyboard::keyToSDLKey = { - // Array must be static so its lifetime continues once the function returns. - static SDL_Keycode k[Keyboard::KEY_MAX_ENUM] = {SDLK_UNKNOWN}; + // ASCII characters don't need to go here since they can be directly + // converted. - k[Keyboard::KEY_UNKNOWN] = SDLK_UNKNOWN; + { KEY_UNKNOWN, SDLK_UNKNOWN }, - k[Keyboard::KEY_RETURN] = SDLK_RETURN; - k[Keyboard::KEY_ESCAPE] = SDLK_ESCAPE; - k[Keyboard::KEY_BACKSPACE] = SDLK_BACKSPACE; - k[Keyboard::KEY_TAB] = SDLK_TAB; - k[Keyboard::KEY_SPACE] = SDLK_SPACE; - k[Keyboard::KEY_EXCLAIM] = SDLK_EXCLAIM; - k[Keyboard::KEY_QUOTEDBL] = SDLK_QUOTEDBL; - k[Keyboard::KEY_HASH] = SDLK_HASH; - k[Keyboard::KEY_PERCENT] = SDLK_PERCENT; - k[Keyboard::KEY_DOLLAR] = SDLK_DOLLAR; - k[Keyboard::KEY_AMPERSAND] = SDLK_AMPERSAND; - k[Keyboard::KEY_QUOTE] = SDLK_QUOTE; - k[Keyboard::KEY_LEFTPAREN] = SDLK_LEFTPAREN; - k[Keyboard::KEY_RIGHTPAREN] = SDLK_RIGHTPAREN; - k[Keyboard::KEY_ASTERISK] = SDLK_ASTERISK; - k[Keyboard::KEY_PLUS] = SDLK_PLUS; - k[Keyboard::KEY_COMMA] = SDLK_COMMA; - k[Keyboard::KEY_MINUS] = SDLK_MINUS; - k[Keyboard::KEY_PERIOD] = SDLK_PERIOD; - k[Keyboard::KEY_SLASH] = SDLK_SLASH; - k[Keyboard::KEY_0] = SDLK_0; - k[Keyboard::KEY_1] = SDLK_1; - k[Keyboard::KEY_2] = SDLK_2; - k[Keyboard::KEY_3] = SDLK_3; - k[Keyboard::KEY_4] = SDLK_4; - k[Keyboard::KEY_5] = SDLK_5; - k[Keyboard::KEY_6] = SDLK_6; - k[Keyboard::KEY_7] = SDLK_7; - k[Keyboard::KEY_8] = SDLK_8; - k[Keyboard::KEY_9] = SDLK_9; - k[Keyboard::KEY_COLON] = SDLK_COLON; - k[Keyboard::KEY_SEMICOLON] = SDLK_SEMICOLON; - k[Keyboard::KEY_LESS] = SDLK_LESS; - k[Keyboard::KEY_EQUALS] = SDLK_EQUALS; - k[Keyboard::KEY_GREATER] = SDLK_GREATER; - k[Keyboard::KEY_QUESTION] = SDLK_QUESTION; - k[Keyboard::KEY_AT] = SDLK_AT; + { KEY_CAPSLOCK, SDLK_CAPSLOCK }, - k[Keyboard::KEY_LEFTBRACKET] = SDLK_LEFTBRACKET; - k[Keyboard::KEY_BACKSLASH] = SDLK_BACKSLASH; - k[Keyboard::KEY_RIGHTBRACKET] = SDLK_RIGHTBRACKET; - k[Keyboard::KEY_CARET] = SDLK_CARET; - k[Keyboard::KEY_UNDERSCORE] = SDLK_UNDERSCORE; - k[Keyboard::KEY_BACKQUOTE] = SDLK_BACKQUOTE; - k[Keyboard::KEY_A] = SDLK_a; - k[Keyboard::KEY_B] = SDLK_b; - k[Keyboard::KEY_C] = SDLK_c; - k[Keyboard::KEY_D] = SDLK_d; - k[Keyboard::KEY_E] = SDLK_e; - k[Keyboard::KEY_F] = SDLK_f; - k[Keyboard::KEY_G] = SDLK_g; - k[Keyboard::KEY_H] = SDLK_h; - k[Keyboard::KEY_I] = SDLK_i; - k[Keyboard::KEY_J] = SDLK_j; - k[Keyboard::KEY_K] = SDLK_k; - k[Keyboard::KEY_L] = SDLK_l; - k[Keyboard::KEY_M] = SDLK_m; - k[Keyboard::KEY_N] = SDLK_n; - k[Keyboard::KEY_O] = SDLK_o; - k[Keyboard::KEY_P] = SDLK_p; - k[Keyboard::KEY_Q] = SDLK_q; - k[Keyboard::KEY_R] = SDLK_r; - k[Keyboard::KEY_S] = SDLK_s; - k[Keyboard::KEY_T] = SDLK_t; - k[Keyboard::KEY_U] = SDLK_u; - k[Keyboard::KEY_V] = SDLK_v; - k[Keyboard::KEY_W] = SDLK_w; - k[Keyboard::KEY_X] = SDLK_x; - k[Keyboard::KEY_Y] = SDLK_y; - k[Keyboard::KEY_Z] = SDLK_z; + { KEY_F1, SDLK_F1 }, + { KEY_F2, SDLK_F2 }, + { KEY_F3, SDLK_F3 }, + { KEY_F4, SDLK_F4 }, + { KEY_F5, SDLK_F5 }, + { KEY_F6, SDLK_F6 }, + { KEY_F7, SDLK_F7 }, + { KEY_F8, SDLK_F8 }, + { KEY_F9, SDLK_F9 }, + { KEY_F10, SDLK_F10 }, + { KEY_F11, SDLK_F11 }, + { KEY_F12, SDLK_F12 }, - k[Keyboard::KEY_CAPSLOCK] = SDLK_CAPSLOCK; + { KEY_PRINTSCREEN, SDLK_PRINTSCREEN }, + { KEY_SCROLLLOCK, SDLK_SCROLLLOCK }, + { KEY_PAUSE, SDLK_PAUSE }, + { KEY_INSERT, SDLK_INSERT }, + { KEY_HOME, SDLK_HOME }, + { KEY_PAGEUP, SDLK_PAGEUP }, + { KEY_DELETE, SDLK_DELETE }, + { KEY_END, SDLK_END }, + { KEY_PAGEDOWN, SDLK_PAGEDOWN }, + { KEY_RIGHT, SDLK_RIGHT }, + { KEY_LEFT, SDLK_LEFT }, + { KEY_DOWN, SDLK_DOWN }, + { KEY_UP, SDLK_UP }, - k[Keyboard::KEY_F1] = SDLK_F1; - k[Keyboard::KEY_F2] = SDLK_F2; - k[Keyboard::KEY_F3] = SDLK_F3; - k[Keyboard::KEY_F4] = SDLK_F4; - k[Keyboard::KEY_F5] = SDLK_F5; - k[Keyboard::KEY_F6] = SDLK_F6; - k[Keyboard::KEY_F7] = SDLK_F7; - k[Keyboard::KEY_F8] = SDLK_F8; - k[Keyboard::KEY_F9] = SDLK_F9; - k[Keyboard::KEY_F10] = SDLK_F10; - k[Keyboard::KEY_F11] = SDLK_F11; - k[Keyboard::KEY_F12] = SDLK_F12; + { KEY_NUMLOCKCLEAR, SDLK_NUMLOCKCLEAR }, + { KEY_KP_DIVIDE, SDLK_KP_DIVIDE }, + { KEY_KP_MULTIPLY, SDLK_KP_MULTIPLY }, + { KEY_KP_MINUS, SDLK_KP_MINUS }, + { KEY_KP_PLUS, SDLK_KP_PLUS }, + { KEY_KP_ENTER, SDLK_KP_ENTER }, + { KEY_KP_0, SDLK_KP_0 }, + { KEY_KP_1, SDLK_KP_1 }, + { KEY_KP_2, SDLK_KP_2 }, + { KEY_KP_3, SDLK_KP_3 }, + { KEY_KP_4, SDLK_KP_4 }, + { KEY_KP_5, SDLK_KP_5 }, + { KEY_KP_6, SDLK_KP_6 }, + { KEY_KP_7, SDLK_KP_7 }, + { KEY_KP_8, SDLK_KP_8 }, + { KEY_KP_9, SDLK_KP_9 }, + { KEY_KP_PERIOD, SDLK_KP_PERIOD }, + { KEY_KP_COMMA, SDLK_KP_COMMA }, + { KEY_KP_EQUALS, SDLK_KP_EQUALS }, - k[Keyboard::KEY_PRINTSCREEN] = SDLK_PRINTSCREEN; - k[Keyboard::KEY_SCROLLLOCK] = SDLK_SCROLLLOCK; - k[Keyboard::KEY_PAUSE] = SDLK_PAUSE; - k[Keyboard::KEY_INSERT] = SDLK_INSERT; - k[Keyboard::KEY_HOME] = SDLK_HOME; - k[Keyboard::KEY_PAGEUP] = SDLK_PAGEUP; - k[Keyboard::KEY_DELETE] = SDLK_DELETE; - k[Keyboard::KEY_END] = SDLK_END; - k[Keyboard::KEY_PAGEDOWN] = SDLK_PAGEDOWN; - k[Keyboard::KEY_RIGHT] = SDLK_RIGHT; - k[Keyboard::KEY_LEFT] = SDLK_LEFT; - k[Keyboard::KEY_DOWN] = SDLK_DOWN; - k[Keyboard::KEY_UP] = SDLK_UP; + { KEY_APPLICATION, SDLK_APPLICATION }, + { KEY_POWER, SDLK_POWER }, + { KEY_F13, SDLK_F13 }, + { KEY_F14, SDLK_F14 }, + { KEY_F15, SDLK_F15 }, + { KEY_F16, SDLK_F16 }, + { KEY_F17, SDLK_F17 }, + { KEY_F18, SDLK_F18 }, + { KEY_F19, SDLK_F19 }, + { KEY_F20, SDLK_F20 }, + { KEY_F21, SDLK_F21 }, + { KEY_F22, SDLK_F22 }, + { KEY_F23, SDLK_F23 }, + { KEY_F24, SDLK_F24 }, + { KEY_EXECUTE, SDLK_EXECUTE }, + { KEY_HELP, SDLK_HELP }, + { KEY_MENU, SDLK_MENU }, + { KEY_SELECT, SDLK_SELECT }, + { KEY_STOP, SDLK_STOP }, + { KEY_AGAIN, SDLK_AGAIN }, + { KEY_UNDO, SDLK_UNDO }, + { KEY_CUT, SDLK_CUT }, + { KEY_COPY, SDLK_COPY }, + { KEY_PASTE, SDLK_PASTE }, + { KEY_FIND, SDLK_FIND }, + { KEY_MUTE, SDLK_MUTE }, + { KEY_VOLUMEUP, SDLK_VOLUMEUP }, + { KEY_VOLUMEDOWN, SDLK_VOLUMEDOWN }, - k[Keyboard::KEY_NUMLOCKCLEAR] = SDLK_NUMLOCKCLEAR; - k[Keyboard::KEY_KP_DIVIDE] = SDLK_KP_DIVIDE; - k[Keyboard::KEY_KP_MULTIPLY] = SDLK_KP_MULTIPLY; - k[Keyboard::KEY_KP_MINUS] = SDLK_KP_MINUS; - k[Keyboard::KEY_KP_PLUS] = SDLK_KP_PLUS; - k[Keyboard::KEY_KP_ENTER] = SDLK_KP_ENTER; - k[Keyboard::KEY_KP_0] = SDLK_KP_0; - k[Keyboard::KEY_KP_1] = SDLK_KP_1; - k[Keyboard::KEY_KP_2] = SDLK_KP_2; - k[Keyboard::KEY_KP_3] = SDLK_KP_3; - k[Keyboard::KEY_KP_4] = SDLK_KP_4; - k[Keyboard::KEY_KP_5] = SDLK_KP_5; - k[Keyboard::KEY_KP_6] = SDLK_KP_6; - k[Keyboard::KEY_KP_7] = SDLK_KP_7; - k[Keyboard::KEY_KP_8] = SDLK_KP_8; - k[Keyboard::KEY_KP_9] = SDLK_KP_9; - k[Keyboard::KEY_KP_PERIOD] = SDLK_KP_PERIOD; - k[Keyboard::KEY_KP_COMMA] = SDLK_KP_COMMA; - k[Keyboard::KEY_KP_EQUALS] = SDLK_KP_EQUALS; + { KEY_ALTERASE, SDLK_ALTERASE }, + { KEY_SYSREQ, SDLK_SYSREQ }, + { KEY_CANCEL, SDLK_CANCEL }, + { KEY_CLEAR, SDLK_CLEAR }, + { KEY_PRIOR, SDLK_PRIOR }, + { KEY_RETURN2, SDLK_RETURN2 }, + { KEY_SEPARATOR, SDLK_SEPARATOR }, + { KEY_OUT, SDLK_OUT }, + { KEY_OPER, SDLK_OPER }, + { KEY_CLEARAGAIN, SDLK_CLEARAGAIN }, - k[Keyboard::KEY_APPLICATION] = SDLK_APPLICATION; - k[Keyboard::KEY_POWER] = SDLK_POWER; - k[Keyboard::KEY_F13] = SDLK_F13; - k[Keyboard::KEY_F14] = SDLK_F14; - k[Keyboard::KEY_F15] = SDLK_F15; - k[Keyboard::KEY_F16] = SDLK_F16; - k[Keyboard::KEY_F17] = SDLK_F17; - k[Keyboard::KEY_F18] = SDLK_F18; - k[Keyboard::KEY_F19] = SDLK_F19; - k[Keyboard::KEY_F20] = SDLK_F20; - k[Keyboard::KEY_F21] = SDLK_F21; - k[Keyboard::KEY_F22] = SDLK_F22; - k[Keyboard::KEY_F23] = SDLK_F23; - k[Keyboard::KEY_F24] = SDLK_F24; - k[Keyboard::KEY_EXECUTE] = SDLK_EXECUTE; - k[Keyboard::KEY_HELP] = SDLK_HELP; - k[Keyboard::KEY_MENU] = SDLK_MENU; - k[Keyboard::KEY_SELECT] = SDLK_SELECT; - k[Keyboard::KEY_STOP] = SDLK_STOP; - k[Keyboard::KEY_AGAIN] = SDLK_AGAIN; - k[Keyboard::KEY_UNDO] = SDLK_UNDO; - k[Keyboard::KEY_CUT] = SDLK_CUT; - k[Keyboard::KEY_COPY] = SDLK_COPY; - k[Keyboard::KEY_PASTE] = SDLK_PASTE; - k[Keyboard::KEY_FIND] = SDLK_FIND; - k[Keyboard::KEY_MUTE] = SDLK_MUTE; - k[Keyboard::KEY_VOLUMEUP] = SDLK_VOLUMEUP; - k[Keyboard::KEY_VOLUMEDOWN] = SDLK_VOLUMEDOWN; + { KEY_THOUSANDSSEPARATOR, SDLK_THOUSANDSSEPARATOR }, + { KEY_DECIMALSEPARATOR, SDLK_DECIMALSEPARATOR }, + { KEY_CURRENCYUNIT, SDLK_CURRENCYUNIT }, + { KEY_CURRENCYSUBUNIT, SDLK_CURRENCYSUBUNIT }, - k[Keyboard::KEY_ALTERASE] = SDLK_ALTERASE; - k[Keyboard::KEY_SYSREQ] = SDLK_SYSREQ; - k[Keyboard::KEY_CANCEL] = SDLK_CANCEL; - k[Keyboard::KEY_CLEAR] = SDLK_CLEAR; - k[Keyboard::KEY_PRIOR] = SDLK_PRIOR; - k[Keyboard::KEY_RETURN2] = SDLK_RETURN2; - k[Keyboard::KEY_SEPARATOR] = SDLK_SEPARATOR; - k[Keyboard::KEY_OUT] = SDLK_OUT; - k[Keyboard::KEY_OPER] = SDLK_OPER; - k[Keyboard::KEY_CLEARAGAIN] = SDLK_CLEARAGAIN; + { KEY_LCTRL, SDLK_LCTRL }, + { KEY_LSHIFT, SDLK_LSHIFT }, + { KEY_LALT, SDLK_LALT }, + { KEY_LGUI, SDLK_LGUI }, + { KEY_RCTRL, SDLK_RCTRL }, + { KEY_RSHIFT, SDLK_RSHIFT }, + { KEY_RALT, SDLK_RALT }, + { KEY_RGUI, SDLK_RGUI }, - k[Keyboard::KEY_THOUSANDSSEPARATOR] = SDLK_THOUSANDSSEPARATOR; - k[Keyboard::KEY_DECIMALSEPARATOR] = SDLK_DECIMALSEPARATOR; - k[Keyboard::KEY_CURRENCYUNIT] = SDLK_CURRENCYUNIT; - k[Keyboard::KEY_CURRENCYSUBUNIT] = SDLK_CURRENCYSUBUNIT; + { KEY_MODE, SDLK_MODE }, - k[Keyboard::KEY_LCTRL] = SDLK_LCTRL; - k[Keyboard::KEY_LSHIFT] = SDLK_LSHIFT; - k[Keyboard::KEY_LALT] = SDLK_LALT; - k[Keyboard::KEY_LGUI] = SDLK_LGUI; - k[Keyboard::KEY_RCTRL] = SDLK_RCTRL; - k[Keyboard::KEY_RSHIFT] = SDLK_RSHIFT; - k[Keyboard::KEY_RALT] = SDLK_RALT; - k[Keyboard::KEY_RGUI] = SDLK_RGUI; + { KEY_AUDIONEXT, SDLK_AUDIONEXT }, + { KEY_AUDIOPREV, SDLK_AUDIOPREV }, + { KEY_AUDIOSTOP, SDLK_AUDIOSTOP }, + { KEY_AUDIOPLAY, SDLK_AUDIOPLAY }, + { KEY_AUDIOMUTE, SDLK_AUDIOMUTE }, + { KEY_MEDIASELECT, SDLK_MEDIASELECT }, + { KEY_WWW, SDLK_WWW }, + { KEY_MAIL, SDLK_MAIL }, + { KEY_CALCULATOR, SDLK_CALCULATOR }, + { KEY_COMPUTER, SDLK_COMPUTER }, + { KEY_APP_SEARCH, SDLK_AC_SEARCH }, + { KEY_APP_HOME, SDLK_AC_HOME }, + { KEY_APP_BACK, SDLK_AC_BACK }, + { KEY_APP_FORWARD, SDLK_AC_FORWARD }, + { KEY_APP_STOP, SDLK_AC_STOP }, + { KEY_APP_REFRESH, SDLK_AC_REFRESH }, + { KEY_APP_BOOKMARKS, SDLK_AC_BOOKMARKS }, - k[Keyboard::KEY_MODE] = SDLK_MODE; + { KEY_BRIGHTNESSDOWN, SDLK_BRIGHTNESSDOWN }, + { KEY_BRIGHTNESSUP, SDLK_BRIGHTNESSUP }, + { KEY_DISPLAYSWITCH, SDLK_DISPLAYSWITCH }, + { KEY_KBDILLUMTOGGLE, SDLK_KBDILLUMTOGGLE }, + { KEY_KBDILLUMDOWN, SDLK_KBDILLUMDOWN }, + { KEY_KBDILLUMUP, SDLK_KBDILLUMUP }, + { KEY_EJECT, SDLK_EJECT }, + { KEY_SLEEP, SDLK_SLEEP }, +}; - k[Keyboard::KEY_AUDIONEXT] = SDLK_AUDIONEXT; - k[Keyboard::KEY_AUDIOPREV] = SDLK_AUDIOPREV; - k[Keyboard::KEY_AUDIOSTOP] = SDLK_AUDIOSTOP; - k[Keyboard::KEY_AUDIOPLAY] = SDLK_AUDIOPLAY; - k[Keyboard::KEY_AUDIOMUTE] = SDLK_AUDIOMUTE; - k[Keyboard::KEY_MEDIASELECT] = SDLK_MEDIASELECT; - k[Keyboard::KEY_WWW] = SDLK_WWW; - k[Keyboard::KEY_MAIL] = SDLK_MAIL; - k[Keyboard::KEY_CALCULATOR] = SDLK_CALCULATOR; - k[Keyboard::KEY_COMPUTER] = SDLK_COMPUTER; - k[Keyboard::KEY_APP_SEARCH] = SDLK_AC_SEARCH; - k[Keyboard::KEY_APP_HOME] = SDLK_AC_HOME; - k[Keyboard::KEY_APP_BACK] = SDLK_AC_BACK; - k[Keyboard::KEY_APP_FORWARD] = SDLK_AC_FORWARD; - k[Keyboard::KEY_APP_STOP] = SDLK_AC_STOP; - k[Keyboard::KEY_APP_REFRESH] = SDLK_AC_REFRESH; - k[Keyboard::KEY_APP_BOOKMARKS] = SDLK_AC_BOOKMARKS; - - k[Keyboard::KEY_BRIGHTNESSDOWN] = SDLK_BRIGHTNESSDOWN; - k[Keyboard::KEY_BRIGHTNESSUP] = SDLK_BRIGHTNESSUP; - k[Keyboard::KEY_DISPLAYSWITCH] = SDLK_DISPLAYSWITCH; - k[Keyboard::KEY_KBDILLUMTOGGLE] = SDLK_KBDILLUMTOGGLE; - k[Keyboard::KEY_KBDILLUMDOWN] = SDLK_KBDILLUMDOWN; - k[Keyboard::KEY_KBDILLUMUP] = SDLK_KBDILLUMUP; - k[Keyboard::KEY_EJECT] = SDLK_EJECT; - k[Keyboard::KEY_SLEEP] = SDLK_SLEEP; - - return k; -} - -const SDL_Keycode *Keyboard::keymap = Keyboard::createKeyMap(); +std::map Keyboard::sdlKeyToKey; EnumMap::Entry Keyboard::scancodeEntries[] = { diff --git a/src/modules/keyboard/sdl/Keyboard.h b/src/modules/keyboard/sdl/Keyboard.h index a2dff098d..084bcab13 100644 --- a/src/modules/keyboard/sdl/Keyboard.h +++ b/src/modules/keyboard/sdl/Keyboard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -28,6 +28,8 @@ // SDL #include +#include + namespace love { namespace keyboard @@ -41,9 +43,6 @@ public: Keyboard(); - // Implements Module. - const char *getName() const; - void setKeyRepeat(bool enable); bool hasKeyRepeat() const; bool isDown(const std::vector &keylist) const; @@ -58,6 +57,9 @@ public: bool hasTextInput() const; bool hasScreenKeyboard() const; + static bool getConstant(Key in, SDL_Keycode &out); + static bool getConstant(SDL_Keycode in, Key &out); + static bool getConstant(Scancode in, SDL_Scancode &out); static bool getConstant(SDL_Scancode in, Scancode &out); @@ -67,8 +69,8 @@ private: // The real implementation is in love::event::sdl::Event::Convert. bool key_repeat; - static const SDL_Keycode *createKeyMap(); - static const SDL_Keycode *keymap; + static std::map keyToSDLKey; + static std::map sdlKeyToKey; static EnumMap::Entry scancodeEntries[]; static EnumMap scancodes; diff --git a/src/modules/keyboard/wrap_Keyboard.cpp b/src/modules/keyboard/wrap_Keyboard.cpp index f221709df..78cc7a1ff 100644 --- a/src/modules/keyboard/wrap_Keyboard.cpp +++ b/src/modules/keyboard/wrap_Keyboard.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/keyboard/wrap_Keyboard.h b/src/modules/keyboard/wrap_Keyboard.h index 8983393ef..462d3fa74 100644 --- a/src/modules/keyboard/wrap_Keyboard.h +++ b/src/modules/keyboard/wrap_Keyboard.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/love/arg.lua b/src/modules/love/arg.lua index 934a217c7..41d339de2 100644 --- a/src/modules/love/arg.lua +++ b/src/modules/love/arg.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/love/boot.lua b/src/modules/love/boot.lua index 03610f31a..5ff38a13c 100644 --- a/src/modules/love/boot.lua +++ b/src/modules/love/boot.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -136,11 +136,11 @@ function love.boot() if not can_has_game then -- when editing this message, change it at love.cpp too - print([[LÖVE is an *awesome* framework you can use to make 2D games in Lua + print([[LOVE is an *awesome* framework you can use to make 2D games in Lua https://love2d.org usage: - love --version prints LÖVE version and quits + love --version prints LOVE version and quits love --help prints this message and quits love path/to/gamedir runs the game from the given directory which contains a main.lua file love path/to/packagedgame.love runs the packaged game from the provided .love file diff --git a/src/modules/love/callbacks.lua b/src/modules/love/callbacks.lua index a7560e678..98d7afad5 100644 --- a/src/modules/love/callbacks.lua +++ b/src/modules/love/callbacks.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/love/jitsetup.lua b/src/modules/love/jitsetup.lua index 39e85c18a..0049cc8dc 100644 --- a/src/modules/love/jitsetup.lua +++ b/src/modules/love/jitsetup.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -33,9 +33,9 @@ jit.opt.start("maxtrace=2000", "maxrecord=8000") -- and higher than the default (512) because that's already too low. jit.opt.start("maxmcode=16384") -if jit.arch == "arm64" then +if jit.arch == "arm64" or jit.arch == "arm" then -- https://github.com/LuaJIT/LuaJIT/issues/285 - -- LuaJIT 2.1 on arm64 currently (as of commit b4b2dce) can only use memory + -- LuaJIT 2.1 on arm(64) currently (as of commit b4b2dce) can only use memory -- for JIT compilation within a certain short range. Other libraries such as -- SDL can take all the usable space in that range and cause attempts at JIT -- compilation to both fail and take a long time. @@ -62,6 +62,10 @@ if jit.arch == "arm64" then jit.opt.start("sizemcode=128") for i=1, 100 do end + + -- Actually just turn the whole thing off for arm(64). It's very hard to get + -- reliable performance in non-trivial games even with the above workaround. + jit.off() else -- Somewhat arbitrary value (>= the default). jit.opt.start("sizemcode=128") diff --git a/src/modules/love/love.cpp b/src/modules/love/love.cpp index 7c14d3ea8..81503e955 100644 --- a/src/modules/love/love.cpp +++ b/src/modules/love/love.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,10 +38,6 @@ #ifdef LOVE_ANDROID #include -extern "C" -{ -#include "luajit.h" -} #endif // LOVE_ANDROID #ifdef LOVE_LEGENDARY_CONSOLE_IO_HACK @@ -529,11 +525,6 @@ int luaopen_love(lua_State *L) for (int i = 0; modules[i].name != nullptr; i++) love::luax_preload(L, modules[i].func, modules[i].name); - // jitsetup is also loaded in the love executable runlove function. It's - // needed here too for threads. Note that it doesn't use the love table. - love::luax_require(L, "love.jitsetup"); - lua_pop(L, 1); - love::luax_insistpinnedthread(L); love::luax_insistglobal(L, "love"); @@ -553,7 +544,6 @@ int luaopen_love(lua_State *L) lua_setfield(L, -2, "_version_codename"); #ifdef LOVE_ANDROID - luaJIT_setmode(L, 0, LUAJIT_MODE_ENGINE | LUAJIT_MODE_OFF); lua_register(L, "print", w_print_sdl_log); #endif diff --git a/src/modules/love/love.h b/src/modules/love/love.h index be63092c0..1ee3f6b0f 100644 --- a/src/modules/love/love.h +++ b/src/modules/love/love.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/BezierCurve.cpp b/src/modules/math/BezierCurve.cpp index 56d2eb5e3..2fc46865f 100644 --- a/src/modules/math/BezierCurve.cpp +++ b/src/modules/math/BezierCurve.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/BezierCurve.h b/src/modules/math/BezierCurve.h index 0235f105a..4e0420cb7 100644 --- a/src/modules/math/BezierCurve.h +++ b/src/modules/math/BezierCurve.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/MathModule.cpp b/src/modules/math/MathModule.cpp index 02a41477f..122c35163 100644 --- a/src/modules/math/MathModule.cpp +++ b/src/modules/math/MathModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -200,11 +200,13 @@ float linearToGamma(float c) } Math::Math() - : rng() + : Module(M_MATH, "love.math") { RandomGenerator::Seed seed; seed.b64 = (uint64) time(nullptr); - rng.setSeed(seed); + + rng.set(new RandomGenerator(), Acquire::NORETAIN); + rng->setSeed(seed); } Math::~Math() diff --git a/src/modules/math/MathModule.h b/src/modules/math/MathModule.h index 67b11249d..645df8aae 100644 --- a/src/modules/math/MathModule.h +++ b/src/modules/math/MathModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -102,7 +102,7 @@ public: RandomGenerator *getRandomGenerator() { - return &rng; + return rng.get(); } /** @@ -118,20 +118,11 @@ public: Transform *newTransform(); Transform *newTransform(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky); - // Implements Module. - virtual ModuleType getModuleType() const - { - return M_MATH; - } - - virtual const char *getName() const - { - return "love.math"; - } - private: - RandomGenerator rng; + // All love objects accessible in Lua should be heap-allocated, + // to guarantee a minimum pointer alignment. + StrongRef rng; }; // Math diff --git a/src/modules/math/RandomGenerator.cpp b/src/modules/math/RandomGenerator.cpp index 29359b58b..3c7439a64 100644 --- a/src/modules/math/RandomGenerator.cpp +++ b/src/modules/math/RandomGenerator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/RandomGenerator.h b/src/modules/math/RandomGenerator.h index 58e1990fd..749dc097a 100644 --- a/src/modules/math/RandomGenerator.h +++ b/src/modules/math/RandomGenerator.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/Transform.cpp b/src/modules/math/Transform.cpp index a53d71d73..00bb74e20 100644 --- a/src/modules/math/Transform.cpp +++ b/src/modules/math/Transform.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/Transform.h b/src/modules/math/Transform.h index 40068b77a..e340b0bb2 100644 --- a/src/modules/math/Transform.h +++ b/src/modules/math/Transform.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_BezierCurve.cpp b/src/modules/math/wrap_BezierCurve.cpp index 53167c1a1..c1be7a4b6 100644 --- a/src/modules/math/wrap_BezierCurve.cpp +++ b/src/modules/math/wrap_BezierCurve.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_BezierCurve.h b/src/modules/math/wrap_BezierCurve.h index d748b8253..9ed9ac59f 100644 --- a/src/modules/math/wrap_BezierCurve.h +++ b/src/modules/math/wrap_BezierCurve.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 26701d749..1e91e3675 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_Math.h b/src/modules/math/wrap_Math.h index 8d5bbe2b4..ca40caba1 100644 --- a/src/modules/math/wrap_Math.h +++ b/src/modules/math/wrap_Math.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_Math.lua b/src/modules/math/wrap_Math.lua index f6e145ed2..c89012c7d 100644 --- a/src/modules/math/wrap_Math.lua +++ b/src/modules/math/wrap_Math.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_RandomGenerator.cpp b/src/modules/math/wrap_RandomGenerator.cpp index ebe7fdffc..007cad60c 100644 --- a/src/modules/math/wrap_RandomGenerator.cpp +++ b/src/modules/math/wrap_RandomGenerator.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_RandomGenerator.h b/src/modules/math/wrap_RandomGenerator.h index a1459da9c..9bbe807e6 100644 --- a/src/modules/math/wrap_RandomGenerator.h +++ b/src/modules/math/wrap_RandomGenerator.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_RandomGenerator.lua b/src/modules/math/wrap_RandomGenerator.lua index 4e96f5f61..e394833ec 100644 --- a/src/modules/math/wrap_RandomGenerator.lua +++ b/src/modules/math/wrap_RandomGenerator.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/math/wrap_Transform.cpp b/src/modules/math/wrap_Transform.cpp index 3ac5b2f78..24e2aa45a 100644 --- a/src/modules/math/wrap_Transform.cpp +++ b/src/modules/math/wrap_Transform.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -30,6 +30,99 @@ Transform *luax_checktransform(lua_State *L, int idx) return luax_checktype(L, idx, Transform::type); } +void luax_checkmatrix(lua_State *L, int idx, Transform::MatrixLayout layout, float elements[16]) +{ + bool columnmajor = layout == Transform::MATRIX_COLUMN_MAJOR; + + if (lua_istable(L, idx)) + { + lua_rawgeti(L, idx, 1); + bool tableoftables = lua_istable(L, -1); + lua_pop(L, 1); + + if (tableoftables) + { + if (columnmajor) + { + for (int column = 0; column < 4; column++) + { + lua_rawgeti(L, idx, column + 1); + + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, -(row + 1), row + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + + lua_pop(L, 4 + 1); + } + } + else + { + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, idx, row + 1); + + for (int column = 0; column < 4; column++) + { + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, -(column + 1), column + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + + lua_pop(L, 4 + 1); + } + } + } + else + { + if (columnmajor) + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + { + lua_rawgeti(L, idx, column * 4 + row + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + } + } + else + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + { + // The table has the matrix elements laid out in row-major + // order, but we need to store them column-major in memory. + lua_rawgeti(L, idx, row * 4 + column + 1); + elements[column * 4 + row] = (float) luaL_checknumber(L, -1); + } + } + } + + lua_pop(L, 16); + } + } + else + { + if (columnmajor) + { + for (int i = 0; i < 16; i++) + elements[i] = (float) luaL_checknumber(L, idx + i); + } + else + { + for (int column = 0; column < 4; column++) + { + for (int row = 0; row < 4; row++) + elements[column * 4 + row] = (float) luaL_checknumber(L, row * 4 + column + idx); + } + } + } +} + int w_Transform_clone(lua_State *L) { Transform *t = luax_checktransform(L, 1); @@ -131,110 +224,20 @@ int w_Transform_setTransformation(lua_State *L) int w_Transform_setMatrix(lua_State *L) { Transform *t = luax_checktransform(L, 1); - - bool columnmajor = false; + Transform::MatrixLayout layout = Transform::MATRIX_ROW_MAJOR; int idx = 2; if (lua_type(L, idx) == LUA_TSTRING) { const char *layoutstr = lua_tostring(L, idx); - Transform::MatrixLayout layout; if (!Transform::getConstant(layoutstr, layout)) return luax_enumerror(L, "matrix layout", Transform::getConstants(layout), layoutstr); - columnmajor = (layout == Transform::MATRIX_COLUMN_MAJOR); idx++; } float elements[16]; - - if (lua_istable(L, idx)) - { - lua_rawgeti(L, idx, 1); - bool tableoftables = lua_istable(L, -1); - lua_pop(L, 1); - - if (tableoftables) - { - if (columnmajor) - { - for (int column = 0; column < 4; column++) - { - lua_rawgeti(L, idx, column + 1); - - for (int row = 0; row < 4; row++) - { - lua_rawgeti(L, -(row + 1), row + 1); - elements[column * 4 + row] = (float) luaL_checknumber(L, -1); - } - - lua_pop(L, 4 + 1); - } - } - else - { - for (int row = 0; row < 4; row++) - { - lua_rawgeti(L, idx, row + 1); - - for (int column = 0; column < 4; column++) - { - // The table has the matrix elements laid out in row-major - // order, but we need to store them column-major in memory. - lua_rawgeti(L, -(column + 1), column + 1); - elements[column * 4 + row] = (float) luaL_checknumber(L, -1); - } - - lua_pop(L, 4 + 1); - } - } - } - else - { - if (columnmajor) - { - for (int column = 0; column < 4; column++) - { - for (int row = 0; row < 4; row++) - { - lua_rawgeti(L, idx, column * 4 + row + 1); - elements[column * 4 + row] = (float) luaL_checknumber(L, -1); - } - } - } - else - { - for (int column = 0; column < 4; column++) - { - for (int row = 0; row < 4; row++) - { - // The table has the matrix elements laid out in row-major - // order, but we need to store them column-major in memory. - lua_rawgeti(L, idx, row * 4 + column + 1); - elements[column * 4 + row] = (float) luaL_checknumber(L, -1); - } - } - } - - lua_pop(L, 16); - } - } - else - { - if (columnmajor) - { - for (int i = 0; i < 16; i++) - elements[i] = (float) luaL_checknumber(L, idx + i); - } - else - { - for (int column = 0; column < 4; column++) - { - for (int row = 0; row < 4; row++) - elements[column * 4 + row] = (float) luaL_checknumber(L, row * 4 + column + idx); - } - } - } + luax_checkmatrix(L, idx, layout, elements); t->setMatrix(Matrix4(elements)); lua_pushvalue(L, 1); diff --git a/src/modules/math/wrap_Transform.h b/src/modules/math/wrap_Transform.h index 830794807..53feb3b7a 100644 --- a/src/modules/math/wrap_Transform.h +++ b/src/modules/math/wrap_Transform.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -30,6 +30,7 @@ namespace math { Transform *luax_checktransform(lua_State *L, int idx); +void luax_checkmatrix(lua_State *L, int idx, Transform::MatrixLayout layout, float elements[16]); extern "C" int luaopen_transform(lua_State *L); } // math diff --git a/src/modules/mouse/Cursor.cpp b/src/modules/mouse/Cursor.cpp index 6f537de91..dada2b616 100644 --- a/src/modules/mouse/Cursor.cpp +++ b/src/modules/mouse/Cursor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/mouse/Cursor.h b/src/modules/mouse/Cursor.h index 69e220f9a..352c6b392 100644 --- a/src/modules/mouse/Cursor.h +++ b/src/modules/mouse/Cursor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/mouse/Mouse.h b/src/modules/mouse/Mouse.h index d57c49406..4ad70dc56 100644 --- a/src/modules/mouse/Mouse.h +++ b/src/modules/mouse/Mouse.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -53,12 +53,9 @@ public: virtual bool isCursorSupported() const = 0; - virtual double getX() const = 0; - virtual double getY() const = 0; virtual void getPosition(double &x, double &y) const = 0; - virtual void setX(double x) = 0; - virtual void setY(double y) = 0; virtual void setPosition(double x, double y) = 0; + virtual void getGlobalPosition(double &x, double &y, int &displayindex) const = 0; virtual void setVisible(bool visible) = 0; virtual bool isDown(const std::vector &buttons) const = 0; virtual bool isVisible() const = 0; @@ -67,6 +64,12 @@ public: virtual bool setRelativeMode(bool relative) = 0; virtual bool getRelativeMode() const = 0; +protected: + + Mouse(const char *name) + : Module(M_MOUSE, name) + {} + }; // Mouse } // mouse diff --git a/src/modules/mouse/sdl/Cursor.cpp b/src/modules/mouse/sdl/Cursor.cpp index 6e17c00cf..bc059bea6 100644 --- a/src/modules/mouse/sdl/Cursor.cpp +++ b/src/modules/mouse/sdl/Cursor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -22,6 +22,8 @@ #include "Cursor.h" #include "common/config.h" +#include + namespace love { namespace mouse @@ -34,6 +36,13 @@ Cursor::Cursor(image::ImageData *data, int hotx, int hoty) , type(CURSORTYPE_IMAGE) , systemType(CURSOR_MAX_ENUM) { + int w = data->getWidth(); + int h = data->getHeight(); + int pitch = w * 4; + +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Surface *surface = SDL_CreateSurfaceFrom(data->getData(), w, h, pitch, SDL_PIXELFORMAT_RGBA8888); +#else Uint32 rmask, gmask, bmask, amask; #ifdef LOVE_BIG_ENDIAN rmask = 0xFF000000; @@ -47,17 +56,19 @@ Cursor::Cursor(image::ImageData *data, int hotx, int hoty) amask = 0xFF000000; #endif - int w = data->getWidth(); - int h = data->getHeight(); - int pitch = w * 4; - SDL_Surface *surface = SDL_CreateRGBSurfaceFrom(data->getData(), w, h, 32, pitch, rmask, gmask, bmask, amask); +#endif if (!surface) throw love::Exception("Cannot create cursor: out of memory!"); cursor = SDL_CreateColorCursor(surface, hotx, hoty); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DestroySurface(surface); +#else SDL_FreeSurface(surface); +#endif + if (!cursor) throw love::Exception("Cannot create cursor: %s", SDL_GetError()); } @@ -80,8 +91,13 @@ Cursor::Cursor(mouse::Cursor::SystemCursor cursortype) Cursor::~Cursor() { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (cursor) + SDL_DestroyCursor(cursor); +#else if (cursor) SDL_FreeCursor(cursor); +#endif } void *Cursor::getHandle() const diff --git a/src/modules/mouse/sdl/Cursor.h b/src/modules/mouse/sdl/Cursor.h index 9f6b37a0f..b72d46131 100644 --- a/src/modules/mouse/sdl/Cursor.h +++ b/src/modules/mouse/sdl/Cursor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/mouse/sdl/Mouse.cpp b/src/modules/mouse/sdl/Mouse.cpp index 8ff555ea2..934b2b911 100644 --- a/src/modules/mouse/sdl/Mouse.cpp +++ b/src/modules/mouse/sdl/Mouse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ // SDL #include +#include namespace love { @@ -56,13 +57,9 @@ static void clampToWindow(double *x, double *y) window->clampPositionInWindow(x, y); } -const char *Mouse::getName() const -{ - return "love.mouse.sdl"; -} - Mouse::Mouse() - : curCursor(nullptr) + : love::mouse::Mouse("love.mouse.sdl") + , curCursor(nullptr) { // SDL may need the video subsystem in order to clean up the cursor when // quitting. Subsystems are reference-counted. @@ -124,24 +121,15 @@ bool Mouse::isCursorSupported() const return SDL_GetDefaultCursor() != nullptr; } -double Mouse::getX() const -{ - double x, y; - getPosition(x, y); - return x; -} - -double Mouse::getY() const -{ - double x, y; - getPosition(x, y); - return y; -} - void Mouse::getPosition(double &x, double &y) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + float mx, my; + SDL_GetMouseState(&mx, &my); +#else int mx, my; SDL_GetMouseState(&mx, &my); +#endif x = (double) mx; y = (double) my; @@ -173,19 +161,70 @@ void Mouse::setPosition(double x, double y) SDL_PumpEvents(); } -void Mouse::setX(double x) +void Mouse::getGlobalPosition(double &x, double &y, int &displayindex) const { - setPosition(x, getY()); -} +#if SDL_VERSION_ATLEAST(3, 0, 0) + float globalx, globaly; +#else + int globalx, globaly; +#endif + SDL_GetGlobalMouseState(&globalx, &globaly); -void Mouse::setY(double y) -{ - setPosition(getX(), y); + auto mx = globalx; + auto my = globaly; + +#if SDL_VERSION_ATLEAST(3, 0, 0) + int displaycount = 0; + SDL_DisplayID *displays = SDL_GetDisplays(&displaycount); + + for (displayindex = 0; displayindex < displaycount; displayindex++) + { + SDL_Rect r = {}; + SDL_GetDisplayBounds(displays[displayindex], &r); + + SDL_FRect frect = {(float)r.x, (float)r.y, (float)r.w, (float)r.h}; + + mx -= frect.x; + my -= frect.y; + + SDL_FPoint p = { globalx, globaly }; + if (SDL_PointInRectFloat(&p, &frect)) + break; + } +#else + int displaycount = SDL_GetNumVideoDisplays(); + + for (displayindex = 0; displayindex < displaycount; displayindex++) + { + SDL_Rect rect = {}; + SDL_GetDisplayBounds(displayindex, &rect); + + mx -= rect.x; + my -= rect.y; + + SDL_Point p = { globalx, globaly }; + if (SDL_PointInRect(&p, &rect)) + break; + } +#endif + + if (displayindex >= displaycount) + displayindex = 0; + + x = (double)mx; + y = (double)my; } void Mouse::setVisible(bool visible) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (visible) + SDL_ShowCursor(); + else + SDL_HideCursor(); +#else SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE); +#endif } bool Mouse::isDown(const std::vector &buttons) const @@ -218,7 +257,11 @@ bool Mouse::isDown(const std::vector &buttons) const bool Mouse::isVisible() const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + return SDL_CursorVisible(); +#else return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE; +#endif } void Mouse::setGrabbed(bool grab) diff --git a/src/modules/mouse/sdl/Mouse.h b/src/modules/mouse/sdl/Mouse.h index abab2d61b..a74dd334d 100644 --- a/src/modules/mouse/sdl/Mouse.h +++ b/src/modules/mouse/sdl/Mouse.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,9 +39,6 @@ class Mouse : public love::mouse::Mouse { public: - // Implements Module. - const char *getName() const override; - Mouse(); virtual ~Mouse(); @@ -55,12 +52,9 @@ public: bool isCursorSupported() const override; - double getX() const override; - double getY() const override; void getPosition(double &x, double &y) const override; - void setX(double x) override; - void setY(double y) override; void setPosition(double x, double y) override; + void getGlobalPosition(double &x, double &y, int &displayindex) const override; void setVisible(bool visible) override; bool isDown(const std::vector &buttons) const override; bool isVisible() const override; diff --git a/src/modules/mouse/wrap_Cursor.cpp b/src/modules/mouse/wrap_Cursor.cpp index fc3bed46e..dc4a871cf 100644 --- a/src/modules/mouse/wrap_Cursor.cpp +++ b/src/modules/mouse/wrap_Cursor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/mouse/wrap_Cursor.h b/src/modules/mouse/wrap_Cursor.h index 963bb8802..14304c489 100644 --- a/src/modules/mouse/wrap_Cursor.h +++ b/src/modules/mouse/wrap_Cursor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/mouse/wrap_Mouse.cpp b/src/modules/mouse/wrap_Mouse.cpp index 999be9969..f54a69803 100644 --- a/src/modules/mouse/wrap_Mouse.cpp +++ b/src/modules/mouse/wrap_Mouse.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -100,13 +100,17 @@ int w_isCursorSupported(lua_State *L) int w_getX(lua_State *L) { - lua_pushnumber(L, instance()->getX()); + double x, y; + instance()->getPosition(x, y); + lua_pushnumber(L, x); return 1; } int w_getY(lua_State *L) { - lua_pushnumber(L, instance()->getY()); + double x, y; + instance()->getPosition(x, y); + lua_pushnumber(L, y); return 1; } @@ -121,15 +125,19 @@ int w_getPosition(lua_State *L) int w_setX(lua_State *L) { - double x = luaL_checknumber(L, 1); - instance()->setX(x); + double x, y; + instance()->getPosition(x, y); + x = luaL_checknumber(L, 1); + instance()->setPosition(x, y); return 0; } int w_setY(lua_State *L) { - double y = luaL_checknumber(L, 1); - instance()->setY(y); + double x, y; + instance()->getPosition(x, y); + y = luaL_checknumber(L, 1); + instance()->setPosition(x, y); return 0; } @@ -141,6 +149,17 @@ int w_setPosition(lua_State *L) return 0; } +int w_getGlobalPosition(lua_State *L) +{ + double x, y; + int displayindex; + instance()->getGlobalPosition(x, y, displayindex); + lua_pushnumber(L, x); + lua_pushnumber(L, y); + lua_pushinteger(L, displayindex + 1); + return 3; +} + int w_isDown(lua_State *L) { bool istable = lua_istable(L, 1); @@ -220,6 +239,7 @@ static const luaL_Reg functions[] = { "setX", w_setX }, { "setY", w_setY }, { "setPosition", w_setPosition }, + { "getGlobalPosition", w_getGlobalPosition }, { "isDown", w_isDown }, { "setVisible", w_setVisible }, { "isVisible", w_isVisible }, diff --git a/src/modules/mouse/wrap_Mouse.h b/src/modules/mouse/wrap_Mouse.h index 9cc285ee5..f39564eb6 100644 --- a/src/modules/mouse/wrap_Mouse.h +++ b/src/modules/mouse/wrap_Mouse.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Body.cpp b/src/modules/physics/Body.cpp index fc93a401e..ec7214594 100644 --- a/src/modules/physics/Body.cpp +++ b/src/modules/physics/Body.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Body.h b/src/modules/physics/Body.h index 97b578e63..eca01fd3f 100644 --- a/src/modules/physics/Body.h +++ b/src/modules/physics/Body.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Joint.cpp b/src/modules/physics/Joint.cpp index 8b12e78a5..83cb91789 100644 --- a/src/modules/physics/Joint.cpp +++ b/src/modules/physics/Joint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Joint.h b/src/modules/physics/Joint.h index 89b3fb2d4..d30c4aec7 100644 --- a/src/modules/physics/Joint.h +++ b/src/modules/physics/Joint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Shape.cpp b/src/modules/physics/Shape.cpp index fe184b829..712b10830 100644 --- a/src/modules/physics/Shape.cpp +++ b/src/modules/physics/Shape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/Shape.h b/src/modules/physics/Shape.h index ca5a5f7a9..49ae39229 100644 --- a/src/modules/physics/Shape.h +++ b/src/modules/physics/Shape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/Body.cpp b/src/modules/physics/box2d/Body.cpp index 0e846cdc3..d4a569d08 100644 --- a/src/modules/physics/box2d/Body.cpp +++ b/src/modules/physics/box2d/Body.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,12 +23,12 @@ #include "common/math.h" #include "Shape.h" -#include "Fixture.h" #include "World.h" #include "Physics.h" // Needed for luax_pushjoint. #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -39,29 +39,21 @@ namespace box2d Body::Body(World *world, b2Vec2 p, Body::Type type) : world(world) - , udata(nullptr) + , hasCustomMass(false) { - udata = new bodyudata(); - udata->ref = nullptr; b2BodyDef def; def.position = Physics::scaleDown(p); - def.userData.pointer = (uintptr_t)udata; + def.userData.pointer = (uintptr_t)this; body = world->world->CreateBody(&def); // Box2D body holds a reference to the love Body. this->retain(); this->setType(type); - world->registerObject(body, this); } Body::~Body() { - if (!udata) - return; - - if (udata->ref) - delete udata->ref; - - delete udata; + if (ref) + delete ref; } float Body::getX() @@ -258,6 +250,7 @@ void Body::setLinearDamping(float d) void Body::resetMassData() { body->ResetMassData(); + hasCustomMass = false; } void Body::setMassData(float x, float y, float m, float i) @@ -267,6 +260,7 @@ void Body::setMassData(float x, float y, float m, float i) massData.mass = m; massData.I = Physics::scaleDown(Physics::scaleDown(i)); body->SetMassData(&massData); + hasCustomMass = true; } void Body::setMass(float m) @@ -275,6 +269,7 @@ void Body::setMass(float m) body->GetMassData(&data); data.mass = m; body->SetMassData(&data); + hasCustomMass = true; } void Body::setInertia(float i) @@ -284,6 +279,7 @@ void Body::setInertia(float i) massData.mass = body->GetMass(); massData.I = Physics::scaleDown(Physics::scaleDown(i)); body->SetMassData(&massData); + hasCustomMass = true; } void Body::setGravityScale(float scale) @@ -470,7 +466,20 @@ World *Body::getWorld() const return world; } -int Body::getFixtures(lua_State *L) const +Shape *Body::getShape() const +{ + b2Fixture *f = body->GetFixtureList(); + if (f == nullptr) + return nullptr; + + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + + return shape; +} + +int Body::getShapes(lua_State *L) const { lua_newtable(L); b2Fixture *f = body->GetFixtureList(); @@ -479,10 +488,10 @@ int Body::getFixtures(lua_State *L) const { if (!f) break; - Fixture *fixture = (Fixture *)world->findObject(f); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; } @@ -501,7 +510,7 @@ int Body::getJoints(lua_State *L) const if (!je) break; - Joint *joint = (Joint *) world->findObject(je->joint); + Joint *joint = (Joint *) (je->joint->GetUserData().pointer); if (!joint) throw love::Exception("A joint has escaped Memoizer!"); @@ -550,12 +559,11 @@ void Body::destroy() } world->world->DestroyBody(body); - world->unregisterObject(body); - body = NULL; + body = nullptr; // Remove userdata reference to avoid it sticking around after GC - if (udata && udata->ref) - udata->ref->unref(); + if (ref) + ref->unref(); // Box2D body destroyed. Release its reference to the love Body. this->release(); @@ -565,24 +573,18 @@ int Body::setUserData(lua_State *L) { love::luax_assert_argc(L, 1, 1); - if (udata == nullptr) - { - udata = new bodyudata(); - body->GetUserData().pointer = (uintptr_t)udata; - } + if(!ref) + ref = new Reference(); - if(!udata->ref) - udata->ref = new Reference(); - - udata->ref->ref(L); + ref->ref(L); return 0; } int Body::getUserData(lua_State *L) { - if (udata != nullptr && udata->ref != nullptr) - udata->ref->push(L); + if (ref != nullptr) + ref->push(L); else lua_pushnil(L); diff --git a/src/modules/physics/box2d/Body.h b/src/modules/physics/box2d/Body.h index 95ae911e8..f69511d48 100644 --- a/src/modules/physics/box2d/Body.h +++ b/src/modules/physics/box2d/Body.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,17 +39,6 @@ namespace box2d // Forward declarations. class World; class Shape; -class Fixture; - -/** - * This struct is stored in a void pointer in the Box2D Body class. For now, all - * we need is a Lua reference to arbitrary data, but we might need more later. - **/ -struct bodyudata -{ - // Reference to arbitrary data. - Reference *ref = nullptr; -}; /** * A Body is an entity which has position and orientation @@ -67,7 +56,6 @@ public: friend class CircleShape; friend class PolygonShape; friend class Shape; - friend class Fixture; // Public because joints et al ask for b2body b2Body *body; @@ -149,6 +137,8 @@ public: **/ int getMassData(lua_State *L); + bool hasCustomMassData() const { return hasCustomMass; } + /** * Gets the Body's angular damping. **/ @@ -401,10 +391,14 @@ public: World *getWorld() const; /** - * Get an array of all the Fixtures attached to this Body. - * @return An array of Fixtures. + * Gets the first Shape attached to this Body. **/ - int getFixtures(lua_State *L) const; + Shape *getShape() const; + + /** + * Get an array of all the Shapes attached to this Body. + **/ + int getShapes(lua_State *L) const; /** * Get an array of all Joints attached to this Body. @@ -441,7 +435,10 @@ private: // unowned? World *world; - bodyudata *udata; + bool hasCustomMass; + + // Reference to arbitrary data. + Reference* ref = nullptr; }; // Body diff --git a/src/modules/physics/box2d/ChainShape.cpp b/src/modules/physics/box2d/ChainShape.cpp index 9bfef155c..76ed1952f 100644 --- a/src/modules/physics/box2d/ChainShape.cpp +++ b/src/modules/physics/box2d/ChainShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,8 +34,8 @@ namespace box2d love::Type ChainShape::type("ChainShape", &Shape::type); -ChainShape::ChainShape(b2ChainShape *c, bool own) - : Shape(c, own) +ChainShape::ChainShape(Body *body, const b2ChainShape &c) + : Shape(body, c) { } @@ -45,6 +45,7 @@ ChainShape::~ChainShape() void ChainShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_nextVertex = Physics::scaleDown(v); @@ -52,6 +53,7 @@ void ChainShape::setNextVertex(float x, float y) void ChainShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2Vec2 v(x, y); b2ChainShape *c = (b2ChainShape *)shape; c->m_prevVertex = Physics::scaleDown(v); @@ -59,44 +61,40 @@ void ChainShape::setPreviousVertex(float x, float y) b2Vec2 ChainShape::getNextVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_nextVertex); } b2Vec2 ChainShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; - return Physics::scaleUp(c->m_prevVertex); } EdgeShape *ChainShape::getChildEdge(int index) const { + throwIfShapeNotValid(); + b2ChainShape *c = (b2ChainShape *)shape; - b2EdgeShape *e = new b2EdgeShape; - try - { - c->GetChildEdge(e, index); - } - catch (love::Exception &) - { - delete e; - throw; - } + b2EdgeShape e; + c->GetChildEdge(&e, index); - return new EdgeShape(e, true); + return new EdgeShape(nullptr, e); } int ChainShape::getVertexCount() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_count; } b2Vec2 ChainShape::getPoint(int index) const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; if (index < 0 || index >= c->m_count) throw love::Exception("Physics error: index out of bounds"); @@ -106,6 +104,7 @@ b2Vec2 ChainShape::getPoint(int index) const const b2Vec2 *ChainShape::getPoints() const { + throwIfShapeNotValid(); b2ChainShape *c = (b2ChainShape *)shape; return c->m_vertices; } diff --git a/src/modules/physics/box2d/ChainShape.h b/src/modules/physics/box2d/ChainShape.h index 07f89f440..e73fa0f4a 100644 --- a/src/modules/physics/box2d/ChainShape.h +++ b/src/modules/physics/box2d/ChainShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,7 +45,7 @@ public: * Create a new ChainShape from a Box2D chain shape. * @param c The chain shape. **/ - ChainShape(b2ChainShape *c, bool own = true); + ChainShape(Body *body, const b2ChainShape &c); virtual ~ChainShape(); diff --git a/src/modules/physics/box2d/CircleShape.cpp b/src/modules/physics/box2d/CircleShape.cpp index 545620f81..29fc6ba88 100644 --- a/src/modules/physics/box2d/CircleShape.cpp +++ b/src/modules/physics/box2d/CircleShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,8 +34,8 @@ namespace box2d love::Type CircleShape::type("CircleShape", &Shape::type); -CircleShape::CircleShape(b2CircleShape *c, bool own) - : Shape(c, own) +CircleShape::CircleShape(Body *body, const b2CircleShape &c) + : Shape(body, c) { } @@ -45,16 +45,19 @@ CircleShape::~CircleShape() float CircleShape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } void CircleShape::setRadius(float r) { + throwIfShapeNotValid(); shape->m_radius = Physics::scaleDown(r); } void CircleShape::getPoint(float &x_o, float &y_o) const { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; x_o = Physics::scaleUp(c->m_p.x); y_o = Physics::scaleUp(c->m_p.y); @@ -62,6 +65,7 @@ void CircleShape::getPoint(float &x_o, float &y_o) const void CircleShape::setPoint(float x, float y) { + throwIfShapeNotValid(); b2CircleShape *c = (b2CircleShape *) shape; c->m_p = Physics::scaleDown(b2Vec2(x, y)); } diff --git a/src/modules/physics/box2d/CircleShape.h b/src/modules/physics/box2d/CircleShape.h index 438034bb8..1f314f43c 100644 --- a/src/modules/physics/box2d/CircleShape.h +++ b/src/modules/physics/box2d/CircleShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -50,7 +50,7 @@ public: * Create a new CircleShape from the a Box2D CircleShape definition. * @param c The CircleShape definition. **/ - CircleShape(b2CircleShape *c, bool own = true); + CircleShape(Body *body, const b2CircleShape &c); virtual ~CircleShape(); diff --git a/src/modules/physics/box2d/Contact.cpp b/src/modules/physics/box2d/Contact.cpp index 5b110dcc3..a25e7f921 100644 --- a/src/modules/physics/box2d/Contact.cpp +++ b/src/modules/physics/box2d/Contact.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,16 +45,16 @@ Contact::~Contact() void Contact::invalidate() { - if (contact != NULL) + if (contact != nullptr) { world->unregisterObject(contact); - contact = NULL; + contact = nullptr; } } bool Contact::isValid() { - return contact != NULL; + return contact != nullptr; } int Contact::getPositions(lua_State *L) @@ -143,13 +143,13 @@ void Contact::getChildren(int &childA, int &childB) childB = contact->GetChildIndexB(); } -void Contact::getFixtures(Fixture *&fixtureA, Fixture *&fixtureB) +void Contact::getShapes(Shape *&shapeA, Shape *&shapeB) { - fixtureA = (Fixture *) world->findObject(contact->GetFixtureA()); - fixtureB = (Fixture *) world->findObject(contact->GetFixtureB()); + shapeA = (Shape *) (contact->GetFixtureA()->GetUserData().pointer); + shapeB = (Shape *) (contact->GetFixtureB()->GetUserData().pointer); - if (!fixtureA || !fixtureB) - throw love::Exception("A fixture has escaped Memoizer!"); + if (!shapeA || !shapeB) + throw love::Exception("A Shape has escaped Memoizer!"); } } // box2d diff --git a/src/modules/physics/box2d/Contact.h b/src/modules/physics/box2d/Contact.h index afbe587d6..9407f32ab 100644 --- a/src/modules/physics/box2d/Contact.h +++ b/src/modules/physics/box2d/Contact.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -151,9 +151,9 @@ public: void getChildren(int &childA, int &childB); /** - * Gets the Fixtures associated with this Contact. + * Gets the Shapes associated with this Contact. **/ - void getFixtures(Fixture *&fixtureA, Fixture *&fixtureB); + void getShapes(Shape *&shapeA, Shape *&shapeB); private: diff --git a/src/modules/physics/box2d/DistanceJoint.cpp b/src/modules/physics/box2d/DistanceJoint.cpp index 3e63638c3..a3f77f33a 100644 --- a/src/modules/physics/box2d/DistanceJoint.cpp +++ b/src/modules/physics/box2d/DistanceJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -32,6 +32,8 @@ namespace physics namespace box2d { +love::Type DistanceJoint::type("DistanceJoint", &Joint::type); + DistanceJoint::DistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) : Joint(body1, body2) , joint(NULL) diff --git a/src/modules/physics/box2d/DistanceJoint.h b/src/modules/physics/box2d/DistanceJoint.h index fe571b5af..5b59d9905 100644 --- a/src/modules/physics/box2d/DistanceJoint.h +++ b/src/modules/physics/box2d/DistanceJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,6 +39,8 @@ class DistanceJoint : public Joint { public: + static love::Type type; + /** * Creates a DistanceJoint connecting body1 to body2. **/ diff --git a/src/modules/physics/box2d/EdgeShape.cpp b/src/modules/physics/box2d/EdgeShape.cpp index e4f3c146f..3c612738b 100644 --- a/src/modules/physics/box2d/EdgeShape.cpp +++ b/src/modules/physics/box2d/EdgeShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,8 +34,8 @@ namespace box2d love::Type EdgeShape::type("EdgeShape", &Shape::type); -EdgeShape::EdgeShape(b2EdgeShape *e, bool own) - : Shape(e, own) +EdgeShape::EdgeShape(Body *body, const b2EdgeShape &e) + : Shape(body, e) { } @@ -45,34 +45,39 @@ EdgeShape::~EdgeShape() void EdgeShape::setNextVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex3 = Physics::scaleDown(v); + e->m_oneSided = true; } b2Vec2 EdgeShape::getNextVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex3); } void EdgeShape::setPreviousVertex(float x, float y) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v(x, y); e->m_vertex0 = Physics::scaleDown(v); + e->m_oneSided = true; } b2Vec2 EdgeShape::getPreviousVertex() const { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; - return Physics::scaleUp(e->m_vertex0); } int EdgeShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); b2EdgeShape *e = (b2EdgeShape *)shape; b2Vec2 v1 = Physics::scaleUp(e->m_vertex1); b2Vec2 v2 = Physics::scaleUp(e->m_vertex2); diff --git a/src/modules/physics/box2d/EdgeShape.h b/src/modules/physics/box2d/EdgeShape.h index 4db2383ce..8e57b6704 100644 --- a/src/modules/physics/box2d/EdgeShape.h +++ b/src/modules/physics/box2d/EdgeShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -45,7 +45,7 @@ public: * Create a new EdgeShape from a Box2D edge shape. * @param e The edge shape. **/ - EdgeShape(b2EdgeShape *e, bool own = true); + EdgeShape(Body *body, const b2EdgeShape &e); virtual ~EdgeShape(); diff --git a/src/modules/physics/box2d/Fixture.cpp b/src/modules/physics/box2d/Fixture.cpp deleted file mode 100644 index a1d3dc994..000000000 --- a/src/modules/physics/box2d/Fixture.cpp +++ /dev/null @@ -1,364 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "Fixture.h" - -// Module -#include "Body.h" -#include "World.h" -#include "Physics.h" - -// STD -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -love::Type Fixture::type("Fixture", &Object::type); - -Fixture::Fixture(Body *body, Shape *shape, float density) - : body(body) - , fixture(nullptr) -{ - udata = new fixtureudata(); - udata->ref = nullptr; - b2FixtureDef def; - def.shape = shape->shape; - def.userData.pointer = (uintptr_t)udata; - def.density = density; - fixture = body->body->CreateFixture(&def); - this->retain(); - body->world->registerObject(fixture, this); -} - -Fixture::~Fixture() -{ - if (!udata) - return; - - if (udata->ref) - delete udata->ref; - - delete udata; -} - -void Fixture::checkCreateShape() -{ - if (shape.get() != nullptr || fixture == nullptr || fixture->GetShape() == nullptr) - return; - - b2Shape *bshape = fixture->GetShape(); - - switch (bshape->GetType()) - { - case b2Shape::e_circle: - shape.set(new CircleShape((b2CircleShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_edge: - shape.set(new EdgeShape((b2EdgeShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_polygon: - shape.set(new PolygonShape((b2PolygonShape *) bshape, false), Acquire::NORETAIN); - break; - case b2Shape::e_chain: - shape.set(new ChainShape((b2ChainShape *) bshape, false), Acquire::NORETAIN); - break; - default: - break; - } -} - -Shape::Type Fixture::getType() -{ - checkCreateShape(); - if (shape.get() == nullptr) - return Shape::SHAPE_INVALID; - else - return shape->getType(); -} - -void Fixture::setFriction(float friction) -{ - fixture->SetFriction(friction); -} - -void Fixture::setRestitution(float restitution) -{ - fixture->SetRestitution(restitution); -} - -void Fixture::setDensity(float density) -{ - fixture->SetDensity(density); -} - -void Fixture::setSensor(bool sensor) -{ - fixture->SetSensor(sensor); -} - -float Fixture::getFriction() const -{ - return fixture->GetFriction(); -} - -float Fixture::getRestitution() const -{ - return fixture->GetRestitution(); -} - -float Fixture::getDensity() const -{ - return fixture->GetDensity(); -} - -bool Fixture::isSensor() const -{ - return fixture->IsSensor(); -} - -Body *Fixture::getBody() const -{ - return body; -} - -Shape *Fixture::getShape() -{ - checkCreateShape(); - return shape; -} - -bool Fixture::isValid() const -{ - return fixture != nullptr; -} - -void Fixture::setFilterData(int *v) -{ - b2Filter f; - f.categoryBits = (uint16) v[0]; - f.maskBits = (uint16) v[1]; - f.groupIndex = (int16) v[2]; - fixture->SetFilterData(f); -} - -void Fixture::getFilterData(int *v) -{ - b2Filter f = fixture->GetFilterData(); - v[0] = (int) f.categoryBits; - v[1] = (int) f.maskBits; - v[2] = (int) f.groupIndex; -} - -int Fixture::setCategory(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.categoryBits = (uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -int Fixture::setMask(lua_State *L) -{ - b2Filter f = fixture->GetFilterData(); - f.maskBits = ~(uint16)getBits(L); - fixture->SetFilterData(f); - return 0; -} - -void Fixture::setGroupIndex(int index) -{ - b2Filter f = fixture->GetFilterData(); - f.groupIndex = (uint16)index; - fixture->SetFilterData(f); -} - -int Fixture::getGroupIndex() const -{ - b2Filter f = fixture->GetFilterData(); - return f.groupIndex; -} - -int Fixture::getCategory(lua_State *L) -{ - return pushBits(L, fixture->GetFilterData().categoryBits); -} - -int Fixture::getMask(lua_State *L) -{ - return pushBits(L, ~(fixture->GetFilterData().maskBits)); -} - -uint16 Fixture::getBits(lua_State *L) -{ - // Get number of args. - bool istable = lua_istable(L, 1); - int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); - - // The new bitset. - std::bitset<16> b; - - for (int i = 1; i <= argc; i++) - { - size_t bpos = 0; - - if (istable) - { - lua_rawgeti(L, 1, i); - bpos = (size_t) (lua_tointeger(L, -1) - 1); - lua_pop(L, 1); - } - else - bpos = (size_t) (lua_tointeger(L, i) - 1); - - if (bpos >= 16) - luaL_error(L, "Values must be in range 1-16."); - - b.set(bpos, true); - } - - return (uint16)b.to_ulong(); -} - -int Fixture::pushBits(lua_State *L, uint16 bits) -{ - // Create a bitset. - std::bitset<16> b((int)bits); - - // Push all set bits. - for (int i = 0; i<16; i++) - if (b.test(i)) - lua_pushinteger(L, i+1); - - // Count number of set bits. - return (int)b.count(); -} - -int Fixture::setUserData(lua_State *L) -{ - love::luax_assert_argc(L, 1, 1); - - if (udata == nullptr) - { - udata = new fixtureudata(); - fixture->GetUserData().pointer = (uintptr_t)udata; - } - - if(!udata->ref) - udata->ref = new Reference(); - - udata->ref->ref(L); - - return 0; -} - -int Fixture::getUserData(lua_State *L) -{ - if (udata->ref != nullptr) - udata->ref->push(L); - else - lua_pushnil(L); - - return 1; -} - -bool Fixture::testPoint(float x, float y) const -{ - return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); -} - -int Fixture::rayCast(lua_State *L) const -{ - float p1x = Physics::scaleDown((float)luaL_checknumber(L, 1)); - float p1y = Physics::scaleDown((float)luaL_checknumber(L, 2)); - float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); - float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); - float maxFraction = (float)luaL_checknumber(L, 5); - int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index - b2RayCastInput input; - input.p1.Set(p1x, p1y); - input.p2.Set(p2x, p2y); - input.maxFraction = maxFraction; - b2RayCastOutput output; - if (!fixture->RayCast(&output, input, childIndex)) - return 0; // Nothing hit. - lua_pushnumber(L, output.normal.x); - lua_pushnumber(L, output.normal.y); - lua_pushnumber(L, output.fraction); - return 3; -} - -int Fixture::getBoundingBox(lua_State *L) const -{ - int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index - b2AABB box; - luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); - box = Physics::scaleUp(box); - lua_pushnumber(L, box.lowerBound.x); - lua_pushnumber(L, box.lowerBound.y); - lua_pushnumber(L, box.upperBound.x); - lua_pushnumber(L, box.upperBound.y); - return 4; -} - -int Fixture::getMassData(lua_State *L) const -{ - b2MassData data; - fixture->GetMassData(&data); - b2Vec2 center = Physics::scaleUp(data.center); - lua_pushnumber(L, center.x); - lua_pushnumber(L, center.y); - lua_pushnumber(L, data.mass); - lua_pushnumber(L, data.I); - return 4; -} - -void Fixture::destroy(bool implicit) -{ - if (body->world->world->IsLocked()) - { - // Called during time step. Save reference for destruction afterwards. - this->retain(); - body->world->destructFixtures.push_back(this); - return; - } - - shape.set(nullptr); - - if (!implicit && fixture != nullptr) - body->body->DestroyFixture(fixture); - body->world->unregisterObject(fixture); - fixture = nullptr; - - // Remove userdata reference to avoid it sticking around after GC - if (udata && udata->ref) - udata->ref->unref(); - - // Box2D fixture destroyed. Release its reference to the love Fixture. - this->release(); -} - -} // box2d -} // physics -} // love diff --git a/src/modules/physics/box2d/Fixture.h b/src/modules/physics/box2d/Fixture.h deleted file mode 100644 index d4087c5c3..000000000 --- a/src/modules/physics/box2d/Fixture.h +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_FIXTURE_H - -// LOVE -#include "physics/Shape.h" -#include "physics/box2d/Body.h" -#include "physics/box2d/Shape.h" -#include "common/Object.h" -#include "common/Reference.h" - -// Box2D -#include - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -class World; - -/** - * This struct is stored in a void pointer - * in the Box2D Fixture class. For now, all we - * need is a Lua reference to arbitrary data, - * but we might need more later. - **/ -struct fixtureudata -{ - // Reference to arbitrary data. - Reference *ref = nullptr; -}; - -/** - * A Fixture is used to attach a shape to a body for collision detection. - * A Fixture inherits its transform from its parent. Fixtures hold - * additional non-geometric data such as friction, collision filters, - * etc. - **/ -class Fixture : public Object -{ -public: - friend class Physics; - - static love::Type type; - - /** - * Creates a Fixture. - **/ - Fixture(Body *body, Shape *shape, float density); - - virtual ~Fixture(); - - /** - * Gets the type of the Fixture's Shape. Useful for - * debug drawing. - **/ - Shape::Type getType(); - - /** - * Gets the Shape attached to this Fixture. - **/ - Shape *getShape(); - - /** - * Returns true if the fixture is active in a Box2D world. - **/ - bool isValid() const; - - /** - * Checks whether this Fixture acts as a sensor. - * @return True if sensor, false otherwise. - **/ - bool isSensor() const; - - /** - * Set whether this Fixture should be a sensor or not. - * @param sensor True if sensor, false if not. - **/ - void setSensor(bool sensor); - - /** - * Gets the Body this Fixture is attached to. - **/ - Body *getBody() const; - - /** - * Sets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void setFilterData(int *v); - - /** - * Gets the filter data. An integer array is used even though the - * first two elements are unsigned shorts. The elements are: - * category (16-bits), mask (16-bits) and group (32-bits/int). - **/ - void getFilterData(int *v); - - /** - * This function stores an in-C reference to - * arbitrary Lua data in the Box2D Fixture object. - **/ - int setUserData(lua_State *L); - - /** - * Gets the data set with setData. If no - * data is set, nil is returned. - **/ - int getUserData(lua_State *L); - - /** - * Sets the friction of the Fixture. - * @param friction The new friction. - **/ - void setFriction(float friction); - - /** - * Sets the restitution for the Fixture. - * @param restitution The restitution. - **/ - void setRestitution(float restitution); - - /** - * Sets the density of the Fixture. - * @param density The density of the Fixture. - **/ - void setDensity(float density); - - /** - * Gets the friction of the Fixture. - * @returns The friction. - **/ - float getFriction() const; - - /** - * Gets the restitution of the Fixture. - * @return The restitution of the Fixture. - **/ - float getRestitution() const; - - /** - * Gets the density of the Fixture. - * @return The density. - **/ - float getDensity() const; - - /** - * Checks if a point is inside the Fixture. - * @param x The x-component of the point. - * @param y The y-component of the point. - **/ - bool testPoint(float x, float y) const; - - /** - * Cast a ray against this Fixture. - **/ - int rayCast(lua_State *L) const; - - void setGroupIndex(int index); - int getGroupIndex() const; - - int setCategory(lua_State *L); - int setMask(lua_State *L); - int getCategory(lua_State *L); - int getMask(lua_State *L); - uint16 getBits(lua_State *L); - int pushBits(lua_State *L, uint16 bits); - - /** - * Gets the bounding box for this Fixture. - * The function returns eight values which can be - * passed directly to love.graphics.polygon. - **/ - int getBoundingBox(lua_State *L) const; - - /** - * Gets the mass data for this Fixture. - * This operation may be expensive. - **/ - int getMassData(lua_State *L) const; - - /** - * Destroys this fixture. - **/ - void destroy(bool implicit = false); - -protected: - - void checkCreateShape(); - - Body *body; - fixtureudata *udata; - b2Fixture *fixture; - - StrongRef shape; - -}; - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_FIXTURE_H diff --git a/src/modules/physics/box2d/FrictionJoint.cpp b/src/modules/physics/box2d/FrictionJoint.cpp index af0066e30..80ec092df 100644 --- a/src/modules/physics/box2d/FrictionJoint.cpp +++ b/src/modules/physics/box2d/FrictionJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/FrictionJoint.h b/src/modules/physics/box2d/FrictionJoint.h index 145bbf78d..d8d7391be 100644 --- a/src/modules/physics/box2d/FrictionJoint.h +++ b/src/modules/physics/box2d/FrictionJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/GearJoint.cpp b/src/modules/physics/box2d/GearJoint.cpp index 8f0968285..691bc5c12 100644 --- a/src/modules/physics/box2d/GearJoint.cpp +++ b/src/modules/physics/box2d/GearJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -69,7 +69,7 @@ Joint *GearJoint::getJointA() const if (b2joint == nullptr) return nullptr; - Joint *j = (Joint *) world->findObject(b2joint); + Joint *j = (Joint *) (b2joint->GetUserData().pointer); if (j == nullptr) throw love::Exception("A joint has escaped Memoizer!"); @@ -82,7 +82,7 @@ Joint *GearJoint::getJointB() const if (b2joint == nullptr) return nullptr; - Joint *j = (Joint *) world->findObject(b2joint); + Joint *j = (Joint *) (b2joint->GetUserData().pointer); if (j == nullptr) throw love::Exception("A joint has escaped Memoizer!"); diff --git a/src/modules/physics/box2d/GearJoint.h b/src/modules/physics/box2d/GearJoint.h index f6199de0b..2c434ea1a 100644 --- a/src/modules/physics/box2d/GearJoint.h +++ b/src/modules/physics/box2d/GearJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/Joint.cpp b/src/modules/physics/box2d/Joint.cpp index bb5cf8aba..635f42401 100644 --- a/src/modules/physics/box2d/Joint.cpp +++ b/src/modules/physics/box2d/Joint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,33 +38,22 @@ namespace box2d Joint::Joint(Body *body1) : world(body1->world) - , udata(nullptr) , body1(body1) , body2(nullptr) { - udata = new jointudata(); - udata->ref = nullptr; } Joint::Joint(Body *body1, Body *body2) : world(body1->world) - , udata(nullptr) , body1(body1) , body2(body2) { - udata = new jointudata(); - udata->ref = nullptr; } Joint::~Joint() { - if (!udata) - return; - - if (udata->ref) - delete udata->ref; - - delete udata; + if (ref) + delete ref; } Joint::Type Joint::getType() const @@ -104,7 +93,7 @@ Body *Joint::getBodyA() const if (b2body == nullptr) return nullptr; - Body *body = (Body *) world->findObject(b2body); + Body *body = (Body *) (b2body->GetUserData().pointer); if (body == nullptr) throw love::Exception("A body has escaped Memoizer!"); @@ -117,7 +106,7 @@ Body *Joint::getBodyB() const if (b2body == nullptr) return nullptr; - Body *body = (Body *) world->findObject(b2body); + Body *body = (Body *) (b2body->GetUserData().pointer); if (body == nullptr) throw love::Exception("A body has escaped Memoizer!"); @@ -154,9 +143,8 @@ float Joint::getReactionTorque(float dt) b2Joint *Joint::createJoint(b2JointDef *def) { - def->userData.pointer = (uintptr_t)udata; + def->userData.pointer = (uintptr_t)this; joint = world->world->CreateJoint(def); - world->registerObject(joint, this); // Box2D joint has a reference to this love Joint. this->retain(); return joint; @@ -174,12 +162,11 @@ void Joint::destroyJoint(bool implicit) if (!implicit && joint != nullptr) world->world->DestroyJoint(joint); - world->unregisterObject(joint); - joint = NULL; + joint = nullptr; // Remove userdata reference to avoid it sticking around after GC - if (udata && udata->ref) - udata->ref->unref(); + if (ref) + ref->unref(); // Release the reference of the Box2D joint. this->release(); @@ -199,24 +186,18 @@ int Joint::setUserData(lua_State *L) { love::luax_assert_argc(L, 1, 1); - if (udata == nullptr) - { - udata = new jointudata(); - joint->GetUserData().pointer = (uintptr_t)udata; - } + if(!ref) + ref = new Reference(); - if(!udata->ref) - udata->ref = new Reference(); - - udata->ref->ref(L); + ref->ref(L); return 0; } int Joint::getUserData(lua_State *L) { - if (udata != nullptr && udata->ref != nullptr) - udata->ref->push(L); + if (ref != nullptr) + ref->push(L); else lua_pushnil(L); diff --git a/src/modules/physics/box2d/Joint.h b/src/modules/physics/box2d/Joint.h index 0ef205588..f8f120e60 100644 --- a/src/modules/physics/box2d/Joint.h +++ b/src/modules/physics/box2d/Joint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,16 +39,6 @@ namespace box2d class Body; class World; -/** - * This struct is stored in a void pointer in the Box2D Joint class. For now, all - * we need is a Lua reference to arbitrary data, but we might need more later. - **/ -struct jointudata -{ - // Reference to arbitrary data. - Reference *ref = nullptr; -}; - /** * A Joint acts as positioning constraints on Bodies. * A Joint can be used to prevent Bodies from going to @@ -140,7 +130,8 @@ protected: World *world; - jointudata *udata; + // Reference to arbitrary data. + Reference* ref = nullptr; private: diff --git a/src/modules/physics/box2d/MotorJoint.cpp b/src/modules/physics/box2d/MotorJoint.cpp index bff22662c..9ee884634 100644 --- a/src/modules/physics/box2d/MotorJoint.cpp +++ b/src/modules/physics/box2d/MotorJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/MotorJoint.h b/src/modules/physics/box2d/MotorJoint.h index ef0faf0c0..a3a875c42 100644 --- a/src/modules/physics/box2d/MotorJoint.h +++ b/src/modules/physics/box2d/MotorJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/MouseJoint.cpp b/src/modules/physics/box2d/MouseJoint.cpp index 81f8831ea..a47b367e5 100644 --- a/src/modules/physics/box2d/MouseJoint.cpp +++ b/src/modules/physics/box2d/MouseJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/MouseJoint.h b/src/modules/physics/box2d/MouseJoint.h index 1588b2024..032c58b4d 100644 --- a/src/modules/physics/box2d/MouseJoint.h +++ b/src/modules/physics/box2d/MouseJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/Physics.cpp b/src/modules/physics/box2d/Physics.cpp index abf26e2da..8b5e70d9d 100644 --- a/src/modules/physics/box2d/Physics.cpp +++ b/src/modules/physics/box2d/Physics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,6 +35,8 @@ namespace box2d float Physics::meter = Physics::DEFAULT_METER; Physics::Physics() + : Module(M_PHYSICS, "love.physics.box2d") + , blockAllocator() { meter = DEFAULT_METER; } @@ -43,11 +45,6 @@ Physics::~Physics() { } -const char *Physics::getName() const -{ - return "love.physics.box2d"; -} - World *Physics::newWorld(float gx, float gy, bool sleep) { return new World(b2Vec2(gx, gy), sleep); @@ -63,173 +60,176 @@ Body *Physics::newBody(World *world, Body::Type type) return new Body(world, b2Vec2(0, 0), type); } -CircleShape *Physics::newCircleShape(float radius) +Body *Physics::newCircleBody(World *world, Body::Type type, float x, float y, float radius) { - return newCircleShape(0, 0, radius); + StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); + StrongRef shape(newCircleShape(body, 0, 0, radius), Acquire::NORETAIN); + body->retain(); + return body.get(); } -CircleShape *Physics::newCircleShape(float x, float y, float radius) +Body *Physics::newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle) { - b2CircleShape *s = new b2CircleShape(); - s->m_p = Physics::scaleDown(b2Vec2(x, y)); - s->m_radius = Physics::scaleDown(radius); - return new CircleShape(s); + StrongRef body(newBody(world, x, y, type), Acquire::NORETAIN); + StrongRef shape(newRectangleShape(body, 0, 0, w, h, angle), Acquire::NORETAIN); + body->retain(); + return body.get(); } -PolygonShape *Physics::newRectangleShape(float w, float h) +Body *Physics::newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count) { - return newRectangleShape(0, 0, w, h, 0); + Vector2 origin(0, 0); + + for (int i = 0; i < count; i++) + origin += coords[i] / count; + + std::vector localcoords; + for (int i = 0; i < count; i++) + localcoords.push_back(coords[i] - origin); + + StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); + StrongRef shape(newPolygonShape(body, localcoords.data(), count), Acquire::NORETAIN); + body->retain(); + return body.get(); } -PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h) +Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2) { - return newRectangleShape(x, y, w, h, 0); + float wx = (x2 - x1) / 2.0f; + float wy = (y2 - y1) / 2.0f; + StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN); + StrongRef shape(newEdgeShape(body, x1 - wx, y1 - wy, x2 - wx, y2 - wy), Acquire::NORETAIN); + body->retain(); + return body.get(); } -PolygonShape *Physics::newRectangleShape(float x, float y, float w, float h, float angle) +Body *Physics::newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, float prevx, float prevy, float nextx, float nexty) { - b2PolygonShape *s = new b2PolygonShape(); - s->SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); - return new PolygonShape(s); + float wx = (x2 - x1) / 2.0f; + float wy = (y2 - y1) / 2.0f; + StrongRef body(newBody(world, wx, wy, type), Acquire::NORETAIN); + StrongRef shape(newEdgeShape(body, x1 - wx, y1 - wy, x2 - wx, y2 - wy, prevx - wx, prevy - wy, nextx - wx, nexty - wy), Acquire::NORETAIN); + body->retain(); + return body.get(); } -EdgeShape *Physics::newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided) +Body *Physics::newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count) { - b2EdgeShape *s = new b2EdgeShape(); - if (oneSided) + Vector2 origin(0, 0); + + for (int i = 0; i < count; i++) + origin += coords[i] / count; + + std::vector localcoords; + for (int i = 0; i < count; i++) + localcoords.push_back(coords[i] - origin); + + StrongRef body(newBody(world, origin.x, origin.y, type), Acquire::NORETAIN); + StrongRef shape(newChainShape(body, loop, localcoords.data(), count), Acquire::NORETAIN); + body->retain(); + return body.get(); +} + +Shape *Physics::newAttachedShape(Body *body, Shape *prototype, float density) +{ + if (prototype->isValid()) + throw love::Exception("The given Shape must not be part of the World."); + + Shape *shape = nullptr; + + switch (prototype->getType()) { - b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); - b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); - s->SetOneSided(v1, v1, v2, v2); + case Shape::SHAPE_CIRCLE: + shape = new CircleShape(body, *(b2CircleShape *) prototype->shape); + break; + case Shape::SHAPE_POLYGON: + shape = new PolygonShape(body, *(b2PolygonShape *) prototype->shape); + break; + case Shape::SHAPE_EDGE: + shape = new EdgeShape(body, *(b2EdgeShape *) prototype->shape); + break; + case Shape::SHAPE_CHAIN: + shape = new ChainShape(body, *(b2ChainShape *) prototype->shape); + break; + default: + throw love::Exception("Unknown shape type."); + break; } - else - { - s->SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); - } - return new EdgeShape(s); + + shape->setDensity(density); + body->resetMassData(); + + return shape; } -int Physics::newPolygonShape(lua_State *L) +CircleShape *Physics::newCircleShape(Body *body, float x, float y, float radius) { - int argc = lua_gettop(L); + b2CircleShape s; + s.m_p = Physics::scaleDown(b2Vec2(x, y)); + s.m_radius = Physics::scaleDown(radius); + return new CircleShape(body, s); +} - bool istable = lua_istable(L, 1); +PolygonShape *Physics::newRectangleShape(Body *body, float x, float y, float w, float h, float angle) +{ + b2PolygonShape s; + s.SetAsBox(Physics::scaleDown(w/2.0f), Physics::scaleDown(h/2.0f), Physics::scaleDown(b2Vec2(x, y)), angle); + return new PolygonShape(body, s); +} - if (istable) - argc = (int) luax_objlen(L, 1); +EdgeShape *Physics::newEdgeShape(Body *body, float x1, float y1, float x2, float y2) +{ + b2EdgeShape s; + s.SetTwoSided(Physics::scaleDown(b2Vec2(x1, y1)), Physics::scaleDown(b2Vec2(x2, y2))); + return new EdgeShape(body, s); +} - if (argc % 2 != 0) - return luaL_error(L, "Number of vertex components must be a multiple of two."); +EdgeShape *Physics::newEdgeShape(Body *body, float x1, float y1, float x2, float y2, float prevx, float prevy, float nextx, float nexty) +{ + b2EdgeShape s; + b2Vec2 v0 = Physics::scaleDown(b2Vec2(prevx, prevy)); + b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); + b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); + b2Vec2 v3 = Physics::scaleDown(b2Vec2(nextx, nexty)); + s.SetOneSided(v0, v1, v2, v3); + return new EdgeShape(body, s); +} +PolygonShape *Physics::newPolygonShape(Body *body, const Vector2 *coords, int count) +{ // 3 to 8 (b2_maxPolygonVertices) vertices - int vcount = argc / 2; - if (vcount < 3) - return luaL_error(L, "Expected a minimum of 3 vertices, got %d.", vcount); - else if (vcount > b2_maxPolygonVertices) - return luaL_error(L, "Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, vcount); + if (count < 3) + throw love::Exception("Expected a minimum of 3 vertices, got %d.", count); + else if (count > b2_maxPolygonVertices) + throw love::Exception("Expected a maximum of %d vertices, got %d.", b2_maxPolygonVertices, count); b2Vec2 vecs[b2_maxPolygonVertices]; - if (istable) - { - for (int i = 0; i < vcount; i++) - { - lua_rawgeti(L, 1, 1 + i * 2); - lua_rawgeti(L, 1, 2 + i * 2); - float x = (float)luaL_checknumber(L, -2); - float y = (float)luaL_checknumber(L, -1); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - lua_pop(L, 2); - } - } - else - { - for (int i = 0; i < vcount; i++) - { - float x = (float)luaL_checknumber(L, 1 + i * 2); - float y = (float)luaL_checknumber(L, 2 + i * 2); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - } - } + for (int i = 0; i < count; i++) + vecs[i] = Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y)); - b2PolygonShape *s = new b2PolygonShape(); + b2PolygonShape s; - try - { - s->Set(vecs, vcount); - } - catch (love::Exception &) - { - delete s; - throw; - } + s.Set(vecs, count); - PolygonShape *p = new PolygonShape(s); - luax_pushtype(L, p); - p->release(); - return 1; + return new PolygonShape(body, s); } -int Physics::newChainShape(lua_State *L) +ChainShape *Physics::newChainShape(Body *body, bool loop, const Vector2 *coords, int count) { - int argc = lua_gettop(L)-1; // first argument is looping + std::vector vecs; - bool istable = lua_istable(L, 2); + for (int i = 0; i < count; i++) + vecs.push_back(Physics::scaleDown(b2Vec2(coords[i].x, coords[i].y))); - if (istable) - argc = (int) luax_objlen(L, 2); + b2ChainShape s; - if (argc == 0 || argc % 2 != 0) - return luaL_error(L, "Number of vertex components must be a multiple of two."); - - int vcount = argc/2; - bool loop = luax_checkboolean(L, 1); - b2Vec2 *vecs = new b2Vec2[vcount]; - - if (istable) - { - for (int i = 0; i < vcount; i++) - { - lua_rawgeti(L, 2, 1 + i * 2); - lua_rawgeti(L, 2, 2 + i * 2); - float x = (float)lua_tonumber(L, -2); - float y = (float)lua_tonumber(L, -1); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - lua_pop(L, 2); - } - } + if (loop) + s.CreateLoop(vecs.data(), count); else - { - for (int i = 0; i < vcount; i++) - { - float x = (float)luaL_checknumber(L, 2 + i * 2); - float y = (float)luaL_checknumber(L, 3 + i * 2); - vecs[i] = Physics::scaleDown(b2Vec2(x, y)); - } - } + s.CreateChain(vecs.data(), count, vecs[0], vecs[count - 1]); - b2ChainShape *s = new b2ChainShape(); - - try - { - if (loop) - s->CreateLoop(vecs, vcount); - else - s->CreateChain(vecs, vcount, vecs[0], vecs[vcount-1]); - } - catch (love::Exception &) - { - delete[] vecs; - delete s; - throw; - } - - delete[] vecs; - - ChainShape *c = new ChainShape(s); - luax_pushtype(L, c); - c->release(); - return 1; + return new ChainShape(body, s); } DistanceJoint *Physics::newDistanceJoint(Body *body1, Body *body2, float x1, float y1, float x2, float y2, bool collideConnected) @@ -307,16 +307,10 @@ MotorJoint *Physics::newMotorJoint(Body *body1, Body *body2, float correctionFac return new MotorJoint(body1, body2, correctionFactor, collideConnected); } - -Fixture *Physics::newFixture(Body *body, Shape *shape, float density) -{ - return new Fixture(body, shape, density); -} - int Physics::getDistance(lua_State *L) { - Fixture *fixtureA = luax_checktype(L, 1); - Fixture *fixtureB = luax_checktype(L, 2); + Shape *shapeA = luax_checktype(L, 1); + Shape *shapeB = luax_checktype(L, 2); b2DistanceProxy pA, pB; b2DistanceInput i; b2DistanceOutput o; @@ -324,12 +318,15 @@ int Physics::getDistance(lua_State *L) c.count = 0; luax_catchexcept(L, [&]() { - pA.Set(fixtureA->fixture->GetShape(), 0); - pB.Set(fixtureB->fixture->GetShape(), 0); + if (!shapeA->isValid() || !shapeB->isValid()) + throw love::Exception("The given Shape is not active in the physics World."); + + pA.Set(shapeA->fixture->GetShape(), 0); + pB.Set(shapeB->fixture->GetShape(), 0); i.proxyA = pA; i.proxyB = pB; - i.transformA = fixtureA->fixture->GetBody()->GetTransform(); - i.transformB = fixtureB->fixture->GetBody()->GetTransform(); + i.transformA = shapeA->fixture->GetBody()->GetTransform(); + i.transformB = shapeB->fixture->GetBody()->GetTransform(); i.useRadii = true; b2Distance(&o, &c, &i); }); diff --git a/src/modules/physics/box2d/Physics.h b/src/modules/physics/box2d/Physics.h index 6d3305dcd..c67411e37 100644 --- a/src/modules/physics/box2d/Physics.h +++ b/src/modules/physics/box2d/Physics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,10 +23,11 @@ // LOVE #include "common/Module.h" +#include "common/Vector.h" + #include "World.h" #include "Contact.h" #include "Body.h" -#include "Fixture.h" #include "Shape.h" #include "CircleShape.h" #include "PolygonShape.h" @@ -64,10 +65,6 @@ public: Physics(); virtual ~Physics(); - // Implements Module. - const char *getName() const; - virtual ModuleType getModuleType() const { return M_PHYSICS; } - /** * Creates a new World. * @param gx Gravity along x-axis. @@ -93,10 +90,19 @@ public: Body *newBody(World *world, Body::Type type); /** - * Creates a new CircleShape at (0, 0). - * @param radius The radius of the circle. + * Convenience functions for creating a Body and Shape all in one call. The + * body's world position is the center/average of the given coordinates, + * and the shape is centered at the local origin. **/ - CircleShape *newCircleShape(float radius); + Body *newCircleBody(World *world, Body::Type type, float x, float y, float radius); + Body *newRectangleBody(World *world, Body::Type type, float x, float y, float w, float h, float angle); + Body *newPolygonBody(World *world, Body::Type type, const Vector2 *coords, int count); + Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2); + Body *newEdgeBody(World *world, Body::Type type, float x1, float y1, float x2, float y2, float prevx, float prevy, float nextx, float nexty); + Body *newChainBody(World *world, Body::Type type, bool loop, const Vector2 *coords, int count); + + // Necessary to support the deprecated newFixture API. + Shape *newAttachedShape(Body *body, Shape *prototype, float density); /** * Creates a new CircleShape at (x,y) in local coordinates. @@ -104,25 +110,7 @@ public: * @param y The offset along the y-axis. * @param radius The radius of the circle. **/ - CircleShape *newCircleShape(float x, float y, float radius); - - /** - * Shorthand for creating rectangular PolygonShapes. The rectangle - * will be created at the local origin. - * @param w The width of the rectangle. - * @param h The height of the rectangle. - **/ - PolygonShape *newRectangleShape(float w, float h); - - /** - * Shorthand for creating rectangular PolygonShapes. The rectangle - * will be created at (x,y) in local coordinates. - * @param x The offset along the x-axis. - * @param y The offset along the y-axis. - * @param w The width of the rectangle. - * @param h The height of the rectangle. - **/ - PolygonShape *newRectangleShape(float x, float y, float w, float h); + CircleShape *newCircleShape(Body *body, float x, float y, float radius); /** * Shorthand for creating rectangular PolygonShapes. The rectangle @@ -133,7 +121,7 @@ public: * @param h The height of the rectangle. * @param angle The angle of the rectangle. (rad) **/ - PolygonShape *newRectangleShape(float x, float y, float w, float h, float angle); + PolygonShape *newRectangleShape(Body *body, float x, float y, float w, float h, float angle); /** * Creates a new EdgeShape. The edge will be created from @@ -143,17 +131,18 @@ public: * @param x2 The x coordinate of the second point. * @param y2 The y coordinate of the second point. **/ - EdgeShape *newEdgeShape(float x1, float y1, float x2, float y2, bool oneSided); + EdgeShape *newEdgeShape(Body *body, float x1, float y1, float x2, float y2); + EdgeShape *newEdgeShape(Body *body, float x1, float y1, float x2, float y2, float prevx, float prevy, float nextx, float nexty); /** * Creates a new PolygonShape from a variable number of vertices. **/ - int newPolygonShape(lua_State *L); + PolygonShape *newPolygonShape(Body *body, const Vector2 *coords, int count); /** * Creates a new ChainShape from a variable number of vertices. **/ - int newChainShape(lua_State *L); + ChainShape *newChainShape(Body *body, bool loop, const Vector2 *coords, int count); /** * Creates a new DistanceJoint connecting body1 with body2. @@ -273,15 +262,6 @@ public: MotorJoint *newMotorJoint(Body *body1, Body *body2); MotorJoint *newMotorJoint(Body *body1, Body *body2, float correctionFactor, bool collideConnected); - /** - * Creates a new Fixture attaching shape to body. - * @param body The body to attach the Fixture to. - * @param shape The shape to attach to the Fixture, - * @param density The density of the Fixture. - **/ - - Fixture *newFixture(Body *body, Shape *shape, float density); - /** * Calculates the distance between two Fixtures. * @param fixtureA The first Fixture. @@ -403,10 +383,15 @@ public: **/ static void computeAngularFrequency(float &frequency, float &ratio, float stiffness, float damping, b2Body *bodyA, b2Body *bodyB); + b2BlockAllocator *getBlockAllocator() { return &blockAllocator; } + private: // The length of one meter in pixels. static float meter; + + b2BlockAllocator blockAllocator; + }; // Physics } // box2d diff --git a/src/modules/physics/box2d/PolygonShape.cpp b/src/modules/physics/box2d/PolygonShape.cpp index 4655c8cc4..a3d209b6f 100644 --- a/src/modules/physics/box2d/PolygonShape.cpp +++ b/src/modules/physics/box2d/PolygonShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,8 +34,8 @@ namespace box2d love::Type PolygonShape::type("PolygonShape", &Shape::type); -PolygonShape::PolygonShape(b2PolygonShape *p, bool own) - : Shape(p, own) +PolygonShape::PolygonShape(Body *body, const b2PolygonShape &p) + : Shape(body, p) { } @@ -45,6 +45,7 @@ PolygonShape::~PolygonShape() int PolygonShape::getPoints(lua_State *L) { + throwIfShapeNotValid(); love::luax_assert_argc(L, 0); b2PolygonShape *p = (b2PolygonShape *)shape; int count = p->m_count; @@ -59,6 +60,7 @@ int PolygonShape::getPoints(lua_State *L) bool PolygonShape::validate() const { + throwIfShapeNotValid(); b2PolygonShape *p = (b2PolygonShape *)shape; return p->Validate(); } diff --git a/src/modules/physics/box2d/PolygonShape.h b/src/modules/physics/box2d/PolygonShape.h index 9a632ae6d..3ff0d8e0c 100644 --- a/src/modules/physics/box2d/PolygonShape.h +++ b/src/modules/physics/box2d/PolygonShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,7 +48,7 @@ public: * Create a new PolygonShape from a Box2D polygon definition. * @param p The polygon definition. **/ - PolygonShape(b2PolygonShape *p, bool own = true); + PolygonShape(Body *body, const b2PolygonShape &p); virtual ~PolygonShape(); diff --git a/src/modules/physics/box2d/PrismaticJoint.cpp b/src/modules/physics/box2d/PrismaticJoint.cpp index dba52f8e2..ecaad09d1 100644 --- a/src/modules/physics/box2d/PrismaticJoint.cpp +++ b/src/modules/physics/box2d/PrismaticJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/PrismaticJoint.h b/src/modules/physics/box2d/PrismaticJoint.h index 0c774367b..939caa0b3 100644 --- a/src/modules/physics/box2d/PrismaticJoint.h +++ b/src/modules/physics/box2d/PrismaticJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/PulleyJoint.cpp b/src/modules/physics/box2d/PulleyJoint.cpp index afc1c0d88..b4c73f782 100644 --- a/src/modules/physics/box2d/PulleyJoint.cpp +++ b/src/modules/physics/box2d/PulleyJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/PulleyJoint.h b/src/modules/physics/box2d/PulleyJoint.h index 61be4cfef..6c3ad5aea 100644 --- a/src/modules/physics/box2d/PulleyJoint.h +++ b/src/modules/physics/box2d/PulleyJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/RevoluteJoint.cpp b/src/modules/physics/box2d/RevoluteJoint.cpp index cead503ee..2144386e9 100644 --- a/src/modules/physics/box2d/RevoluteJoint.cpp +++ b/src/modules/physics/box2d/RevoluteJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/RevoluteJoint.h b/src/modules/physics/box2d/RevoluteJoint.h index 5d6feab95..c4980731e 100644 --- a/src/modules/physics/box2d/RevoluteJoint.h +++ b/src/modules/physics/box2d/RevoluteJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/RopeJoint.cpp b/src/modules/physics/box2d/RopeJoint.cpp index 426697910..f42dce6e8 100644 --- a/src/modules/physics/box2d/RopeJoint.cpp +++ b/src/modules/physics/box2d/RopeJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/RopeJoint.h b/src/modules/physics/box2d/RopeJoint.h index 927cca30b..393e23a13 100644 --- a/src/modules/physics/box2d/RopeJoint.h +++ b/src/modules/physics/box2d/RopeJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/Shape.cpp b/src/modules/physics/box2d/Shape.cpp index e65807582..cec11f5c3 100644 --- a/src/modules/physics/box2d/Shape.cpp +++ b/src/modules/physics/box2d/Shape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,54 +35,357 @@ namespace physics namespace box2d { -Shape::Shape() +Shape::Shape(Body *body, const b2Shape &shape) : shape(nullptr) , own(false) + , shapeType(SHAPE_INVALID) + , body(body) + , fixture(nullptr) { -} + if (body) + { + b2FixtureDef def; + def.shape = &shape; + def.userData.pointer = (uintptr_t)this; -Shape::Shape(b2Shape *shape, bool own) - : shape(shape) - , own(own) -{ + // 0 density stops CreateFixture from calling b2Body::ResetMassData(). + def.density = body->hasCustomMassData() ? 0.0f : 1.0f; + + fixture = body->body->CreateFixture(&def); + this->shape = fixture->GetShape(); + + if (body->hasCustomMassData()) + setDensity(1.0f); + + retain(); // Shape::destroy does the release(). + } + else + { + // Path to support deprecated APIs. + auto physics = Module::getInstance(Module::M_PHYSICS); + this->shape = shape.Clone(physics->getBlockAllocator()); + own = true; + } + + switch (this->shape->GetType()) + { + case b2Shape::e_circle: + shapeType = SHAPE_CIRCLE; + break; + case b2Shape::e_polygon: + shapeType = SHAPE_POLYGON; + break; + case b2Shape::e_edge: + shapeType = SHAPE_EDGE; + break; + case b2Shape::e_chain: + shapeType = SHAPE_CHAIN; + break; + default: + shapeType = SHAPE_INVALID; + break; + } } Shape::~Shape() { if (shape && own) - delete shape; + { + auto physics = Module::getInstance(Module::M_PHYSICS); + auto allocator = physics->getBlockAllocator(); + + // Taken from b2Fixture::Destroy. Not very pretty... + switch (shapeType) + { + case SHAPE_CIRCLE: + { + b2CircleShape *s = (b2CircleShape*)shape; + s->~b2CircleShape(); + allocator->Free(s, sizeof(b2CircleShape)); + break; + } + case SHAPE_EDGE: + { + b2EdgeShape *s = (b2EdgeShape*)shape; + s->~b2EdgeShape(); + allocator->Free(s, sizeof(b2EdgeShape)); + break; + } + case SHAPE_POLYGON: + { + b2PolygonShape *s = (b2PolygonShape*)shape; + s->~b2PolygonShape(); + allocator->Free(s, sizeof(b2PolygonShape)); + break; + } + case SHAPE_CHAIN: + { + b2ChainShape *s = (b2ChainShape*)shape; + s->~b2ChainShape(); + allocator->Free(s, sizeof(b2ChainShape)); + break; + } + default: + break; + } + } + + if (ref) + delete ref; +} + +void Shape::destroy(bool implicit) +{ + if (fixture == nullptr) + return; + + if (body->world->world->IsLocked()) + { + // Called during time step. Save reference for destruction afterwards. + this->retain(); + body->world->destructShapes.push_back(this); + return; + } + + if (!implicit && fixture != nullptr) + body->body->DestroyFixture(fixture); + + fixture = nullptr; shape = nullptr; + body = nullptr; + + // Remove userdata reference to avoid it sticking around after GC + if (ref) + ref->unref(); + + // Box2D fixture destroyed. Release its reference to the love Shape. + release(); +} + +void Shape::throwIfFixtureNotValid() const +{ + if (fixture == nullptr) + throw love::Exception("Shape must be active in the physics World to use this method."); +} + +void Shape::throwIfShapeNotValid() const +{ + if (shape == nullptr) + throw love::Exception("Cannot call this method on a destroyed Shape."); } Shape::Type Shape::getType() const { - switch (shape->GetType()) - { - case b2Shape::e_circle: - return SHAPE_CIRCLE; - case b2Shape::e_polygon: - return SHAPE_POLYGON; - case b2Shape::e_edge: - return SHAPE_EDGE; - case b2Shape::e_chain: - return SHAPE_CHAIN; - default: - return SHAPE_INVALID; - } + return shapeType; +} + +void Shape::setFriction(float friction) +{ + throwIfFixtureNotValid(); + fixture->SetFriction(friction); +} + +void Shape::setRestitution(float restitution) +{ + throwIfFixtureNotValid(); + fixture->SetRestitution(restitution); +} + +void Shape::setDensity(float density) +{ + throwIfFixtureNotValid(); + fixture->SetDensity(density); + if (!body->hasCustomMassData()) + body->resetMassData(); +} + +void Shape::setSensor(bool sensor) +{ + throwIfFixtureNotValid(); + fixture->SetSensor(sensor); +} + +float Shape::getFriction() const +{ + throwIfFixtureNotValid(); + return fixture->GetFriction(); +} + +float Shape::getRestitution() const +{ + throwIfFixtureNotValid(); + return fixture->GetRestitution(); +} + +float Shape::getDensity() const +{ + throwIfFixtureNotValid(); + return fixture->GetDensity(); +} + +bool Shape::isSensor() const +{ + throwIfFixtureNotValid(); + return fixture->IsSensor(); +} + +Body *Shape::getBody() const +{ + return body; } float Shape::getRadius() const { + throwIfShapeNotValid(); return Physics::scaleUp(shape->m_radius); } int Shape::getChildCount() const { + throwIfShapeNotValid(); return shape->GetChildCount(); } +void Shape::setFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f; + f.categoryBits = (uint16) v[0]; + f.maskBits = (uint16) v[1]; + f.groupIndex = (int16) v[2]; + fixture->SetFilterData(f); +} + +void Shape::getFilterData(int *v) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + v[0] = (int) f.categoryBits; + v[1] = (int) f.maskBits; + v[2] = (int) f.groupIndex; +} + +int Shape::setCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.categoryBits = (uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +int Shape::setMask(lua_State *L) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.maskBits = ~(uint16)getBits(L); + fixture->SetFilterData(f); + return 0; +} + +void Shape::setGroupIndex(int index) +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + f.groupIndex = (uint16)index; + fixture->SetFilterData(f); +} + +int Shape::getGroupIndex() const +{ + throwIfFixtureNotValid(); + b2Filter f = fixture->GetFilterData(); + return f.groupIndex; +} + +int Shape::getCategory(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, fixture->GetFilterData().categoryBits); +} + +int Shape::getMask(lua_State *L) +{ + throwIfFixtureNotValid(); + return pushBits(L, ~(fixture->GetFilterData().maskBits)); +} + +uint16 Shape::getBits(lua_State *L) +{ + // Get number of args. + bool istable = lua_istable(L, 1); + int argc = istable ? (int) luax_objlen(L, 1) : lua_gettop(L); + + // The new bitset. + std::bitset<16> b; + + for (int i = 1; i <= argc; i++) + { + size_t bpos = 0; + + if (istable) + { + lua_rawgeti(L, 1, i); + bpos = (size_t) (lua_tointeger(L, -1) - 1); + lua_pop(L, 1); + } + else + bpos = (size_t) (lua_tointeger(L, i) - 1); + + if (bpos >= 16) + luaL_error(L, "Values must be in range 1-16."); + + b.set(bpos, true); + } + + return (uint16)b.to_ulong(); +} + +int Shape::pushBits(lua_State *L, uint16 bits) +{ + // Create a bitset. + std::bitset<16> b((int)bits); + + // Push all set bits. + for (int i = 0; i<16; i++) + if (b.test(i)) + lua_pushinteger(L, i+1); + + // Count number of set bits. + return (int)b.count(); +} + +int Shape::setUserData(lua_State *L) +{ + love::luax_assert_argc(L, 1, 1); + + if(!ref) + ref = new Reference(); + + ref->ref(L); + + return 0; +} + +int Shape::getUserData(lua_State *L) +{ + if (ref != nullptr) + ref->push(L); + else + lua_pushnil(L); + + return 1; +} + +bool Shape::testPoint(float x, float y) const +{ + throwIfFixtureNotValid(); + return fixture->TestPoint(Physics::scaleDown(b2Vec2(x, y))); +} + bool Shape::testPoint(float x, float y, float r, float px, float py) const { + throwIfShapeNotValid(); b2Vec2 point(px, py); b2Transform transform(Physics::scaleDown(b2Vec2(x, y)), b2Rot(r)); return shape->TestPoint(transform, Physics::scaleDown(point)); @@ -95,18 +398,34 @@ int Shape::rayCast(lua_State *L) const float p2x = Physics::scaleDown((float)luaL_checknumber(L, 3)); float p2y = Physics::scaleDown((float)luaL_checknumber(L, 4)); float maxFraction = (float)luaL_checknumber(L, 5); - float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); - float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); - float r = (float)luaL_checknumber(L, 8); - int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + b2RayCastInput input; + b2RayCastOutput output; input.p1.Set(p1x, p1y); input.p2.Set(p2x, p2y); input.maxFraction = maxFraction; - b2Transform transform(b2Vec2(x, y), b2Rot(r)); - b2RayCastOutput output; - if (!shape->RayCast(&output, input, transform, childIndex)) - return 0; // No hit. + + if (lua_isnoneornil(L, 7)) + { + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 6, 1) - 1; // Convert from 1-based index + if (!fixture->RayCast(&output, input, childIndex)) + return 0; // Nothing hit. + } + else + { + throwIfShapeNotValid(); + float x = Physics::scaleDown((float)luaL_checknumber(L, 6)); + float y = Physics::scaleDown((float)luaL_checknumber(L, 7)); + float r = (float)luaL_checknumber(L, 8); + int childIndex = (int) luaL_optinteger(L, 9, 1) - 1; // Convert from 1-based index + + b2Transform transform(b2Vec2(x, y), b2Rot(r)); + + if (!shape->RayCast(&output, input, transform, childIndex)) + return 0; // No hit. + } + lua_pushnumber(L, output.normal.x); lua_pushnumber(L, output.normal.y); lua_pushnumber(L, output.fraction); @@ -115,6 +434,7 @@ int Shape::rayCast(lua_State *L) const int Shape::computeAABB(lua_State *L) const { + throwIfShapeNotValid(); float x = Physics::scaleDown((float)luaL_checknumber(L, 1)); float y = Physics::scaleDown((float)luaL_checknumber(L, 2)); float r = (float)luaL_checknumber(L, 3); @@ -132,6 +452,7 @@ int Shape::computeAABB(lua_State *L) const int Shape::computeMass(lua_State *L) const { + throwIfShapeNotValid(); float density = (float)luaL_checknumber(L, 1); b2MassData data; shape->ComputeMass(&data, density); @@ -143,6 +464,33 @@ int Shape::computeMass(lua_State *L) const return 4; } +int Shape::getBoundingBox(lua_State *L) const +{ + throwIfFixtureNotValid(); + int childIndex = (int) luaL_optinteger(L, 1, 1) - 1; // Convert from 1-based index + b2AABB box; + luax_catchexcept(L, [&]() { box = fixture->GetAABB(childIndex); }); + box = Physics::scaleUp(box); + lua_pushnumber(L, box.lowerBound.x); + lua_pushnumber(L, box.lowerBound.y); + lua_pushnumber(L, box.upperBound.x); + lua_pushnumber(L, box.upperBound.y); + return 4; +} + +int Shape::getMassData(lua_State *L) const +{ + throwIfFixtureNotValid(); + b2MassData data; + fixture->GetMassData(&data); + b2Vec2 center = Physics::scaleUp(data.center); + lua_pushnumber(L, center.x); + lua_pushnumber(L, center.y); + lua_pushnumber(L, data.mass); + lua_pushnumber(L, data.I); + return 4; +} + } // box2d } // physics } // love diff --git a/src/modules/physics/box2d/Shape.h b/src/modules/physics/box2d/Shape.h index 94b314dc9..43f754598 100644 --- a/src/modules/physics/box2d/Shape.h +++ b/src/modules/physics/box2d/Shape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -24,6 +24,7 @@ // LOVE #include "physics/Shape.h" #include "physics/box2d/Body.h" +#include "common/Reference.h" // Box2D #include @@ -45,34 +46,155 @@ class Shape : public love::physics::Shape { public: - friend class Fixture; + friend class Physics; /** * Creates a Shape. **/ - Shape(); - Shape(b2Shape *shape, bool own = true); + Shape(Body *body, const b2Shape &shape); virtual ~Shape(); + void destroy(bool implicit = false); + + /** + * Returns true if the shape is active in a Box2D world. + **/ + bool isValid() const { return fixture != nullptr; } + + /** + * Returns true if the shape has not been destroyed. + **/ + bool isShapeValid() const { return shape != nullptr; } + + /** + * Checks whether this Shape acts as a sensor. + **/ + bool isSensor() const; + + /** + * Set whether this Shape should be a sensor or not. + **/ + void setSensor(bool sensor); + + /** + * Gets the Body this Shape is attached to. + **/ + Body *getBody() const; + + /** + * Sets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void setFilterData(int *v); + + /** + * Gets the filter data. An integer array is used even though the + * first two elements are unsigned shorts. The elements are: + * category (16-bits), mask (16-bits) and group (32-bits/int). + **/ + void getFilterData(int *v); + + /** + * This function stores an in-C reference to + * arbitrary Lua data in the Shape object. + **/ + int setUserData(lua_State *L); + + /** + * Gets the data set with setUserData. If no + * data is set, nil is returned. + **/ + int getUserData(lua_State *L); + + /** + * Sets the friction of the Shape. + **/ + void setFriction(float friction); + + /** + * Sets the restitution for the Shape. + **/ + void setRestitution(float restitution); + + /** + * Sets the density of the Shape. + **/ + void setDensity(float density); + + /** + * Gets the friction of the Shape. + **/ + float getFriction() const; + + /** + * Gets the restitution of the Shape. + **/ + float getRestitution() const; + + /** + * Gets the density of the Shape. + **/ + float getDensity() const; + + /** + * Checks if a point is inside the Shape. + **/ + bool testPoint(float x, float y) const; + bool testPoint(float x, float y, float r, float px, float py) const; + /** * Gets the type of Shape. Useful for * debug drawing. **/ Type getType() const; + float getRadius() const; int getChildCount() const; - bool testPoint(float x, float y, float r, float px, float py) const; int rayCast(lua_State *L) const; int computeAABB(lua_State *L) const; int computeMass(lua_State *L) const; + void setGroupIndex(int index); + int getGroupIndex() const; + + int setCategory(lua_State *L); + int setMask(lua_State *L); + int getCategory(lua_State *L); + int getMask(lua_State *L); + uint16 getBits(lua_State *L); + int pushBits(lua_State *L, uint16 bits); + + /** + * Gets the bounding box for this Shape. + **/ + int getBoundingBox(lua_State *L) const; + + /** + * Gets the mass data for this Shape. + * This operation may be expensive. + **/ + int getMassData(lua_State *L) const; + + void throwIfFixtureNotValid() const; + void throwIfShapeNotValid() const; + protected: // The Box2D shape. b2Shape *shape; bool own; -}; + + Shape::Type shapeType; + + Body *body; + b2Fixture *fixture; + + // Reference to arbitrary data. + Reference* ref = nullptr; + +}; // Shape } // box2d } // physics diff --git a/src/modules/physics/box2d/WeldJoint.cpp b/src/modules/physics/box2d/WeldJoint.cpp index ff5aeed2e..e84036ac0 100644 --- a/src/modules/physics/box2d/WeldJoint.cpp +++ b/src/modules/physics/box2d/WeldJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/WeldJoint.h b/src/modules/physics/box2d/WeldJoint.h index 73f74a4f6..e277fe0a7 100644 --- a/src/modules/physics/box2d/WeldJoint.h +++ b/src/modules/physics/box2d/WeldJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/WheelJoint.cpp b/src/modules/physics/box2d/WheelJoint.cpp index cc42e4224..867ae4383 100644 --- a/src/modules/physics/box2d/WheelJoint.cpp +++ b/src/modules/physics/box2d/WheelJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/WheelJoint.h b/src/modules/physics/box2d/WheelJoint.h index 83182a1bf..9f98c83d2 100644 --- a/src/modules/physics/box2d/WheelJoint.h +++ b/src/modules/physics/box2d/WheelJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/World.cpp b/src/modules/physics/box2d/World.cpp index 0538730a5..5bb68a159 100644 --- a/src/modules/physics/box2d/World.cpp +++ b/src/modules/physics/box2d/World.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -20,7 +20,6 @@ #include "World.h" -#include "Fixture.h" #include "Shape.h" #include "Contact.h" #include "Physics.h" @@ -28,6 +27,7 @@ // Needed for World::getJoints. It should be moved to wrapper code... #include "wrap_Joint.h" +#include "wrap_Shape.h" namespace love { @@ -58,22 +58,22 @@ void World::ContactCallback::process(b2Contact *contact, const b2ContactImpulse { ref->push(L); - // Push first fixture. + // Push first shape. { - Fixture *a = (Fixture *)world->findObject(contact->GetFixtureA()); + Shape *a = (Shape *)(contact->GetFixtureA()->GetUserData().pointer); if (a != nullptr) - luax_pushtype(L, a); + luax_pushshape(L, a); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } - // Push second fixture. + // Push second shape. { - Fixture *b = (Fixture *)world->findObject(contact->GetFixtureB()); + Shape *b = (Shape *)(contact->GetFixtureB()->GetUserData().pointer); if (b != nullptr) - luax_pushtype(L, b); + luax_pushshape(L, b); else - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); } Contact *cobj = (Contact *)world->findObject(contact); @@ -112,32 +112,17 @@ World::ContactFilter::~ContactFilter() delete ref; } -bool World::ContactFilter::process(Fixture *a, Fixture *b) +bool World::ContactFilter::process(Shape *a, Shape *b) { - // Handle masks, reimplemented from the manual - int filterA[3], filterB[3]; - // [0] categoryBits - // [1] maskBits - // [2] groupIndex - a->getFilterData(filterA); - b->getFilterData(filterB); - - if (filterA[2] != 0 && // 0 is the default group, so this does not count - filterA[2] == filterB[2]) // if they are in the same group - return filterA[2] > 0; // Negative indexes mean you don't collide - - if ((filterA[1] & filterB[0]) == 0 || - (filterB[1] & filterA[0]) == 0) - return false; // A and B aren't set to collide - if (ref != nullptr && L != nullptr) { ref->push(L); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); lua_call(L, 2, 1); return luax_toboolean(L, -1); } + return true; } @@ -147,6 +132,7 @@ World::QueryCallback::QueryCallback(World *world, lua_State *L, int idx) , funcidx(idx) { luaL_checktype(L, funcidx, LUA_TFUNCTION); + userargs = lua_gettop(L) - funcidx; } World::QueryCallback::~QueryCallback() @@ -158,11 +144,13 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture) if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)world->findObject(fixture); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); - lua_call(L, 1, 1); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); + for (int i = 1; i <= userargs; i++) + lua_pushvalue(L, funcidx + i); + lua_call(L, 1 + userargs, 1); bool cont = luax_toboolean(L, -1); lua_pop(L, 1); return cont; @@ -171,8 +159,9 @@ bool World::QueryCallback::ReportFixture(b2Fixture *fixture) return true; } -World::CollectCallback::CollectCallback(World *world, lua_State *L) +World::CollectCallback::CollectCallback(World *world, uint16 categoryMask, lua_State *L) : world(world) + , categoryMask(categoryMask) , L(L) { lua_newtable(L); @@ -184,10 +173,13 @@ World::CollectCallback::~CollectCallback() bool World::CollectCallback::ReportFixture(b2Fixture *f) { - Fixture *fixture = (Fixture *)world->findObject(f); - if (!fixture) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, fixture); + if (categoryMask != 0xFFFF && (categoryMask & f->GetFilterData().categoryBits) == 0) + return true; + + Shape *shape = (Shape *)(f->GetUserData().pointer); + if (!shape) + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, shape); lua_rawseti(L, -2, i); i++; return true; @@ -199,6 +191,7 @@ World::RayCastCallback::RayCastCallback(World *world, lua_State *L, int idx) , funcidx(idx) { luaL_checktype(L, funcidx, LUA_TFUNCTION); + userargs = lua_gettop(L) - funcidx; } World::RayCastCallback::~RayCastCallback() @@ -210,17 +203,19 @@ float World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &po if (L != nullptr) { lua_pushvalue(L, funcidx); - Fixture *f = (Fixture *)world->findObject(fixture); + Shape *f = (Shape *)(fixture->GetUserData().pointer); if (!f) - throw love::Exception("A fixture has escaped Memoizer!"); - luax_pushtype(L, f); + throw love::Exception("A Shape has escaped Memoizer!"); + luax_pushshape(L, f); b2Vec2 scaledPoint = Physics::scaleUp(point); lua_pushnumber(L, scaledPoint.x); lua_pushnumber(L, scaledPoint.y); lua_pushnumber(L, normal.x); lua_pushnumber(L, normal.y); lua_pushnumber(L, fraction); - lua_call(L, 6, 1); + for (int i = 1; i <= userargs; i++) + lua_pushvalue(L, funcidx + i); + lua_call(L, 6 + userargs, 1); if (!lua_isnumber(L, -1)) luaL_error(L, "Raycast callback didn't return a number!"); float fraction = (float) lua_tonumber(L, -1); @@ -231,16 +226,40 @@ float World::RayCastCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &po return 0; } +World::RayCastOneCallback::RayCastOneCallback(uint16 categoryMask, bool any) + : hitFixture(nullptr) + , hitPoint() + , hitNormal() + , hitFraction(1.0f) + , categoryMask(categoryMask) + , any(any) +{ +} + +float World::RayCastOneCallback::ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction) +{ + if (categoryMask != 0xFFFF && (categoryMask & fixture->GetFilterData().categoryBits) == 0) + return -1; + + hitFixture = fixture; + hitPoint = point; + hitNormal = normal; + hitFraction = fraction; + + // Returning the fraction makes sure it doesn't process anything farther away in subsequent iterations. + return any ? 0 : fraction; +} + void World::SayGoodbye(b2Fixture *fixture) { - Fixture *f = (Fixture *)findObject(fixture); + Shape *s = (Shape *)(fixture->GetUserData().pointer); // Hint implicit destruction with true. - if (f) f->destroy(true); + if (s) s->destroy(true); } void World::SayGoodbye(b2Joint *joint) { - Joint *j = (Joint *)findObject(joint); + Joint *j = (Joint *)(joint->GetUserData().pointer); // Hint implicit destruction with true. if (j) j->destroyJoint(true); } @@ -302,11 +321,11 @@ void World::update(float dt, int velocityIterations, int positionIterations) // Release for reference in vector. b->release(); } - for (Fixture *f : destructFixtures) + for (Shape *s : destructShapes) { - if (f->isValid()) f->destroy(); + if (s->isValid()) s->destroy(); // Release for reference in vector. - f->release(); + s->release(); } for (Joint *j : destructJoints) { @@ -315,7 +334,7 @@ void World::update(float dt, int velocityIterations, int positionIterations) j->release(); } destructBodies.clear(); - destructFixtures.clear(); + destructShapes.clear(); destructJoints.clear(); if (destructWorld) @@ -350,11 +369,24 @@ void World::PostSolve(b2Contact *contact, const b2ContactImpulse *impulse) bool World::ShouldCollide(b2Fixture *fixtureA, b2Fixture *fixtureB) { - // Fixtures should be memoized, if we created them - Fixture *a = (Fixture *)findObject(fixtureA); - Fixture *b = (Fixture *)findObject(fixtureB); + const b2Filter &filterA = fixtureA->GetFilterData(); + const b2Filter &filterB = fixtureB->GetFilterData(); + + // From b2_world_callbacks.cpp + // 0 is the default group index. If they're customized to be the same group, + // allow collisions if it's positive and disallow if it's negative. + if (filterA.groupIndex != 0 && filterA.groupIndex == filterB.groupIndex) + return filterA.groupIndex > 0; + + if ((filterA.maskBits & filterB.categoryBits) == 0 || (filterA.categoryBits & filterB.maskBits) == 0) + return false; + + // Shapes should be memoized, if we created them + Shape *a = (Shape *)(fixtureA->GetUserData().pointer); + Shape *b = (Shape *)(fixtureB->GetUserData().pointer); if (!a || !b) - throw love::Exception("A fixture has escaped Memoizer!"); + throw love::Exception("A Shape has escaped Memoizer!"); + return filter.process(a, b); } @@ -507,7 +539,7 @@ int World::getBodies(lua_State *L) const break; if (b == groundBody) continue; - Body *body = (Body *)findObject(b); + Body *body = (Body *)(b->GetUserData().pointer); if (!body) throw love::Exception("A body has escaped Memoizer!"); luax_pushtype(L, body); @@ -526,7 +558,7 @@ int World::getJoints(lua_State *L) const do { if (!j) break; - Joint *joint = (Joint *)findObject(j); + Joint *joint = (Joint *)(j->GetUserData().pointer); if (!joint) throw love::Exception("A joint has escaped Memoizer!"); luax_pushjoint(L, joint); lua_rawseti(L, -2, i); @@ -563,7 +595,7 @@ b2Body *World::getGroundBody() const return groundBody; } -int World::queryBoundingBox(lua_State *L) +int World::queryShapesInArea(lua_State *L) { b2AABB box; float lx = (float)luaL_checknumber(L, 1); @@ -578,16 +610,17 @@ int World::queryBoundingBox(lua_State *L) return 0; } -int World::getFixturesInArea(lua_State *L) +int World::getShapesInArea(lua_State *L) { float lx = (float)luaL_checknumber(L, 1); float ly = (float)luaL_checknumber(L, 2); float ux = (float)luaL_checknumber(L, 3); float uy = (float)luaL_checknumber(L, 4); + uint16 categoryMaskBits = (uint16)luaL_optinteger(L, 5, 0xFFFF); b2AABB box; box.lowerBound = Physics::scaleDown(b2Vec2(lx, ly)); box.upperBound = Physics::scaleDown(b2Vec2(ux, uy)); - CollectCallback query(this, L); + CollectCallback query(this, categoryMaskBits, L); world->QueryAABB(&query, box); return 1; } @@ -606,6 +639,64 @@ int World::rayCast(lua_State *L) return 0; } +int World::rayCastAny(lua_State *L) +{ + float x1 = (float)luaL_checknumber(L, 1); + float y1 = (float)luaL_checknumber(L, 2); + float x2 = (float)luaL_checknumber(L, 3); + float y2 = (float)luaL_checknumber(L, 4); + uint16 categoryMaskBits = (uint16)luaL_optinteger(L, 5, 0xFFFF); + b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); + b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); + RayCastOneCallback raycast(categoryMaskBits, true); + world->RayCast(&raycast, v1, v2); + if (raycast.hitFixture) + { + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); + if (f == nullptr) + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); + + b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); + lua_pushnumber(L, hitPoint.x); + lua_pushnumber(L, hitPoint.y); + lua_pushnumber(L, raycast.hitNormal.x); + lua_pushnumber(L, raycast.hitNormal.y); + lua_pushnumber(L, raycast.hitFraction); + return 6; + } + return 0; +} + +int World::rayCastClosest(lua_State *L) +{ + float x1 = (float)luaL_checknumber(L, 1); + float y1 = (float)luaL_checknumber(L, 2); + float x2 = (float)luaL_checknumber(L, 3); + float y2 = (float)luaL_checknumber(L, 4); + uint16 categoryMaskBits = (uint16)luaL_optinteger(L, 5, 0xFFFF); + b2Vec2 v1 = Physics::scaleDown(b2Vec2(x1, y1)); + b2Vec2 v2 = Physics::scaleDown(b2Vec2(x2, y2)); + RayCastOneCallback raycast(categoryMaskBits, false); + world->RayCast(&raycast, v1, v2); + if (raycast.hitFixture) + { + Shape *f = (Shape *)(raycast.hitFixture->GetUserData().pointer); + if (f == nullptr) + return luaL_error(L, "A Shape has escaped Memoizer!"); + luax_pushshape(L, f); + + b2Vec2 hitPoint = Physics::scaleUp(raycast.hitPoint); + lua_pushnumber(L, hitPoint.x); + lua_pushnumber(L, hitPoint.y); + lua_pushnumber(L, raycast.hitNormal.x); + lua_pushnumber(L, raycast.hitNormal.y); + lua_pushnumber(L, raycast.hitFraction); + return 6; + } + return 0; +} + void World::destroy() { if (world == nullptr) @@ -635,7 +726,7 @@ void World::destroy() b = b->GetNext(); if (t == groundBody) continue; - Body *body = (Body *)findObject(t); + Body *body = (Body *)(t->GetUserData().pointer); if (!body) throw love::Exception("A body has escaped Memoizer!"); body->destroy(); diff --git a/src/modules/physics/box2d/World.h b/src/modules/physics/box2d/World.h index ff81271ec..ce7d7bd97 100644 --- a/src/modules/physics/box2d/World.h +++ b/src/modules/physics/box2d/World.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -42,7 +42,7 @@ namespace box2d class Contact; class Body; -class Fixture; +class Shape; class Joint; /** @@ -65,7 +65,7 @@ public: friend class DistanceJoint; friend class MouseJoint; friend class Body; - friend class Fixture; + friend class Shape; static love::Type type; @@ -87,29 +87,31 @@ public: lua_State *L; ContactFilter(); ~ContactFilter(); - bool process(Fixture *a, Fixture *b); + bool process(Shape *a, Shape *b); }; class QueryCallback : public b2QueryCallback { public: QueryCallback(World *world, lua_State *L, int idx); - ~QueryCallback(); - virtual bool ReportFixture(b2Fixture *fixture); + virtual ~QueryCallback(); + bool ReportFixture(b2Fixture *fixture) override; private: World *world; lua_State *L; int funcidx; + int userargs; }; class CollectCallback : public b2QueryCallback { public: - CollectCallback(World *world, lua_State *L); - ~CollectCallback(); - virtual bool ReportFixture(b2Fixture *fixture); + CollectCallback(World *world, uint16 categoryMask, lua_State *L); + virtual ~CollectCallback(); + bool ReportFixture(b2Fixture *fixture) override; private: World *world; + uint16 categoryMask; lua_State *L; int i = 1; }; @@ -118,12 +120,30 @@ public: { public: RayCastCallback(World *world, lua_State *L, int idx); - ~RayCastCallback(); - virtual float ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction); + virtual ~RayCastCallback(); + float ReportFixture(b2Fixture *fixture, const b2Vec2 &point, const b2Vec2 &normal, float fraction) override; private: World *world; lua_State *L; int funcidx; + int userargs; + }; + + class RayCastOneCallback : public b2RayCastCallback + { + public: + RayCastOneCallback(uint16 categoryMask, bool any); + virtual ~RayCastOneCallback() {}; + float ReportFixture(b2Fixture* fixture, const b2Vec2& point, const b2Vec2& normal, float fraction) override; + + b2Fixture *hitFixture; + b2Vec2 hitPoint; + b2Vec2 hitNormal; + float hitFraction; + + private: + uint16 categoryMask; + bool any; }; /** @@ -282,20 +302,23 @@ public: b2Body *getGroundBody() const; /** - * Calls a callback on all fixtures that overlap a given bounding box. + * Calls a callback on all Shapes that overlap a given bounding box. **/ - int queryBoundingBox(lua_State *L); + int queryShapesInArea(lua_State *L); /** - * Gets all fixtures that overlap a given bounding box. + * Gets all Shapes that overlap a given bounding box. **/ - int getFixturesInArea(lua_State *L); + int getShapesInArea(lua_State *L); /** * Raycasts the World for all Fixtures in the path of the ray. **/ int rayCast(lua_State *L); + int rayCastAny(lua_State *L); + int rayCastClosest(lua_State *L); + /** * Destroy this world. **/ @@ -315,7 +338,7 @@ private: // The list of to be destructed bodies. std::vector destructBodies; - std::vector destructFixtures; + std::vector destructShapes; std::vector destructJoints; bool destructWorld; diff --git a/src/modules/physics/box2d/wrap_Body.cpp b/src/modules/physics/box2d/wrap_Body.cpp index 479e5bc27..9f83d7a4f 100644 --- a/src/modules/physics/box2d/wrap_Body.cpp +++ b/src/modules/physics/box2d/wrap_Body.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -20,6 +20,7 @@ #include "wrap_Body.h" #include "wrap_Physics.h" +#include "wrap_Shape.h" namespace love { @@ -161,6 +162,13 @@ int w_Body_getMassData(lua_State *L) return t->getMassData(L); } +int w_Body_hasCustomMassData(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + luax_pushboolean(L, t->hasCustomMassData()); + return 1; +} + int w_Body_getAngularDamping(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -599,15 +607,32 @@ int w_Body_getWorld(lua_State *L) return 1; } -int w_Body_getFixtures(lua_State *L) +int w_Body_getShape(lua_State *L) +{ + Body *t = luax_checkbody(L, 1); + Shape *s = t->getShape(); + if (s) + luax_pushshape(L, s); + else + lua_pushnil(L); + return 1; +} + +int w_Body_getShapes(lua_State *L) { Body *t = luax_checkbody(L, 1); lua_remove(L, 1); int n = 0; - luax_catchexcept(L, [&](){ n = t->getFixtures(L); }); + luax_catchexcept(L, [&](){ n = t->getShapes(L); }); return n; } +int w_Body_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Body:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Body:getShapes"); + return w_Body_getShapes(L); +} + int w_Body_getJoints(lua_State *L) { Body *t = luax_checkbody(L, 1); @@ -670,6 +695,7 @@ static const luaL_Reg w_Body_functions[] = { "getMass", w_Body_getMass }, { "getInertia", w_Body_getInertia }, { "getMassData", w_Body_getMassData }, + { "hasCustomMassData", w_Body_hasCustomMassData }, { "getAngularDamping", w_Body_getAngularDamping }, { "getLinearDamping", w_Body_getLinearDamping }, { "getGravityScale", w_Body_getGravityScale }, @@ -713,7 +739,8 @@ static const luaL_Reg w_Body_functions[] = { "isFixedRotation", w_Body_isFixedRotation }, { "isTouching", w_Body_isTouching }, { "getWorld", w_Body_getWorld }, - { "getFixtures", w_Body_getFixtures }, + { "getShape", w_Body_getShape }, + { "getShapes", w_Body_getShapes }, { "getJoints", w_Body_getJoints }, { "getContacts", w_Body_getContacts }, { "destroy", w_Body_destroy }, @@ -721,6 +748,9 @@ static const luaL_Reg w_Body_functions[] = { "setUserData", w_Body_setUserData }, { "getUserData", w_Body_getUserData }, + // Deprecated + { "getFixtures", w_Body_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Body.h b/src/modules/physics/box2d/wrap_Body.h index bf2398d0b..66e657b31 100644 --- a/src/modules/physics/box2d/wrap_Body.h +++ b/src/modules/physics/box2d/wrap_Body.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_ChainShape.cpp b/src/modules/physics/box2d/wrap_ChainShape.cpp index 52c94ef70..f39021a0c 100644 --- a/src/modules/physics/box2d/wrap_ChainShape.cpp +++ b/src/modules/physics/box2d/wrap_ChainShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -54,9 +54,10 @@ int w_ChainShape_setPreviousVertex(lua_State *L) int w_ChainShape_getChildEdge(lua_State *L) { + luax_markdeprecated(L, 1, "ChainShape:getChildEdge", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); ChainShape *c = luax_checkchainshape(L, 1); int index = (int) luaL_checkinteger(L, 2) - 1; // Convert from 1-based index - EdgeShape *e = 0; + EdgeShape *e = nullptr; luax_catchexcept(L, [&](){ e = c->getChildEdge(index); }); luax_pushtype(L, e); e->release(); @@ -66,7 +67,8 @@ int w_ChainShape_getChildEdge(lua_State *L) int w_ChainShape_getVertexCount(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - int count = c->getVertexCount(); + int count = 0; + luax_catchexcept(L, [&]() { count = c->getVertexCount(); }); lua_pushinteger(L, count); return 1; } @@ -85,7 +87,8 @@ int w_ChainShape_getPoint(lua_State *L) int w_ChainShape_getNextVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -94,7 +97,8 @@ int w_ChainShape_getNextVertex(lua_State *L) int w_ChainShape_getPreviousVertex(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - b2Vec2 v = c->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = c->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -103,7 +107,8 @@ int w_ChainShape_getPreviousVertex(lua_State *L) int w_ChainShape_getPoints(lua_State *L) { ChainShape *c = luax_checkchainshape(L, 1); - const b2Vec2 *verts = c->getPoints(); + const b2Vec2 *verts; + luax_catchexcept(L, [&]() { verts = c->getPoints(); }); int count = c->getVertexCount(); if (!lua_checkstack(L, count*2)) return luaL_error(L, "Too many return values"); diff --git a/src/modules/physics/box2d/wrap_ChainShape.h b/src/modules/physics/box2d/wrap_ChainShape.h index ce283df01..ce40c0de8 100644 --- a/src/modules/physics/box2d/wrap_ChainShape.h +++ b/src/modules/physics/box2d/wrap_ChainShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_CircleShape.cpp b/src/modules/physics/box2d/wrap_CircleShape.cpp index f9ec8394a..d0fe71509 100644 --- a/src/modules/physics/box2d/wrap_CircleShape.cpp +++ b/src/modules/physics/box2d/wrap_CircleShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,7 +35,9 @@ CircleShape *luax_checkcircleshape(lua_State *L, int idx) int w_CircleShape_getRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); - lua_pushnumber(L, c->getRadius()); + float r = 0; + luax_catchexcept(L, [&]() { r = c->getRadius(); }); + lua_pushnumber(L, r); return 1; } @@ -43,7 +45,7 @@ int w_CircleShape_setRadius(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float r = (float)luaL_checknumber(L, 2); - c->setRadius(r); + luax_catchexcept(L, [&]() { c->setRadius(r); }); return 0; } @@ -51,7 +53,7 @@ int w_CircleShape_getPoint(lua_State *L) { CircleShape *c = luax_checkcircleshape(L, 1); float x, y; - c->getPoint(x, y); + luax_catchexcept(L, [&]() { c->getPoint(x, y); }); lua_pushnumber(L, x); lua_pushnumber(L, y); return 2; diff --git a/src/modules/physics/box2d/wrap_CircleShape.h b/src/modules/physics/box2d/wrap_CircleShape.h index 9e9ef36fc..7e0ccacbd 100644 --- a/src/modules/physics/box2d/wrap_CircleShape.h +++ b/src/modules/physics/box2d/wrap_CircleShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Contact.cpp b/src/modules/physics/box2d/wrap_Contact.cpp index d18d39402..4b965bd92 100644 --- a/src/modules/physics/box2d/wrap_Contact.cpp +++ b/src/modules/physics/box2d/wrap_Contact.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -19,7 +19,7 @@ **/ #include "wrap_Contact.h" -#include "Fixture.h" +#include "wrap_Shape.h" namespace love { @@ -139,18 +139,24 @@ int w_Contact_getChildren(lua_State *L) return 2; } -int w_Contact_getFixtures(lua_State *L) +int w_Contact_getShapes(lua_State *L) { Contact *t = luax_checkcontact(L, 1); - Fixture *a = nullptr; - Fixture *b = nullptr; - luax_catchexcept(L, [&](){ t->getFixtures(a, b); }); + Shape *a = nullptr; + Shape *b = nullptr; + luax_catchexcept(L, [&](){ t->getShapes(a, b); }); - luax_pushtype(L, a); - luax_pushtype(L, b); + luax_pushshape(L, a); + luax_pushshape(L, b); return 2; } +int w_Contact_getFixtures(lua_State *L) +{ + luax_markdeprecated(L, 1, "Contact:getFixtures", API_METHOD, DEPRECATED_REPLACED, "Contact:getShapes"); + return w_Contact_getShapes(L); +} + int w_Contact_isDestroyed(lua_State *L) { Contact *c = luax_checktype(L, 1); @@ -174,8 +180,12 @@ static const luaL_Reg w_Contact_functions[] = { "setTangentSpeed", w_Contact_setTangentSpeed }, { "getTangentSpeed", w_Contact_getTangentSpeed }, { "getChildren", w_Contact_getChildren }, - { "getFixtures", w_Contact_getFixtures }, + { "getShapes", w_Contact_getShapes }, { "isDestroyed", w_Contact_isDestroyed }, + + // Deprecated + { "getFixtures", w_Contact_getFixtures }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Contact.h b/src/modules/physics/box2d/wrap_Contact.h index 3dd811344..40f8d4235 100644 --- a/src/modules/physics/box2d/wrap_Contact.h +++ b/src/modules/physics/box2d/wrap_Contact.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_DistanceJoint.cpp b/src/modules/physics/box2d/wrap_DistanceJoint.cpp index 96aa5c286..ca691b730 100644 --- a/src/modules/physics/box2d/wrap_DistanceJoint.cpp +++ b/src/modules/physics/box2d/wrap_DistanceJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_DistanceJoint.h b/src/modules/physics/box2d/wrap_DistanceJoint.h index 583e60a01..86a5f1b85 100644 --- a/src/modules/physics/box2d/wrap_DistanceJoint.h +++ b/src/modules/physics/box2d/wrap_DistanceJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_EdgeShape.cpp b/src/modules/physics/box2d/wrap_EdgeShape.cpp index fbc0c0574..2ffca1f79 100644 --- a/src/modules/physics/box2d/wrap_EdgeShape.cpp +++ b/src/modules/physics/box2d/wrap_EdgeShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -37,7 +37,7 @@ int w_EdgeShape_setNextVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setNextVertex(x, y); + luax_catchexcept(L, [&]() { t->setNextVertex(x, y); }); return 0; } @@ -46,14 +46,15 @@ int w_EdgeShape_setPreviousVertex(lua_State *L) EdgeShape *t = luax_checkedgeshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - t->setPreviousVertex(x, y); + luax_catchexcept(L, [&]() { t->setPreviousVertex(x, y); }); return 0; } int w_EdgeShape_getNextVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getNextVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getNextVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -62,7 +63,8 @@ int w_EdgeShape_getNextVertex(lua_State *L) int w_EdgeShape_getPreviousVertex(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); - b2Vec2 v = t->getPreviousVertex(); + b2Vec2 v; + luax_catchexcept(L, [&]() { v = t->getPreviousVertex(); }); lua_pushnumber(L, v.x); lua_pushnumber(L, v.y); return 2; @@ -72,7 +74,9 @@ int w_EdgeShape_getPoints(lua_State *L) { EdgeShape *t = luax_checkedgeshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } static const luaL_Reg w_EdgeShape_functions[] = diff --git a/src/modules/physics/box2d/wrap_EdgeShape.h b/src/modules/physics/box2d/wrap_EdgeShape.h index 35f07cd34..c92e92c3f 100644 --- a/src/modules/physics/box2d/wrap_EdgeShape.h +++ b/src/modules/physics/box2d/wrap_EdgeShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Fixture.cpp b/src/modules/physics/box2d/wrap_Fixture.cpp deleted file mode 100644 index 4056874c9..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.cpp +++ /dev/null @@ -1,311 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#include "wrap_Fixture.h" -#include "common/StringMap.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx) -{ - Fixture *f = luax_checktype(L, idx); - if (!f->isValid()) - luaL_error(L, "Attempt to use destroyed fixture."); - return f; -} - -int w_Fixture_getType(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - const char *type = ""; - Shape::getConstant(t->getType(), type); - lua_pushstring(L, type); - return 1; -} - -int w_Fixture_setFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setFriction(arg1); - return 0; -} - -int w_Fixture_setRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - t->setRestitution(arg1); - return 0; -} - -int w_Fixture_setDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float arg1 = (float)luaL_checknumber(L, 2); - luax_catchexcept(L, [&](){ t->setDensity(arg1); }); - return 0; -} - -int w_Fixture_setSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - bool arg1 = luax_checkboolean(L, 2); - t->setSensor(arg1); - return 0; -} - -int w_Fixture_getFriction(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getFriction()); - return 1; -} - -int w_Fixture_getRestitution(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getRestitution()); - return 1; -} - -int w_Fixture_getDensity(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_pushnumber(L, t->getDensity()); - return 1; -} - -int w_Fixture_isSensor(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_pushboolean(L, t->isSensor()); - return 1; -} - -int w_Fixture_getBody(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Body *body = t->getBody(); - if (body == 0) - return 0; - luax_pushtype(L, body); - return 1; -} - -int w_Fixture_getShape(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - Shape * shape = t->getShape(); - if (shape == nullptr) - return 0; - switch (shape->getType()) - { - case Shape::SHAPE_EDGE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CHAIN: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_CIRCLE: - luax_pushtype(L, dynamic_cast(shape)); - break; - case Shape::SHAPE_POLYGON: - luax_pushtype(L, dynamic_cast(shape)); - break; - default: - luax_pushtype(L, shape); - break; - } - return 1; -} - -int w_Fixture_testPoint(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - float x = (float)luaL_checknumber(L, 2); - float y = (float)luaL_checknumber(L, 3); - luax_pushboolean(L, t->testPoint(x, y)); - return 1; -} - -int w_Fixture_rayCast(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - int ret = 0; - luax_catchexcept(L, [&](){ ret = t->rayCast(L); }); - return ret; -} - -int w_Fixture_setFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - v[0] = (int) luaL_checkinteger(L, 2); - v[1] = (int) luaL_checkinteger(L, 3); - v[2] = (int) luaL_checkinteger(L, 4); - t->setFilterData(v); - return 0; -} - -int w_Fixture_getFilterData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int v[3]; - t->getFilterData(v); - lua_pushinteger(L, v[0]); - lua_pushinteger(L, v[1]); - lua_pushinteger(L, v[2]); - return 3; -} - -int w_Fixture_setCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setCategory(L); -} - -int w_Fixture_getCategory(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getCategory(L); -} - -int w_Fixture_setMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setMask(L); -} - -int w_Fixture_getMask(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMask(L); -} - -int w_Fixture_setUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->setUserData(L); -} - -int w_Fixture_getUserData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getUserData(L); -} - -int w_Fixture_getBoundingBox(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getBoundingBox(L); -} - -int w_Fixture_getMassData(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - lua_remove(L, 1); - return t->getMassData(L); -} - -int w_Fixture_getGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = t->getGroupIndex(); - lua_pushinteger(L, i); - return 1; -} - -int w_Fixture_setGroupIndex(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - int i = (int) luaL_checkinteger(L, 2); - t->setGroupIndex(i); - return 0; -} - -int w_Fixture_destroy(lua_State *L) -{ - Fixture *t = luax_checkfixture(L, 1); - luax_catchexcept(L, [&](){ t->destroy(); }); - return 0; -} - -int w_Fixture_isDestroyed(lua_State *L) -{ - Fixture *f = luax_checktype(L, 1); - luax_pushboolean(L, !f->isValid()); - return 1; -} - -static const luaL_Reg w_Fixture_functions[] = -{ - { "getType", w_Fixture_getType }, - { "setFriction", w_Fixture_setFriction }, - { "setRestitution", w_Fixture_setRestitution }, - { "setDensity", w_Fixture_setDensity }, - { "setSensor", w_Fixture_setSensor }, - { "getFriction", w_Fixture_getFriction }, - { "getRestitution", w_Fixture_getRestitution }, - { "getDensity", w_Fixture_getDensity }, - { "getBody", w_Fixture_getBody }, - { "getShape", w_Fixture_getShape }, - { "isSensor", w_Fixture_isSensor }, - { "testPoint", w_Fixture_testPoint }, - { "rayCast", w_Fixture_rayCast }, - { "setFilterData", w_Fixture_setFilterData }, - { "getFilterData", w_Fixture_getFilterData }, - { "setCategory", w_Fixture_setCategory }, - { "getCategory", w_Fixture_getCategory }, - { "setMask", w_Fixture_setMask }, - { "getMask", w_Fixture_getMask }, - { "setUserData", w_Fixture_setUserData }, - { "getUserData", w_Fixture_getUserData }, - { "getBoundingBox", w_Fixture_getBoundingBox }, - { "getMassData", w_Fixture_getMassData }, - { "getGroupIndex", w_Fixture_getGroupIndex }, - { "setGroupIndex", w_Fixture_setGroupIndex }, - { "destroy", w_Fixture_destroy }, - { "isDestroyed", w_Fixture_isDestroyed }, - { 0, 0 } -}; - -extern "C" int luaopen_fixture(lua_State *L) -{ - return luax_register_type(L, &Fixture::type, w_Fixture_functions, nullptr); -} - -} // box2d -} // physics -} // love - diff --git a/src/modules/physics/box2d/wrap_Fixture.h b/src/modules/physics/box2d/wrap_Fixture.h deleted file mode 100644 index 0d31d6fa0..000000000 --- a/src/modules/physics/box2d/wrap_Fixture.h +++ /dev/null @@ -1,43 +0,0 @@ -/** - * Copyright (c) 2006-2023 LOVE Development Team - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - **/ - -#ifndef LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H -#define LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H - -// LOVE -#include "common/runtime.h" -#include "Fixture.h" -#include "wrap_Physics.h" - -namespace love -{ -namespace physics -{ -namespace box2d -{ - -Fixture *luax_checkfixture(lua_State *L, int idx); -extern "C" int luaopen_fixture(lua_State *L); - -} // box2d -} // physics -} // love - -#endif // LOVE_PHYSICS_BOX2D_WRAP_FIXTURE_H diff --git a/src/modules/physics/box2d/wrap_FrictionJoint.cpp b/src/modules/physics/box2d/wrap_FrictionJoint.cpp index 14caa958b..fcb3230a8 100644 --- a/src/modules/physics/box2d/wrap_FrictionJoint.cpp +++ b/src/modules/physics/box2d/wrap_FrictionJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_FrictionJoint.h b/src/modules/physics/box2d/wrap_FrictionJoint.h index 16561bfa7..490e819e3 100644 --- a/src/modules/physics/box2d/wrap_FrictionJoint.h +++ b/src/modules/physics/box2d/wrap_FrictionJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_GearJoint.cpp b/src/modules/physics/box2d/wrap_GearJoint.cpp index 905a619f6..b7d0966cc 100644 --- a/src/modules/physics/box2d/wrap_GearJoint.cpp +++ b/src/modules/physics/box2d/wrap_GearJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_GearJoint.h b/src/modules/physics/box2d/wrap_GearJoint.h index 9469750b2..eb58da935 100644 --- a/src/modules/physics/box2d/wrap_GearJoint.h +++ b/src/modules/physics/box2d/wrap_GearJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Joint.cpp b/src/modules/physics/box2d/wrap_Joint.cpp index 71ed39225..8139ff39a 100644 --- a/src/modules/physics/box2d/wrap_Joint.cpp +++ b/src/modules/physics/box2d/wrap_Joint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Joint.h b/src/modules/physics/box2d/wrap_Joint.h index 47e976daa..e9794525b 100644 --- a/src/modules/physics/box2d/wrap_Joint.h +++ b/src/modules/physics/box2d/wrap_Joint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_MotorJoint.cpp b/src/modules/physics/box2d/wrap_MotorJoint.cpp index 62513b120..3001d4df3 100644 --- a/src/modules/physics/box2d/wrap_MotorJoint.cpp +++ b/src/modules/physics/box2d/wrap_MotorJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_MotorJoint.h b/src/modules/physics/box2d/wrap_MotorJoint.h index 3d684041d..464b2b09b 100644 --- a/src/modules/physics/box2d/wrap_MotorJoint.h +++ b/src/modules/physics/box2d/wrap_MotorJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_MouseJoint.cpp b/src/modules/physics/box2d/wrap_MouseJoint.cpp index 570962b26..084f37653 100644 --- a/src/modules/physics/box2d/wrap_MouseJoint.cpp +++ b/src/modules/physics/box2d/wrap_MouseJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_MouseJoint.h b/src/modules/physics/box2d/wrap_MouseJoint.h index c36a8f241..a45f79167 100644 --- a/src/modules/physics/box2d/wrap_MouseJoint.h +++ b/src/modules/physics/box2d/wrap_MouseJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Physics.cpp b/src/modules/physics/box2d/wrap_Physics.cpp index 29c3e2e62..f05402787 100644 --- a/src/modules/physics/box2d/wrap_Physics.cpp +++ b/src/modules/physics/box2d/wrap_Physics.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,7 +23,6 @@ #include "wrap_World.h" #include "wrap_Contact.h" #include "wrap_Body.h" -#include "wrap_Fixture.h" #include "wrap_Shape.h" #include "wrap_CircleShape.h" #include "wrap_PolygonShape.h" @@ -83,38 +82,236 @@ int w_newBody(lua_State *L) return 1; } +int w_newCircleBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + float radius = (float)luaL_checknumber(L, 5); + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newCircleBody(world, btype, x, y, radius); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newRectangleBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x = (float)luaL_checknumber(L, 3); + float y = (float)luaL_checknumber(L, 4); + float w = (float)luaL_checknumber(L, 5); + float h = (float)luaL_checknumber(L, 6); + float angle = (float)luaL_optnumber(L, 7, 0.0); + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newRectangleBody(world, btype, x, y, w, h, angle); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newPolygonBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + int argc = lua_gettop(L); + + bool istable = lua_istable(L, 3); + if (istable) + argc = (int)luax_objlen(L, 3); + + if (argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 3, 1 + i * 2); + lua_rawgeti(L, 3, 2 + i * 2); + float x = (float)luaL_checknumber(L, -2); + float y = (float)luaL_checknumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 3 + i * 2); + float y = (float)luaL_checknumber(L, 4 + i * 2); + coords.emplace_back(x, y); + } + } + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newPolygonBody(world, btype, coords.data(), (int)coords.size()); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newEdgeBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + float x1 = (float)luaL_checknumber(L, 3); + float y1 = (float)luaL_checknumber(L, 4); + float x2 = (float)luaL_checknumber(L, 5); + float y2 = (float)luaL_checknumber(L, 6); + + Body *body = nullptr; + + if (lua_isnoneornil(L, 7)) + { + luax_catchexcept(L, [&]() { body = instance()->newEdgeBody(world, btype, x1, y1, x2, y2); }); + } + else + { + float prevx = (float)luaL_checknumber(L, 7); + float prevy = (float)luaL_checknumber(L, 8); + float nextx = (float)luaL_checknumber(L, 9); + float nexty = (float)luaL_checknumber(L, 10); + luax_catchexcept(L, [&]() { body = instance()->newEdgeBody(world, btype, x1, y1, x2, y2, prevx, prevy, nextx, nexty); }); + } + + luax_pushtype(L, body); + body->release(); + return 1; +} + +int w_newChainBody(lua_State *L) +{ + World *world = luax_checkworld(L, 1); + + const char *typestr = luaL_checkstring(L, 2); + Body::Type btype = Body::BODY_STATIC; + if (!Body::getConstant(typestr, btype)) + return luax_enumerror(L, "Body type", Body::getConstants(btype), typestr); + + bool loop = luax_checkboolean(L, 3); + + int argc = lua_gettop(L) - 3; + + bool istable = lua_istable(L, 4); + if (istable) + argc = (int)luax_objlen(L, 4); + + if (argc == 0 || argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, 4, 1 + i * 2); + lua_rawgeti(L, 4, 2 + i * 2); + float x = (float)lua_tonumber(L, -2); + float y = (float)lua_tonumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, 4 + i * 2); + float y = (float)luaL_checknumber(L, 5 + i * 2); + coords.emplace_back(x, y); + } + } + + Body *body = nullptr; + luax_catchexcept(L, [&]() { body = instance()->newChainBody(world, btype, loop, coords.data(), (int)coords.size()); }); + + luax_pushtype(L, body); + body->release(); + return 1; +} + int w_newFixture(lua_State *L) { + luax_markdeprecated(L, 1, "love.physics.newFixture", API_FUNCTION, DEPRECATED_REPLACED, "love.physics.newCircle/Rectangle/Polygon/Edge/ChainShape"); + Body *body = luax_checkbody(L, 1); Shape *shape = luax_checkshape(L, 2); float density = (float)luaL_optnumber(L, 3, 1.0f); - Fixture *fixture; - luax_catchexcept(L, [&](){ fixture = instance()->newFixture(body, shape, density); }); - luax_pushtype(L, fixture); - fixture->release(); + + Shape *newShape; + luax_catchexcept(L, [&]() { newShape = instance()->newAttachedShape(body, shape, density); }); + + luax_pushshape(L, newShape); + newShape->release(); return 1; } +static Body *luax_optbodyforshape(lua_State *L, int idx, const char *name) +{ + if (lua_isnoneornil(L, idx) || luax_istype(L, idx, Object::type)) + return luax_checkbody(L, idx); + + luax_markdeprecated(L, 1, name, API_FUNCTION_VARIANT, DEPRECATED_REPLACED, "variant with Body parameter"); + return nullptr; +} + int w_newCircleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newCircleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 1) { - float radius = (float)luaL_checknumber(L, 1); + float radius = (float)luaL_checknumber(L, bodyidx + 1); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, 0, 0, radius); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 3) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float radius = (float)luaL_checknumber(L, 3); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float radius = (float)luaL_checknumber(L, bodyidx + 3); CircleShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(x, y, radius); }); + luax_catchexcept(L, [&](){ shape = instance()->newCircleShape(body, x, y, radius); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -125,27 +322,30 @@ int w_newCircleShape(lua_State *L) int w_newRectangleShape(lua_State *L) { - int top = lua_gettop(L); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newRectangleShape"); + int bodyidx = body ? 1 : 0; + + int top = lua_gettop(L) - bodyidx; if (top == 2) { - float w = (float)luaL_checknumber(L, 1); - float h = (float)luaL_checknumber(L, 2); + float w = (float)luaL_checknumber(L, bodyidx + 1); + float h = (float)luaL_checknumber(L, bodyidx + 2); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(w, h); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, 0, 0, w, h, 0); }); luax_pushtype(L, shape); shape->release(); return 1; } else if (top == 4 || top == 5) { - float x = (float)luaL_checknumber(L, 1); - float y = (float)luaL_checknumber(L, 2); - float w = (float)luaL_checknumber(L, 3); - float h = (float)luaL_checknumber(L, 4); - float angle = (float)luaL_optnumber(L, 5, 0); + float x = (float)luaL_checknumber(L, bodyidx + 1); + float y = (float)luaL_checknumber(L, bodyidx + 2); + float w = (float)luaL_checknumber(L, bodyidx + 3); + float h = (float)luaL_checknumber(L, bodyidx + 4); + float angle = (float)luaL_optnumber(L, bodyidx + 5, 0); PolygonShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(x, y, w, h, angle); }); + luax_catchexcept(L, [&](){ shape = instance()->newRectangleShape(body, x, y, w, h, angle); }); luax_pushtype(L, shape); shape->release(); return 1; @@ -156,13 +356,26 @@ int w_newRectangleShape(lua_State *L) int w_newEdgeShape(lua_State *L) { - float x1 = (float)luaL_checknumber(L, 1); - float y1 = (float)luaL_checknumber(L, 2); - float x2 = (float)luaL_checknumber(L, 3); - float y2 = (float)luaL_checknumber(L, 4); - bool oneSided = luax_optboolean(L, 5, false); + Body *body = luax_optbodyforshape(L, 1, "love.physics.newEdgeShape"); + int bodyidx = body ? 1 : 0; + + float x1 = (float)luaL_checknumber(L, bodyidx + 1); + float y1 = (float)luaL_checknumber(L, bodyidx + 2); + float x2 = (float)luaL_checknumber(L, bodyidx + 3); + float y2 = (float)luaL_checknumber(L, bodyidx + 4); EdgeShape *shape; - luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(x1, y1, x2, y2, oneSided); }); + if (lua_isnoneornil(L, bodyidx + 5)) + { + luax_catchexcept(L, [&](){ shape = instance()->newEdgeShape(body, x1, y1, x2, y2); }); + } + else + { + float prevx = (float)luaL_checknumber(L, bodyidx + 5); + float prevy = (float)luaL_checknumber(L, bodyidx + 6); + float nextx = (float)luaL_checknumber(L, bodyidx + 7); + float nexty = (float)luaL_checknumber(L, bodyidx + 8); + luax_catchexcept(L, [&]() { shape = instance()->newEdgeShape(body, x1, y1, x2, y2, prevx, prevy, nextx, nexty); }); + } luax_pushtype(L, shape); shape->release(); return 1; @@ -170,16 +383,97 @@ int w_newEdgeShape(lua_State *L) int w_newPolygonShape(lua_State *L) { - int ret = 0; - luax_catchexcept(L, [&](){ ret = instance()->newPolygonShape(L); }); - return ret; + Body *body = luax_optbodyforshape(L, 1, "love.physics.newPolygonShape"); + int bodyidx = body ? 1 : 0; + + int argc = lua_gettop(L) - bodyidx; + + bool istable = lua_istable(L, bodyidx + 1); + + if (istable) + argc = (int)luax_objlen(L, bodyidx + 1); + + if (argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, bodyidx + 1, 1 + i * 2); + lua_rawgeti(L, bodyidx + 1, 2 + i * 2); + float x = (float)luaL_checknumber(L, -2); + float y = (float)luaL_checknumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, bodyidx + 1 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); + coords.emplace_back(x, y); + } + } + + PolygonShape *shape = nullptr; + luax_catchexcept(L, [&](){ shape = instance()->newPolygonShape(body, coords.data(), (int)coords.size()); }); + luax_pushtype(L, shape); + shape->release(); + return 1; } int w_newChainShape(lua_State *L) { - int ret = 0; - luax_catchexcept(L, [&](){ ret = instance()->newChainShape(L); }); - return ret; + Body *body = luax_optbodyforshape(L, 1, "love.physics.newChainShape"); + int bodyidx = body ? 1 : 0; + + int argc = lua_gettop(L) - 1 - bodyidx; // first argument is looping + + bool istable = lua_istable(L, bodyidx + 2); + + if (istable) + argc = (int)luax_objlen(L, bodyidx + 2); + + if (argc == 0 || argc % 2 != 0) + return luaL_error(L, "Number of vertex components must be a multiple of two."); + + int vcount = argc / 2; + bool loop = luax_checkboolean(L, bodyidx + 1); + std::vector coords; + + if (istable) + { + for (int i = 0; i < vcount; i++) + { + lua_rawgeti(L, bodyidx + 2, 1 + i * 2); + lua_rawgeti(L, bodyidx + 2, 2 + i * 2); + float x = (float)lua_tonumber(L, -2); + float y = (float)lua_tonumber(L, -1); + coords.emplace_back(x, y); + lua_pop(L, 2); + } + } + else + { + for (int i = 0; i < vcount; i++) + { + float x = (float)luaL_checknumber(L, bodyidx + 2 + i * 2); + float y = (float)luaL_checknumber(L, bodyidx + 3 + i * 2); + coords.emplace_back(x, y); + } + } + + ChainShape *shape = nullptr; + luax_catchexcept(L, [&]() { shape = instance()->newChainShape(body, loop, coords.data(), coords.size()); }); + luax_pushtype(L, shape); + shape->release(); + return 1; } int w_newDistanceJoint(lua_State *L) @@ -573,7 +867,11 @@ static const luaL_Reg functions[] = { { "newWorld", w_newWorld }, { "newBody", w_newBody }, - { "newFixture", w_newFixture }, + { "newCircleBody", w_newCircleBody }, + { "newRectangleBody", w_newRectangleBody }, + { "newPolygonBody", w_newPolygonBody }, + { "newEdgeBody", w_newEdgeBody }, + { "newChainBody", w_newChainBody }, { "newCircleShape", w_newCircleShape }, { "newRectangleShape", w_newRectangleShape }, { "newPolygonShape", w_newPolygonShape }, @@ -597,6 +895,10 @@ static const luaL_Reg functions[] = { "computeLinearFrequency", w_computeLinearFrequency }, { "computeAngularStiffness", w_computeAngularStiffness }, { "computeAngularFrequency", w_computeAngularFrequency }, + + // Deprecated + { "newFixture", w_newFixture }, + { 0, 0 }, }; @@ -605,7 +907,6 @@ static const lua_CFunction types[] = luaopen_world, luaopen_contact, luaopen_body, - luaopen_fixture, luaopen_shape, luaopen_circleshape, luaopen_polygonshape, diff --git a/src/modules/physics/box2d/wrap_Physics.h b/src/modules/physics/box2d/wrap_Physics.h index 0d8b93b5f..0b56b17bd 100644 --- a/src/modules/physics/box2d/wrap_Physics.h +++ b/src/modules/physics/box2d/wrap_Physics.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_PolygonShape.cpp b/src/modules/physics/box2d/wrap_PolygonShape.cpp index 522b1bf9f..b416d8ee6 100644 --- a/src/modules/physics/box2d/wrap_PolygonShape.cpp +++ b/src/modules/physics/box2d/wrap_PolygonShape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -36,13 +36,17 @@ int w_PolygonShape_getPoints(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); lua_remove(L, 1); - return t->getPoints(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getPoints(L); }); + return ret; } int w_PolygonShape_validate(lua_State *L) { PolygonShape *t = luax_checkpolygonshape(L, 1); - luax_pushboolean(L, t->validate()); + bool valid = false; + luax_catchexcept(L, [&]() { valid = t->validate(); }); + luax_pushboolean(L, valid); return 1; } diff --git a/src/modules/physics/box2d/wrap_PolygonShape.h b/src/modules/physics/box2d/wrap_PolygonShape.h index 0eda5f054..c281dfe13 100644 --- a/src/modules/physics/box2d/wrap_PolygonShape.h +++ b/src/modules/physics/box2d/wrap_PolygonShape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_PrismaticJoint.cpp b/src/modules/physics/box2d/wrap_PrismaticJoint.cpp index 11cdce0ed..359ec4d89 100644 --- a/src/modules/physics/box2d/wrap_PrismaticJoint.cpp +++ b/src/modules/physics/box2d/wrap_PrismaticJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_PrismaticJoint.h b/src/modules/physics/box2d/wrap_PrismaticJoint.h index b66651652..307a1d1df 100644 --- a/src/modules/physics/box2d/wrap_PrismaticJoint.h +++ b/src/modules/physics/box2d/wrap_PrismaticJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_PulleyJoint.cpp b/src/modules/physics/box2d/wrap_PulleyJoint.cpp index d41e64031..7e376f4b8 100644 --- a/src/modules/physics/box2d/wrap_PulleyJoint.cpp +++ b/src/modules/physics/box2d/wrap_PulleyJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_PulleyJoint.h b/src/modules/physics/box2d/wrap_PulleyJoint.h index e365478fb..2cec64fbe 100644 --- a/src/modules/physics/box2d/wrap_PulleyJoint.h +++ b/src/modules/physics/box2d/wrap_PulleyJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_RevoluteJoint.cpp b/src/modules/physics/box2d/wrap_RevoluteJoint.cpp index 4b3efa370..ff7a61df1 100644 --- a/src/modules/physics/box2d/wrap_RevoluteJoint.cpp +++ b/src/modules/physics/box2d/wrap_RevoluteJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_RevoluteJoint.h b/src/modules/physics/box2d/wrap_RevoluteJoint.h index 9347606fd..66e4b3386 100644 --- a/src/modules/physics/box2d/wrap_RevoluteJoint.h +++ b/src/modules/physics/box2d/wrap_RevoluteJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_RopeJoint.cpp b/src/modules/physics/box2d/wrap_RopeJoint.cpp index d91445288..c3fef9faf 100644 --- a/src/modules/physics/box2d/wrap_RopeJoint.cpp +++ b/src/modules/physics/box2d/wrap_RopeJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_RopeJoint.h b/src/modules/physics/box2d/wrap_RopeJoint.h index c264c710c..2b0fd7414 100644 --- a/src/modules/physics/box2d/wrap_RopeJoint.h +++ b/src/modules/physics/box2d/wrap_RopeJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_Shape.cpp b/src/modules/physics/box2d/wrap_Shape.cpp index 497f5d95f..50ca1c8dc 100644 --- a/src/modules/physics/box2d/wrap_Shape.cpp +++ b/src/modules/physics/box2d/wrap_Shape.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -33,6 +33,35 @@ Shape *luax_checkshape(lua_State *L, int idx) return luax_checktype(L, idx); } +void luax_pushshape(lua_State *L, Shape *shape) +{ + if (shape != nullptr) + { + switch (shape->getType()) + { + case Shape::SHAPE_CIRCLE: + luax_pushtype(L, (CircleShape *) shape); + break; + case Shape::SHAPE_POLYGON: + luax_pushtype(L, (PolygonShape *) shape); + break; + case Shape::SHAPE_EDGE: + luax_pushtype(L, (EdgeShape *) shape); + break; + case Shape::SHAPE_CHAIN: + luax_pushtype(L, (ChainShape *) shape); + break; + default: + luax_pushtype(L, shape); + break; + } + } + else + { + lua_pushnil(L); + } +} + int w_Shape_getType(lua_State *L) { Shape *t = luax_checkshape(L, 1); @@ -45,7 +74,8 @@ int w_Shape_getType(lua_State *L) int w_Shape_getRadius(lua_State *L) { Shape *t = luax_checkshape(L, 1); - float radius = t->getRadius(); + float radius = 0; + luax_catchexcept(L, [&]() { radius = t->getRadius(); }); lua_pushnumber(L, radius); return 1; } @@ -53,20 +83,115 @@ int w_Shape_getRadius(lua_State *L) int w_Shape_getChildCount(lua_State *L) { Shape *t = luax_checkshape(L, 1); - int childCount = t->getChildCount(); + int childCount = 0; + luax_catchexcept(L, [&]() { childCount = t->getChildCount(); }); lua_pushinteger(L, childCount); return 1; } +int w_Shape_setFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setFriction(arg1); }); + return 0; +} + +int w_Shape_setRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&]() { t->setRestitution(arg1); }); + return 0; +} + +int w_Shape_setDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float arg1 = (float)luaL_checknumber(L, 2); + luax_catchexcept(L, [&](){ t->setDensity(arg1); }); + return 0; +} + +int w_Shape_setSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool arg1 = luax_checkboolean(L, 2); + luax_catchexcept(L, [&]() { t->setSensor(arg1); }); + return 0; +} + +int w_Shape_getFriction(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float friction = 0; + luax_catchexcept(L, [&]() { friction = t->getFriction(); }); + lua_pushnumber(L, friction); + return 1; +} + +int w_Shape_getRestitution(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float r = 0; + luax_catchexcept(L, [&]() { r = t->getRestitution(); }); + lua_pushnumber(L, r); + return 1; +} + +int w_Shape_getDensity(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + float d = 0; + luax_catchexcept(L, [&]() { d = t->getDensity(); }); + lua_pushnumber(L, d); + return 1; +} + +int w_Shape_isSensor(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + bool sensor = false; + luax_catchexcept(L, [&]() { sensor = t->isSensor(); }); + luax_pushboolean(L, sensor); + return 1; +} + +int w_Shape_getBody(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + Body *body = t->getBody(); + if (body == nullptr) + return 0; + luax_pushtype(L, body); + return 1; +} + +int w_Shape_getShape(lua_State *L) +{ + luax_markdeprecated(L, 1, "Fixture:getShape", API_METHOD, DEPRECATED_NO_REPLACEMENT, nullptr); + Shape *t = luax_checkshape(L, 1); + luax_pushshape(L, t); + return 1; +} + int w_Shape_testPoint(lua_State *L) { Shape *t = luax_checkshape(L, 1); float x = (float)luaL_checknumber(L, 2); float y = (float)luaL_checknumber(L, 3); - float r = (float)luaL_checknumber(L, 4); - float px = (float)luaL_checknumber(L, 5); - float py = (float)luaL_checknumber(L, 6); - bool result = t->testPoint(x, y, r, px, py); + bool result = false; + if (!lua_isnoneornil(L, 4)) + { + float r = (float)luaL_checknumber(L, 4); + float px = (float)luaL_checknumber(L, 5); + float py = (float)luaL_checknumber(L, 6); + luax_catchexcept(L, [&]() { result = t->testPoint(x, y, r, px, py); }); + } + else + { + luax_catchexcept(L, [&]() { result = t->testPoint(x, y); }); + } lua_pushboolean(L, result); return 1; } @@ -84,14 +209,143 @@ int w_Shape_computeAABB(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeAABB(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeAABB(L); }); + return ret; } int w_Shape_computeMass(lua_State *L) { Shape *t = luax_checkshape(L, 1); lua_remove(L, 1); - return t->computeMass(L); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->computeMass(L); }); + return ret; +} + +int w_Shape_setFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + v[0] = (int) luaL_checkinteger(L, 2); + v[1] = (int) luaL_checkinteger(L, 3); + v[2] = (int) luaL_checkinteger(L, 4); + luax_catchexcept(L, [&]() { t->setFilterData(v); }); + return 0; +} + +int w_Shape_getFilterData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int v[3]; + luax_catchexcept(L, [&]() { t->getFilterData(v); }); + lua_pushinteger(L, v[0]); + lua_pushinteger(L, v[1]); + lua_pushinteger(L, v[2]); + return 3; +} + +int w_Shape_setCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setCategory(L); }); + return ret; +} + +int w_Shape_getCategory(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getCategory(L); }); + return ret; +} + +int w_Shape_setMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setMask(L); }); + return ret; +} + +int w_Shape_getMask(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMask(L); }); + return ret; +} + +int w_Shape_setUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->setUserData(L); }); + return ret; +} + +int w_Shape_getUserData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getUserData(L); }); + return ret; +} + +int w_Shape_getBoundingBox(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getBoundingBox(L); }); + return ret; +} + +int w_Shape_getMassData(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->getMassData(L); }); + return ret; +} + +int w_Shape_getGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = 0; + luax_catchexcept(L, [&]() { i = t->getGroupIndex(); }); + lua_pushinteger(L, i); + return 1; +} + +int w_Shape_setGroupIndex(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + int i = (int) luaL_checkinteger(L, 2); + luax_catchexcept(L, [&]() { t->setGroupIndex(i); }); + return 0; +} + +int w_Shape_destroy(lua_State *L) +{ + Shape *t = luax_checkshape(L, 1); + luax_catchexcept(L, [&](){ t->destroy(); }); + return 0; +} + +int w_Shape_isDestroyed(lua_State *L) +{ + Shape *f = luax_checktype(L, 1); + luax_pushboolean(L, !f->isValid()); + return 1; } const luaL_Reg w_Shape_functions[] = @@ -99,10 +353,34 @@ const luaL_Reg w_Shape_functions[] = { "getType", w_Shape_getType }, { "getRadius", w_Shape_getRadius }, { "getChildCount", w_Shape_getChildCount }, + { "setFriction", w_Shape_setFriction }, + { "setRestitution", w_Shape_setRestitution }, + { "setDensity", w_Shape_setDensity }, + { "setSensor", w_Shape_setSensor }, + { "getFriction", w_Shape_getFriction }, + { "getRestitution", w_Shape_getRestitution }, + { "getDensity", w_Shape_getDensity }, + { "getBody", w_Shape_getBody }, + { "getShape", w_Shape_getShape }, + { "isSensor", w_Shape_isSensor }, { "testPoint", w_Shape_testPoint }, { "rayCast", w_Shape_rayCast }, { "computeAABB", w_Shape_computeAABB }, { "computeMass", w_Shape_computeMass }, + { "setFilterData", w_Shape_setFilterData }, + { "getFilterData", w_Shape_getFilterData }, + { "setCategory", w_Shape_setCategory }, + { "getCategory", w_Shape_getCategory }, + { "setMask", w_Shape_setMask }, + { "getMask", w_Shape_getMask }, + { "setUserData", w_Shape_setUserData }, + { "getUserData", w_Shape_getUserData }, + { "getBoundingBox", w_Shape_getBoundingBox }, + { "getMassData", w_Shape_getMassData }, + { "getGroupIndex", w_Shape_getGroupIndex }, + { "setGroupIndex", w_Shape_setGroupIndex }, + { "destroy", w_Shape_destroy }, + { "isDestroyed", w_Shape_isDestroyed }, { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_Shape.h b/src/modules/physics/box2d/wrap_Shape.h index e5cd01cbe..25ddba824 100644 --- a/src/modules/physics/box2d/wrap_Shape.h +++ b/src/modules/physics/box2d/wrap_Shape.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,6 +34,7 @@ namespace box2d { Shape *luax_checkshape(lua_State *L, int idx); +void luax_pushshape(lua_State *L, Shape *shape); extern "C" int luaopen_shape(lua_State *L); extern const luaL_Reg w_Shape_functions[]; diff --git a/src/modules/physics/box2d/wrap_WeldJoint.cpp b/src/modules/physics/box2d/wrap_WeldJoint.cpp index f03d99405..ad51f9e29 100644 --- a/src/modules/physics/box2d/wrap_WeldJoint.cpp +++ b/src/modules/physics/box2d/wrap_WeldJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_WeldJoint.h b/src/modules/physics/box2d/wrap_WeldJoint.h index 234c7350c..f9a3e1132 100644 --- a/src/modules/physics/box2d/wrap_WeldJoint.h +++ b/src/modules/physics/box2d/wrap_WeldJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_WheelJoint.cpp b/src/modules/physics/box2d/wrap_WheelJoint.cpp index fa116833e..56b34e9f3 100644 --- a/src/modules/physics/box2d/wrap_WheelJoint.cpp +++ b/src/modules/physics/box2d/wrap_WheelJoint.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_WheelJoint.h b/src/modules/physics/box2d/wrap_WheelJoint.h index 827863d02..5bfdd48af 100644 --- a/src/modules/physics/box2d/wrap_WheelJoint.h +++ b/src/modules/physics/box2d/wrap_WheelJoint.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/physics/box2d/wrap_World.cpp b/src/modules/physics/box2d/wrap_World.cpp index 68305b9ae..016e5b4db 100644 --- a/src/modules/physics/box2d/wrap_World.cpp +++ b/src/modules/physics/box2d/wrap_World.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -178,19 +178,25 @@ int w_World_getContacts(lua_State *L) return ret; } -int w_World_queryBoundingBox(lua_State *L) +int w_World_queryShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); - return t->queryBoundingBox(L); + return t->queryShapesInArea(L); } -int w_World_getFixturesInArea(lua_State *L) +int w_World_queryBoundingBox(lua_State *L) +{ + luax_markdeprecated(L, 1, "World:queryBoundingBox", API_METHOD, DEPRECATED_RENAMED, "World:queryShapesInArea"); + return w_World_queryShapesInArea(L); +} + +int w_World_getShapesInArea(lua_State *L) { World *t = luax_checkworld(L, 1); lua_remove(L, 1); int ret = 0; - luax_catchexcept(L, [&](){ ret = t->getFixturesInArea(L); }); + luax_catchexcept(L, [&](){ ret = t->getShapesInArea(L); }); return ret; } @@ -203,6 +209,24 @@ int w_World_rayCast(lua_State *L) return ret; } +int w_World_rayCastAny(lua_State *L) +{ + World *t = luax_checkworld(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->rayCastAny(L); }); + return ret; +} + +int w_World_rayCastClosest(lua_State *L) +{ + World *t = luax_checkworld(L, 1); + lua_remove(L, 1); + int ret = 0; + luax_catchexcept(L, [&]() { ret = t->rayCastClosest(L); }); + return ret; +} + int w_World_destroy(lua_State *L) { World *t = luax_checkworld(L, 1); @@ -236,12 +260,17 @@ static const luaL_Reg w_World_functions[] = { "getBodies", w_World_getBodies }, { "getJoints", w_World_getJoints }, { "getContacts", w_World_getContacts }, - { "queryBoundingBox", w_World_queryBoundingBox }, - { "getFixturesInArea", w_World_getFixturesInArea }, + { "queryShapesInArea", w_World_queryShapesInArea }, + { "getShapesInArea", w_World_getShapesInArea }, { "rayCast", w_World_rayCast }, + { "rayCastAny", w_World_rayCastAny }, + { "rayCastClosest", w_World_rayCastClosest }, { "destroy", w_World_destroy }, { "isDestroyed", w_World_isDestroyed }, + // Deprecated + { "queryBoundingBox", w_World_queryBoundingBox }, + { 0, 0 } }; diff --git a/src/modules/physics/box2d/wrap_World.h b/src/modules/physics/box2d/wrap_World.h index cf0660299..e65f83b7b 100644 --- a/src/modules/physics/box2d/wrap_World.h +++ b/src/modules/physics/box2d/wrap_World.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sensor/Sensor.cpp b/src/modules/sensor/Sensor.cpp index c1235967e..7e991baa1 100644 --- a/src/modules/sensor/Sensor.cpp +++ b/src/modules/sensor/Sensor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -26,6 +26,11 @@ namespace love namespace sensor { +Sensor::Sensor(const char *name) + : Module(M_SENSOR, name) +{ +} + STRINGMAP_CLASS_BEGIN(Sensor, Sensor::SensorType, Sensor::SENSOR_MAX_ENUM, sensorType) { { "accelerometer", Sensor::SENSOR_ACCELEROMETER }, diff --git a/src/modules/sensor/Sensor.h b/src/modules/sensor/Sensor.h index 1fd51dc7f..bf79d1d87 100644 --- a/src/modules/sensor/Sensor.h +++ b/src/modules/sensor/Sensor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,9 +43,6 @@ public: virtual ~Sensor() {} - // Implements Module. - ModuleType getModuleType() const override { return M_SENSOR; } - /** * Check the availability of the sensor. **/ @@ -75,6 +72,10 @@ public: STRINGMAP_CLASS_DECLARE(SensorType); +protected: + + Sensor(const char *name); + }; // Sensor } // sensor diff --git a/src/modules/sensor/sdl/Sensor.cpp b/src/modules/sensor/sdl/Sensor.cpp index 35689c902..0337ade3a 100644 --- a/src/modules/sensor/sdl/Sensor.cpp +++ b/src/modules/sensor/sdl/Sensor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -33,7 +33,8 @@ namespace sdl { Sensor::Sensor() -: sensors() + : love::sensor::Sensor("love.sensor.sdl") + , sensors() { if (SDL_InitSubSystem(SDL_INIT_SENSOR) < 0) throw love::Exception("Could not initialize SDL sensor subsystem (%s)", SDL_GetError()); @@ -44,18 +45,27 @@ Sensor::~Sensor() SDL_QuitSubSystem(SDL_INIT_SENSOR); } -const char *Sensor::getName() const -{ - return "love.sensor.sdl"; -} - bool Sensor::hasSensor(SensorType type) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + SDL_SensorID *sensorIDs = SDL_GetSensors(&count); + for (int i = 0; i < count; i++) + { + if (convert(SDL_GetSensorInstanceType(sensorIDs[i])) == type) + { + SDL_free(sensorIDs); + return true; + } + } + SDL_free(sensorIDs); +#else for (int i = 0; i < SDL_NumSensors(); i++) { if (convert(SDL_SensorGetDeviceType(i)) == type) return true; } +#endif return false; } @@ -69,11 +79,38 @@ void Sensor::setEnabled(SensorType type, bool enable) { if (sensors[type] && !enable) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_CloseSensor(sensors[type]); +#else SDL_SensorClose(sensors[type]); +#endif sensors[type] = nullptr; } else if (sensors[type] == nullptr && enable) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + SDL_SensorID *sensorIDs = SDL_GetSensors(&count); + for (int i = 0; i < count; i++) + { + if (convert(SDL_GetSensorInstanceType(sensorIDs[i])) == type) + { + SDL_Sensor *sensorHandle = SDL_OpenSensor(sensorIDs[i]); + + if (sensorHandle == nullptr) + { + SDL_free(sensorIDs); + + const char *name = nullptr; + getConstant(type, name); + throw love::Exception("Could not open \"%s\" SDL sensor (%s)", name, SDL_GetError()); + } + + sensors[type] = sensorHandle; + } + } + SDL_free(sensorIDs); +#else for (int i = 0; i < SDL_NumSensors(); i++) { if (convert(SDL_SensorGetDeviceType(i)) == type) @@ -84,13 +121,13 @@ void Sensor::setEnabled(SensorType type, bool enable) { const char *name = nullptr; getConstant(type, name); - throw love::Exception("Could not open \"%s\" SDL sensor (%s)", name, SDL_GetError()); } sensors[type] = sensorHandle; } } +#endif } } @@ -106,7 +143,11 @@ std::vector Sensor::getData(SensorType type) std::vector values(3); +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_GetSensorData(sensors[type], values.data(), (int) values.size()) != 0) +#else if (SDL_SensorGetData(sensors[type], values.data(), (int) values.size()) != 0) +#endif { const char *name = nullptr; getConstant(type, name); @@ -121,7 +162,7 @@ std::vector Sensor::getHandles() { std::vector nativeSensor; - for (const std::pair &data: sensors) + for (std::pair data : sensors) { if (data.second) nativeSensor.push_back(data.second); @@ -140,7 +181,11 @@ const char *Sensor::getSensorName(SensorType type) throw love::Exception("\"%s\" sensor is not enabled", name); } +#if SDL_VERSION_ATLEAST(3, 0, 0) + return SDL_GetSensorName(sensors[type]); +#else return SDL_SensorGetName(sensors[type]); +#endif } Sensor::SensorType Sensor::convert(SDL_SensorType type) diff --git a/src/modules/sensor/sdl/Sensor.h b/src/modules/sensor/sdl/Sensor.h index afd28a701..02491add7 100644 --- a/src/modules/sensor/sdl/Sensor.h +++ b/src/modules/sensor/sdl/Sensor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,9 +43,6 @@ public: Sensor(); ~Sensor() override; - // Implements Module. - const char *getName() const override; - bool hasSensor(SensorType type) override; bool isEnabled(SensorType type) override; void setEnabled(SensorType type, bool enable) override; diff --git a/src/modules/sensor/wrap_Sensor.cpp b/src/modules/sensor/wrap_Sensor.cpp index 98c13cc8a..f5dde10a4 100644 --- a/src/modules/sensor/wrap_Sensor.cpp +++ b/src/modules/sensor/wrap_Sensor.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sensor/wrap_Sensor.h b/src/modules/sensor/wrap_Sensor.h index e4628deca..eaf5c76e1 100644 --- a/src/modules/sensor/wrap_Sensor.h +++ b/src/modules/sensor/wrap_Sensor.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/Decoder.cpp b/src/modules/sound/Decoder.cpp index a7562f1b4..326e8097a 100644 --- a/src/modules/sound/Decoder.cpp +++ b/src/modules/sound/Decoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/Decoder.h b/src/modules/sound/Decoder.h index 1fbd9dbb4..2925338b8 100644 --- a/src/modules/sound/Decoder.h +++ b/src/modules/sound/Decoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/Sound.cpp b/src/modules/sound/Sound.cpp index 99ff80992..f4f3da271 100644 --- a/src/modules/sound/Sound.cpp +++ b/src/modules/sound/Sound.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -27,6 +27,11 @@ namespace sound love::Type Sound::type("Sound", &Module::type); +Sound::Sound(const char *name) + : Module(M_SOUND, name) +{ +} + Sound::~Sound() { } diff --git a/src/modules/sound/Sound.h b/src/modules/sound/Sound.h index 7ccc1be6c..3b0685b08 100644 --- a/src/modules/sound/Sound.h +++ b/src/modules/sound/Sound.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,9 +46,6 @@ public: virtual ~Sound(); - // Implements Module. - virtual ModuleType getModuleType() const { return M_SOUND; } - /** * Creates new SoundData from a decoder. Fully expands the * encoded sound data into raw sound data. Not recommended @@ -89,6 +86,10 @@ public: **/ virtual Decoder *newDecoder(Stream *stream, int bufferSize) = 0; +protected: + + Sound(const char *name); + }; // Sound } // sound diff --git a/src/modules/sound/SoundData.cpp b/src/modules/sound/SoundData.cpp index 39ed8ee78..ac441f04d 100644 --- a/src/modules/sound/SoundData.cpp +++ b/src/modules/sound/SoundData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/SoundData.h b/src/modules/sound/SoundData.h index e08fef043..7b7864328 100644 --- a/src/modules/sound/SoundData.h +++ b/src/modules/sound/SoundData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/CoreAudioDecoder.cpp b/src/modules/sound/lullaby/CoreAudioDecoder.cpp index ff3c44450..421cdf7a2 100644 --- a/src/modules/sound/lullaby/CoreAudioDecoder.cpp +++ b/src/modules/sound/lullaby/CoreAudioDecoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/CoreAudioDecoder.h b/src/modules/sound/lullaby/CoreAudioDecoder.h index 3f9582685..8e461e1f4 100644 --- a/src/modules/sound/lullaby/CoreAudioDecoder.h +++ b/src/modules/sound/lullaby/CoreAudioDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/FLACDecoder.cpp b/src/modules/sound/lullaby/FLACDecoder.cpp index b39206abb..1a4662716 100644 --- a/src/modules/sound/lullaby/FLACDecoder.cpp +++ b/src/modules/sound/lullaby/FLACDecoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/FLACDecoder.h b/src/modules/sound/lullaby/FLACDecoder.h index 9795e5785..109399295 100644 --- a/src/modules/sound/lullaby/FLACDecoder.h +++ b/src/modules/sound/lullaby/FLACDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/MP3Decoder.cpp b/src/modules/sound/lullaby/MP3Decoder.cpp index cd50f44a9..c5b55b152 100644 --- a/src/modules/sound/lullaby/MP3Decoder.cpp +++ b/src/modules/sound/lullaby/MP3Decoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/MP3Decoder.h b/src/modules/sound/lullaby/MP3Decoder.h index aa3349feb..ea08183ea 100644 --- a/src/modules/sound/lullaby/MP3Decoder.h +++ b/src/modules/sound/lullaby/MP3Decoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/ModPlugDecoder.cpp b/src/modules/sound/lullaby/ModPlugDecoder.cpp index e03706912..7f297fd39 100644 --- a/src/modules/sound/lullaby/ModPlugDecoder.cpp +++ b/src/modules/sound/lullaby/ModPlugDecoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/ModPlugDecoder.h b/src/modules/sound/lullaby/ModPlugDecoder.h index f36f58b17..8e0d38f86 100644 --- a/src/modules/sound/lullaby/ModPlugDecoder.h +++ b/src/modules/sound/lullaby/ModPlugDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/Sound.cpp b/src/modules/sound/lullaby/Sound.cpp index fbb6a36be..a5fe66411 100644 --- a/src/modules/sound/lullaby/Sound.cpp +++ b/src/modules/sound/lullaby/Sound.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -59,6 +59,7 @@ namespace lullaby { Sound::Sound() + : love::sound::Sound("love.sound.lullaby") { } @@ -66,11 +67,6 @@ Sound::~Sound() { } -const char *Sound::getName() const -{ - return "love.sound.lullaby"; -} - sound::Decoder *Sound::newDecoder(Stream *stream, int bufferSize) { std::vector possibleDecoders = { diff --git a/src/modules/sound/lullaby/Sound.h b/src/modules/sound/lullaby/Sound.h index 03bfd49e5..13e5e1fa3 100644 --- a/src/modules/sound/lullaby/Sound.h +++ b/src/modules/sound/lullaby/Sound.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,9 +48,6 @@ public: Sound(); virtual ~Sound(); - /// @copydoc love::Module::getName - const char *getName() const override; - /// @copydoc love::sound::Sound::newDecoder sound::Decoder *newDecoder(Stream *stream, int bufferSize) override; diff --git a/src/modules/sound/lullaby/VorbisDecoder.cpp b/src/modules/sound/lullaby/VorbisDecoder.cpp index 2d2ac5af6..829825112 100644 --- a/src/modules/sound/lullaby/VorbisDecoder.cpp +++ b/src/modules/sound/lullaby/VorbisDecoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/VorbisDecoder.h b/src/modules/sound/lullaby/VorbisDecoder.h index 7d453b7b5..cf7a58bca 100644 --- a/src/modules/sound/lullaby/VorbisDecoder.h +++ b/src/modules/sound/lullaby/VorbisDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/WaveDecoder.cpp b/src/modules/sound/lullaby/WaveDecoder.cpp index 8a9cd608c..fdefd4df9 100644 --- a/src/modules/sound/lullaby/WaveDecoder.cpp +++ b/src/modules/sound/lullaby/WaveDecoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/lullaby/WaveDecoder.h b/src/modules/sound/lullaby/WaveDecoder.h index 4abfb6cd5..525a9b052 100644 --- a/src/modules/sound/lullaby/WaveDecoder.h +++ b/src/modules/sound/lullaby/WaveDecoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_Decoder.cpp b/src/modules/sound/wrap_Decoder.cpp index 8054111bd..ff2193bf3 100644 --- a/src/modules/sound/wrap_Decoder.cpp +++ b/src/modules/sound/wrap_Decoder.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_Decoder.h b/src/modules/sound/wrap_Decoder.h index 974ec5306..55533f2c3 100644 --- a/src/modules/sound/wrap_Decoder.h +++ b/src/modules/sound/wrap_Decoder.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_Sound.cpp b/src/modules/sound/wrap_Sound.cpp index b5190e5e0..1a1395393 100644 --- a/src/modules/sound/wrap_Sound.cpp +++ b/src/modules/sound/wrap_Sound.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_Sound.h b/src/modules/sound/wrap_Sound.h index 995b626c0..c2fc31c41 100644 --- a/src/modules/sound/wrap_Sound.h +++ b/src/modules/sound/wrap_Sound.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_SoundData.cpp b/src/modules/sound/wrap_SoundData.cpp index 79ce4d11e..67554bca4 100644 --- a/src/modules/sound/wrap_SoundData.cpp +++ b/src/modules/sound/wrap_SoundData.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_SoundData.h b/src/modules/sound/wrap_SoundData.h index 218fbefea..84fac0145 100644 --- a/src/modules/sound/wrap_SoundData.h +++ b/src/modules/sound/wrap_SoundData.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/sound/wrap_SoundData.lua b/src/modules/sound/wrap_SoundData.lua index 4e074101e..ebc2c8879 100644 --- a/src/modules/sound/wrap_SoundData.lua +++ b/src/modules/sound/wrap_SoundData.lua @@ -3,7 +3,7 @@ R"luastring"--( -- There is a matching delimiter at the bottom of the file. --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/system/System.cpp b/src/modules/system/System.cpp index 4864bc0d8..cee7674c9 100644 --- a/src/modules/system/System.cpp +++ b/src/modules/system/System.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -58,7 +58,8 @@ namespace love namespace system { -System::System() +System::System(const char *name) + : Module(M_SYSTEM, name) { } diff --git a/src/modules/system/System.h b/src/modules/system/System.h index 6abef3cd3..7a7ed764e 100644 --- a/src/modules/system/System.h +++ b/src/modules/system/System.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -48,12 +48,9 @@ public: POWER_MAX_ENUM }; - System(); + System(const char *name); virtual ~System() {} - // Implements Module. - virtual ModuleType getModuleType() const { return M_SYSTEM; } - /** * Gets the current operating system. **/ diff --git a/src/modules/system/sdl/System.cpp b/src/modules/system/sdl/System.cpp index 1bae95e73..b25f6334f 100644 --- a/src/modules/system/sdl/System.cpp +++ b/src/modules/system/sdl/System.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -39,14 +39,10 @@ namespace sdl { System::System() + : love::system::System("love.system.sdl") { } -const char *System::getName() const -{ - return "love.system.sdl"; -} - int System::getProcessorCount() const { return SDL_GetCPUCount(); diff --git a/src/modules/system/sdl/System.h b/src/modules/system/sdl/System.h index 7c1da5aef..39787e9d4 100644 --- a/src/modules/system/sdl/System.h +++ b/src/modules/system/sdl/System.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -42,9 +42,6 @@ public: System(); virtual ~System() {} - // Implements Module. - const char *getName() const override; - int getProcessorCount() const override; void setClipboardText(const std::string &text) const override; diff --git a/src/modules/system/wrap_System.cpp b/src/modules/system/wrap_System.cpp index feac514c5..bfe461366 100644 --- a/src/modules/system/wrap_System.cpp +++ b/src/modules/system/wrap_System.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/system/wrap_System.h b/src/modules/system/wrap_System.h index b89e3b111..94e0d1a81 100644 --- a/src/modules/system/wrap_System.h +++ b/src/modules/system/wrap_System.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/Channel.cpp b/src/modules/thread/Channel.cpp index 7c20158e2..0b352d9c1 100644 --- a/src/modules/thread/Channel.cpp +++ b/src/modules/thread/Channel.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/Channel.h b/src/modules/thread/Channel.h index 1409488a4..121f2321b 100644 --- a/src/modules/thread/Channel.h +++ b/src/modules/thread/Channel.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/LuaThread.cpp b/src/modules/thread/LuaThread.cpp index 14ce40d01..948ecfe7c 100644 --- a/src/modules/thread/LuaThread.cpp +++ b/src/modules/thread/LuaThread.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -25,6 +25,7 @@ #ifdef LOVE_BUILD_STANDALONE extern "C" int luaopen_love(lua_State * L); +extern "C" int luaopen_love_jitsetup(lua_State * L); #endif // LOVE_BUILD_STANDALONE namespace love @@ -55,6 +56,13 @@ void LuaThread::threadFunction() luaL_openlibs(L); #ifdef LOVE_BUILD_STANDALONE + // Call LuaJIT-specific setup again. While it's quite late to call it at + // this point, it still needed to turn off JIT compilation (if necessary) + // for this thread. + luax_preload(L, luaopen_love_jitsetup, "love.jitsetup"); + luax_require(L, "love.jitsetup"); + lua_pop(L, 1); + luax_preload(L, luaopen_love, "love"); luax_require(L, "love"); lua_pop(L, 1); diff --git a/src/modules/thread/LuaThread.h b/src/modules/thread/LuaThread.h index 4e7cc8c8d..5142751fe 100644 --- a/src/modules/thread/LuaThread.h +++ b/src/modules/thread/LuaThread.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/Thread.h b/src/modules/thread/Thread.h index b761190bd..19c8cd5da 100644 --- a/src/modules/thread/Thread.h +++ b/src/modules/thread/Thread.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/ThreadModule.cpp b/src/modules/thread/ThreadModule.cpp index f48af26ea..3d94bae53 100644 --- a/src/modules/thread/ThreadModule.cpp +++ b/src/modules/thread/ThreadModule.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -25,6 +25,11 @@ namespace love namespace thread { +ThreadModule::ThreadModule() + : love::Module(M_THREAD, "love.thread.sdl") +{ +} + LuaThread *ThreadModule::newThread(const std::string &name, love::Data *data) { return new LuaThread(name, data); @@ -48,10 +53,5 @@ Channel *ThreadModule::getChannel(const std::string &name) return c; } -const char *ThreadModule::getName() const -{ - return "love.thread.sdl"; -} - } // thread } // love diff --git a/src/modules/thread/ThreadModule.h b/src/modules/thread/ThreadModule.h index 819b05557..516c23392 100644 --- a/src/modules/thread/ThreadModule.h +++ b/src/modules/thread/ThreadModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,15 +43,12 @@ class ThreadModule : public love::Module { public: + ThreadModule(); virtual ~ThreadModule() {} virtual LuaThread *newThread(const std::string &name, love::Data *data); virtual Channel *newChannel(); virtual Channel *getChannel(const std::string &name); - // Implements Module. - virtual const char *getName() const; - virtual ModuleType getModuleType() const { return M_THREAD; } - private: std::map> namedChannels; diff --git a/src/modules/thread/sdl/Thread.cpp b/src/modules/thread/sdl/Thread.cpp index aa69b9276..f9f59e932 100644 --- a/src/modules/thread/sdl/Thread.cpp +++ b/src/modules/thread/sdl/Thread.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/sdl/Thread.h b/src/modules/thread/sdl/Thread.h index 3545e1b16..a01926b63 100644 --- a/src/modules/thread/sdl/Thread.h +++ b/src/modules/thread/sdl/Thread.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/sdl/threads.cpp b/src/modules/thread/sdl/threads.cpp index 64fd5063d..67fd9652f 100644 --- a/src/modules/thread/sdl/threads.cpp +++ b/src/modules/thread/sdl/threads.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -50,22 +50,38 @@ void Mutex::unlock() Conditional::Conditional() { +#if SDL_VERSION_ATLEAST(3, 0, 0) + cond = SDL_CreateCondition(); +#else cond = SDL_CreateCond(); +#endif } Conditional::~Conditional() { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DestroyCondition(cond); +#else SDL_DestroyCond(cond); +#endif } void Conditional::signal() { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SignalCondition(cond); +#else SDL_CondSignal(cond); +#endif } void Conditional::broadcast() { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_BroadcastCondition(cond); +#else SDL_CondBroadcast(cond); +#endif } bool Conditional::wait(thread::Mutex *_mutex, int timeout) @@ -74,10 +90,17 @@ bool Conditional::wait(thread::Mutex *_mutex, int timeout) // however, you're asking for it if you're // mixing thread implementations. Mutex *mutex = (Mutex *) _mutex; +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (timeout < 0) + return !SDL_WaitCondition(cond, mutex->mutex); + else + return (SDL_WaitConditionTimeout(cond, mutex->mutex, timeout) == 0); +#else if (timeout < 0) return !SDL_CondWait(cond, mutex->mutex); else return (SDL_CondWaitTimeout(cond, mutex->mutex, timeout) == 0); +#endif } } // sdl diff --git a/src/modules/thread/sdl/threads.h b/src/modules/thread/sdl/threads.h index 8c2726566..4a7bbde6e 100644 --- a/src/modules/thread/sdl/threads.h +++ b/src/modules/thread/sdl/threads.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -25,6 +25,7 @@ #include "thread/threads.h" #include +#include namespace love { @@ -47,7 +48,11 @@ public: private: +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Mutex *mutex; +#else SDL_mutex *mutex; +#endif Mutex(const Mutex&/* mutex*/) {} friend class Conditional; @@ -67,7 +72,11 @@ public: private: +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Condition *cond; +#else SDL_cond *cond; +#endif }; // Conditional diff --git a/src/modules/thread/threads.cpp b/src/modules/thread/threads.cpp index cf76dcbf9..2e76865dc 100644 --- a/src/modules/thread/threads.cpp +++ b/src/modules/thread/threads.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/threads.h b/src/modules/thread/threads.h index e5d8bd059..d20c7e4ec 100644 --- a/src/modules/thread/threads.h +++ b/src/modules/thread/threads.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/wrap_Channel.h b/src/modules/thread/wrap_Channel.h index 01097e474..5842fb569 100644 --- a/src/modules/thread/wrap_Channel.h +++ b/src/modules/thread/wrap_Channel.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/wrap_LuaThread.h b/src/modules/thread/wrap_LuaThread.h index 554b01b07..942134e4d 100644 --- a/src/modules/thread/wrap_LuaThread.h +++ b/src/modules/thread/wrap_LuaThread.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/thread/wrap_ThreadModule.h b/src/modules/thread/wrap_ThreadModule.h index a31eafda2..8c14455f3 100644 --- a/src/modules/thread/wrap_ThreadModule.h +++ b/src/modules/thread/wrap_ThreadModule.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/timer/Timer.cpp b/src/modules/timer/Timer.cpp index c1cf900da..c9c602f3d 100644 --- a/src/modules/timer/Timer.cpp +++ b/src/modules/timer/Timer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,7 +43,8 @@ namespace timer { Timer::Timer() - : currTime(0) + : Module(M_TIMER, "love.timer") + , currTime(0) , prevFpsUpdate(0) , fps(0) , averageDelta(0) @@ -84,7 +85,7 @@ double Timer::step() void Timer::sleep(double seconds) const { if (seconds >= 0) - love::sleep((unsigned int)(seconds*1000)); + love::sleep(seconds*1000); } double Timer::getDelta() const diff --git a/src/modules/timer/Timer.h b/src/modules/timer/Timer.h index c3a7f43bb..883a6230b 100644 --- a/src/modules/timer/Timer.h +++ b/src/modules/timer/Timer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -36,10 +36,6 @@ public: Timer(); virtual ~Timer() {} - // Implements Module. - ModuleType getModuleType() const override { return M_TIMER; } - const char *getName() const override { return "love.timer"; } - /** * Measures the time between this call and the previous call, * and updates internal values accordingly. diff --git a/src/modules/timer/wrap_Timer.cpp b/src/modules/timer/wrap_Timer.cpp index 8f9c18a20..9896c4902 100644 --- a/src/modules/timer/wrap_Timer.cpp +++ b/src/modules/timer/wrap_Timer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/timer/wrap_Timer.h b/src/modules/timer/wrap_Timer.h index 7f9897396..0f2daaa41 100644 --- a/src/modules/timer/wrap_Timer.h +++ b/src/modules/timer/wrap_Timer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/touch/Touch.h b/src/modules/touch/Touch.h index 2fdf8d6cd..08b9de60a 100644 --- a/src/modules/touch/Touch.h +++ b/src/modules/touch/Touch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -51,9 +51,6 @@ public: virtual ~Touch() {} - // Implements Module. - virtual ModuleType getModuleType() const { return M_TOUCH; } - /** * Gets all currently active touches. **/ @@ -64,6 +61,12 @@ public: **/ virtual const TouchInfo &getTouch(int64 id) const = 0; +protected: + + Touch(const char *name) + : Module(M_TOUCH, name) + {} + }; // Touch } // touch diff --git a/src/modules/touch/sdl/Touch.cpp b/src/modules/touch/sdl/Touch.cpp index cd5915233..a004ff85c 100644 --- a/src/modules/touch/sdl/Touch.cpp +++ b/src/modules/touch/sdl/Touch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -23,6 +23,8 @@ #include "common/Exception.h" #include "Touch.h" +#include + // C++ #include @@ -33,6 +35,11 @@ namespace touch namespace sdl { +Touch::Touch() + : love::touch::Touch("love.touch.sdl") +{ +} + const std::vector &Touch::getTouches() const { return touches; @@ -49,11 +56,6 @@ const Touch::TouchInfo &Touch::getTouch(int64 id) const throw love::Exception("Invalid active touch ID: %d", id); } -const char *Touch::getName() const -{ - return "love.touch.sdl"; -} - void Touch::onEvent(Uint32 eventtype, const TouchInfo &info) { auto compare = [&](const TouchInfo &touch) -> bool @@ -63,11 +65,19 @@ void Touch::onEvent(Uint32 eventtype, const TouchInfo &info) switch (eventtype) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_EVENT_FINGER_DOWN: +#else case SDL_FINGERDOWN: +#endif touches.erase(std::remove_if(touches.begin(), touches.end(), compare), touches.end()); touches.push_back(info); break; +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_EVENT_FINGER_MOTION: +#else case SDL_FINGERMOTION: +#endif { for (TouchInfo &touch : touches) { @@ -76,7 +86,11 @@ void Touch::onEvent(Uint32 eventtype, const TouchInfo &info) } break; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + case SDL_EVENT_FINGER_UP: +#else case SDL_FINGERUP: +#endif touches.erase(std::remove_if(touches.begin(), touches.end(), compare), touches.end()); break; default: diff --git a/src/modules/touch/sdl/Touch.h b/src/modules/touch/sdl/Touch.h index f0465f8a8..8bd5c918d 100644 --- a/src/modules/touch/sdl/Touch.h +++ b/src/modules/touch/sdl/Touch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -38,14 +38,12 @@ class Touch : public love::touch::Touch { public: + Touch(); virtual ~Touch() {} const std::vector &getTouches() const override; const TouchInfo &getTouch(int64 id) const override; - // Implements Module. - const char *getName() const override; - // SDL has functions to query the state of touch presses, but unfortunately // they are updated on a different thread in some backends, which causes // issues especially if the user is iterating through the current touches diff --git a/src/modules/touch/wrap_Touch.cpp b/src/modules/touch/wrap_Touch.cpp index e9df11861..69b72cae3 100644 --- a/src/modules/touch/wrap_Touch.cpp +++ b/src/modules/touch/wrap_Touch.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/touch/wrap_Touch.h b/src/modules/touch/wrap_Touch.h index 0e9097a34..5cb4dbab3 100644 --- a/src/modules/touch/wrap_Touch.h +++ b/src/modules/touch/wrap_Touch.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/Video.h b/src/modules/video/Video.h index 90767f11d..9cfc16298 100644 --- a/src/modules/video/Video.h +++ b/src/modules/video/Video.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -35,15 +35,20 @@ namespace video class Video : public Module { public: - virtual ~Video() {} - // Implements Module - virtual ModuleType getModuleType() const { return M_VIDEO; } + virtual ~Video() {} /** * Create a VideoStream representing video frames **/ virtual VideoStream *newVideoStream(love::filesystem::File *file) = 0; + +protected: + + Video(const char *name) + : Module(M_VIDEO, name) + {} + }; // Video } // video diff --git a/src/modules/video/VideoStream.cpp b/src/modules/video/VideoStream.cpp index 1b7528b94..9a16a5c12 100644 --- a/src/modules/video/VideoStream.cpp +++ b/src/modules/video/VideoStream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/VideoStream.h b/src/modules/video/VideoStream.h index abe61c115..f9a0a0d19 100644 --- a/src/modules/video/VideoStream.h +++ b/src/modules/video/VideoStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/theora/OggDemuxer.cpp b/src/modules/video/theora/OggDemuxer.cpp index 30455afa9..390dadf35 100644 --- a/src/modules/video/theora/OggDemuxer.cpp +++ b/src/modules/video/theora/OggDemuxer.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/theora/OggDemuxer.h b/src/modules/video/theora/OggDemuxer.h index 2cb31259c..65edff46f 100644 --- a/src/modules/video/theora/OggDemuxer.h +++ b/src/modules/video/theora/OggDemuxer.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/theora/TheoraVideoStream.cpp b/src/modules/video/theora/TheoraVideoStream.cpp index a54ccb42d..3711466f9 100644 --- a/src/modules/video/theora/TheoraVideoStream.cpp +++ b/src/modules/video/theora/TheoraVideoStream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/theora/TheoraVideoStream.h b/src/modules/video/theora/TheoraVideoStream.h index 79b6c30db..ae45ab517 100644 --- a/src/modules/video/theora/TheoraVideoStream.h +++ b/src/modules/video/theora/TheoraVideoStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/theora/Video.cpp b/src/modules/video/theora/Video.cpp index 73a8dd714..f3fd0db2c 100644 --- a/src/modules/video/theora/Video.cpp +++ b/src/modules/video/theora/Video.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -34,6 +34,7 @@ namespace theora { Video::Video() + : love::video::Video("love.video.theora") { workerThread = new Worker(); workerThread->start(); @@ -51,11 +52,6 @@ VideoStream *Video::newVideoStream(love::filesystem::File *file) return stream; } -const char *Video::getName() const -{ - return "love.video.theora"; -} - Worker::Worker() : stopping(false) { diff --git a/src/modules/video/theora/Video.h b/src/modules/video/theora/Video.h index 0bd5265f1..744822d73 100644 --- a/src/modules/video/theora/Video.h +++ b/src/modules/video/theora/Video.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -46,9 +46,6 @@ public: Video(); virtual ~Video(); - // Implements Module - virtual const char *getName() const; - VideoStream *newVideoStream(love::filesystem::File* file); private: diff --git a/src/modules/video/wrap_Video.cpp b/src/modules/video/wrap_Video.cpp index 8329c9aa6..32b59c45e 100644 --- a/src/modules/video/wrap_Video.cpp +++ b/src/modules/video/wrap_Video.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/wrap_Video.h b/src/modules/video/wrap_Video.h index 16eaa4542..5c12ac558 100644 --- a/src/modules/video/wrap_Video.h +++ b/src/modules/video/wrap_Video.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/wrap_VideoStream.cpp b/src/modules/video/wrap_VideoStream.cpp index 34f1ae3c2..bbf75e822 100644 --- a/src/modules/video/wrap_VideoStream.cpp +++ b/src/modules/video/wrap_VideoStream.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/video/wrap_VideoStream.h b/src/modules/video/wrap_VideoStream.h index 39c03c125..4fa5fd4d5 100644 --- a/src/modules/video/wrap_VideoStream.h +++ b/src/modules/video/wrap_VideoStream.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/modules/window/Window.cpp b/src/modules/window/Window.cpp index 57dc62172..6b6b282da 100644 --- a/src/modules/window/Window.cpp +++ b/src/modules/window/Window.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -43,6 +43,11 @@ bool isHighDPIAllowed() return highDPIAllowed; } +Window::Window(const char *name) + : Module(M_WINDOW, name) +{ +} + Window::~Window() { } diff --git a/src/modules/window/Window.h b/src/modules/window/Window.h index d15091e43..cae80beab 100644 --- a/src/modules/window/Window.h +++ b/src/modules/window/Window.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -131,9 +131,6 @@ public: virtual ~Window(); - // Implements Module. - virtual ModuleType getModuleType() const { return M_WINDOW; } - virtual void setGraphics(graphics::Graphics *graphics) = 0; virtual bool setWindow(int width = 800, int height = 600, WindowSettings *settings = nullptr) = 0; @@ -217,7 +214,7 @@ public: virtual double fromPixels(double x) const = 0; virtual void fromPixels(double px, double py, double &wx, double &wy) const = 0; - virtual const void *getHandle() const = 0; + virtual void *getHandle() const = 0; virtual bool showMessageBox(const std::string &title, const std::string &message, MessageBoxType type, bool attachtowindow) = 0; virtual int showMessageBox(const MessageBoxData &data) = 0; @@ -239,6 +236,10 @@ public: static bool getConstant(DisplayOrientation in, const char *&out); static std::vector getConstants(DisplayOrientation); +protected: + + Window(const char *name); + private: static StringMap::Entry settingEntries[]; @@ -262,7 +263,7 @@ struct WindowSettings int vsync = 1; int msaa = 0; bool stencil = true; - int depth = 0; + bool depth = false; bool resizable = false; int minwidth = 1; int minheight = 1; diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index b124bd54e..c72d389aa 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -44,7 +44,9 @@ #include // SDL +#if !SDL_VERSION_ATLEAST(3, 0, 0) #include +#endif #ifdef LOVE_GRAPHICS_VULKAN #include @@ -88,7 +90,8 @@ namespace sdl { Window::Window() - : open(false) + : love::window::Window("love.window.sdl") + , open(false) , mouseGrabbed(false) , window(nullptr) , glcontext(nullptr) @@ -103,6 +106,12 @@ Window::Window() // Make sure the screensaver doesn't activate by default. setDisplaySleepEnabled(false); + +#ifdef LOVE_WINDOWS + // Turned off by default, because it (ironically) causes stuttering issues + // on some setups. More investigation is needed before enabling it. + canUseDwmFlush = SDL_GetHintBoolean("LOVE_GRAPHICS_VSYNC_DWM", SDL_FALSE) != SDL_FALSE; +#endif } Window::~Window() @@ -127,8 +136,7 @@ void Window::setGLFramebufferAttributes(bool sRGB) SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0); - // Always use 24/8 depth/stencil (make sure any Graphics implementations - // that have their own backbuffer match this, too). + // Always use 24/8 depth/stencil. // Changing this after initial window creation would need the context to be // destroyed and recreated, which we really don't want. SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); @@ -251,9 +259,6 @@ std::vector Window::getContextAttribsList() const // Do we want a debug context? bool debug = love::graphics::isDebugEnabled(); - const char *preferGL2hint = SDL_GetHint("LOVE_GRAPHICS_USE_GL2"); - bool preferGL2 = (preferGL2hint != nullptr && preferGL2hint[0] != '0'); - const char *preferGL3hint = SDL_GetHint("LOVE_GRAPHICS_USE_GL3"); bool preferGL3 = (preferGL3hint != nullptr && preferGL3hint[0] != '0'); @@ -261,22 +266,15 @@ std::vector Window::getContextAttribsList() const { {4, 3, false, debug}, {3, 3, false, debug}, - {2, 1, false, debug}, }; std::vector glescontexts = { {3, 2, true, debug}, {3, 0, true, debug}, - {2, 0, true, debug} }; - if (preferGL2) - { - std::swap(glcontexts[0], glcontexts[2]); - std::swap(glescontexts[0], glescontexts[2]); - } - else if (preferGL3) + if (preferGL3) { std::swap(glcontexts[0], glcontexts[1]); std::swap(glescontexts[0], glescontexts[1]); @@ -334,11 +332,19 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla if (window) { SDL_DestroyWindow(window); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_FlushEvents(SDL_EVENT_WINDOW_FIRST, SDL_EVENT_WINDOW_LAST); +#else SDL_FlushEvent(SDL_WINDOWEVENT); +#endif window = nullptr; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + window = SDL_CreateWindow(title.c_str(), w, h, windowflags); +#else window = SDL_CreateWindow(title.c_str(), x, y, w, h, windowflags); +#endif if (!window) { @@ -346,6 +352,10 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla return false; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SetWindowPosition(window, x, y); +#endif + if (attribs != nullptr && renderer == love::graphics::Renderer::RENDERER_OPENGL) { #ifdef LOVE_MACOS @@ -438,7 +448,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla if (failed) { std::string title = "Unable to create renderer"; - std::string message = "This program requires a graphics card and video drivers which support OpenGL 2.1 or OpenGL ES 2."; + std::string message = "This program requires a graphics card and video drivers which support OpenGL 3.3 or OpenGL ES 3.0."; if (!glversion.empty()) message += "\n\nDetected OpenGL version:\n" + glversion; @@ -464,6 +474,33 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla return true; } +#if SDL_VERSION_ATLEAST(3, 0, 0) +struct SDLDisplayIDs +{ + SDLDisplayIDs() + { + ids = SDL_GetDisplays(&count); + } + + ~SDLDisplayIDs() + { + if (ids) + SDL_free(ids); + } + + int count = 0; + SDL_DisplayID *ids = nullptr; +}; + +static SDL_DisplayID GetSDLDisplayIDForIndex(int displayindex) +{ + SDLDisplayIDs displayids; + if (displayindex < 0 || displayindex >= displayids.count) + return (SDL_DisplayID) 0; + return displayids.ids[displayindex]; +} +#endif + bool Window::setWindow(int width, int height, WindowSettings *settings) { if (!graphics.get()) @@ -485,15 +522,28 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) f.minwidth = std::max(f.minwidth, 1); f.minheight = std::max(f.minheight, 1); - f.displayindex = std::min(std::max(f.displayindex, 0), getDisplayCount() - 1); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDLDisplayIDs displays; + int displaycount = displays.count; +#else + int displaycount = getDisplayCount(); +#endif + + f.displayindex = std::min(std::max(f.displayindex, 0), displaycount - 1); // Use the desktop resolution if a width or height of 0 is specified. if (width == 0 || height == 0) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + const SDL_DisplayMode *mode = SDL_GetDesktopDisplayMode(displays.ids[f.displayindex]); + width = mode->w; + height = mode->h; +#else SDL_DisplayMode mode = {}; SDL_GetDesktopDisplayMode(f.displayindex, &mode); width = mode.w; height = mode.h; +#endif } // On Android, disable fullscreen first on window creation so it's @@ -528,43 +578,72 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) x = y = SDL_WINDOWPOS_UNDEFINED_DISPLAY(f.displayindex); } - SDL_DisplayMode fsmode = {0, width, height, 0, nullptr}; - - if (f.fullscreen && f.fstype == FULLSCREEN_EXCLUSIVE) - { - // Fullscreen window creation will bug out if no mode can be used. - if (SDL_GetClosestDisplayMode(f.displayindex, &fsmode, &fsmode) == nullptr) - { - // GetClosestDisplayMode will fail if we request a size larger - // than the largest available display mode, so we'll try to use - // the largest (first) mode in that case. - if (SDL_GetDisplayMode(f.displayindex, 0, &fsmode) < 0) - return false; - } - } - - bool needsetmode = false; - Uint32 sdlflags = 0; +#if SDL_VERSION_ATLEAST(3, 0, 0) + const SDL_DisplayMode *fsmode = nullptr; +#endif if (f.fullscreen) { - if (f.fstype == FULLSCREEN_DESKTOP) - sdlflags |= SDL_WINDOW_FULLSCREEN_DESKTOP; - else +#if SDL_VERSION_ATLEAST(3, 0, 0) + sdlflags |= SDL_WINDOW_FULLSCREEN; + + if (f.fstype == FULLSCREEN_EXCLUSIVE) { + SDL_DisplayID display = displays.ids[f.displayindex]; + fsmode = SDL_GetClosestFullscreenDisplayMode(display, width, height, 0, isHighDPIAllowed()); + if (fsmode == nullptr) + { + // GetClosestDisplayMode will fail if we request a size larger + // than the largest available display mode, so we'll try to use + // the largest (first) mode in that case. + int modecount = 0; + const SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(display, &modecount); + fsmode = modecount > 0 ? modes[0] : nullptr; + SDL_free(modes); + if (fsmode == nullptr) + return false; + } + } +#else + if (f.fstype == FULLSCREEN_EXCLUSIVE) + { + SDL_DisplayMode fsmode = {0, width, height, 0, nullptr}; + + // Fullscreen window creation will bug out if no mode can be used. + if (SDL_GetClosestDisplayMode(f.displayindex, &fsmode, &fsmode) == nullptr) + { + // GetClosestDisplayMode will fail if we request a size larger + // than the largest available display mode, so we'll try to use + // the largest (first) mode in that case. + if (SDL_GetDisplayMode(f.displayindex, 0, &fsmode) < 0) + return false; + } + sdlflags |= SDL_WINDOW_FULLSCREEN; width = fsmode.w; height = fsmode.h; } + else + { + sdlflags |= SDL_WINDOW_FULLSCREEN_DESKTOP; + } +#endif } + bool needsetmode = false; + if (renderer != windowRenderer && isOpen()) close(); if (isOpen()) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SetWindowFullscreenMode(window, fsmode); + if (SDL_SetWindowFullscreen(window, (sdlflags & SDL_WINDOW_FULLSCREEN) != 0) == 0 && renderer == graphics::RENDERER_OPENGL) +#else if (SDL_SetWindowFullscreen(window, sdlflags) == 0 && renderer == graphics::RENDERER_OPENGL) +#endif SDL_GL_MakeCurrent(window, glcontext); if (!f.fullscreen) @@ -595,11 +674,29 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) sdlflags |= SDL_WINDOW_BORDERLESS; // Note: this flag is ignored on Windows. +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (isHighDPIAllowed()) + sdlflags |= SDL_WINDOW_HIGH_PIXEL_DENSITY; +#else if (isHighDPIAllowed()) sdlflags |= SDL_WINDOW_ALLOW_HIGHDPI; +#endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + Uint32 createflags = sdlflags & (~SDL_WINDOW_FULLSCREEN); + + if (!createWindowAndContext(x, y, width, height, createflags, renderer)) + return false; + + if (f.fullscreen) + { + SDL_SetWindowFullscreenMode(window, fsmode); + SDL_SetWindowFullscreen(window, SDL_TRUE); + } +#else if (!createWindowAndContext(x, y, width, height, sdlflags, renderer)) return false; +#endif needsetmode = true; } @@ -639,12 +736,12 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) context = (void *) SDL_Metal_GetLayer(metalView); #endif - graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.msaa); + graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.depth, f.msaa); this->settings.msaa = graphics->getBackbufferMSAA(); } else { - graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight); + graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.depth, f.msaa); } } @@ -655,6 +752,10 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) love::android::setImmersive(fullscreen); #endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SyncWindow(window); +#endif + return true; } @@ -663,9 +764,16 @@ bool Window::onSizeChanged(int width, int height) if (!window) return false; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_GetWindowSize(window, &windowWidth, &windowHeight); +#else windowWidth = width; windowHeight = height; +#endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (SDL_GetWindowSizeInPixels(window, &pixelWidth, &pixelHeight) < 0) +#else // TODO: Use SDL_GetWindowSizeInPixels here when supported. if (glcontext != nullptr) SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); @@ -678,6 +786,7 @@ bool Window::onSizeChanged(int width, int height) SDL_Vulkan_GetDrawableSize(window, &pixelWidth, &pixelHeight); #endif else +#endif { pixelWidth = width; pixelHeight = height; @@ -687,7 +796,7 @@ bool Window::onSizeChanged(int width, int height) { double scaledw, scaledh; fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh); - graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight); + graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight); } return true; @@ -695,6 +804,10 @@ bool Window::onSizeChanged(int width, int height) void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphicsViewport) { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SyncWindow(window); +#endif + Uint32 wflags = SDL_GetWindowFlags(window); // Set the new display mode as the current display mode. @@ -703,6 +816,9 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi pixelWidth = windowWidth; pixelHeight = windowHeight; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_GetWindowSizeInPixels(window, &pixelWidth, &pixelHeight); +#else // TODO: Use SDL_GetWindowSizeInPixels here when supported. if ((wflags & SDL_WINDOW_OPENGL) != 0) SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); @@ -714,8 +830,13 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi else if ((wflags & SDL_WINDOW_VULKAN) != 0) SDL_Vulkan_GetDrawableSize(window, &pixelWidth, &pixelHeight); #endif +#endif +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (((wflags & SDL_WINDOW_FULLSCREEN) == SDL_WINDOW_FULLSCREEN) && SDL_GetWindowFullscreenMode(window) == nullptr) +#else if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) +#endif { settings.fullscreen = true; settings.fstype = FULLSCREEN_DESKTOP; @@ -745,7 +866,11 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi getPosition(settings.x, settings.y, settings.displayindex); +#if SDL_VERSION_ATLEAST(3, 0, 0) + setHighDPIAllowed((wflags & SDL_WINDOW_HIGH_PIXEL_DENSITY) != 0); +#else setHighDPIAllowed((wflags & SDL_WINDOW_ALLOW_HIGHDPI) != 0); +#endif settings.usedpiscale = newsettings.usedpiscale; @@ -760,18 +885,26 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi settings.stencil = newsettings.stencil; settings.depth = newsettings.depth; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDLDisplayIDs displayids; + const SDL_DisplayMode *dmode = SDL_GetCurrentDisplayMode(displayids.ids[settings.displayindex]); + + // May be 0 if the refresh rate can't be determined. + settings.refreshrate = dmode->refresh_rate; +#else SDL_DisplayMode dmode = {}; SDL_GetCurrentDisplayMode(settings.displayindex, &dmode); // May be 0 if the refresh rate can't be determined. settings.refreshrate = (double) dmode.refresh_rate; +#endif // Update the viewport size now instead of waiting for event polling. if (updateGraphicsViewport && graphics.get()) { double scaledw, scaledh; fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh); - graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight); + graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight); } } @@ -822,7 +955,11 @@ void Window::close(bool allowExceptions) // The old window may have generated pending events which are no longer // relevant. Destroy them all! +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_FlushEvents(SDL_EVENT_WINDOW_FIRST, SDL_EVENT_WINDOW_LAST); +#else SDL_FlushEvent(SDL_WINDOWEVENT); +#endif } open = false; @@ -840,6 +977,21 @@ bool Window::setFullscreen(bool fullscreen, FullscreenType fstype) newsettings.fullscreen = fullscreen; newsettings.fstype = fstype; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_bool sdlflags = fullscreen; + if (fullscreen) + { + if (fstype == FULLSCREEN_DESKTOP) + SDL_SetWindowFullscreenMode(window, nullptr); + else + { + SDL_DisplayID displayid = SDL_GetDisplayForWindow(window); + const SDL_DisplayMode *mode = SDL_GetClosestFullscreenDisplayMode(displayid, windowWidth, windowHeight, 0, isHighDPIAllowed()); + if (mode != nullptr) + SDL_SetWindowFullscreenMode(window, mode); + } + } +#else Uint32 sdlflags = 0; if (fullscreen) @@ -858,6 +1010,7 @@ bool Window::setFullscreen(bool fullscreen, FullscreenType fstype) SDL_SetWindowDisplayMode(window, &mode); } } +#endif #ifdef LOVE_ANDROID love::android::setImmersive(fullscreen); @@ -882,12 +1035,21 @@ bool Window::setFullscreen(bool fullscreen) int Window::getDisplayCount() const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDLDisplayIDs displayids; + return displayids.count; +#else return SDL_GetNumVideoDisplays(); +#endif } const char *Window::getDisplayName(int displayindex) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + const char *name = SDL_GetDisplayName(GetSDLDisplayIDForIndex(displayindex)); +#else const char *name = SDL_GetDisplayName(displayindex); +#endif if (name == nullptr) throw love::Exception("Invalid display index: %d", displayindex + 1); @@ -897,7 +1059,11 @@ const char *Window::getDisplayName(int displayindex) const Window::DisplayOrientation Window::getDisplayOrientation(int displayindex) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + switch (SDL_GetCurrentDisplayOrientation(GetSDLDisplayIDForIndex(displayindex))) +#else switch (SDL_GetDisplayOrientation(displayindex)) +#endif { case SDL_ORIENTATION_UNKNOWN: return ORIENTATION_UNKNOWN; case SDL_ORIENTATION_LANDSCAPE: return ORIENTATION_LANDSCAPE; @@ -913,12 +1079,22 @@ std::vector Window::getFullscreenSizes(int displayindex) con { std::vector sizes; +#if SDL_VERSION_ATLEAST(3, 0, 0) + int count = 0; + const SDL_DisplayMode **modes = SDL_GetFullscreenDisplayModes(GetSDLDisplayIDForIndex(displayindex), &count); + + for (int i = 0; i < count; i++) + { + // TODO: other mode properties? + WindowSize w = {modes[i]->w, modes[i]->h}; +#else for (int i = 0; i < SDL_GetNumDisplayModes(displayindex); i++) { SDL_DisplayMode mode = {}; SDL_GetDisplayMode(displayindex, i, &mode); WindowSize w = {mode.w, mode.h}; +#endif // SDL2's display mode list has multiple entries for modes of the same // size with different bits per pixel, so we need to filter those out. @@ -926,11 +1102,24 @@ std::vector Window::getFullscreenSizes(int displayindex) con sizes.push_back(w); } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_free(modes); +#endif + return sizes; } void Window::getDesktopDimensions(int displayindex, int &width, int &height) const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + const SDL_DisplayMode *mode = SDL_GetDesktopDisplayMode(GetSDLDisplayIDForIndex(displayindex)); + if (mode != nullptr) + { + // TODO: other properties? + width = mode->w; + height = mode->h; + } +#else if (displayindex >= 0 && displayindex < getDisplayCount()) { SDL_DisplayMode mode = {}; @@ -938,6 +1127,7 @@ void Window::getDesktopDimensions(int displayindex, int &width, int &height) con width = mode.w; height = mode.h; } +#endif else { width = 0; @@ -961,6 +1151,10 @@ void Window::setPosition(int x, int y, int displayindex) SDL_SetWindowPosition(window, x, y); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SyncWindow(window); +#endif + settings.useposition = true; } @@ -973,7 +1167,21 @@ void Window::getPosition(int &x, int &y, int &displayindex) return; } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DisplayID displayid = SDL_GetDisplayForWindow(window); + SDLDisplayIDs displayids; + displayindex = 0; + for (int i = 0; i < displayids.count; i++) + { + if (displayids.ids[i] == displayid) + { + displayindex = i; + break; + } + } +#else displayindex = std::max(SDL_GetWindowDisplayIndex(window), 0); +#endif SDL_GetWindowPosition(window, &x, &y); @@ -983,7 +1191,11 @@ void Window::getPosition(int &x, int &y, int &displayindex) if (x != 0 || y != 0) { SDL_Rect displaybounds = {}; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_GetDisplayBounds(displayid, &displaybounds); +#else SDL_GetDisplayBounds(displayindex, &displaybounds); +#endif x -= displaybounds.x; y -= displaybounds.y; @@ -1048,6 +1260,7 @@ bool Window::setIcon(love::image::ImageData *imgd) if (!window) return false; +#if !SDL_VERSION_ATLEAST(3, 0, 0) Uint32 rmask, gmask, bmask, amask; #ifdef LOVE_BIG_ENDIAN rmask = 0xFF000000; @@ -1059,6 +1272,7 @@ bool Window::setIcon(love::image::ImageData *imgd) gmask = 0x0000FF00; bmask = 0x00FF0000; amask = 0xFF000000; +#endif #endif int w = imgd->getWidth(); @@ -1066,19 +1280,21 @@ bool Window::setIcon(love::image::ImageData *imgd) int bytesperpixel = (int) getPixelFormatBlockSize(imgd->getFormat()); int pitch = w * bytesperpixel; - SDL_Surface *sdlicon = nullptr; - - { - // We don't want another thread modifying the ImageData mid-copy. - love::thread::Lock lock(imgd->getMutex()); - sdlicon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, bytesperpixel * 8, pitch, rmask, gmask, bmask, amask); - } +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_Surface *sdlicon = SDL_CreateSurfaceFrom(imgd->getData(), w, h, pitch, SDL_PIXELFORMAT_RGBA8888); +#else + SDL_Surface *sdlicon = SDL_CreateRGBSurfaceFrom(imgd->getData(), w, h, bytesperpixel * 8, pitch, rmask, gmask, bmask, amask); +#endif if (!sdlicon) return false; SDL_SetWindowIcon(window, sdlicon); +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DestroySurface(sdlicon); +#else SDL_FreeSurface(sdlicon); +#endif return true; } @@ -1096,8 +1312,18 @@ void Window::setVSync(int vsync) // Check if adaptive vsync was requested but not supported, and fall // back to regular vsync if so. +#if SDL_VERSION_ATLEAST(3, 0, 0) + if (vsync == -1) + { + int actualvsync = 0; + SDL_GL_GetSwapInterval(&actualvsync); + if (actualvsync != -1) + SDL_GL_SetSwapInterval(1); + } +#else if (vsync == -1 && SDL_GL_GetSwapInterval() != -1) SDL_GL_SetSwapInterval(1); +#endif } #ifdef LOVE_GRAPHICS_VULKAN @@ -1120,7 +1346,15 @@ void Window::setVSync(int vsync) int Window::getVSync() const { if (glcontext != nullptr) + { +#if SDL_VERSION_ATLEAST(3, 0, 0) + int interval = 0; + SDL_GL_GetSwapInterval(&interval); + return interval; +#else return SDL_GL_GetSwapInterval(); +#endif + } #if defined(LOVE_GRAPHICS_METAL) if (metalView != nullptr) @@ -1155,7 +1389,11 @@ void Window::setDisplaySleepEnabled(bool enable) bool Window::isDisplaySleepEnabled() const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + return SDL_ScreenSaverEnabled() != SDL_FALSE; +#else return SDL_IsScreenSaverEnabled() != SDL_FALSE; +#endif } void Window::minimize() @@ -1216,7 +1454,7 @@ void Window::swapBuffers() // - DWM refreshes don't always match the refresh rate of the monitor the window is in (or the requested swap // interval), so we only use it when they do match. // - The user may force GL vsync, and DwmFlush shouldn't be used together with GL vsync. - if (!settings.fullscreen && swapInterval == 1) + if (canUseDwmFlush && !settings.fullscreen && swapInterval == 1) { // Desktop composition is always enabled in Windows 8+. But DwmIsCompositionEnabled won't always return true... // (see DwmIsCompositionEnabled docs). @@ -1230,15 +1468,27 @@ void Window::swapBuffers() dwmRefreshRate = (double)info.rateRefresh.uiNumerator / (double)info.rateRefresh.uiDenominator; SDL_DisplayMode dmode = {}; +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_DisplayID display = SDL_GetDisplayForWindow(window); + const SDL_DisplayMode* modePtr = SDL_GetCurrentDisplayMode(display); + if (modePtr) + dmode = *modePtr; +#else int displayindex = SDL_GetWindowDisplayIndex(window); if (displayindex >= 0) SDL_GetCurrentDisplayMode(displayindex, &dmode); +#endif if (dmode.refresh_rate > 0 && dwmRefreshRate > 0 && (fabs(dmode.refresh_rate - dwmRefreshRate) < 2)) { SDL_GL_SetSwapInterval(0); +#if SDL_VERSION_ATLEAST(3, 0, 0) + int interval = 0; + if (SDL_GL_GetSwapInterval(&interval) == 0 && interval == 0) +#else if (SDL_GL_GetSwapInterval() == 0) +#endif useDwmFlush = true; else SDL_GL_SetSwapInterval(swapInterval); @@ -1271,20 +1521,32 @@ bool Window::hasMouseFocus() const bool Window::isVisible() const { +#if SDL_VERSION_ATLEAST(3, 0, 0) + return window && (SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN) == 0; +#else return window && (SDL_GetWindowFlags(window) & SDL_WINDOW_SHOWN) != 0; +#endif } void Window::setMouseGrab(bool grab) { mouseGrabbed = grab; if (window) +#if SDL_VERSION_ATLEAST(3, 0, 0) + SDL_SetWindowMouseGrab(window, (SDL_bool) grab); +#else SDL_SetWindowGrab(window, (SDL_bool) grab); +#endif } bool Window::isMouseGrabbed() const { if (window) +#if SDL_VERSION_ATLEAST(3, 0, 0) + return SDL_GetWindowMouseGrab(window); +#else return SDL_GetWindowGrab(window) != SDL_FALSE; +#endif else return mouseGrabbed; } @@ -1406,7 +1668,7 @@ void Window::fromPixels(double px, double py, double &wx, double &wy) const wy = py / scale; } -const void *Window::getHandle() const +void *Window::getHandle() const { return window; } @@ -1450,7 +1712,11 @@ int Window::showMessageBox(const MessageBoxData &data) { SDL_MessageBoxButtonData sdlbutton = {}; +#if SDL_VERSION_ATLEAST(3, 0, 0) + sdlbutton.buttonID = i; +#else sdlbutton.buttonid = i; +#endif sdlbutton.text = data.buttons[i].c_str(); if (i == data.enterButtonIndex) @@ -1477,26 +1743,30 @@ void Window::requestAttention(bool continuous) if (hasFocus()) return; + FLASHWINFO flashinfo = { sizeof(FLASHWINFO) }; + +#if SDL_VERSION_ATLEAST(3, 0, 0) + flashinfo.hwnd = (HWND)SDL_GetProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL); +#else SDL_SysWMinfo wminfo = {}; SDL_VERSION(&wminfo.version); + if (!SDL_GetWindowWMInfo(window, &wminfo)) + return; - if (SDL_GetWindowWMInfo(window, &wminfo)) + flashinfo.hwnd = wminfo.info.win.window; +#endif + + flashinfo.uCount = 1; + flashinfo.dwFlags = FLASHW_ALL; + + if (continuous) { - FLASHWINFO flashinfo = {}; - flashinfo.cbSize = sizeof(FLASHWINFO); - flashinfo.hwnd = wminfo.info.win.window; - flashinfo.uCount = 1; - flashinfo.dwFlags = FLASHW_ALL; - - if (continuous) - { - flashinfo.uCount = 0; - flashinfo.dwFlags |= FLASHW_TIMERNOFG; - } - - FlashWindowEx(&flashinfo); + flashinfo.uCount = 0; + flashinfo.dwFlags |= FLASHW_TIMERNOFG; } + FlashWindowEx(&flashinfo); + #elif defined(LOVE_MACOS) love::macos::requestAttention(continuous); @@ -1510,11 +1780,6 @@ void Window::requestAttention(bool continuous) // TODO: Linux? } -const char *Window::getName() const -{ - return "love.window.sdl"; -} - } // sdl } // window } // love diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index d97dbd38a..96b857357 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -123,15 +123,13 @@ public: double fromPixels(double x) const override; void fromPixels(double px, double py, double &wx, double &wy) const override; - const void *getHandle() const override; + void *getHandle() const override; bool showMessageBox(const std::string &title, const std::string &message, MessageBoxType type, bool attachtowindow) override; int showMessageBox(const MessageBoxData &data) override; void requestAttention(bool continuous) override; - const char *getName() const override; - private: struct ContextAttribs @@ -164,6 +162,10 @@ private: WindowSettings settings; StrongRef icon; +#ifdef LOVE_WINDOWS + bool canUseDwmFlush = false; +#endif + bool open; bool mouseGrabbed; diff --git a/src/modules/window/wrap_Window.cpp b/src/modules/window/wrap_Window.cpp index 3d3d86708..19efd9991 100644 --- a/src/modules/window/wrap_Window.cpp +++ b/src/modules/window/wrap_Window.cpp @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -68,7 +68,6 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings) settings.fullscreen = luax_boolflag(L, idx, settingName(Window::SETTING_FULLSCREEN), settings.fullscreen); settings.msaa = luax_intflag(L, idx, settingName(Window::SETTING_MSAA), settings.msaa); settings.stencil = luax_boolflag(L, idx, settingName(Window::SETTING_STENCIL), settings.stencil); - settings.depth = luax_intflag(L, idx, settingName(Window::SETTING_DEPTH), settings.depth); settings.resizable = luax_boolflag(L, idx, settingName(Window::SETTING_RESIZABLE), settings.resizable); settings.minwidth = luax_intflag(L, idx, settingName(Window::SETTING_MIN_WIDTH), settings.minwidth); settings.minheight = luax_intflag(L, idx, settingName(Window::SETTING_MIN_HEIGHT), settings.minheight); @@ -76,6 +75,16 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings) settings.centered = luax_boolflag(L, idx, settingName(Window::SETTING_CENTERED), settings.centered); settings.usedpiscale = luax_boolflag(L, idx, settingName(Window::SETTING_USE_DPISCALE), settings.usedpiscale); + lua_getfield(L, idx, settingName(Window::SETTING_DEPTH)); + if (lua_type(L, -1) == LUA_TNUMBER) + { + luax_markdeprecated(L, 1, "window.depth number", API_FIELD, DEPRECATED_REPLACED, "window.depth boolean field"); + settings.depth = (int) luaL_checknumber(L, -1); + } + else if (!lua_isnoneornil(L, -1)) + settings.depth = lua_toboolean(L, -1); + lua_pop(L, 1); + settings.displayindex = luax_intflag(L, idx, settingName(Window::SETTING_DISPLAYINDEX), settings.displayindex + 1) - 1; lua_getfield(L, idx, settingName(Window::SETTING_DISPLAY)); if (!lua_isnoneornil(L, -1)) @@ -197,7 +206,7 @@ int w_getMode(lua_State *L) luax_pushboolean(L, settings.stencil); lua_setfield(L, -2, settingName(Window::SETTING_STENCIL)); - lua_pushinteger(L, settings.depth); + luax_pushboolean(L, settings.depth); lua_setfield(L, -2, settingName(Window::SETTING_DEPTH)); luax_pushboolean(L, settings.resizable); @@ -339,6 +348,7 @@ int w_isOpen(lua_State *L) int w_close(lua_State *L) { + luax_markdeprecated(L, 1, "love.window.close", API_FUNCTION, DEPRECATED_NO_REPLACEMENT, nullptr); luax_catchexcept(L, [&]() { instance()->close(); }); return 0; } @@ -638,6 +648,12 @@ int w_requestAttention(lua_State *L) return 0; } +int w_getPointer(lua_State *L) +{ + lua_pushlightuserdata(L, instance()->getHandle()); + return 1; +} + static const luaL_Reg functions[] = { { "getDisplayCount", w_getDisplayCount }, @@ -679,6 +695,7 @@ static const luaL_Reg functions[] = { "isMinimized", w_isMinimized }, { "showMessageBox", w_showMessageBox }, { "requestAttention", w_requestAttention }, + { "getPointer", w_getPointer }, { 0, 0 } }; diff --git a/src/modules/window/wrap_Window.h b/src/modules/window/wrap_Window.h index 382ce7c65..6c1069ebf 100644 --- a/src/modules/window/wrap_Window.h +++ b/src/modules/window/wrap_Window.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages diff --git a/src/scripts/auto.lua b/src/scripts/auto.lua index ce59487f6..8f70ee667 100644 --- a/src/scripts/auto.lua +++ b/src/scripts/auto.lua @@ -7,7 +7,7 @@ local max_width = 18 local pattern = [[ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -77,13 +77,14 @@ local function auto(name) local out_data = "" --go through the input file line-by-line for line in src_file:lines() do + line = line:gsub("\r", "") --if the line is non-empty if #line > 0 then --set the counter to -1 --this will start a new line (see tohex) counter = -1 --append the output to what we had, plus a newline character (0x0a is newline) - out_data = ("%s%s0x0a,"):format(out_data, line:gsub("\r", ""):gsub(".", tohex)) + out_data = ("%s%s0x0a,"):format(out_data, line:gsub(".", tohex)) else out_data = out_data .. "\n\t0x0a," end diff --git a/src/scripts/nogame.lua b/src/scripts/nogame.lua index ea66f72af..3fe8c67df 100644 --- a/src/scripts/nogame.lua +++ b/src/scripts/nogame.lua @@ -1,5 +1,5 @@ --[[ -Copyright (c) 2006-2023 LOVE Development Team +Copyright (c) 2006-2024 LOVE Development Team This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -2948,9 +2948,8 @@ function love.nogame() self.body = love.physics.newBody(world, x, y, "dynamic") self.body:setLinearDamping(0.8) self.body:setAngularDamping(0.8) - self.shape = love.physics.newPolygonShape(-55, -60, 0, 90, 55, -60) - self.fixture = love.physics.newFixture(self.body, self.shape, 1) - self.fixture:setRestitution(0.5) + self.shape = love.physics.newPolygonShape(self.body, -55, -60, 0, 90, 55, -60) + self.shape:setRestitution(0.5) self.img_normal = img_duckloon_normal self.img_blink = img_duckloon_blink self.img = self.img_normal @@ -3041,8 +3040,8 @@ function love.nogame() link.body = love.physics.newBody(world, link.x, link.y, "dynamic") link.body:setLinearDamping(0.5) link.body:setAngularDamping(0.5) - link.shape = love.physics.newCircleShape(link.radius) - link.fixture = love.physics.newFixture(link.body, link.shape, 0.1 / i) + link.shape = love.physics.newCircleShape(link.body, link.radius) + link.shape:setDensity(0.1 / i) link.state = State(link.body) -- Note: every link must also be attached to the Duckloon. Otherwise the diff --git a/src/scripts/nogame.lua.h b/src/scripts/nogame.lua.h index 3bcdeb681..83feae732 100644 --- a/src/scripts/nogame.lua.h +++ b/src/scripts/nogame.lua.h @@ -1,5 +1,5 @@ /** - * Copyright (c) 2006-2023 LOVE Development Team + * Copyright (c) 2006-2024 LOVE Development Team * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages @@ -27,7 +27,7 @@ const unsigned char nogame_lua[] = 0x2d, 0x2d, 0x5b, 0x5b, 0x0a, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74, 0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x36, - 0x2d, 0x32, 0x30, 0x32, 0x31, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, + 0x2d, 0x32, 0x30, 0x32, 0x34, 0x20, 0x4c, 0x4f, 0x56, 0x45, 0x20, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20, 0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65, 0x20, 0x69, 0x73, 0x20, 0x70, @@ -11440,14 +11440,11 @@ const unsigned char nogame_lua[] = 0x75, 0x6c, 0x61, 0x72, 0x44, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x2e, 0x38, 0x29, 0x0a, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x50, 0x6f, 0x6c, 0x79, 0x67, - 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x2d, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x2c, 0x20, - 0x30, 0x2c, 0x20, 0x39, 0x30, 0x2c, 0x20, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x29, 0x0a, - 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x3d, 0x20, 0x6c, - 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x46, 0x69, 0x78, - 0x74, 0x75, 0x72, 0x65, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x20, 0x73, 0x65, - 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2c, 0x20, 0x31, 0x29, 0x0a, - 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x3a, 0x73, 0x65, 0x74, - 0x52, 0x65, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, + 0x6f, 0x6e, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, + 0x20, 0x2d, 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x2c, 0x20, 0x30, 0x2c, 0x20, 0x39, 0x30, 0x2c, 0x20, + 0x35, 0x35, 0x2c, 0x20, 0x2d, 0x36, 0x30, 0x29, 0x0a, + 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x3a, 0x73, 0x65, 0x74, 0x52, 0x65, + 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, 0x09, 0x09, 0x73, 0x65, 0x6c, 0x66, 0x2e, 0x69, 0x6d, 0x67, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x69, 0x6d, 0x67, 0x5f, 0x64, 0x75, 0x63, 0x6b, 0x6c, 0x6f, 0x6f, 0x6e, 0x5f, 0x6e, 0x6f, 0x72, 0x6d, 0x61, 0x6c, 0x0a, @@ -11619,13 +11616,10 @@ const unsigned char nogame_lua[] = 0x67, 0x75, 0x6c, 0x61, 0x72, 0x44, 0x61, 0x6d, 0x70, 0x69, 0x6e, 0x67, 0x28, 0x30, 0x2e, 0x35, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x43, 0x69, 0x72, 0x63, - 0x6c, 0x65, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, - 0x73, 0x29, 0x0a, - 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x66, 0x69, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x3d, 0x20, - 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x73, 0x2e, 0x6e, 0x65, 0x77, 0x46, 0x69, - 0x78, 0x74, 0x75, 0x72, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x20, 0x6c, - 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x2c, 0x20, 0x30, 0x2e, 0x31, 0x20, 0x2f, 0x20, 0x69, - 0x29, 0x0a, + 0x6c, 0x65, 0x53, 0x68, 0x61, 0x70, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x2c, + 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x72, 0x61, 0x64, 0x69, 0x75, 0x73, 0x29, 0x0a, + 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x68, 0x61, 0x70, 0x65, 0x3a, 0x73, 0x65, 0x74, 0x44, + 0x65, 0x6e, 0x73, 0x69, 0x74, 0x79, 0x28, 0x30, 0x2e, 0x31, 0x20, 0x2f, 0x20, 0x69, 0x29, 0x0a, 0x09, 0x09, 0x09, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x20, 0x3d, 0x20, 0x53, 0x74, 0x61, 0x74, 0x65, 0x28, 0x6c, 0x69, 0x6e, 0x6b, 0x2e, 0x62, 0x6f, 0x64, 0x79, 0x29, 0x0a, 0x0a, diff --git a/testing/classes/TestMethod.lua b/testing/classes/TestMethod.lua new file mode 100644 index 000000000..405b9275b --- /dev/null +++ b/testing/classes/TestMethod.lua @@ -0,0 +1,629 @@ +-- @class - TestMethod +-- @desc - used to run a specific method from a module's /test/ suite +-- each assertion is tracked and then printed to output +TestMethod = { + + + -- @method - TestMethod:new() + -- @desc - create a new TestMethod object + -- @param {string} method - string of method name to run + -- @param {TestMethod} testmethod - parent testmethod this test belongs to + -- @return {table} - returns the new Test object + new = function(self, method, testmodule) + local test = { + testmodule = testmodule, + method = method, + asserts = {}, + start = love.timer.getTime(), + finish = 0, + count = 0, + passed = false, + skipped = false, + skipreason = '', + rgba_tolerance = 0, + pixel_tolerance = 0, + fatal = '', + message = nil, + result = {}, + colors = { + red = {1, 0, 0, 1}, + redpale = {1, 0.5, 0.5, 1}, + red07 = {0.7, 0, 0, 1}, + green = {0, 1, 0, 1}, + greenhalf = {0, 0.5, 0, 1}, + greenfade = {0, 1, 0, 0.5}, + blue = {0, 0, 1, 1}, + bluefade = {0, 0, 1, 0.5}, + yellow = {1, 1, 0, 1}, + pink = {1, 0, 1, 1}, + black = {0, 0, 0, 1}, + white = {1, 1, 1, 1}, + lovepink = {214/255, 86/255, 151/255, 1}, + loveblue = {83/255, 168/255, 220/255, 1} + }, + imgs = 1, + delay = 0, + delayed = false, + store = {}, + co = nil + } + setmetatable(test, self) + self.__index = self + return test + end, + + + -- @method - TestMethod:assertEquals() + -- @desc - used to assert two values are equals + -- @param {any} expected - expected value of the test + -- @param {any} actual - actual value of the test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertEquals = function(self, expected, actual, label) + self.count = self.count + 1 + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = expected == actual, + message = 'expected \'' .. tostring(expected) .. '\' got \'' .. + tostring(actual) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertTrue() + -- @desc - used to assert a value is true + -- @param {any} value - value to test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertTrue = function(self, value, label) + self.count = self.count + 1 + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = value == true, + message = 'expected \'true\' got \'' .. + tostring(value) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertFalse() + -- @desc - used to assert a value is false + -- @param {any} value - value to test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertFalse = function(self, value, label) + self.count = self.count + 1 + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = value == false, + message = 'expected \'false\' got \'' .. + tostring(value) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertNotEquals() + -- @desc - used to assert two values are not equal + -- @param {any} expected - expected value of the test + -- @param {any} actual - actual value of the test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertNotEquals = function(self, expected, actual, label) + self.count = self.count + 1 + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = expected ~= actual, + message = 'avoiding \'' .. tostring(expected) .. '\' got \'' .. + tostring(actual) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertRange() + -- @desc - used to check a value is within an expected range + -- @param {number} actual - actual value of the test + -- @param {number} min - minimum value the actual should be >= to + -- @param {number} max - maximum value the actual should be <= to + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertRange = function(self, actual, min, max, label) + self.count = self.count + 1 + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = actual >= min and actual <= max, + message = 'value \'' .. tostring(actual) .. '\' out of range \'' .. + tostring(min) .. '-' .. tostring(max) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertMatch() + -- @desc - used to check a value is within a list of values + -- @param {number} list - list of valid values for the test + -- @param {number} actual - actual value of the test to check is in the list + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertMatch = function(self, list, actual, label) + self.count = self.count + 1 + local found = false + for l=1,#list do + if list[l] == actual then found = true end; + end + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = found == true, + message = 'value \'' .. tostring(actual) .. '\' not found in \'' .. + table.concat(list, ',') .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertGreaterEqual() + -- @desc - used to check a value is >= than a certain target value + -- @param {any} target - value to check the test agaisnt + -- @param {any} actual - actual value of the test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertGreaterEqual = function(self, target, actual, label) + self.count = self.count + 1 + local passing = false + if target ~= nil and actual ~= nil then + passing = actual >= target + end + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = passing, + message = 'value \'' .. tostring(actual) .. '\' not >= \'' .. + tostring(target) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertLessEqual() + -- @desc - used to check a value is <= than a certain target value + -- @param {any} target - value to check the test agaisnt + -- @param {any} actual - actual value of the test + -- @param {string} label - label for this test to use in exports + -- @return {nil} + assertLessEqual = function(self, target, actual, label) + self.count = self.count + 1 + local passing = false + if target ~= nil and actual ~= nil then + passing = actual <= target + end + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = passing, + message = 'value \'' .. tostring(actual) .. '\' not <= \'' .. + tostring(target) .. '\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertObject() + -- @desc - used to check a table is a love object, this runs 3 seperate + -- tests to check table has the basic properties of an object + -- @note - actual object functionality tests have their own methods + -- @param {table} obj - table to check is a valid love object + -- @return {nil} + assertObject = function(self, obj) + self:assertNotNil(obj) + self:assertEquals('userdata', type(obj), 'check is userdata') + if obj ~= nil then + self:assertNotEquals(nil, obj:type(), 'check has :type()') + end + end, + + + -- @method - TestMethod:assertCoords() + -- @desc - used to check a pair of values (usually coordinates) + -- @param {table} obj - table to check is a valid love object + -- @return {nil} + assertCoords = function(self, expected, actual, label) + self.count = self.count + 1 + local passing = false + if expected ~= nil and actual ~= nil then + if expected[1] == actual[1] and expected[2] == actual[2] then + passing = true + end + end + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = passing, + message = 'expected \'' .. tostring(expected[1]) .. 'x,' .. + tostring(expected[2]) .. 'y\' got \'' .. + tostring(actual[1]) .. 'x,' .. tostring(actual[2]) .. 'y\'', + test = label or 'no label given' + }) + end, + + + -- @method - TestMethod:assertNotNil() + -- @desc - quick assert for value not nil + -- @param {any} value - value to check not nil + -- @return {nil} + assertNotNil = function (self, value, err) + self:assertNotEquals(nil, value, 'check not nil') + if err ~= nil then + table.insert(self.asserts, { + key = 'assert ' .. tostring(self.count), + passed = false, + message = err, + test = 'assert not nil catch' + }) + end + end, + + + -- @method - TestMethod:compareImg() + -- @desc - compares a given image to the 'expected' version, with a tolerance of + -- 1px in any direction, and then saves it as the 'actual' version for + -- report viewing + -- @param {table} imgdata - imgdata to save as a png + -- @return {nil} + compareImg = function(self, imgdata) + local expected_path = 'tempoutput/expected/love.test.graphics.' .. + self.method .. '-' .. tostring(self.imgs) .. '.png' + local ok, chunk, _ = pcall(love.image.newImageData, expected_path) + if ok == false then return self:assertEquals(true, false, chunk) end + local expected = chunk + local iw = imgdata:getWidth()-1 + local ih = imgdata:getHeight()-1 + local differences = {} + local rgba_tolerance = self.rgba_tolerance * (1/255) + + -- for each pixel, compare the expected vs the actual pixel data + -- by default rgba_tolerance is 0 + for ix=0,iw do + for iy=0,ih do + local ir, ig, ib, ia = imgdata:getPixel(ix, iy) + local points = { + {expected:getPixel(ix, iy)} + } + if self.pixel_tolerance > 0 then + if ix > 0 and iy < ih-1 then table.insert(points, {expected:getPixel(ix-1, iy+1)}) end + if ix > 0 then table.insert(points, {expected:getPixel(ix-1, iy)}) end + if ix > 0 and iy > 0 then table.insert(points, {expected:getPixel(ix-1, iy-1)}) end + if iy < ih-1 then table.insert(points, {expected:getPixel(ix, iy+1)}) end + if iy > 0 then table.insert(points, {expected:getPixel(ix, iy-1)}) end + if ix < iw-1 and iy < ih-1 then table.insert(points, {expected:getPixel(ix+1, iy+1)}) end + if ix < iw-1 then table.insert(points, {expected:getPixel(ix+1, iy)}) end + if ix < iw-1 and iy > 0 then table.insert(points, {expected:getPixel(ix+1, iy-1)}) end + end + local has_match_r = false + local has_match_g = false + local has_match_b = false + local has_match_a = false + for t=1,#points do + local epoint = points[t] + if ir >= epoint[1] - rgba_tolerance and ir <= epoint[1] + rgba_tolerance then has_match_r = true; end + if ig >= epoint[2] - rgba_tolerance and ig <= epoint[2] + rgba_tolerance then has_match_g = true; end + if ib >= epoint[3] - rgba_tolerance and ib <= epoint[3] + rgba_tolerance then has_match_b = true; end + if ia >= epoint[4] - rgba_tolerance and ia <= epoint[4] + rgba_tolerance then has_match_a = true; end + end + local matching = has_match_r and has_match_g and has_match_b and has_match_a + local ymatch = '' + local nmatch = '' + if has_match_r then ymatch = ymatch .. 'r' else nmatch = nmatch .. 'r' end + if has_match_g then ymatch = ymatch .. 'g' else nmatch = nmatch .. 'g' end + if has_match_b then ymatch = ymatch .. 'b' else nmatch = nmatch .. 'b' end + if has_match_a then ymatch = ymatch .. 'a' else nmatch = nmatch .. 'a' end + local pixel = tostring(ir)..','..tostring(ig)..','..tostring(ib)..','..tostring(ia) + self:assertEquals(true, matching, 'compare image pixel (' .. pixel .. ') at ' .. + tostring(ix) .. ',' .. tostring(iy) .. ', matching = ' .. ymatch .. + ', not matching = ' .. nmatch .. ' (' .. self.method .. '-' .. tostring(self.imgs) .. ')' + ) + -- add difference co-ord for rendering later + if matching ~= true then + table.insert(differences, ix+1) + table.insert(differences, iy+1) + end + end + end + local path = 'tempoutput/actual/love.test.graphics.' .. + self.method .. '-' .. tostring(self.imgs) .. '.png' + imgdata:encode('png', path) + + -- if we have differences draw them to a new canvas to display in HTML report + local dpath = 'tempoutput/difference/love.test.graphics.' .. + self.method .. '-' .. tostring(self.imgs) .. '.png' + if #differences > 0 then + local difference = love.graphics.newCanvas(iw+1, ih+1) + love.graphics.setCanvas(difference) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 1, 1) + love.graphics.points(differences) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + love.graphics.readbackTexture(difference):encode('png', dpath) + + -- otherwise clear the old difference file (if any) to stop it coming up + -- in future reports when there's no longer a difference + elseif love.filesystem.openFile(dpath, 'r') then + love.filesystem.remove(dpath) + end + + self.imgs = self.imgs + 1 + end, + + + -- @method - TestMethod:exportImg() + -- @desc - exports the given imgdata to the 'output/expected/' folder, to use when + -- writing new graphics tests to set the expected image output + -- @NOTE - you should not leave this method in when you are finished this is + -- for test writing only + -- @param {table} imgdata - imgdata to save as a png + -- @param {integer} imgdata - index of the png, graphic tests are run sequentially + -- and each test image is numbered in order that its + -- compared to, so set the number here to match + -- @return {nil} + exportImg = function(self, imgdata, index) + local path = 'tempoutput/expected/love.test.graphics.' .. + self.method .. '-' .. tostring(index) .. '.png' + imgdata:encode('png', path) + end, + + + -- @method - TestMethod:skipTest() + -- @desc - used to mark this test as skipped for a specific reason + -- @param {string} reason - reason why method is being skipped + -- @return {nil} + skipTest = function(self, reason) + self.skipped = true + self.skipreason = reason + end, + + + -- @method - TestMethod:waitFrames() + -- @desc - yields the method for x amount of frames + -- @param {number} frames - no. frames to wait + -- @return {nil} + waitFrames = function(self, frames) + for _=1,frames do coroutine.yield() end + end, + + + -- @method - TestMethod:waitSeconds() + -- @desc - yields the method for x amount of seconds + -- @param {number} seconds - no. seconds to wait + -- @return {nil} + waitSeconds = function(self, seconds) + local start = love.timer.getTime() + while love.timer.getTime() < start + seconds do + coroutine.yield() + end + end, + + + -- @method - TestMethod:isOS() + -- @desc - checks for a specific OS (or list of OSs) + -- @param {string/s} - each arg passed will be checked as a valid OS, as long + -- as one passed the function will return true + -- @return {boolean} - returns true if one of the OSs given matches actual OS + isOS = function(self, ...) + for os=1,select("#", ...) do + if select(os, ...) == love.test.current_os then return true end + end + return false + end, + + -- @method - TestMethod:isLuaVersion() + -- @desc - checks for a specific Lua version (or list of versions) + -- @param {number} - the minimum Lua version to check against + -- @return {boolean} - returns true if the current Lua version is at least the given version + isAtLeastLuaVersion = function(self, version) + return love.test.lua_version >= version + end, + + -- @method - TestMethod:isLuaJITEnabled() + -- @desc - checks if LuaJIT is enabled + -- @return {boolean} - returns true if LuaJIT is enabled + isLuaJITEnabled = function(self) + return love.test.has_lua_jit + end, + + -- @method - TestMethod:evaluateTest() + -- @desc - evaluates the results of all assertions for a final restult + -- @return {nil} + evaluateTest = function(self) + local failure = '' + local failures = 0 + + -- check all asserts for failures, additional failures are also printed + local assert_failures = {} + for a=1,#self.asserts do + if not self.asserts[a].passed and not self.skipped then + if failure == '' then failure = self.asserts[a] end + table.insert(assert_failures, self.asserts[a]) + failures = failures + 1 + end + end + if self.fatal ~= '' then failure = self.fatal end + local passed = tostring(#self.asserts - failures) + local total = '(' .. passed .. '/' .. tostring(#self.asserts) .. ')' + + -- skipped tests have a special log + if self.skipped then + self.testmodule.skipped = self.testmodule.skipped + 1 + love.test.totals[3] = love.test.totals[3] + 1 + self.result = { + total = '', + result = "SKIP", + passed = false, + message = '(0/0) - method skipped [' .. self.skipreason .. ']', + failures = {} + } + else + + -- if no failure but has asserts, then passed + if failure == '' and #self.asserts > 0 then + self.passed = true + self.testmodule.passed = self.testmodule.passed + 1 + love.test.totals[1] = love.test.totals[1] + 1 + self.result = { + total = total, + result = 'PASS', + passed = true, + message = nil, + failures = {} + } + + -- otherwise it failed + else + self.passed = false + self.testmodule.failed = self.testmodule.failed + 1 + love.test.totals[2] = love.test.totals[2] + 1 + + -- no asserts means invalid test + if #self.asserts == 0 then + local msg = 'no asserts defined' + if self.fatal ~= '' then msg = self.fatal end + self.result = { + total = total, + result = 'FAIL', + passed = false, + key = 'test', + message = msg, + failures = {} + } + + -- otherwise we had failures, log the first and supply the list of + -- additional failures if any for printResult() + else + local key = failure['key'] + if failure['test'] ~= nil then + key = key .. ' [' .. failure['test'] .. ']' + end + local msg = failure['message'] + if self.fatal ~= '' then + key = 'code' + msg = self.fatal + end + self.result = { + total = total, + result = 'FAIL', + passed = false, + key = key, + message = msg, + failures = assert_failures + } + end + end + end + self:printResult() + end, + + + -- @method - TestMethod:printResult() + -- @desc - prints the result of the test to the console as well as appends + -- the XML + HTML for the test to the testsuite output + -- @return {nil} + printResult = function(self) + + -- get total timestamp + self.finish = love.timer.getTime() - self.start + love.test.time = love.test.time + self.finish + self.testmodule.time = self.testmodule.time + self.finish + local endtime = UtilTimeFormat(love.timer.getTime() - self.start) + + -- get failure/skip message for output (if any) + local failure = '' + local output = '' + if not self.passed and not self.skipped then + failure = '\t\t\t' .. self.result.key .. ' ' .. self.result.message .. '\n' + output = self.result.key .. ' ' .. self.result.message + -- append failures if any to report md + love.test.mdfailures = love.test.mdfailures .. '> 🔴 ' .. self.method .. ' \n' .. + '> ' .. output .. ' \n\n' + end + if output == '' and self.skipped then + failure = '\t\t\t\n' + output = self.skipreason + end + + + -- append XML for the test class result + self.testmodule.xml = self.testmodule.xml .. '\t\t\n' .. + failure .. '\t\t\n' + + -- unused currently, adds a preview image for certain graphics methods to the output + local preview = '' + if self.testmodule.module == 'graphics' then + local filename = 'love.test.graphics.' .. self.method + for f=1,5 do + local fstr = tostring(f) + if love.filesystem.openFile('tempoutput/actual/' .. filename .. '-' .. fstr .. '.png', 'r') then + preview = preview .. '
' + preview = preview .. '
' .. '

Expected

' .. + '
' .. '

Actual

' + if love.filesystem.openFile('tempoutput/difference/' .. filename .. '-' .. fstr .. '.png', 'r') then + preview = preview .. '
' .. '

Difference

' + end + preview = preview .. '
' + end + end + end + + -- append HTML for the test class result + local status = '' + local cls = 'red' + if self.passed then status = '
'; cls = 'green' end + if self.skipped then status = ''; cls = 'yellow' end + self.testmodule.html = self.testmodule.html .. + '' .. + '' .. status .. '' .. + '' .. self.method .. '' .. + '' .. endtime .. 's' .. + '' .. output .. preview .. '' .. + '' + + -- add message if assert failed + local msg = '' + if self.result.message ~= nil and not self.skipped then + msg = ' - ' .. self.result.key .. + ' failed - (' .. self.result.message .. ')' + end + if self.skipped then + msg = self.result.message + end + + -- log final test result to console + -- i know its hacky but its neat soz + local tested = 'love.' .. self.testmodule.module .. '.' .. self.method .. '()' + local matching = string.sub(self.testmodule.spacer, string.len(tested), 40) + self.testmodule:log( + self.testmodule.colors[self.result.result], + ' ' .. tested .. matching, + ' ==> ' .. self.result.result .. ' - ' .. endtime .. 's ' .. + self.result.total .. msg + ) + + -- if we failed on multiple asserts, list them here - makes it easier for + -- debugging new methods added that are failing multiple asserts + if #self.result.failures > 1 then + for f=2,#self.result.failures do + local addf = self.result.failures[f] + self.testmodule:log( + self.testmodule.colors[self.result.result], + ' ' .. tested .. matching, + ' ==> ' .. + addf['key'] .. ' [' .. addf['test'] .. '] failed - ' .. addf['message'] + ) + end + end + + end + + +} diff --git a/testing/classes/TestModule.lua b/testing/classes/TestModule.lua new file mode 100644 index 000000000..e4a446116 --- /dev/null +++ b/testing/classes/TestModule.lua @@ -0,0 +1,130 @@ +-- @class - TestModule +-- @desc - used to run tests for a given module, each test method will spawn +-- a love.test.Test object +TestModule = { + + + -- @method - TestModule:new() + -- @desc - create a new Suite object + -- @param {string} module - string of love module the suite is for + -- @return {table} - returns the new Suite object + new = function(self, module, method) + local testmodule = { + time = 0, + spacer = ' ', + colors = { + PASS = 'green', FAIL = 'red', SKIP = 'grey' + }, + colormap = { + grey = '\27[37m', + green = '\27[32m', + red = '\27[31m', + yellow = '\27[33m' + }, + xml = '', + html = '', + tests = {}, + running = {}, + called = {}, + passed = 0, + failed = 0, + skipped = 0, + module = module, + method = method, + index = 1, + start = false, + } + setmetatable(testmodule, self) + self.__index = self + return testmodule + end, + + + -- @method - TestModule:log() + -- @desc - log to console with specific colors, split out to make it easier + -- to adjust all console output across the tests + -- @param {string} color - color key to use for the log + -- @param {string} line - main message to write (LHS) + -- @param {string} result - result message to write (RHS) + -- @return {nil} + log = function(self, color, line, result) + if result == nil then result = '' end + print(self.colormap[color] .. line .. result) + end, + + + -- @method - TestModule:runTests() + -- @desc - starts the running of tests and sets up the list of methods to test + -- @param {string} module - module to set for the test suite + -- @param {string} method - specific method to test, if nil all methods tested + -- @return {nil} + runTests = function(self) + self.running = {} + self.passed = 0 + self.failed = 0 + if self.method ~= nil then + table.insert(self.running, self.method) + else + for i,_ in pairs(love.test[self.module]) do + table.insert(self.running, i) + end + table.sort(self.running) + end + self.index = 1 + self.start = true + self:log('yellow', '\nlove.' .. self.module .. '.testmodule.start') + end, + + + -- @method - TestModule:printResult() + -- @desc - prints the result of the module to the console as well as appends + -- the XML + HTML for the test to the testsuite output + -- @return {nil} + printResult = function(self) + local finaltime = UtilTimeFormat(self.time) + local status = '
' + if self.failed == 0 then status = '
' end + -- add md row to main output + love.test.mdrows = love.test.mdrows .. '| ' .. status .. + ' ' .. self.module .. + ' | ' .. tostring(self.passed) .. + ' | ' .. tostring(self.failed) .. + ' | ' .. tostring(self.skipped) .. + ' | ' .. finaltime .. 's |' .. '\n' + -- add xml to main output + love.test.xml = love.test.xml .. '\t\n' .. self.xml .. '\t\n' + -- add html to main output + local module_cls = 'toggle close' + local module_txt = '▶' + local wrap_cls = '' + if self.failed > 0 then + module_cls = 'toggle open' + module_txt = '▼' + wrap_cls = 'fail' + end + love.test.html = love.test.html .. '
' .. + '
' .. module_txt .. '
' .. + '

' .. status .. ' love.' .. self.module .. '

    ' .. + '
  • ' .. tostring(self.passed) .. ' Passed
  • ' .. + '
  • ' .. tostring(self.failed) .. ' Failed
  • ' .. + '
  • ' .. tostring(self.skipped) .. ' Skipped
  • ' .. + '
  • ' .. finaltime .. 's
  • ' .. '


' .. + '' .. + self.html .. '
MethodTimeDetails
' + -- print module results to console + self:log('yellow', 'love.' .. self.module .. '.testmodule.end') + local failedcol = '\27[31m' + if self.failed == 0 then failedcol = '\27[37m' end + self:log('green', tostring(self.passed) .. ' PASSED' .. ' || ' .. + failedcol .. tostring(self.failed) .. ' FAILED || \27[37m' .. + tostring(self.skipped) .. ' SKIPPED || ' .. finaltime .. 's') + self.start = false + self.fakequit = false + end + + +} diff --git a/testing/classes/TestSuite.lua b/testing/classes/TestSuite.lua new file mode 100644 index 000000000..8a4d7c777 --- /dev/null +++ b/testing/classes/TestSuite.lua @@ -0,0 +1,248 @@ +TestSuite = { + + + -- @method - TestSuite:new() + -- @desc - creates a new TestSuite object that handles all the tests + -- @return {table} - returns the new TestSuite object + new = function(self) + local test = { + + -- testsuite internals + modules = {}, + module = nil, + test = nil, + testcanvas = nil, + current = 1, + output = '', + totals = {0, 0, 0}, + time = 0, + xml = '', + html = '', + mdrows = '', + mdfailures = '', + delayed = nil, + fakequit = false, + windowmode = true, + current_os = love._os, + lua_version = tonumber(_VERSION:match("%d%.%d")), + has_lua_jit = type(jit) == 'table', + + -- love modules to test + audio = {}, + data = {}, + event = {}, + filesystem = {}, + font = {}, + graphics = {}, + image = {}, + joystick = {}, + love = {}, + keyboard = {}, + math = {}, + mouse = {}, + physics = {}, + sensor = {}, + sound = {}, + system = {}, + thread = {}, + timer = {}, + touch = {}, + video = {}, + window = {} + + } + setmetatable(test, self) + self.__index = self + return test + end, + + + -- @method - TestSuite:runSuite() + -- @desc - called in love.update, runs through every method or every module + -- @param {number} delta - delta from love.update to track time elapsed + -- @return {nil} + runSuite = function(self, delta) + + -- stagger between tests + if self.module ~= nil then + + if self.module.start then + + -- work through each test method 1 by 1 + if self.module.index <= #self.module.running then + + -- run method once + if self.module.called[self.module.index] == nil then + self.module.called[self.module.index] = true + local method = self.module.running[self.module.index] + self.test = TestMethod:new(method, self.module) + TextRun = 'love.' .. self.module.module .. '.' .. method + + self.test.co = coroutine.create(function() + local ok, chunk, err = pcall( + love.test[love.test.module.module][method], + love.test.test + ) + if ok == false then + love.test.test['passed'] = false + love.test.test['fatal'] = tostring(chunk) .. tostring(err) + end + end) + + + -- once called we have a corouting, so just call resume every frame + -- until we have finished + else + + -- move onto next yield if any + -- pauses can be set with TestMethod:waitFrames(frames) + coroutine.resume(self.test.co) + + -- when wait finished (or no yields) + if coroutine.status(self.test.co) == 'dead' then + -- now we're all done evaluate the test + local ok, chunk, err = pcall(self.test.evaluateTest, self.test) + if ok == false then + self.test.passed = false + self.test.fatal = tostring(chunk) .. tostring(err) + end + -- save having to :release() anything we made in the last test + collectgarbage("collect") + -- move onto the next test + self.module.index = self.module.index + 1 + end + + end + + -- once all tests have run + else + + -- print module results and add to output + self.module:printResult() + + -- if we have more modules to go run the next one + self.current = self.current + 1 + if #self.modules >= self.current then + self.module = self.modules[self.current] + self.module:runTests() + + -- otherwise print the final results and export output + else + self:printResult() + love.event.quit(0) + end + + end + end + end + + end, + + + -- @method - TestSuite:printResult() + -- @desc - prints the result of the whole test suite as well as writes + -- the MD, XML + HTML of the testsuite output + -- @return {nil} + printResult = function(self) + local finaltime = UtilTimeFormat(self.time) + + -- in case we dont have love.graphics loaded, for future module specific disabling + local name = 'NONE' + local version = 'NONE' + local vendor = 'NONE' + local device = 'NONE' + if love.graphics then + name, version, vendor, device = love.graphics.getRendererInfo() + end + + local md = '\n\n### Info\n' .. + '**' .. tostring(self.totals[1] + self.totals[2] + self.totals[3]) .. '** tests were completed in **' .. + finaltime .. 's** with **' .. + tostring(self.totals[1]) .. '** passed, **' .. + tostring(self.totals[2]) .. '** failed, and **' .. + tostring(self.totals[3]) .. '** skipped\n\n' .. + 'Renderer: ' .. name .. ' | ' .. version .. ' | ' .. vendor .. ' | ' .. device .. '\n\n' .. + '### Report\n' .. + '| Module | Pass | Fail | Skip | Time |\n' .. + '| --------------------- | ------ | ------ | ------- | ------ |\n' .. + self.mdrows .. '\n### Failures\n' .. self.mdfailures + + local xml = '\n' + + local status = '
' + if self.totals[2] == 0 then status = '
' end + local html = [[ + + + + + + ]] + local wrap_cls = '' + if self.totals[2] > 0 then wrap_cls = 'fail' end + html = html .. '

' .. status .. ' love.test report

' .. + '

Renderer: ' .. name .. ' | ' .. version .. ' | ' .. vendor .. ' | ' .. device .. '

' .. + '
    ' + html = html .. + '
  • ' .. tostring(self.totals[1]) .. ' Passed
  • ' .. + '
  • ' .. tostring(self.totals[2]) .. ' Failed
  • ' .. + '
  • ' .. tostring(self.totals[3]) .. ' Skipped
  • ' .. + '
  • ' .. finaltime .. 's


' + + love.filesystem.write('tempoutput/' .. self.output .. '.xml', xml .. self.xml .. '') + love.filesystem.write('tempoutput/' .. self.output .. '.html', html .. self.html .. '
') + love.filesystem.write('tempoutput/' .. self.output .. '.md', md) + + self.module:log('grey', '\nFINISHED - ' .. finaltime .. 's\n') + local failedcol = '\27[31m' + if self.totals[2] == 0 then failedcol = '\27[37m' end + self.module:log('green', tostring(self.totals[1]) .. ' PASSED' .. ' || ' .. failedcol .. tostring(self.totals[2]) .. ' FAILED || \27[37m' .. tostring(self.totals[3]) .. ' SKIPPED') + + end + + +} diff --git a/testing/conf.lua b/testing/conf.lua new file mode 100644 index 000000000..6dc92770f --- /dev/null +++ b/testing/conf.lua @@ -0,0 +1,20 @@ +function love.conf(t) + print("love.conf") + t.console = true + t.window.name = 'love.test' + t.window.width = 360 + t.window.height = 240 + t.window.resizable = true + t.window.depth = true + t.window.stencil = true +end + +-- custom crash message here to catch anything that might occur with modules +-- loading before we hit main.lua +local function error_printer(msg, layer) + print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) +end +function love.errorhandler(msg) + msg = tostring(msg) + error_printer(msg, 2) +end diff --git a/testing/examples/lovetest_runAllTests.html b/testing/examples/lovetest_runAllTests.html new file mode 100644 index 000000000..d46909ad8 --- /dev/null +++ b/testing/examples/lovetest_runAllTests.html @@ -0,0 +1,3 @@ +

🔴 love.test

  • 🟢 343 Tests
  • 🔴 2 Failures
  • 🟡 10 Skipped
  • 14.567s


🟢 love.audio

  • 🟢 31 Tests
  • 🔴 0 Failures
  • 🟡 0 Skipped
  • 1.328s


    • MethodTimeDetails
      🟢RecordingDevice0.816s
      🟢Source0.021s
      🟢getActiveEffects0.018s
      🟢getActiveSourceCount0.018s
      🟢getDistanceModel0.017s
      🟢getDopplerScale0.017s
      🟢getEffect0.016s
      🟢getMaxSceneEffects0.017s
      🟢getMaxSourceEffects0.017s
      🟢getOrientation0.017s
      🟢getPlaybackDevice0.017s
      🟢getPlaybackDevices0.017s
      🟢getPosition0.017s
      🟢getRecordingDevices0.017s
      🟢getVelocity0.017s
      🟢getVolume0.017s
      🟢isEffectsSupported0.017s
      🟢newQueueableSource0.017s
      🟢newSource0.018s
      🟢pause0.018s
      🟢play0.018s
      🟢setDistanceModel0.017s
      🟢setDopplerScale0.017s
      🟢setEffect0.017s
      🟢setMixWithSystem0.017s
      🟢setOrientation0.017s
      🟢setPlaybackDevice0.017s
      🟢setPosition0.017s
      🟢setVelocity0.017s
      🟢setVolume0.017s
      🟢stop0.018s

      🟢 love.data

      • 🟢 12 Tests
      • 🔴 0 Failures
      • 🟡 0 Skipped
      • 0.197s


        • MethodTimeDetails
          🟢ByteData0.017s
          🟢CompressedData0.017s
          🟢compress0.016s
          🟢decode0.017s
          🟢decompress0.013s
          🟢encode0.017s
          🟢getPackedSize0.015s
          🟢hash0.019s
          🟢newByteData0.017s
          🟢newDataView0.017s
          🟢pack0.017s
          🟢unpack0.018s

          🟢 love.event

          • 🟢 4 Tests
          • 🔴 0 Failures
          • 🟡 2 Skipped
          • 0.100s


            • MethodTimeDetails
              🟢clear0.017s
              🟢poll0.017s
              🟡pump0.016sused internally
              🟢push0.017s
              🟢quit0.016s
              🟡wait0.018sused internally

              🟢 love.filesystem

              • 🟢 33 Tests
              • 🔴 0 Failures
              • 🟡 2 Skipped
              • 0.601s


                • MethodTimeDetails
                  🟢File0.018s
                  🟢FileData0.017s
                  🟢append0.019s
                  🟢areSymlinksEnabled0.017s
                  🟢createDirectory0.018s
                  🟢getAppdataDirectory0.017s
                  🟢getCRequirePath0.016s
                  🟢getDirectoryItems0.019s
                  🟢getFullCommonPath0.017s
                  🟢getIdentity0.017s
                  🟢getInfo0.019s
                  🟢getRealDirectory0.018s
                  🟢getRequirePath0.016s
                  🟢getSaveDirectory0.017s
                  🟡getSource0.018sused internally
                  🟢getSourceBaseDirectory0.017s
                  🟢getUserDirectory0.016s
                  🟢getWorkingDirectory0.018s
                  🟢isFused0.018s
                  🟢lines0.017s
                  🟢load0.018s
                  🟢mount0.017s
                  🟢mountCommonPath0.017s
                  🟢mountFullPath0.017s
                  🟢newFileData0.016s
                  🟢openFile0.017s
                  🟢read0.017s
                  🟢remove0.019s
                  🟢setCRequirePath0.017s
                  🟢setIdentity0.016s
                  🟢setRequirePath0.017s
                  🟡setSource0.016sused internally
                  🟢unmount0.018s
                  🟢unmountFullPath0.016s
                  🟢write0.018s

                  🟢 love.font

                  • 🟢 7 Tests
                  • 🔴 0 Failures
                  • 🟡 0 Skipped
                  • 0.116s


                    • MethodTimeDetails
                      🟢GlyphData0.016s
                      🟢Rasterizer0.018s
                      🟢newBMFontRasterizer0.016s
                      🟢newGlyphData0.016s
                      🟢newImageRasterizer0.017s
                      🟢newRasterizer0.017s
                      🟢newTrueTypeRasterizer0.016s

                      🔴 love.graphics

                      • 🟢 104 Tests
                      • 🔴 1 Failures
                      • 🟡 2 Skipped
                      • 3.463s


                        • MethodTimeDetails
                          🟢Buffer0.017s
                          🟢Canvas0.086s

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢Font0.021s

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢Image0.041s

                          Expected

                          Actual

                          🟢Mesh0.018s
                          🟢ParticleSystem0.040s

                          Expected

                          Actual

                          🟢Quad0.025s

                          Expected

                          Actual

                          🔴Shader0.028sassert 4 [check shader valid] expected '' got 'vertex shader: +pixel shader: +'

                          Expected

                          Actual

                          🟡ShaderStorageBuffer0.017sGLSL 4 and shader storage buffers are not supported on this system
                          🟢SpriteBatch0.085s

                          Expected

                          Actual

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢Text0.026s

                          Expected

                          Actual

                          🟢Video0.885s

                          Expected

                          Actual

                          🟢applyTransform0.034s

                          Expected

                          Actual

                          🟢arc0.021s

                          Expected

                          Actual

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢captureScreenshot0.349s
                          🟢circle0.018s

                          Expected

                          Actual

                          🟢clear0.018s

                          Expected

                          Actual

                          🟡discard0.017scant test this worked
                          🟢draw0.032s

                          Expected

                          Actual

                          🟢drawInstanced0.034s

                          Expected

                          Actual

                          🟢drawLayer0.031s

                          Expected

                          Actual

                          🟢ellipse0.019s

                          Expected

                          Actual

                          🟢flushBatch0.018s
                          🟢getBackgroundColor0.017s
                          🟢getBlendMode0.017s
                          🟢getCanvas0.017s
                          🟢getColor0.017s
                          🟢getColorMask0.017s
                          🟢getDPIScale0.016s
                          🟢getDefaultFilter0.016s
                          🟢getDepthMode0.016s
                          🟢getDimensions0.017s
                          🟢getFont0.017s
                          🟢getFrontFaceWinding0.017s
                          🟢getHeight0.016s
                          🟢getLineJoin0.017s
                          🟢getLineStyle0.017s
                          🟢getLineWidth0.017s
                          🟢getMeshCullMode0.017s
                          🟢getPixelDimensions0.017s
                          🟢getPixelHeight0.018s
                          🟢getPixelWidth0.016s
                          🟢getPointSize0.017s
                          🟢getRendererInfo0.016s
                          🟢getScissor0.017s
                          🟢getShader0.016s
                          🟢getStackDepth0.018s
                          🟢getStats0.017s
                          🟢getStencilState0.017s
                          🟢getSupported0.017s
                          🟢getSystemLimits0.017s
                          🟢getTextureFormats0.017s
                          🟢getTextureTypes0.017s
                          🟢getWidth0.017s
                          🟢intersectScissor0.018s

                          Expected

                          Actual

                          🟢inverseTransformPoint0.017s
                          🟢isActive0.017s
                          🟢isGammaCorrect0.017s
                          🟢isWireframe0.017s
                          🟢line0.018s

                          Expected

                          Actual

                          🟢newArrayImage0.018s
                          🟢newCanvas0.017s
                          🟢newCubeImage0.020s
                          🟢newFont0.018s
                          🟢newImage0.016s
                          🟢newImageFont0.018s
                          🟢newMesh0.017s
                          🟢newParticleSystem0.017s
                          🟢newQuad0.017s
                          🟢newShader0.028s
                          🟢newSpriteBatch0.017s
                          🟢newTextBatch0.018s
                          🟢newVideo0.021s
                          🟢newVolumeImage0.018s
                          🟢origin0.019s

                          Expected

                          Actual

                          🟢points0.022s

                          Expected

                          Actual

                          🟢polygon0.017s

                          Expected

                          Actual

                          🟢pop0.017s

                          Expected

                          Actual

                          🟢print0.028s

                          Expected

                          Actual

                          🟢printf0.020s

                          Expected

                          Actual

                          🟢push0.019s

                          Expected

                          Actual

                          🟢rectangle0.024s

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢replaceTransform0.020s

                          Expected

                          Actual

                          🟢reset0.017s
                          🟢rotate0.035s

                          Expected

                          Actual

                          🟢scale0.019s

                          Expected

                          Actual

                          🟢setBackgroundColor0.017s
                          🟢setBlendMode0.038s

                          Expected

                          Actual

                          🟢setCanvas0.018s

                          Expected

                          Actual

                          🟢setColor0.020s

                          Expected

                          Actual

                          🟢setColorMask0.028s

                          Expected

                          Actual

                          🟢setDefaultFilter0.017s
                          🟢setDepthMode0.017s
                          🟢setFont0.020s

                          Expected

                          Actual

                          🟢setFrontFaceWinding0.017s
                          🟢setLineJoin0.033s

                          Expected

                          Actual

                          🟢setLineStyle0.019s

                          Expected

                          Actual

                          🟢setLineWidth0.019s

                          Expected

                          Actual

                          🟢setMeshCullMode0.018s
                          🟢setScissor0.019s

                          Expected

                          Actual

                          🟢setShader0.031s

                          Expected

                          Actual

                          🟢setStencilState0.018s

                          Expected

                          Actual

                          🟢setWireframe0.018s

                          Expected

                          Actual

                          🟢shear0.020s

                          Expected

                          Actual

                          Expected

                          Actual

                          🟢transformPoint0.017s
                          🟢translate0.018s

                          Expected

                          Actual

                          🟢validateShader0.026s

                          🟢 love.image

                          • 🟢 5 Tests
                          • 🔴 0 Failures
                          • 🟡 0 Skipped
                          • 0.093s


                            • MethodTimeDetails
                              🟢CompressedImageData0.017s
                              🟢ImageData0.026s
                              🟢isCompressed0.017s
                              🟢newCompressedData0.017s
                              🟢newImageData0.017s

                              🟢 love.joystick

                              • 🟢 6 Tests
                              • 🔴 0 Failures
                              • 🟡 0 Skipped
                              • 0.116s


                                • MethodTimeDetails
                                  🟢getGamepadMappingString0.017s
                                  🟢getJoystickCount0.017s
                                  🟢getJoysticks0.017s
                                  🟢loadGamepadMappings0.023s
                                  🟢saveGamepadMappings0.024s
                                  🟢setGamepadMapping0.018s

                                  🟢 love.keyboard

                                  • 🟢 10 Tests
                                  • 🔴 0 Failures
                                  • 🟡 0 Skipped
                                  • 0.170s


                                    • MethodTimeDetails
                                      🟢getKeyFromScancode0.016s
                                      🟢getScancodeFromKey0.018s
                                      🟢hasKeyRepeat0.018s
                                      🟢hasScreenKeyboard0.017s
                                      🟢hasTextInput0.017s
                                      🟢isDown0.017s
                                      🟢isModifierActive0.017s
                                      🟢isScancodeDown0.018s
                                      🟢setKeyRepeat0.018s
                                      🟢setTextInput0.017s

                                      🟢 love.love

                                      • 🟢 6 Tests
                                      • 🔴 0 Failures
                                      • 🟡 0 Skipped
                                      • 0.100s


                                        • MethodTimeDetails
                                          🟢errhand0.017s
                                          🟢getVersion0.016s
                                          🟢hasDeprecationOutput0.017s
                                          🟢isVersionCompatible0.017s
                                          🟢run0.017s
                                          🟢setDeprecationOutput0.017s

                                          🟢 love.math

                                          • 🟢 20 Tests
                                          • 🔴 0 Failures
                                          • 🟡 0 Skipped
                                          • 0.334s


                                            • MethodTimeDetails
                                              🟢BezierCurve0.017s
                                              🟢RandomGenerator0.016s
                                              🟢Transform0.016s
                                              🟢colorFromBytes0.017s
                                              🟢colorToBytes0.016s
                                              🟢gammaToLinear0.017s
                                              🟢getRandomSeed0.018s
                                              🟢getRandomState0.016s
                                              🟢isConvex0.017s
                                              🟢linearToGamma0.017s
                                              🟢newBezierCurve0.016s
                                              🟢newRandomGenerator0.017s
                                              🟢newTransform0.016s
                                              🟢perlinNoise0.017s
                                              🟢random0.017s
                                              🟢randomNormal0.017s
                                              🟢setRandomSeed0.017s
                                              🟢setRandomState0.017s
                                              🟢simplexNoise0.017s
                                              🟢triangulate0.017s

                                              🔴 love.mouse

                                              • 🟢 17 Tests
                                              • 🔴 1 Failures
                                              • 🟡 0 Skipped
                                              • 0.301s


                                                • MethodTimeDetails
                                                  🟢getCursor0.016s
                                                  🟢getPosition0.017s
                                                  🟢getRelativeMode0.016s
                                                  🟢getSystemCursor0.017s
                                                  🟢getX0.017s
                                                  🟢getY0.016s
                                                  🟢isCursorSupported0.017s
                                                  🟢isDown0.016s
                                                  🟢isGrabbed0.017s
                                                  🟢isVisible0.017s
                                                  🟢newCursor0.016s
                                                  🟢setCursor0.017s
                                                  🔴setGrabbed0.016sassert 2 [check now grabbed] expected 'true' got 'false'
                                                  🟢setPosition0.018s
                                                  🟢setRelativeMode0.017s
                                                  🟢setVisible0.018s
                                                  🟢setX0.018s
                                                  🟢setY0.017s

                                                  🟢 love.physics

                                                  • 🟢 26 Tests
                                                  • 🔴 0 Failures
                                                  • 🟡 0 Skipped
                                                  • 0.435s


                                                    • MethodTimeDetails
                                                      🟢Body0.017s
                                                      🟢Contact0.018s
                                                      🟢Joint0.017s
                                                      🟢Shape0.017s
                                                      🟢World0.016s
                                                      🟢getDistance0.017s
                                                      🟢getMeter0.017s
                                                      🟢newBody0.017s
                                                      🟢newChainShape0.013s
                                                      🟢newCircleShape0.017s
                                                      🟢newDistanceJoint0.017s
                                                      🟢newEdgeShape0.017s
                                                      🟢newFrictionJoint0.017s
                                                      🟢newGearJoint0.018s
                                                      🟢newMotorJoint0.017s
                                                      🟢newMouseJoint0.016s
                                                      🟢newPolygonShape0.017s
                                                      🟢newPrismaticJoint0.017s
                                                      🟢newPulleyJoint0.016s
                                                      🟢newRectangleShape0.018s
                                                      🟢newRevoluteJoint0.017s
                                                      🟢newRopeJoint0.017s
                                                      🟢newWeldJoint0.017s
                                                      🟢newWheelJoint0.018s
                                                      🟢newWorld0.018s
                                                      🟢setMeter0.016s

                                                      🟢 love.sensor

                                                      • 🟢 1 Tests
                                                      • 🔴 0 Failures
                                                      • 🟡 0 Skipped
                                                      • 0.017s


                                                        • MethodTimeDetails
                                                          🟢hasSensor0.017s

                                                          🟢 love.sound

                                                          • 🟢 4 Tests
                                                          • 🔴 0 Failures
                                                          • 🟡 0 Skipped
                                                          • 0.075s


                                                            • MethodTimeDetails
                                                              🟢Decoder0.018s
                                                              🟢SoundData0.022s
                                                              🟢newDecoder0.017s
                                                              🟢newSoundData0.019s

                                                              🟢 love.system

                                                              • 🟢 7 Tests
                                                              • 🔴 0 Failures
                                                              • 🟡 2 Skipped
                                                              • 0.150s


                                                                • MethodTimeDetails
                                                                  🟢getClipboardText0.016s
                                                                  🟢getOS0.017s
                                                                  🟢getPowerInfo0.017s
                                                                  🟢getPreferredLocales0.017s
                                                                  🟢getProcessorCount0.016s
                                                                  🟢hasBackgroundMusic0.017s
                                                                  🟡openURL0.017scant test this worked
                                                                  🟢setClipboardText0.016s
                                                                  🟡vibrate0.016scant test this worked

                                                                  🟢 love.thread

                                                                  • 🟢 5 Tests
                                                                  • 🔴 0 Failures
                                                                  • 🟡 0 Skipped
                                                                  • 0.306s


                                                                    • MethodTimeDetails
                                                                      🟢Channel0.231s
                                                                      🟢Thread0.024s
                                                                      🟢getChannel0.018s
                                                                      🟢newChannel0.017s
                                                                      🟢newThread0.015s

                                                                      🟢 love.timer

                                                                      • 🟢 6 Tests
                                                                      • 🔴 0 Failures
                                                                      • 🟡 0 Skipped
                                                                      • 0.298s


                                                                        • MethodTimeDetails
                                                                          🟢getAverageDelta0.017s
                                                                          🟢getDelta0.016s
                                                                          🟢getFPS0.015s
                                                                          🟢getTime0.118s
                                                                          🟢sleep0.117s
                                                                          🟢step0.016s

                                                                          🟢 love.touch

                                                                          • 🟢 3 Tests
                                                                          • 🔴 0 Failures
                                                                          • 🟡 0 Skipped
                                                                          • 0.051s


                                                                            • MethodTimeDetails
                                                                              🟢getPosition0.017s
                                                                              🟢getPressure0.018s
                                                                              🟢getTouches0.017s

                                                                              🟢 love.video

                                                                              • 🟢 2 Tests
                                                                              • 🔴 0 Failures
                                                                              • 🟡 0 Skipped
                                                                              • 0.038s


                                                                                • MethodTimeDetails
                                                                                  🟢VideoStream0.018s
                                                                                  🟢newVideoStream0.020s

                                                                                  🟢 love.window

                                                                                  • 🟢 34 Tests
                                                                                  • 🔴 0 Failures
                                                                                  • 🟡 2 Skipped
                                                                                  • 6.275s


                                                                                    • MethodTimeDetails
                                                                                      🟢focus0.017s
                                                                                      🟢fromPixels0.017s
                                                                                      🟢getDPIScale0.017s
                                                                                      🟢getDesktopDimensions0.016s
                                                                                      🟢getDisplayCount0.016s
                                                                                      🟢getDisplayName0.016s
                                                                                      🟢getDisplayOrientation0.016s
                                                                                      🟢getFullscreen1.351s
                                                                                      🟢getFullscreenModes0.013s
                                                                                      🟢getIcon0.019s
                                                                                      🟢getMode0.017s
                                                                                      🟢getPosition0.017s
                                                                                      🟢getSafeArea0.017s
                                                                                      🟢getTitle0.018s
                                                                                      🟢getVSync0.016s
                                                                                      🟢hasFocus0.017s
                                                                                      🟢hasMouseFocus0.017s
                                                                                      🟢isDisplaySleepEnabled0.016s
                                                                                      🟢isMaximized0.186s
                                                                                      🟢isMinimized0.816s
                                                                                      🟢isOpen0.014s
                                                                                      🟢isVisible0.017s
                                                                                      🟢maximize0.186s
                                                                                      🟢minimize0.807s
                                                                                      🟡requestAttention0.016scant test this worked
                                                                                      🟢restore0.966s
                                                                                      🟢setDisplaySleepEnabled0.018s
                                                                                      🟢setFullscreen1.356s
                                                                                      🟢setIcon0.015s
                                                                                      🟢setMode0.020s
                                                                                      🟢setPosition0.183s
                                                                                      🟢setTitle0.018s
                                                                                      🟢setVSync0.015s
                                                                                      🟡showMessageBox0.002scant test this worked
                                                                                      🟢toPixels0.002s
                                                                                      🟢updateMode0.010s
\ No newline at end of file diff --git a/testing/examples/lovetest_runAllTests.md b/testing/examples/lovetest_runAllTests.md new file mode 100644 index 000000000..7e0b11205 --- /dev/null +++ b/testing/examples/lovetest_runAllTests.md @@ -0,0 +1,41 @@ + + +### Info +**355** tests were completed in **14.567s** with **343** passed, **2** failed, and **10** skipped + +Renderer: OpenGL | 4.1 Metal - 76.3 | Apple | Apple M1 Max + +### Report +| Module | Pass | Fail | Skip | Time | +| --------------------- | ------ | ------ | ------- | ------ | +| 🟢 audio | 31 | 0 | 0 | 1.328s | +| 🟢 data | 12 | 0 | 0 | 0.197s | +| 🟢 event | 4 | 0 | 2 | 0.100s | +| 🟢 filesystem | 33 | 0 | 2 | 0.601s | +| 🟢 font | 7 | 0 | 0 | 0.116s | +| 🔴 graphics | 104 | 1 | 2 | 3.463s | +| 🟢 image | 5 | 0 | 0 | 0.093s | +| 🟢 joystick | 6 | 0 | 0 | 0.116s | +| 🟢 keyboard | 10 | 0 | 0 | 0.170s | +| 🟢 love | 6 | 0 | 0 | 0.100s | +| 🟢 math | 20 | 0 | 0 | 0.334s | +| 🔴 mouse | 17 | 1 | 0 | 0.301s | +| 🟢 physics | 26 | 0 | 0 | 0.435s | +| 🟢 sensor | 1 | 0 | 0 | 0.017s | +| 🟢 sound | 4 | 0 | 0 | 0.075s | +| 🟢 system | 7 | 0 | 2 | 0.150s | +| 🟢 thread | 5 | 0 | 0 | 0.306s | +| 🟢 timer | 6 | 0 | 0 | 0.298s | +| 🟢 touch | 3 | 0 | 0 | 0.051s | +| 🟢 video | 2 | 0 | 0 | 0.038s | +| 🟢 window | 34 | 0 | 2 | 6.275s | + +### Failures +> 🔴 Shader +> assert 4 [check shader valid] expected '' got 'vertex shader: +pixel shader: +' + +> 🔴 setGrabbed +> assert 2 [check now grabbed] expected 'true' got 'false' + diff --git a/testing/examples/lovetest_runAllTests.xml b/testing/examples/lovetest_runAllTests.xml new file mode 100644 index 000000000..888feca6c --- /dev/null +++ b/testing/examples/lovetest_runAllTests.xml @@ -0,0 +1,770 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + assert 4 [check shader valid] expected '' got 'vertex shader: +pixel shader: +' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + assert 2 [check now grabbed] expected 'true' got 'false' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/testing/main.lua b/testing/main.lua new file mode 100644 index 000000000..f3a78ea99 --- /dev/null +++ b/testing/main.lua @@ -0,0 +1,219 @@ +-- load test objs +require('classes.TestSuite') +require('classes.TestModule') +require('classes.TestMethod') + +-- create testsuite obj +love.test = TestSuite:new() + +-- load test scripts if module is active +-- this is so in future if we have per-module disabling it'll still run +if love ~= nil then require('tests.love') end +if love.audio ~= nil then require('tests.audio') end +if love.data ~= nil then require('tests.data') end +if love.event ~= nil then require('tests.event') end +if love.filesystem ~= nil then require('tests.filesystem') end +if love.font ~= nil then require('tests.font') end +if love.graphics ~= nil then require('tests.graphics') end +if love.image ~= nil then require('tests.image') end +if love.joystick ~= nil then require('tests.joystick') end +if love.keyboard ~= nil then require('tests.keyboard') end +if love.math ~= nil then require('tests.math') end +if love.mouse ~= nil then require('tests.mouse') end +if love.physics ~= nil then require('tests.physics') end +if love.sensor ~= nil then require('tests.sensor') end +if love.sound ~= nil then require('tests.sound') end +if love.system ~= nil then require('tests.system') end +if love.thread ~= nil then require('tests.thread') end +if love.timer ~= nil then require('tests.timer') end +if love.touch ~= nil then require('tests.touch') end +if love.video ~= nil then require('tests.video') end +if love.window ~= nil then require('tests.window') end + +-- love.load +-- load given arguments and run the test suite +love.load = function(args) + + -- setup basic img to display + if love.window ~= nil then + love.window.updateMode(360, 240, { + fullscreen = false, + resizable = true, + centered = true + }) + + -- set up some graphics to draw if enabled + if love.graphics ~= nil then + love.graphics.setDefaultFilter("nearest", "nearest") + love.graphics.setLineStyle('rough') + love.graphics.setLineWidth(1) + Logo = { + texture = love.graphics.newImage('resources/love.png'), + img = nil + } + Logo.img = love.graphics.newQuad(0, 0, 64, 64, Logo.texture) + Font = love.graphics.newFont('resources/font.ttf', 8, 'normal') + TextCommand = 'Loading...' + TextRun = '' + end + + end + + -- mount for output later + if love.filesystem.mountFullPath then + love.filesystem.mountFullPath(love.filesystem.getSource() .. "/output", "tempoutput", "readwrite") + end + + -- get all args with any comma lists split out as seperate + local arglist = {} + for a=1,#args do + local splits = UtilStringSplit(args[a], '([^,]+)') + for s=1,#splits do + table.insert(arglist, splits[s]) + end + end + + -- convert args to the cmd to run, modules, method (if any) and disabled + local testcmd = '--all' + local module = '' + local method = '' + local cmderr = 'Invalid flag used' + local modules = { + 'audio', 'data', 'event', 'filesystem', 'font', 'graphics', 'image', + 'joystick', 'keyboard', 'love', 'math', 'mouse', 'physics', 'sensor', + 'sound', 'system', 'thread', 'timer', 'touch', 'video', 'window' + } + GITHUB_RUNNER = false + for a=1,#arglist do + if testcmd == '--method' then + if module == '' and (arglist[a] == 'love' or love[ arglist[a] ] ~= nil) then + module = arglist[a] + table.insert(modules, module) + elseif module ~= '' and love[module] ~= nil and method == '' then + if love.test[module][arglist[a]] ~= nil then method = arglist[a] end + end + end + if testcmd == '--modules' then + if (arglist[a] == 'love' or love[ arglist[a] ] ~= nil) and arglist[a] ~= '--isRunner' then + table.insert(modules, arglist[a]) + end + end + if arglist[a] == '--method' then + testcmd = arglist[a] + modules = {} + end + if arglist[a] == '--modules' then + testcmd = arglist[a] + modules = {} + end + if arglist[a] == '--isRunner' then + GITHUB_RUNNER = true + end + end + + -- method uses the module + method given + if testcmd == '--method' then + local testmodule = TestModule:new(module, method) + table.insert(love.test.modules, testmodule) + if module ~= '' and method ~= '' then + love.test.module = testmodule + love.test.module:log('grey', '--method "' .. module .. '" "' .. method .. '"') + love.test.output = 'lovetest_method_' .. module .. '_' .. method + else + if method == '' then cmderr = 'No valid method specified' end + if module == '' then cmderr = 'No valid module specified' end + end + end + + -- modules runs all methods for all the modules given + if testcmd == '--modules' then + local modulelist = {} + for m=1,#modules do + local testmodule = TestModule:new(modules[m]) + table.insert(love.test.modules, testmodule) + table.insert(modulelist, modules[m]) + end + if #modulelist > 0 then + love.test.module = love.test.modules[1] + love.test.module:log('grey', '--modules "' .. table.concat(modulelist, '" "') .. '"') + love.test.output = 'lovetest_modules_' .. table.concat(modulelist, '_') + else + cmderr = 'No modules specified' + end + end + + -- otherwise default runs all methods for all modules + if arglist[1] == nil or arglist[1] == '' or arglist[1] == '--all' then + for m=1,#modules do + local testmodule = TestModule:new(modules[m]) + table.insert(love.test.modules, testmodule) + end + love.test.module = love.test.modules[1] + love.test.module:log('grey', '--all') + love.test.output = 'lovetest_all' + end + + if GITHUB_RUNNER then + love.test.module:log('grey', '--isRunner') + end + + -- invalid command + if love.test.module == nil then + print(cmderr) + love.event.quit(0) + else + -- start first module + TextCommand = testcmd + love.test.module:runTests() + end + +end + +-- love.update +-- run test suite logic +love.update = function(delta) + love.test:runSuite(delta) +end + + +-- love.draw +-- draw a little logo to the screen +love.draw = function() + local lw = (love.graphics.getWidth() - 128) / 2 + local lh = (love.graphics.getHeight() - 128) / 2 + love.graphics.draw(Logo.texture, Logo.img, lw, lh, 0, 2, 2) + love.graphics.setFont(Font) + love.graphics.print(TextCommand, 4, 12, 0, 2, 2) + love.graphics.print(TextRun, 4, 32, 0, 2, 2) +end + + +-- love.quit +-- add a hook to allow test modules to fake quit +love.quit = function() + if love.test.module ~= nil and love.test.module.fakequit then + return true + else + return false + end +end + + +-- added so bad threads dont fail +function love.threaderror(thread, errorstr) end + + +-- string split helper +function UtilStringSplit(str, splitter) + local splits = {} + for word in string.gmatch(str, splitter) do + table.insert(splits, word) + end + return splits +end + + +-- string time formatter +function UtilTimeFormat(seconds) + return string.format("%.3f", tostring(seconds)) +end diff --git a/testing/output/actual/notes.txt b/testing/output/actual/notes.txt new file mode 100644 index 000000000..2716b1df8 --- /dev/null +++ b/testing/output/actual/notes.txt @@ -0,0 +1,2 @@ +# Actual Graphics Output +The images generated by the tests \ No newline at end of file diff --git a/testing/output/difference/notes.txt b/testing/output/difference/notes.txt new file mode 100644 index 000000000..ac3589e55 --- /dev/null +++ b/testing/output/difference/notes.txt @@ -0,0 +1,3 @@ +# Graphic Differences +If a graphics test fails then a "difference" image will be created to highlight +the differences between the actual + expected image, for use in the HTML report \ No newline at end of file diff --git a/testing/output/expected/love.test.graphics.Canvas-1.png b/testing/output/expected/love.test.graphics.Canvas-1.png new file mode 100644 index 000000000..3727aa3a0 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Canvas-1.png differ diff --git a/testing/output/expected/love.test.graphics.Canvas-2.png b/testing/output/expected/love.test.graphics.Canvas-2.png new file mode 100644 index 000000000..3727aa3a0 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Canvas-2.png differ diff --git a/testing/output/expected/love.test.graphics.Canvas-3.png b/testing/output/expected/love.test.graphics.Canvas-3.png new file mode 100644 index 000000000..15a5cf8e3 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Canvas-3.png differ diff --git a/testing/output/expected/love.test.graphics.Canvas-4.png b/testing/output/expected/love.test.graphics.Canvas-4.png new file mode 100644 index 000000000..9dbe75c20 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Canvas-4.png differ diff --git a/testing/output/expected/love.test.graphics.Font-1.png b/testing/output/expected/love.test.graphics.Font-1.png new file mode 100644 index 000000000..cb2f21a1e Binary files /dev/null and b/testing/output/expected/love.test.graphics.Font-1.png differ diff --git a/testing/output/expected/love.test.graphics.Font-2.png b/testing/output/expected/love.test.graphics.Font-2.png new file mode 100644 index 000000000..d12d68425 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Font-2.png differ diff --git a/testing/output/expected/love.test.graphics.Image-1.png b/testing/output/expected/love.test.graphics.Image-1.png new file mode 100644 index 000000000..5f45cf9e7 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Image-1.png differ diff --git a/testing/output/expected/love.test.graphics.ParticleSystem-1.png b/testing/output/expected/love.test.graphics.ParticleSystem-1.png new file mode 100644 index 000000000..401a2ef39 Binary files /dev/null and b/testing/output/expected/love.test.graphics.ParticleSystem-1.png differ diff --git a/testing/output/expected/love.test.graphics.Quad-1.png b/testing/output/expected/love.test.graphics.Quad-1.png new file mode 100644 index 000000000..22ab17e3e Binary files /dev/null and b/testing/output/expected/love.test.graphics.Quad-1.png differ diff --git a/testing/output/expected/love.test.graphics.Shader-1.png b/testing/output/expected/love.test.graphics.Shader-1.png new file mode 100644 index 000000000..6742f6386 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Shader-1.png differ diff --git a/testing/output/expected/love.test.graphics.Shader-2.png b/testing/output/expected/love.test.graphics.Shader-2.png new file mode 100644 index 000000000..acc6f6932 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Shader-2.png differ diff --git a/testing/output/expected/love.test.graphics.Shader-3.png b/testing/output/expected/love.test.graphics.Shader-3.png new file mode 100644 index 000000000..846cd5a64 Binary files /dev/null and b/testing/output/expected/love.test.graphics.Shader-3.png differ diff --git a/testing/output/expected/love.test.graphics.SpriteBatch-1.png b/testing/output/expected/love.test.graphics.SpriteBatch-1.png new file mode 100644 index 000000000..e3c032481 Binary files /dev/null and b/testing/output/expected/love.test.graphics.SpriteBatch-1.png differ diff --git a/testing/output/expected/love.test.graphics.SpriteBatch-2.png b/testing/output/expected/love.test.graphics.SpriteBatch-2.png new file mode 100644 index 000000000..3427e6141 Binary files /dev/null and b/testing/output/expected/love.test.graphics.SpriteBatch-2.png differ diff --git a/testing/output/expected/love.test.graphics.SpriteBatch-3.png b/testing/output/expected/love.test.graphics.SpriteBatch-3.png new file mode 100644 index 000000000..36ee516f3 Binary files /dev/null and b/testing/output/expected/love.test.graphics.SpriteBatch-3.png differ diff --git a/testing/output/expected/love.test.graphics.SpriteBatch-4.png b/testing/output/expected/love.test.graphics.SpriteBatch-4.png new file mode 100644 index 000000000..d33b0c1ce Binary files /dev/null and b/testing/output/expected/love.test.graphics.SpriteBatch-4.png differ diff --git a/testing/output/expected/love.test.graphics.SpriteBatch-5.png b/testing/output/expected/love.test.graphics.SpriteBatch-5.png new file mode 100644 index 000000000..9171baaec Binary files /dev/null and b/testing/output/expected/love.test.graphics.SpriteBatch-5.png differ diff --git a/testing/output/expected/love.test.graphics.Text-1.png b/testing/output/expected/love.test.graphics.Text-1.png new file mode 100644 index 000000000..4f15348cd Binary files /dev/null and b/testing/output/expected/love.test.graphics.Text-1.png differ diff --git a/testing/output/expected/love.test.graphics.Video-1.png b/testing/output/expected/love.test.graphics.Video-1.png new file mode 100644 index 000000000..ad8b44e9e Binary files /dev/null and b/testing/output/expected/love.test.graphics.Video-1.png differ diff --git a/testing/output/expected/love.test.graphics.applyTransform-1.png b/testing/output/expected/love.test.graphics.applyTransform-1.png new file mode 100644 index 000000000..f80ad8f85 Binary files /dev/null and b/testing/output/expected/love.test.graphics.applyTransform-1.png differ diff --git a/testing/output/expected/love.test.graphics.arc-1.png b/testing/output/expected/love.test.graphics.arc-1.png new file mode 100644 index 000000000..f95e65bb3 Binary files /dev/null and b/testing/output/expected/love.test.graphics.arc-1.png differ diff --git a/testing/output/expected/love.test.graphics.arc-2.png b/testing/output/expected/love.test.graphics.arc-2.png new file mode 100644 index 000000000..18b6bbe27 Binary files /dev/null and b/testing/output/expected/love.test.graphics.arc-2.png differ diff --git a/testing/output/expected/love.test.graphics.arc-3.png b/testing/output/expected/love.test.graphics.arc-3.png new file mode 100644 index 000000000..19354b37a Binary files /dev/null and b/testing/output/expected/love.test.graphics.arc-3.png differ diff --git a/testing/output/expected/love.test.graphics.captureScreenshot-1.png b/testing/output/expected/love.test.graphics.captureScreenshot-1.png new file mode 100644 index 000000000..f26a3a081 Binary files /dev/null and b/testing/output/expected/love.test.graphics.captureScreenshot-1.png differ diff --git a/testing/output/expected/love.test.graphics.circle-1.png b/testing/output/expected/love.test.graphics.circle-1.png new file mode 100644 index 000000000..dbc130407 Binary files /dev/null and b/testing/output/expected/love.test.graphics.circle-1.png differ diff --git a/testing/output/expected/love.test.graphics.clear-1.png b/testing/output/expected/love.test.graphics.clear-1.png new file mode 100644 index 000000000..315c7a936 Binary files /dev/null and b/testing/output/expected/love.test.graphics.clear-1.png differ diff --git a/testing/output/expected/love.test.graphics.draw-1.png b/testing/output/expected/love.test.graphics.draw-1.png new file mode 100644 index 000000000..b2fb6657a Binary files /dev/null and b/testing/output/expected/love.test.graphics.draw-1.png differ diff --git a/testing/output/expected/love.test.graphics.drawInstanced-1.png b/testing/output/expected/love.test.graphics.drawInstanced-1.png new file mode 100644 index 000000000..8211034e0 Binary files /dev/null and b/testing/output/expected/love.test.graphics.drawInstanced-1.png differ diff --git a/testing/output/expected/love.test.graphics.drawLayer-1.png b/testing/output/expected/love.test.graphics.drawLayer-1.png new file mode 100644 index 000000000..876bb6f77 Binary files /dev/null and b/testing/output/expected/love.test.graphics.drawLayer-1.png differ diff --git a/testing/output/expected/love.test.graphics.ellipse-1.png b/testing/output/expected/love.test.graphics.ellipse-1.png new file mode 100644 index 000000000..3fd46b709 Binary files /dev/null and b/testing/output/expected/love.test.graphics.ellipse-1.png differ diff --git a/testing/output/expected/love.test.graphics.intersectScissor-1.png b/testing/output/expected/love.test.graphics.intersectScissor-1.png new file mode 100644 index 000000000..7c40b8c9e Binary files /dev/null and b/testing/output/expected/love.test.graphics.intersectScissor-1.png differ diff --git a/testing/output/expected/love.test.graphics.line-1.png b/testing/output/expected/love.test.graphics.line-1.png new file mode 100644 index 000000000..6fa77e263 Binary files /dev/null and b/testing/output/expected/love.test.graphics.line-1.png differ diff --git a/testing/output/expected/love.test.graphics.origin-1.png b/testing/output/expected/love.test.graphics.origin-1.png new file mode 100644 index 000000000..e018bbfbc Binary files /dev/null and b/testing/output/expected/love.test.graphics.origin-1.png differ diff --git a/testing/output/expected/love.test.graphics.points-1.png b/testing/output/expected/love.test.graphics.points-1.png new file mode 100644 index 000000000..93cc0fa41 Binary files /dev/null and b/testing/output/expected/love.test.graphics.points-1.png differ diff --git a/testing/output/expected/love.test.graphics.polygon-1.png b/testing/output/expected/love.test.graphics.polygon-1.png new file mode 100644 index 000000000..8107330d3 Binary files /dev/null and b/testing/output/expected/love.test.graphics.polygon-1.png differ diff --git a/testing/output/expected/love.test.graphics.pop-1.png b/testing/output/expected/love.test.graphics.pop-1.png new file mode 100644 index 000000000..e018bbfbc Binary files /dev/null and b/testing/output/expected/love.test.graphics.pop-1.png differ diff --git a/testing/output/expected/love.test.graphics.print-1.png b/testing/output/expected/love.test.graphics.print-1.png new file mode 100644 index 000000000..93380064d Binary files /dev/null and b/testing/output/expected/love.test.graphics.print-1.png differ diff --git a/testing/output/expected/love.test.graphics.printf-1.png b/testing/output/expected/love.test.graphics.printf-1.png new file mode 100644 index 000000000..b37a1ac89 Binary files /dev/null and b/testing/output/expected/love.test.graphics.printf-1.png differ diff --git a/testing/output/expected/love.test.graphics.push-1.png b/testing/output/expected/love.test.graphics.push-1.png new file mode 100644 index 000000000..58ace03b3 Binary files /dev/null and b/testing/output/expected/love.test.graphics.push-1.png differ diff --git a/testing/output/expected/love.test.graphics.rectangle-1.png b/testing/output/expected/love.test.graphics.rectangle-1.png new file mode 100644 index 000000000..1f0e94a4e Binary files /dev/null and b/testing/output/expected/love.test.graphics.rectangle-1.png differ diff --git a/testing/output/expected/love.test.graphics.rectangle-2.png b/testing/output/expected/love.test.graphics.rectangle-2.png new file mode 100644 index 000000000..355c64e43 Binary files /dev/null and b/testing/output/expected/love.test.graphics.rectangle-2.png differ diff --git a/testing/output/expected/love.test.graphics.replaceTransform-1.png b/testing/output/expected/love.test.graphics.replaceTransform-1.png new file mode 100644 index 000000000..f80ad8f85 Binary files /dev/null and b/testing/output/expected/love.test.graphics.replaceTransform-1.png differ diff --git a/testing/output/expected/love.test.graphics.rotate-1.png b/testing/output/expected/love.test.graphics.rotate-1.png new file mode 100644 index 000000000..7c40b8c9e Binary files /dev/null and b/testing/output/expected/love.test.graphics.rotate-1.png differ diff --git a/testing/output/expected/love.test.graphics.scale-1.png b/testing/output/expected/love.test.graphics.scale-1.png new file mode 100644 index 000000000..a97348e50 Binary files /dev/null and b/testing/output/expected/love.test.graphics.scale-1.png differ diff --git a/testing/output/expected/love.test.graphics.setBlendMode-1.png b/testing/output/expected/love.test.graphics.setBlendMode-1.png new file mode 100644 index 000000000..71ad3bdd9 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setBlendMode-1.png differ diff --git a/testing/output/expected/love.test.graphics.setCanvas-1.png b/testing/output/expected/love.test.graphics.setCanvas-1.png new file mode 100644 index 000000000..a97348e50 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setCanvas-1.png differ diff --git a/testing/output/expected/love.test.graphics.setCanvas-2.png b/testing/output/expected/love.test.graphics.setCanvas-2.png new file mode 100644 index 000000000..58e329d72 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setCanvas-2.png differ diff --git a/testing/output/expected/love.test.graphics.setColor-1.png b/testing/output/expected/love.test.graphics.setColor-1.png new file mode 100644 index 000000000..3062177c1 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setColor-1.png differ diff --git a/testing/output/expected/love.test.graphics.setColorMask-1.png b/testing/output/expected/love.test.graphics.setColorMask-1.png new file mode 100644 index 000000000..315c7a936 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setColorMask-1.png differ diff --git a/testing/output/expected/love.test.graphics.setFont-1.png b/testing/output/expected/love.test.graphics.setFont-1.png new file mode 100644 index 000000000..31773fcf9 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setFont-1.png differ diff --git a/testing/output/expected/love.test.graphics.setFrontFaceWinding-1.png b/testing/output/expected/love.test.graphics.setFrontFaceWinding-1.png new file mode 100644 index 000000000..acc6f6932 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setFrontFaceWinding-1.png differ diff --git a/testing/output/expected/love.test.graphics.setLineJoin-1.png b/testing/output/expected/love.test.graphics.setLineJoin-1.png new file mode 100644 index 000000000..76397bdbe Binary files /dev/null and b/testing/output/expected/love.test.graphics.setLineJoin-1.png differ diff --git a/testing/output/expected/love.test.graphics.setLineStyle-1.png b/testing/output/expected/love.test.graphics.setLineStyle-1.png new file mode 100644 index 000000000..9df1b3817 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setLineStyle-1.png differ diff --git a/testing/output/expected/love.test.graphics.setLineWidth-1.png b/testing/output/expected/love.test.graphics.setLineWidth-1.png new file mode 100644 index 000000000..ce30d2cfe Binary files /dev/null and b/testing/output/expected/love.test.graphics.setLineWidth-1.png differ diff --git a/testing/output/expected/love.test.graphics.setScissor-1.png b/testing/output/expected/love.test.graphics.setScissor-1.png new file mode 100644 index 000000000..202f26d04 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setScissor-1.png differ diff --git a/testing/output/expected/love.test.graphics.setShader-1.png b/testing/output/expected/love.test.graphics.setShader-1.png new file mode 100644 index 000000000..315c7a936 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setShader-1.png differ diff --git a/testing/output/expected/love.test.graphics.setStencilState-1.png b/testing/output/expected/love.test.graphics.setStencilState-1.png new file mode 100644 index 000000000..773650483 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setStencilState-1.png differ diff --git a/testing/output/expected/love.test.graphics.setWireframe-1.png b/testing/output/expected/love.test.graphics.setWireframe-1.png new file mode 100644 index 000000000..ceea66531 Binary files /dev/null and b/testing/output/expected/love.test.graphics.setWireframe-1.png differ diff --git a/testing/output/expected/love.test.graphics.shear-1.png b/testing/output/expected/love.test.graphics.shear-1.png new file mode 100644 index 000000000..36a779c57 Binary files /dev/null and b/testing/output/expected/love.test.graphics.shear-1.png differ diff --git a/testing/output/expected/love.test.graphics.shear-2.png b/testing/output/expected/love.test.graphics.shear-2.png new file mode 100644 index 000000000..3d1873ea5 Binary files /dev/null and b/testing/output/expected/love.test.graphics.shear-2.png differ diff --git a/testing/output/expected/love.test.graphics.translate-1.png b/testing/output/expected/love.test.graphics.translate-1.png new file mode 100644 index 000000000..bcb6eb159 Binary files /dev/null and b/testing/output/expected/love.test.graphics.translate-1.png differ diff --git a/testing/output/expected/notes.txt b/testing/output/expected/notes.txt new file mode 100644 index 000000000..25b54bba5 --- /dev/null +++ b/testing/output/expected/notes.txt @@ -0,0 +1,2 @@ +# Expected Graphics Output +The images expected by the tests \ No newline at end of file diff --git a/testing/output/notes.txt b/testing/output/notes.txt new file mode 100644 index 000000000..bff4c6375 --- /dev/null +++ b/testing/output/notes.txt @@ -0,0 +1,2 @@ +# Testing Output +Any tests run will output an XML, MD, and HTML file here, assuming the tests are run with readwrite permissions for this repo \ No newline at end of file diff --git a/testing/readme.md b/testing/readme.md new file mode 100644 index 000000000..1e322d2ca --- /dev/null +++ b/testing/readme.md @@ -0,0 +1,142 @@ +# Lövetest +Test suite for the [Löve](https://github.com/love2d/love) APIs, based off of [this issue](https://github.com/love2d/love/issues/1745). + +Currently written for [Löve 12](https://github.com/love2d/love/tree/12.0-development), which is still in development. As such the test suite may fail if you try to run it with an older version of Löve due to it trying to call methods that don't exist. + +While the test suite is part of the main Löve repo, the test suite has it's own repo [here](https://github.com/ellraiser/love-test) so that it can be used with other builds like [love-potion](https://github.com/lovebrew/lovepotion). If you would like to contribute to the test suite please raise a PR on the [love-test](https://github.com/ellraiser/love-test) repo. + +--- + +## Features +- [x] Simple pass/fail tests written in Lua with minimal setup +- [x] Ability to run all tests with a simple command +- [x] Ability to see how many tests are passing/failing +- [x] Ability to run a subset of tests +- [x] Ability to easily run an individual test +- [x] Ability to see all visual results at a glance +- [x] Compare graphics test output with an expected output +- [x] Automatic testing that happens after every commit +- [x] No platform-specific dependencies / scripts + +--- + +## Coverage +This is the status of all module tests. +See the **Todo** section for outstanding tasks if you want to contribute! +| Module | Done | Skip | Modules | Done | Skip | +| ----------------- | ---- | ---- | ---------------- | ---- | ---- | +| 🟢 audio | 31 | 0 | 🟢 mouse | 18 | 0 | +| 🟢 data | 12 | 0 | 🟢 physics | 26 | 0 | +| 🟢 event | 4 | 2 | 🟢 sensor | 1 | 0 | +| 🟢 filesystem | 33 | 2 | 🟢 sound | 4 | 0 | +| 🟢 font | 7 | 0 | 🟢 system | 7 | 2 | +| 🟢 graphics | 105 | 1 | 🟢 thread | 5 | 0 | +| 🟢 image | 5 | 0 | 🟢 timer | 6 | 0 | +| 🟢 joystick | 6 | 0 | 🟢 touch | 3 | 0 | +| 🟢 keyboard | 10 | 0 | 🟢 video | 2 | 0 | +| 🟢 love | 6 | 0 | 🟢 window | 34 | 2 | +| 🟢 math | 20 | 0 | + +> The following modules are covered but at a basic level as we can't emulate hardware input nicely for all platforms + virtual runners: +> `joystick`, `keyboard`, `mouse`, `sensor` and `touch` + +--- + +## Running Tests +The testsuite aims to keep things as simple as possible, and just runs all the tests inside Löve to match how they'd be used by developers in-engine. +To run the tests, download the repo and then run the main.lua as you would a Löve game, i.e: + +WINDOWS: `& 'c:\Program Files\LOVE\love.exe' PATH_TO_TESTING_FOLDER/main.lua --console` +MACOS: `/Applications/love.app/Contents/MacOS/love PATH_TO_TESTING_FOLDER/main.lua` +LINUX: `./love.AppImage PATH_TO_TESTING_FOLDER/main.lua` + +By default all tests will be run for all modules. +If you want to specify a module/s you can use: +`--modules filesystem,audio` +If you want to specify only 1 specific method only you can use: +`--method filesystem write` + +All results will be printed in the console per method as PASS, FAIL, or SKIP with total assertions met on a module level and overall level. + +When finished, the following files will be generated in the `/output` directory with a summary of the test results: +- an `XML` file in the style of [JUnit XML](https://www.ibm.com/docs/en/developer-for-zos/14.1?topic=formats-junit-xml-format) +- a `HTML` file that shows the report + any visual test results +- a `Markdown` file you can use with [this github action](https://github.com/ellraiser/love-test-report) +> An example of all types of output can be found in the `/examples` +> The visual results of any graphic tests can be found in `/output/actual` + +--- + +## Architecture +Each method and object has it's own test method written in `/tests` under the matching module name. + +When you run the tests, a single TestSuite object is created which handles the progress + totals for all the tests. +Each module has a TestModule object created, and each test method has a TestMethod object created which keeps track of assertions for that method. You can currently do the following assertions: +- **assertNotNil**(value) +- **assertEquals**(expected, actual, label) +- **assertTrue**(value, label) +- **assertFalse**(value, label) +- **assertNotEquals**(expected, actual, label) +- **assertRange**(actual, min, max, label) +- **assertMatch**({option1, option2, option3 ...}, actual, label) +- **assertGreaterEqual**(expected, actual, label) +- **assertLessEqual**(expected, actual, label) +- **assertObject**(table) +- **assertCoords**(expected, actual, label) + +Example test method: +```lua +-- love.filesystem.read test method +-- all methods should be put under love.test.MODULE.METHOD, matching the API +love.test.filesystem.read = function(test) + -- setup any data needed then run any asserts using the passed test object + local content, size = love.filesystem.read('resources/test.txt') + test:assertNotNil(content) + test:assertEquals('helloworld', content, 'check content match') + test:assertEquals(10, size, 'check size match') + content, size = love.filesystem.read('resources/test.txt', 5) + test:assertNotNil(content) + test:assertEquals('hello', content, 'check content match') + test:assertEquals(5, size, 'check size match') + -- no need to return anything or cleanup, GCC is called after each method +end +``` + +Each test is run inside it's own coroutine - you can use `test:waitFrames(frames)` or `test:waitSeconds(seconds)` to pause the test for a small period if you need to check things that won't happen for a few frames/seconds. + +After each test method is ran, the assertions are totalled up, printed, and we move onto the next method! Once all methods in the suite are run a total pass/fail/skip is given for that module and we move onto the next module (if any) + +For sanity-checking, if it's currently not covered or it's not possible to test the method we can set the test to be skipped with `test:skipTest(reason)` - this way we still see the method listed in the test output without it affected the pass/fail totals + +--- + +## Todo +If you would like to contribute to the test suite please raise a PR with the main [love-test](https://github.com/ellraiser/love-test) repo. + +There is a list of outstanding methods that require test coverage in `todo.md`, expanding on any existing tests is also very welcome! + +--- + +## Graphics Tolerance +By default all graphic tests are run with pixel precision and 0 rgba tolerance. + +However there are a couple of methods that on some platforms require some slight tolerance to allow for tiny differences in rendering. +| Test | OS | Exception | Reason | +| -------------------------- | --------- | ------------------- | ------ | +| love.graphics.drawInstanced | Windows | 1rgba tolerance | On Windows there's a couple pixels a tiny bit off, most likely due to complexity of the mesh drawn | +| love.graphics.setBlendMode | Win/Lin | 1rgba tolerance | Blendmodes have some small varience on some machines | + +--- + +## Runner Exceptions +The automated tests through Github work for the most part however there are a few exceptions that have to be accounted for due to limitations of the VMs and the graphics emulation used. + +These exceptions are either skipped, or handled by using a 1px or 1/255rgba tolerance - when run locally on real hardware, these tests pass fine at the default 0 tolerance. +You can specify the test suite is being run on a runner by adding the `--isRunner` flag in your workflow file, i.e.: +`& 'c:\Program Files\LOVE\love.exe' PATH_TO_TESTING_FOLDER/main.lua --console --all --isRunner` +| Test | OS | Exception | Reason | +| -------------------------- | --------- | ------------------- | ------ | +| love.graphics.setWireframe | MacOS | 1px tolerance | Wireframes are offset by 1,1 when drawn | +| love.graphica.arc | MacOS | Skipped | Arc curves are drawn slightly off at really low scale | +| love.graphics.setLineStyle | Linux | 1rgba tolerance | 'Rough' lines blend differently with the background rgba | +| love.audio.RecordingDevice | All | Skipped | Recording devices can't be emulated on runners | diff --git a/testing/resources/alsoft.conf b/testing/resources/alsoft.conf new file mode 100644 index 000000000..6d1add00f --- /dev/null +++ b/testing/resources/alsoft.conf @@ -0,0 +1,491 @@ +# OpenAL config file. +# +# Option blocks may appear multiple times, and duplicated options will take the +# last value specified. Environment variables may be specified within option +# values, and are automatically substituted when the config file is loaded. +# Environment variable names may only contain alpha-numeric characters (a-z, +# A-Z, 0-9) and underscores (_), and are prefixed with $. For example, +# specifying "$HOME/file.ext" would typically result in something like +# "/home/user/file.ext". To specify an actual "$" character, use "$$". +# +# Device-specific values may be specified by including the device name in the +# block name, with "general" replaced by the device name. That is, general +# options for the device "Name of Device" would be in the [Name of Device] +# block, while ALSA options would be in the [alsa/Name of Device] block. +# Options marked as "(global)" are not influenced by the device. +# +# The system-wide settings can be put in /etc/openal/alsoft.conf and user- +# specific override settings in $HOME/.alsoftrc. +# For Windows, these settings should go into $AppData\alsoft.ini +# +# Option and block names are case-senstive. The supplied values are only hints +# and may not be honored (though generally it'll try to get as close as +# possible). Note: options that are left unset may default to app- or system- +# specified values. These are the current available settings: + +## +## General stuff +## +[general] + +## disable-cpu-exts: (global) +# Disables use of specialized methods that use specific CPU intrinsics. +# Certain methods may utilize CPU extensions for improved performance, and +# this option is useful for preventing some or all of those methods from being +# used. The available extensions are: sse, sse2, sse3, sse4.1, and neon. +# Specifying 'all' disables use of all such specialized methods. +#disable-cpu-exts = + +## drivers: (global) +# Sets the backend driver list order, comma-seperated. Unknown backends and +# duplicated names are ignored. Unlisted backends won't be considered for use +# unless the list is ended with a comma (e.g. 'oss,' will try OSS first before +# other backends, while 'oss' will try OSS only). Backends prepended with - +# won't be considered for use (e.g. '-oss,' will try all available backends +# except OSS). An empty list means to try all backends. +drivers = wave + +## channels: +# Sets the output channel configuration. If left unspecified, one will try to +# be detected from the system, and defaulting to stereo. The available values +# are: mono, stereo, quad, surround51, surround51rear, surround61, surround71, +# ambi1, ambi2, ambi3. Note that the ambi* configurations provide ambisonic +# channels of the given order (using ACN ordering and SN3D normalization by +# default), which need to be decoded to play correctly on speakers. +#channels = + +## sample-type: +# Sets the output sample type. Currently, all mixing is done with 32-bit float +# and converted to the output sample type as needed. Available values are: +# int8 - signed 8-bit int +# uint8 - unsigned 8-bit int +# int16 - signed 16-bit int +# uint16 - unsigned 16-bit int +# int32 - signed 32-bit int +# uint32 - unsigned 32-bit int +# float32 - 32-bit float +#sample-type = float32 + +## frequency: +# Sets the output frequency. If left unspecified it will try to detect a +# default from the system, otherwise it will default to 44100. +#frequency = + +## period_size: +# Sets the update period size, in frames. This is the number of frames needed +# for each mixing update. Acceptable values range between 64 and 8192. +#period_size = 1024 + +## periods: +# Sets the number of update periods. Higher values create a larger mix ahead, +# which helps protect against skips when the CPU is under load, but increases +# the delay between a sound getting mixed and being heard. Acceptable values +# range between 2 and 16. +#periods = 3 + +## stereo-mode: +# Specifies if stereo output is treated as being headphones or speakers. With +# headphones, HRTF or crossfeed filters may be used for better audio quality. +# Valid settings are auto, speakers, and headphones. +#stereo-mode = auto + +## stereo-encoding: +# Specifies the encoding method for non-HRTF stereo output. 'panpot' (default) +# uses standard amplitude panning (aka pair-wise, stereo pair, etc) between +# -30 and +30 degrees, while 'uhj' creates stereo-compatible two-channel UHJ +# output, which encodes some surround sound information into stereo output +# that can be decoded with a surround sound receiver. If crossfeed filters are +# used, UHJ is disabled. +#stereo-encoding = panpot + +## ambi-format: +# Specifies the channel order and normalization for the "ambi*" set of channel +# configurations. Valid settings are: fuma, acn+sn3d, acn+n3d +#ambi-format = acn+sn3d + +## hrtf: +# Controls HRTF processing. These filters provide better spatialization of +# sounds while using headphones, but do require a bit more CPU power. The +# default filters will only work with 44100hz or 48000hz stereo output. While +# HRTF is used, the cf_level option is ignored. Setting this to auto (default) +# will allow HRTF to be used when headphones are detected or the app requests +# it, while setting true or false will forcefully enable or disable HRTF +# respectively. +#hrtf = auto + +## default-hrtf: +# Specifies the default HRTF to use. When multiple HRTFs are available, this +# determines the preferred one to use if none are specifically requested. Note +# that this is the enumerated HRTF name, not necessarily the filename. +#default-hrtf = + +## hrtf-paths: +# Specifies a comma-separated list of paths containing HRTF data sets. The +# format of the files are described in docs/hrtf.txt. The files within the +# directories must have the .mhr file extension to be recognized. By default, +# OS-dependent data paths will be used. They will also be used if the list +# ends with a comma. On Windows this is: +# $AppData\openal\hrtf +# And on other systems, it's (in order): +# $XDG_DATA_HOME/openal/hrtf (defaults to $HOME/.local/share/openal/hrtf) +# $XDG_DATA_DIRS/openal/hrtf (defaults to /usr/local/share/openal/hrtf and +# /usr/share/openal/hrtf) +#hrtf-paths = + +## cf_level: +# Sets the crossfeed level for stereo output. Valid values are: +# 0 - No crossfeed +# 1 - Low crossfeed +# 2 - Middle crossfeed +# 3 - High crossfeed (virtual speakers are closer to itself) +# 4 - Low easy crossfeed +# 5 - Middle easy crossfeed +# 6 - High easy crossfeed +# Users of headphones may want to try various settings. Has no effect on non- +# stereo modes. +#cf_level = 0 + +## resampler: (global) +# Selects the resampler used when mixing sources. Valid values are: +# point - nearest sample, no interpolation +# linear - extrapolates samples using a linear slope between samples +# cubic - extrapolates samples using a Catmull-Rom spline +# bsinc12 - extrapolates samples using a band-limited Sinc filter (varying +# between 12 and 24 points, with anti-aliasing) +# bsinc24 - extrapolates samples using a band-limited Sinc filter (varying +# between 24 and 48 points, with anti-aliasing) +#resampler = linear + +## rt-prio: (global) +# Sets real-time priority for the mixing thread. Not all drivers may use this +# (eg. PortAudio) as they already control the priority of the mixing thread. +# 0 and negative values will disable it. Note that this may constitute a +# security risk since a real-time priority thread can indefinitely block +# normal-priority threads if it fails to wait. As such, the default is +# disabled. +#rt-prio = 0 + +## sources: +# Sets the maximum number of allocatable sources. Lower values may help for +# systems with apps that try to play more sounds than the CPU can handle. +#sources = 256 + +## slots: +# Sets the maximum number of Auxiliary Effect Slots an app can create. A slot +# can use a non-negligible amount of CPU time if an effect is set on it even +# if no sources are feeding it, so this may help when apps use more than the +# system can handle. +#slots = 64 + +## sends: +# Limits the number of auxiliary sends allowed per source. Setting this higher +# than the default has no effect. +#sends = 16 + +## front-stablizer: +# Applies filters to "stablize" front sound imaging. A psychoacoustic method +# is used to generate a front-center channel signal from the front-left and +# front-right channels, improving the front response by reducing the combing +# artifacts and phase errors. Consequently, it will only work with channel +# configurations that include front-left, front-right, and front-center. +#front-stablizer = false + +## output-limiter: +# Applies a gain limiter on the final mixed output. This reduces the volume +# when the output samples would otherwise clamp, avoiding excessive clipping +# noise. +#output-limiter = true + +## dither: +# Applies dithering on the final mix, for 8- and 16-bit output by default. +# This replaces the distortion created by nearest-value quantization with low- +# level whitenoise. +#dither = true + +## dither-depth: +# Quantization bit-depth for dithered output. A value of 0 (or less) will +# match the output sample depth. For int32, uint32, and float32 output, 0 will +# disable dithering because they're at or beyond the rendered precision. The +# maximum dither depth is 24. +#dither-depth = 0 + +## volume-adjust: +# A global volume adjustment for source output, expressed in decibels. The +# value is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will +# be a scale of 4x, etc. Similarly, -6 will be x1/2, and -12 is about x1/4. A +# value of 0 means no change. +#volume-adjust = 0 + +## excludefx: (global) +# Sets which effects to exclude, preventing apps from using them. This can +# help for apps that try to use effects which are too CPU intensive for the +# system to handle. Available effects are: eaxreverb,reverb,autowah,chorus, +# compressor,distortion,echo,equalizer,flanger,modulator,dedicated,pshifter, +# fshifter +#excludefx = + +## default-reverb: (global) +# A reverb preset that applies by default to all sources on send 0 +# (applications that set their own slots on send 0 will override this). +# Available presets are: None, Generic, PaddedCell, Room, Bathroom, +# Livingroom, Stoneroom, Auditorium, ConcertHall, Cave, Arena, Hangar, +# CarpetedHallway, Hallway, StoneCorridor, Alley, Forest, City, Moutains, +# Quarry, Plain, ParkingLot, SewerPipe, Underwater, Drugged, Dizzy, Psychotic. +#default-reverb = + +## trap-alc-error: (global) +# Generates a SIGTRAP signal when an ALC device error is generated, on systems +# that support it. This helps when debugging, while trying to find the cause +# of a device error. On Windows, a breakpoint exception is generated. +#trap-alc-error = false + +## trap-al-error: (global) +# Generates a SIGTRAP signal when an AL context error is generated, on systems +# that support it. This helps when debugging, while trying to find the cause +# of a context error. On Windows, a breakpoint exception is generated. +#trap-al-error = false + +## +## Ambisonic decoder stuff +## +[decoder] + +## hq-mode: +# Enables a high-quality ambisonic decoder. This mode is capable of frequency- +# dependent processing, creating a better reproduction of 3D sound rendering +# over surround sound speakers. Enabling this also requires specifying decoder +# configuration files for the appropriate speaker configuration you intend to +# use (see the quad, surround51, etc options below). Currently, up to third- +# order decoding is supported. +hq-mode = false + +## distance-comp: +# Enables compensation for the speakers' relative distances to the listener. +# This applies the necessary delays and attenuation to make the speakers +# behave as though they are all equidistant, which is important for proper +# playback of 3D sound rendering. Requires the proper distances to be +# specified in the decoder configuration file. +distance-comp = true + +## nfc: +# Enables near-field control filters. This simulates and compensates for low- +# frequency effects caused by the curvature of nearby sound-waves, which +# creates a more realistic perception of sound distance. Note that the effect +# may be stronger or weaker than intended if the application doesn't use or +# specify an appropriate unit scale, or if incorrect speaker distances are set +# in the decoder configuration file. Requires hq-mode to be enabled. +nfc = true + +## nfc-ref-delay +# Specifies the reference delay value for ambisonic output. When channels is +# set to one of the ambi* formats, this option enables NFC-HOA output with the +# specified Reference Delay parameter. The specified value can then be shared +# with an appropriate NFC-HOA decoder to reproduce correct near-field effects. +# Keep in mind that despite being designed for higher-order ambisonics, this +# applies to first-order output all the same. When left unset, normal output +# is created with no near-field simulation. +nfc-ref-delay = + +## quad: +# Decoder configuration file for Quadraphonic channel output. See +# docs/ambdec.txt for a description of the file format. +quad = + +## surround51: +# Decoder configuration file for 5.1 Surround (Side and Rear) channel output. +# See docs/ambdec.txt for a description of the file format. +surround51 = + +## surround61: +# Decoder configuration file for 6.1 Surround channel output. See +# docs/ambdec.txt for a description of the file format. +surround61 = + +## surround71: +# Decoder configuration file for 7.1 Surround channel output. See +# docs/ambdec.txt for a description of the file format. Note: This can be used +# to enable 3D7.1 with the appropriate configuration and speaker placement, +# see docs/3D7.1.txt. +surround71 = + +## +## Reverb effect stuff (includes EAX reverb) +## +[reverb] + +## boost: (global) +# A global amplification for reverb output, expressed in decibels. The value +# is logarithmic, so +6 will be a scale of (approximately) 2x, +12 will be a +# scale of 4x, etc. Similarly, -6 will be about half, and -12 about 1/4th. A +# value of 0 means no change. +#boost = 0 + +## +## PulseAudio backend stuff +## +[pulse] + +## spawn-server: (global) +# Attempts to autospawn a PulseAudio server whenever needed (initializing the +# backend, enumerating devices, etc). Setting autospawn to false in Pulse's +# client.conf will still prevent autospawning even if this is set to true. +#spawn-server = true + +## allow-moves: (global) +# Allows PulseAudio to move active streams to different devices. Note that the +# device specifier (seen by applications) will not be updated when this +# occurs, and neither will the AL device configuration (sample rate, format, +# etc). +#allow-moves = false + +## fix-rate: +# Specifies whether to match the playback stream's sample rate to the device's +# sample rate. Enabling this forces OpenAL Soft to mix sources and effects +# directly to the actual output rate, avoiding a second resample pass by the +# PulseAudio server. +#fix-rate = false + +## +## ALSA backend stuff +## +[alsa] + +## device: (global) +# Sets the device name for the default playback device. +#device = default + +## device-prefix: (global) +# Sets the prefix used by the discovered (non-default) playback devices. This +# will be appended with "CARD=c,DEV=d", where c is the card id and d is the +# device index for the requested device name. +#device-prefix = plughw: + +## device-prefix-*: (global) +# Card- and device-specific prefixes may be used to override the device-prefix +# option. The option may specify the card id (eg, device-prefix-NVidia), or +# the card id and device index (eg, device-prefix-NVidia-0). The card id is +# case-sensitive. +#device-prefix- = + +## capture: (global) +# Sets the device name for the default capture device. +#capture = default + +## capture-prefix: (global) +# Sets the prefix used by the discovered (non-default) capture devices. This +# will be appended with "CARD=c,DEV=d", where c is the card id and d is the +# device number for the requested device name. +#capture-prefix = plughw: + +## capture-prefix-*: (global) +# Card- and device-specific prefixes may be used to override the +# capture-prefix option. The option may specify the card id (eg, +# capture-prefix-NVidia), or the card id and device index (eg, +# capture-prefix-NVidia-0). The card id is case-sensitive. +#capture-prefix- = + +## mmap: +# Sets whether to try using mmap mode (helps reduce latencies and CPU +# consumption). If mmap isn't available, it will automatically fall back to +# non-mmap mode. True, yes, on, and non-0 values will attempt to use mmap. 0 +# and anything else will force mmap off. +#mmap = true + +## allow-resampler: +# Specifies whether to allow ALSA's built-in resampler. Enabling this will +# allow the playback device to be set to a different sample rate than the +# actual output, causing ALSA to apply its own resampling pass after OpenAL +# Soft resamples and mixes the sources and effects for output. +#allow-resampler = false + +## +## OSS backend stuff +## +[oss] + +## device: (global) +# Sets the device name for OSS output. +#device = /dev/dsp + +## capture: (global) +# Sets the device name for OSS capture. +#capture = /dev/dsp + +## +## Solaris backend stuff +## +[solaris] + +## device: (global) +# Sets the device name for Solaris output. +#device = /dev/audio + +## +## QSA backend stuff +## +[qsa] + +## +## JACK backend stuff +## +[jack] + +## spawn-server: (global) +# Attempts to autospawn a JACK server whenever needed (initializing the +# backend, opening devices, etc). +#spawn-server = false + +## buffer-size: +# Sets the update buffer size, in samples, that the backend will keep buffered +# to handle the server's real-time processing requests. This value must be a +# power of 2, or else it will be rounded up to the next power of 2. If it is +# less than JACK's buffer update size, it will be clamped. This option may +# be useful in case the server's update size is too small and doesn't give the +# mixer time to keep enough audio available for the processing requests. +#buffer-size = 0 + +## +## WASAPI backend stuff +## +[wasapi] + +## +## DirectSound backend stuff +## +[dsound] + +## +## Windows Multimedia backend stuff +## +[winmm] + +## +## PortAudio backend stuff +## +[port] + +## device: (global) +# Sets the device index for output. Negative values will use the default as +# given by PortAudio itself. +#device = -1 + +## capture: (global) +# Sets the device index for capture. Negative values will use the default as +# given by PortAudio itself. +#capture = -1 + +## +## Wave File Writer stuff +## +[wave] + +## file: (global) +# Sets the filename of the wave file to write to. An empty name prevents the +# backend from opening, even when explicitly requested. +# THIS WILL OVERWRITE EXISTING FILES WITHOUT QUESTION! +file = output.wav + +## bformat: (global) +# Creates AMB format files using first-order ambisonics instead of a standard +# single- or multi-channel .wav file. +#bformat = false \ No newline at end of file diff --git a/testing/resources/click.ogg b/testing/resources/click.ogg new file mode 100644 index 000000000..49707b3e8 Binary files /dev/null and b/testing/resources/click.ogg differ diff --git a/testing/resources/clickmono.ogg b/testing/resources/clickmono.ogg new file mode 100644 index 000000000..d1b567e7d Binary files /dev/null and b/testing/resources/clickmono.ogg differ diff --git a/testing/resources/cubemap.png b/testing/resources/cubemap.png new file mode 100644 index 000000000..2b8b2ed0c Binary files /dev/null and b/testing/resources/cubemap.png differ diff --git a/testing/resources/font-letters-ab.png b/testing/resources/font-letters-ab.png new file mode 100644 index 000000000..3ec8aeca3 Binary files /dev/null and b/testing/resources/font-letters-ab.png differ diff --git a/testing/resources/font-letters-cd.png b/testing/resources/font-letters-cd.png new file mode 100644 index 000000000..51190f648 Binary files /dev/null and b/testing/resources/font-letters-cd.png differ diff --git a/testing/resources/font.bmp b/testing/resources/font.bmp new file mode 100644 index 000000000..3180d031c Binary files /dev/null and b/testing/resources/font.bmp differ diff --git a/testing/resources/font.ttf b/testing/resources/font.ttf new file mode 100644 index 000000000..0ff4bf7d3 Binary files /dev/null and b/testing/resources/font.ttf differ diff --git a/testing/resources/love.dxt1 b/testing/resources/love.dxt1 new file mode 100644 index 000000000..88cb9e689 Binary files /dev/null and b/testing/resources/love.dxt1 differ diff --git a/testing/resources/love.png b/testing/resources/love.png new file mode 100644 index 000000000..e2612a857 Binary files /dev/null and b/testing/resources/love.png differ diff --git a/testing/resources/love2.png b/testing/resources/love2.png new file mode 100644 index 000000000..e2612a857 Binary files /dev/null and b/testing/resources/love2.png differ diff --git a/testing/resources/love3.png b/testing/resources/love3.png new file mode 100644 index 000000000..e2612a857 Binary files /dev/null and b/testing/resources/love3.png differ diff --git a/testing/resources/loveinv.png b/testing/resources/loveinv.png new file mode 100644 index 000000000..7be943a20 Binary files /dev/null and b/testing/resources/loveinv.png differ diff --git a/testing/resources/mappings.txt b/testing/resources/mappings.txt new file mode 100644 index 000000000..478b1762e --- /dev/null +++ b/testing/resources/mappings.txt @@ -0,0 +1,1973 @@ +03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, +03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, +03000000d0160000040d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000050d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000060d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000070d000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000d0160000600a000000000000,4Play Adapter,a:b1,b:b3,back:b4,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,leftstick:b14,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b15,righttrigger:b9,rightx:a3,righty:a4,start:b5,x:b0,y:b2,platform:Windows, +03000000c82d00000031000000000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000531000000000000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000951000000000000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows, +03000000008000000210000000000000,8BitDo F30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000003512000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000c82d00001028000000000000,8BitDo F30 Arcade Joystick,a:b0,b:b1,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d000011ab000000000000,8BitDo F30 Arcade Joystick,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000801000000900000000000000,8BitDo F30 Arcade Stick,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001038000000000000,8BitDo F30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000090000000000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001251000000000000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001151000000000000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000150000000000000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000151000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000650000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00005106000000000000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,guide:b2,leftshoulder:b8,lefttrigger:b9,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00002090000000000000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000310000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000451000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a2,rightx:a3,righty:a5,start:b11,platform:Windows, +03000000c82d00002028000000000000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00008010000000000000,8BitDo N30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d0000e002000000000000,8BitDo N30,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b6,platform:Windows, +03000000c82d00000190000000000000,8BitDo N30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001590000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006528000000000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000290000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows, +03000000c82d00003038000000000000,8BitDo N64,+rightx:b9,+righty:b3,-rightx:b4,-righty:b8,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,platform:Windows, +03000000c82d00006928000000000000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b11,platform:Windows, +03000000c82d00002590000000000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000003512000012ab000000000000,8BitDo NES30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Windows, +03000000c82d000012ab000000000000,8BitDo NES30,a:b1,b:b0,back:b10,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000022000000090000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000203800000900000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00002038000000000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000751000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000851000000000000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000360000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000361000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000660000000000000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000131000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000231000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000331000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000431000000000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00002867000000000000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a2,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a5,start:b10,x:b3,y:b4,platform:Windows, +03000000c82d00000130000000000000,8BitDo SF30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000060000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000061000000000000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000102800000900000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000021ab000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003028000000000000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +030000003512000020ab000000000000,8BitDo SN30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000030000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000351000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a2,rightshoulder:b7,rightx:a3,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001290000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d000020ab000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00004028000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00006228000000000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000021000000000000,8BitDo SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000260000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00000261000000000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00001230000000000000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001530000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001630000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001730000000000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001130000000000000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001330000000000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00000121000000000000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000a00500003232000000000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Windows, +03000000c82d00001890000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Windows, +03000000c82d00003032000000000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Windows, +030000008f0e00001200000000000000,Acme GA02,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000355000000000000,Acrux,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fa190000f0ff000000000000,Acteck AGJ 3200,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d1180000402c000000000000,ADT1,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a3,rightx:a2,righty:a5,x:b3,y:b4,platform:Windows, +030000006f0e00008801000000000000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000341a00003608000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000263000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001101000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001401000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001402000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001901000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001a01000000000000,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001301000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001302000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001304000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00001413000000000000,Afterglow Xbox Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00003901000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ab1200000103000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000000f9000000000000,Afterglow Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000100000008200000000000000,Akishop Customs PS360,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000007c1800000006000000000000,Alienware Dual Compatible PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000491900001904000000000000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000710100001904000000000000,Amazon Luna Controller,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b8,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b4,rightstick:b7,rightx:a3,righty:a4,start:b6,x:b3,y:b2,platform:Windows, +03000000830500000160000000000000,Arcade,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b4,platform:Windows, +03000000120c0000100e000000000000,Armor 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000490b00004406000000000000,ASCII Seamic Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000869800002500000000000000,Astro C40 TR PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000a30c00002700000000000000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000a30c00002800000000000000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000050b00000579000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000050b00000679000000000000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000503200000110000000000000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,start:b3,platform:Windows, +03000000503200000210000000000000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +03000000e4150000103f000000000000,Batarang,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000e557000000000000,Batarang PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100001352000000000000,Battalife Joystick,a:b6,b:b7,back:b2,leftshoulder:b0,leftx:a0,lefty:a1,rightshoulder:b1,start:b3,x:b4,y:b5,platform:Windows, +030000006f0e00003201000000000000,Battlefield 4 PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000001f9000000000000,BB 070,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000002a79000000000000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000bc2000005250000000000000,Beitong G3,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a3,righty:a4,start:b15,x:b3,y:b4,platform:Windows, +030000000d0500000208000000000000,Belkin Nostromo N40,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000bc2000006012000000000000,Betop 2126F,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000000055000000000000,Betop BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000006312000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006321000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000bc2000006412000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000555000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000655000000000000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000000700000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000808300000300000000000000,Betop Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00006401000000000000,BF One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000300f00000202000000000000,Bigben,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a5,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +030000006b1400000209000000000000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b1400000055000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006b1400000103000000000000,Bigben PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000120c0000200e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000210e000000000000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f10e000000000000,Brook PS2 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000310c000000000000,Brook Super Converter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00000b00000000000000,Buffalo BSGP1601 Series,a:b5,b:b3,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b4,y:b2,platform:Windows, +030000005b1c00002400000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, +030000005b1c00002500000000000000,Capcom Home Arcade Controller,a:b3,b:b4,back:b7,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b6,x:b0,y:b1,platform:Windows, +030000006d04000042c2000000000000,ChillStream,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000e82000006058000000000000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000457500000401000000000000,Cobra,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000b0400003365000000000000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Windows, +030000004c050000c505000000000000,CronusMax Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000d814000007cd000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000d8140000cefa000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000260900008888000000000000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a4,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Windows, +030000003807000002cb000000000000,Cyborg,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000a306000022f6000000000000,Cyborg V.3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000f806000000a3000000000000,DA Leader,a:b7,b:b6,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b8,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:b3,rightx:a2,righty:a3,start:b12,x:b4,y:b5,platform:Windows, +030000001a1c00000001000000000000,Datel Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000451300000830000000000000,Defender Game Racer X7,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000791d00000103000000000000,Dual Box Wii,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c0160000e105000000000000,Dual Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +030000004f040000070f000000000000,Dual Power,a:b8,b:b9,back:b4,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,leftshoulder:b13,leftstick:b6,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b12,rightstick:b7,righttrigger:b15,start:b5,x:b10,y:b11,platform:Windows, +030000004f04000012b3000000000000,Dual Power 3,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000020b3000000000000,Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000bd12000002e0000000000000,Dual Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000ff1100003133000000000000,DualForce,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b1,platform:Windows, +030000008f0e00000910000000000000,DualShock 2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000317300000100000000000000,DualShock 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000006f0e00003001000000000000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fc0400000250000000000000,Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +030000006e0500000a20000000000000,Elecom DUX60 MMO,a:b2,b:b3,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b14,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b15,righttrigger:b13,rightx:a3,righty:a4,start:b20,x:b0,y:b1,platform:Windows, +03000000b80500000410000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000b80500000610000000000000,Elecom Gamepad,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +030000006e0500000520000000000000,Elecom P301U PlayStation Controller Adapter,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +03000000411200004450000000000000,Elecom U1012,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000320000000000000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000e20000000000000,Elecom U3912T,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000f20000000000000,Elecom U4013S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500001320000000000000,Elecom U4113,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006e0500001020000000000000,Elecom U4113S,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +030000006e0500000720000000000000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +030000007d0400000640000000000000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000120c0000f61c000000000000,Elite,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000430b00000300000000000000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000242f000000b7000000000000,ESM 9110,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, +03000000101c0000181c000000000000,Essential,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b4,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00000f31000000000000,EXEQ,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000341a00000108000000000000,EXEQ RF Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00008401000000000000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008101000000000000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00008001000000000000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000021000000090000000000000,FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Windows, +0300000011040000c600000000000000,FC801,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000852100000201000000000000,FF GP1,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000028f0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b00002ef0000000000000,Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000038f0000000000000,Fightpad TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03005036852100000000000000000000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000f806000001a3000000000000,Firestorm,a:b9,b:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b0,leftstick:b10,lefttrigger:b1,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b12,x:b8,y:b4,platform:Windows, +03000000b50700000399000000000000,Firestorm 2,a:b2,b:b4,back:b10,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,righttrigger:b9,start:b11,x:b3,y:b5,platform:Windows, +03000000b50700001302000000000000,Firestorm D3,a:b0,b:b2,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,x:b1,y:b3,platform:Windows, +03000000b40400001024000000000000,Flydigi Apex,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000151900004000000000000000,Flydigi Vader 2,a:b27,b:b26,back:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b23,leftstick:b17,lefttrigger:b21,leftx:a0,lefty:a1,misc1:b15,paddle1:b11,paddle2:b10,paddle3:b13,paddle4:b12,rightshoulder:b22,rightstick:b16,righttrigger:b20,rightx:a3,righty:a4,start:b18,x:b25,y:b24,platform:Windows, +03000000b40400001124000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b14,paddle1:b4,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b2,y:b3,platform:Windows, +03000000b40400001224000000000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000008305000000a0000000000000,G08XU,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b5,x:b2,y:b3,platform:Windows, +0300000066f700000100000000000000,Game VIB Joystick,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +03000000260900002625000000000000,GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,lefttrigger:a4,leftx:a0,lefty:a1,righttrigger:a5,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Windows, +03000000341a000005f7000000000000,GameCube Controller,a:b2,b:b3,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b1,y:b0,platform:Windows, +03000000430b00000500000000000000,GameCube Controller,a:b0,b:b2,dpdown:b10,dpleft:b8,dpright:b9,dpup:b11,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a3,rightx:a5,righty:a2,start:b7,x:b1,y:b3,platform:Windows, +03000000790000004718000000000000,GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000790000004618000000000000,GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +030000008f0e00000d31000000000000,Gamepad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ac0500003d03000000000000,GameSir G3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500005b05000000000000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000ac0500002d02000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500004d04000000000000,GameSir G4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ac0500001a06000000000000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000004c0e00001035000000000000,Gamester,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00001110000000000000,GameStick Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +0300000047530000616d000000000000,GameStop,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000c01100000140000000000000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000b62500000100000000000000,Gametel GT004 01,a:b3,b:b0,dpdown:b10,dpleft:b9,dpright:b8,dpup:b11,leftshoulder:b4,rightshoulder:b5,start:b7,x:b1,y:b2,platform:Windows, +030000008f0e00001411000000000000,Gamo2 Divaller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000a857000000000000,Gator Claw,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000c9110000f055000000000000,GC100XF,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008305000009a0000000000000,Genius,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000008305000031b0000000000000,Genius Maxfire Blaze 3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000451300000010000000000000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000005c1a00003330000000000000,Genius MaxFire Grandias 12V,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000300f00000b01000000000000,GGE909 Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c283000000000000,Gioteck PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000021c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f025000031c1000000000000,Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c383000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000f0250000c483000000000000,Gioteck VX2 PlayStation Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000026b3000000000000,GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000079000000d418000000000000,GPD Win,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000025b000000000000,GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000007d0400000840000000000000,Gravis Destroyer Tilt,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,x:b0,y:b3,platform:Windows, +030000007d0400000540000000000000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000280400000140000000000000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a3,dpup:-a4,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000610000000000000,GreenAsia,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a5,righty:a2,start:b11,x:b3,y:b0,platform:Windows, +03000000ac0500006b05000000000000,GT2a,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000341a00000302000000000000,Hama Scorpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004900000000000000,Hatsune Miku Sho PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000001008000001e1000000000000,Havit HV G60,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, +030000000d0f00000c00000000000000,HEXT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d81400000862000000000000,HitBox Edition Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000632500002605000000000000,HJD X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00000a00000000000000,Hori DOA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008500000000000000,Hori Fighting Commander 2016 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002500000000000000,Hori Fighting Commander 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002d00000000000000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008400000000000000,Hori Fighting Commander 5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005100000000000000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008600000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000ba00000000000000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008800000000000000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +030000000d0f00008700000000000000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001000000000000000,Hori Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003200000000000000,Hori Fightstick 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c000000000000000,Hori Fightstick 4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00000d00000000000000,Hori Fightstick EX2,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00003701000000000000,Hori Fightstick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Windows, +030000000d0f00004000000000000000,Hori Fightstick Mini 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b4,rightshoulder:b7,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002100000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002700000000000000,Hori Fightstick V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000a000000000000000,Hori Grip TAC4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b13,x:b0,y:b3,platform:Windows, +030000000d0f0000a500000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000a600000000000000,Hori Miku Project Diva X HD PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00000101000000000000,Hori Mini Hatsune Miku FT,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005400000000000000,Hori Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00000900000000000000,Hori Pad 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004d00000000000000,Hori Pad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003801000000000000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Windows, +030000000d0f00009200000000000000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002301000000000000,Hori PS4 Controller Light,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000000d0f00001100000000000000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00002600000000000000,Hori Real Arcade Pro 3P,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004b00000000000000,Hori Real Arcade Pro 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008a00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00008b00000000000000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006f00000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00007000000000000000,Hori Real Arcade Pro 4 VLX,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00003d00000000000000,Hori Real Arcade Pro N3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b4,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b6,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000ae00000000000000,Hori Real Arcade Pro N4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f00008c00000000000000,Hori Real Arcade Pro P4,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000aa00000000000000,Hori Real Arcade Pro S,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000d800000000000000,Hori Real Arcade Pro S,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00002200000000000000,Hori Real Arcade Pro V3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005b00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005c00000000000000,Hori Real Arcade Pro V4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000af00000000000000,Hori Real Arcade Pro VHS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001b00000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000002f5000000000000,Hori Real Arcade Pro VX,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00009c00000000000000,Hori TAC Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c900000000000000,Hori Taiko Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006400000000000000,Horipad 3TP,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00001300000000000000,Horipad 3W,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00005500000000000000,Horipad 4 FPS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006e00000000000000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00006600000000000000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f00004200000000000000,Horipad A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000ad1b000001f5000000000000,Horipad EXT2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000ee00000000000000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000c100000000000000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000000d0f0000f600000000000000,Horipad Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0f00006700000000000000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000000d0f0000dc00000000000000,Horipad Switch,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000242e00000b20000000000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Windows, +03000000242e0000ff0b000000000000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Windows, +03000000790000004e95000000000000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Windows, +03000000242e00006a38000000000000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Windows, +03000000d81d00000e00000000000000,iBuffalo AC02 Arcade Joystick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,rightx:a2,righty:a5,start:b8,x:b4,y:b5,platform:Windows, +03000000d81d00000f00000000000000,iBuffalo BSGP1204 Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d81d00001000000000000000,iBuffalo BSGP1204P Series,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000005c0a00000285000000000000,iDroidCon,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b6,platform:Windows, +03000000696400006964000000000000,iDroidCon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000511d00000230000000000000,iGUGU Gamecore,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b1,leftstick:b4,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b2,platform:Windows, +03000000b50700001403000000000000,Impact Black,a:b2,b:b3,back:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +030000006f0e00002401000000000000,Injustice Fightstick PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000830500005130000000000000,InterAct ActionPad,a:b0,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000ef0500000300000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500000230000000000000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500000030000000000000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000fd0500003902000000000000,InterAct Hammerhead,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,rightshoulder:b7,rightstick:b5,righttrigger:b9,start:b10,x:b0,y:b1,platform:Windows, +03000000fd0500002a26000000000000,InterAct Hammerhead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b0,y:b1,platform:Windows, +03000000fd0500002f26000000000000,InterAct Hammerhead FX,a:b4,b:b5,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b1,y:b2,platform:Windows, +03000000fd0500005302000000000000,InterAct ProPad,a:b3,b:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000ac0500002c02000000000000,Ipega Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000204000000000000,Ipega PG9023,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000491900000304000000000000,Ipega PG9087,+righty:+a5,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +030000007e0500000620000000000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Windows, +030000007e0500000720000000000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000250900000017000000000000,Joypad Adapter,a:b2,b:b1,back:b9,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b8,x:b3,y:b0,platform:Windows, +03000000bd12000003c0000000000000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ff1100004033000000000000,JPD FFB,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a2,start:b15,x:b3,y:b0,platform:Windows, +03000000242f00002d00000000000000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00008a00000000000000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +03000000c4100000c082000000000000,KADE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000828200000180000000000000,Keio,a:b4,b:b5,back:b8,leftshoulder:b2,lefttrigger:b3,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b1,platform:Windows, +03000000790000000200000000000000,King PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000bd12000001e0000000000000,Leadership,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00000103000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00000104000000000000,Logic3,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008f0e00001300000000000000,Logic3,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006d040000d1ca000000000000,Logitech ChillStream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d040000d2ca000000000000,Logitech Cordless Precision,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000011c2000000000000,Logitech Cordless Wingman,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b2,righttrigger:b7,rightx:a3,righty:a4,x:b4,platform:Windows, +030000006d04000016c2000000000000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001dc2000000000000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001ec2000000000000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d04000019c2000000000000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006d0400001ac2000000000000,Logitech Precision,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000009c2000000000000,Logitech WingMan,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000006d0400000bc2000000000000,Logitech WingMan Action Pad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:a5~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:a2~,start:b8,x:b3,y:b4,platform:Windows, +030000006d0400000ac2000000000000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, +03000000380700005645000000000000,Lynx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000222200006000000000000000,Macally,a:b1,b:b2,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700003888000000000000,Mad Catz Arcade Fightstick TE S Plus PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008532000000000000,Mad Catz Arcade Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006352000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006652000000000000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005032000000000000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700005082000000000000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008031000000000000,Mad Catz FightStick Alpha PS3 ,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000003807000038b7000000000000,Mad Catz Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008433000000000000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008483000000000000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008134000000000000,Mad Catz Fightstick TE2 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b4,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008184000000000000,Mad Catz Fightstick TE2 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,leftstick:b10,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700006252000000000000,Mad Catz Micro CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008232000000000000,Mad Catz PlayStation Brawlpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008731000000000000,Mad Catz PlayStation Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000003807000056a8000000000000,Mad Catz PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001888000000000000,Mad Catz SFIV Fightstick PS3,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700008081000000000000,Mad Catz SFV Arcade Fightstick Alpha PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700001847000000000000,Mad Catz Street Fighter 4 Xbox 360 FightStick,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700008034000000000000,Mad Catz TE2 PS3 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000380700008084000000000000,Mad Catz TE2 PS4 Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000002a0600001024000000000000,Matricom,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +030000009f000000adbb000000000000,MaxJoypad Virtual Controller,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000128000000000000,Mayflash Arcade Stick,a:b1,b:b2,back:b8,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b5,y:b6,platform:Windows, +030000008f0e00001330000000000000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00003700000000000000,Mayflash F101,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000790000003018000000000000,Mayflash F300 Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00003900000000000000,Mayflash F300 Elite Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004418000000000000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000790000004318000000000000,Mayflash GameCube Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000242f00007300000000000000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +0300000079000000d218000000000000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d620000010a7000000000000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000242f0000f400000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a5,start:b9,platform:Windows, +03000000790000007918000000000000,Mayflash N64 Controller Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,righttrigger:b7,rightx:a3,righty:a2,start:b8,platform:Windows, +030000008f0e00001030000000000000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +03000000790000000318000000000000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Windows, +03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002418000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b2,start:b9,x:b3,y:b4,platform:Windows, +0300000079000000ae18000000000000,Mega Drive Controller,a:b0,b:b1,back:b7,dpdown:b14,dpleft:b15,dpright:b13,dpup:b2,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000c0160000990a000000000000,Mega Drive Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,righttrigger:b2,start:b3,platform:Windows, +030000005e0400002800000000000000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Windows, +030000005e0400000300000000000000,Microsoft SideWinder,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000005e0400000700000000000000,Microsoft SideWinder,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +030000005e0400000e00000000000000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,start:b8,x:b3,y:b4,platform:Windows, +030000005e0400002700000000000000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Windows, +03000000280d00000202000000000000,Miller Lite Cantroller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b5,x:b2,y:b3,platform:Windows, +03000000ad1b000023f0000000000000,MLG,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a6,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000ad1b00003ef0000000000000,MLG Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b8,rightshoulder:b5,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +03000000380700006382000000000000,MLG PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004523000015e0000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000491900000904000000000000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000ffff00000000000000000000,Mocute M053,a:b3,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b11,leftstick:b7,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b6,righttrigger:b4,rightx:a3,righty:a4,start:b8,x:b1,y:b0,platform:Windows, +03000000d6200000e589000000000000,Moga 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000007162000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +03000000d6200000ad0d000000000000,Moga Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400002a89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400002b89000000000000,Moga XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001a89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c62400001b89000000000000,Moga XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000250900006688000000000000,MP-8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000091200004488000000000000,MUSIA PlayStation 2 Input Display,a:b0,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,leftstick:b6,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:b11,rightx:a2,righty:a3,start:b5,x:b1,y:b3,platform:Windows, +03000000f70600000100000000000000,N64 Adaptoid,+rightx:b2,+righty:b1,-rightx:b4,-righty:b5,a:b0,b:b3,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,start:b8,platform:Windows, +030000006b140000010c000000000000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006b1400001106000000000000,Nacon Revolution 3 PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +0300000085320000170d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +0300000085320000190d000000000000,Nacon Revolution 5 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000006b140000100d000000000000,Nacon Revolution Infinity PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000080d000000000000,Nacon Revolution Unlimited Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000bd12000001c0000000000000,Nebular,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000eb0300000000000000000000,NeGcon Adapter,a:a2,b:b13,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,lefttrigger:a4,leftx:a1,righttrigger:b11,start:b3,x:a3,y:b12,platform:Windows, +0300000038070000efbe000000000000,NEO SE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000092120000474e000000000000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Windows, +03000000921200004b46000000000000,NES 2 port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Windows, +03000000000f00000100000000000000,NES Controller,a:b1,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000921200004346000000000000,NES Controller,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000790000004518000000000000,NEXILUX GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +030000001008000001e5000000000000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Windows, +03000000050b00000045000000000000,Nexus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Windows, +03000000152000000182000000000000,NGDS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000000d0500000308000000000000,Nostromo N45,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Windows, +030000007e0500001920000000000000,NSO N64 Controller,+rightx:b8,+righty:b2,-rightx:b3,-righty:b7,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Windows, +030000007e0500001720000000000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Windows, +03000000550900001472000000000000,NVIDIA Controller,a:b11,b:b10,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b7,leftstick:b5,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b4,righttrigger:a5,rightx:a3,righty:a6,start:b3,x:b9,y:b8,platform:Windows, +03000000550900001072000000000000,NVIDIA Shield,a:b9,b:b8,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b3,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b2,righttrigger:a4,rightx:a2,righty:a5,start:b0,x:b7,y:b6,platform:Windows, +030000005509000000b4000000000000,NVIDIA Virtual,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c00000288000000000000,Nyko Air Flo Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000004b120000014d000000000000,Nyko Airflo,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a3,leftstick:a0,lefttrigger:b6,rightshoulder:b5,rightstick:a2,righttrigger:b7,start:b9,x:b2,y:b3,platform:Windows, +03000000d62000001d57000000000000,Nyko Airflo PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000791d00000900000000000000,Nyko Playpad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000782300000a10000000000000,Onlive Controller,a:b15,b:b14,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b11,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b13,y:b12,platform:Windows, +030000000d0f00000401000000000000,Onyx,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008916000001fd000000000000,Onza CE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a3,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000008916000000fd000000000000,Onza TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000006d57000000000000,OPP PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006b14000001a1000000000000,Orange Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Windows, +03000000362800000100000000000000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,x:b1,y:b2,platform:Windows, +03000000120c0000f60e000000000000,P4 Gamepad,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b7,rightshoulder:b4,righttrigger:b6,start:b9,x:b0,y:b3,platform:Windows, +03000000790000002201000000000000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000006f0e00008501000000000000,PDP Fightpad Pro GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00000901000000000000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00004100000000000000,PlaySega,a:b1,b:b0,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b4,y:b3,platform:Windows, +03000000666600006706000000000000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Windows, +03000000e30500009605000000000000,PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000004c050000da0c000000000000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002306000000000000,PlayStation Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d9040000160f000000000000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000013a7000000000000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +0300000062060000d570000000000000,PowerA PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d620000014a7000000000000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000084ca000000000000,Precision,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c62400001a53000000000000,Pro Ex Mini,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000009f31000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000d6200000c757000000000000,Pro Ex mini PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000110e000000000000,Pro5,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000100800000100000000000000,PS1 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00007530000000000000,PS1 Controller,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b1,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000100800000300000000000000,PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000250900000088000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900006888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b6,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900008888000000000000,PS2 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b1400000303000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000009d0d00001330000000000000,PS2 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000151a00006222000000000000,PS2 Dual Plus Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000120a00000100000000000000,PS3 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000120c00001307000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c00001cf1000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f90e000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000250900000118000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000218000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000250900000500000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +030000004c0500006802000000000000,PS3 Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b10,lefttrigger:a3~,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:a4~,rightx:a2,righty:a5,start:b8,x:b3,y:b0,platform:Windows, +030000004f1f00000800000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +03000000632500007505000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000888800000803000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows, +03000000888800000804000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +030000008f0e00000300000000000000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +030000008f0e00001431000000000000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000ba2200002010000000000000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Windows, +03000000120c00000807000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000111e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000121e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000130e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000150e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000180e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000181e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000191e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c00001e0e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000a957000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000aa57000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f21c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f31c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f41c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f51c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120c0000f70e000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000120e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000160e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000001a1e0000120c000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +030000004c050000f20d000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Windows, +03000000830500005020000000000000,PSX,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Windows, +03000000300f00000111000000000000,Qanba 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00000211000000000000,Qanba 2P,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000300f00000011000000000000,Qanba Arcade Stick 1008,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b10,x:b0,y:b3,platform:Windows, +03000000300f00001611000000000000,Qanba Arcade Stick 4018,a:b1,b:b2,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b8,x:b0,y:b3,platform:Windows, +03000000222c00000025000000000000,Qanba Dragon Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000020000000000000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001211000000000000,Qanba Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001210000000000000,Qanba Joystick Plus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Windows, +03000000341a00000104000000000000,Qanba Joystick Q4RAF,a:b5,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b0,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b7,start:b9,x:b1,y:b2,platform:Windows, +03000000222c00000223000000000000,Qanba Obsidian Arcade Stick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000222c00000023000000000000,Qanba Obsidian Arcade Stick PS4,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000008a2400006682000000000000,R1 Mobile Controller,a:b3,b:b1,back:b7,leftx:a0,lefty:a1,start:b6,x:b4,y:b0,platform:Windows, +03000000086700006626000000000000,RadioShack,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000ff1100004733000000000000,Ramox FPS Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b0,platform:Windows, +030000009b2800002300000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800006900000000000000,Raphnet 3DO Adapter,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b2,start:b3,platform:Windows, +030000009b2800000800000000000000,Raphnet Dreamcast Adapter,a:b2,b:b1,dpdown:b5,dpleft:b6,dpright:b7,dpup:b4,lefttrigger:a2,leftx:a0,righttrigger:a3,righty:a1,start:b3,x:b10,y:b9,platform:Windows, +030000009b2800006200000000000000,Raphnet GameCube Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800003200000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800006000000000000000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:+a2,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Windows, +030000009b2800001800000000000000,Raphnet Jaguar Adapter,a:b2,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b0,righttrigger:b10,start:b3,x:b11,y:b12,platform:Windows, +030000009b2800006300000000000000,Raphnet N64 Adapter,+rightx:b9,+righty:b7,-rightx:b8,-righty:b6,a:b0,b:b1,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,lefttrigger:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Windows, +030000009b2800000200000000000000,Raphnet NES Adapter,a:b7,b:b6,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,start:b4,platform:Windows, +030000009b2800004400000000000000,Raphnet PS1 and PS2 Adapter,a:b1,b:b2,back:b5,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b9,rightx:a3,righty:a4,start:b4,x:b0,y:b3,platform:Windows, +030000009b2800004300000000000000,Raphnet Saturn,a:b0,b:b1,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000009b2800000500000000000000,Raphnet Saturn Adapter 2.0,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +030000009b2800000300000000000000,Raphnet SNES Adapter,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000009b2800005600000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800005700000000000000,Raphnet SNES Adapter,a:b1,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800001e00000000000000,Raphnet Vectrex Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a1,lefty:a2,x:b2,y:b3,platform:Windows, +030000009b2800002b00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800002c00000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +030000009b2800008000000000000000,Raphnet Wii Classic Adapter,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a3,righty:a4,start:b3,x:b0,y:b5,platform:Windows, +03000000321500000003000000000000,Razer Hydra,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000f8270000bf0b000000000000,Razer Kishi,a:b6,b:b7,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b18,leftshoulder:b12,leftstick:b19,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b13,rightstick:b20,righttrigger:b15,rightx:a3,righty:a4,start:b17,x:b9,y:b10,platform:Windows, +03000000321500000204000000000000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000104000000000000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000010000000000000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000507000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000707000000000000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000321500000710000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000a10000000000000,Razer Raiju TE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000410000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000910000000000000,Razer Raiju UE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000011000000000000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000321500000009000000000000,Razer Serval,+lefty:+a2,-lefty:-a1,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,leftx:a0,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000921200004547000000000000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b6,x:b3,y:b4,platform:Windows, +03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +03000000830500006020000000000000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Windows, +0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000bd12000013d0000000000000,Retrolink Sega Saturn Classic Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,lefttrigger:b6,rightshoulder:b2,righttrigger:b7,start:b8,x:b3,y:b4,platform:Windows, +03000000bd12000015d0000000000000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Windows, +0300000000f000000300000000000000,RetroUSB RetroPad,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +0300000000f00000f100000000000000,RetroUSB Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Windows, +03000000830500000960000000000000,Revenger,a:b0,b:b1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b3,x:b4,y:b5,platform:Windows, +030000006b140000010d000000000000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000020d000000000000,Revolution Pro Controller 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006b140000130d000000000000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001f01000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00004601000000000000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000fefa000000000000,Rock Candy Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e00008701000000000000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00001e01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002801000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00002f01000000000000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000050b0000e318000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b0000e518000000000000,ROG Chakram,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00005819000000000000,ROG Chakram Core,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b0000181a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00001a1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +03000000050b00001c1a000000000000,ROG Chakram X,a:b1,b:b0,leftx:a0,lefty:a1,x:b2,y:b3,platform:Windows, +030000004f04000001d0000000000000,Rumble Force,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000008916000000fe000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000045d000000000000,Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000a30600001af5000000000000,Saitek Cyborg,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000023f6000000000000,Saitek Cyborg V.1 Game,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001201000000000000,Saitek Dual Analog,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000701000000000000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Windows, +03000000a30600000cff000000000000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b0,y:b1,platform:Windows, +03000000a30600000d5f000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000a30600000dff000000000000,Saitek P2600,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b8,x:b0,y:b3,platform:Windows, +03000000a30600000c04000000000000,Saitek P2900,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000018f5000000000000,Saitek P3200,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001001000000000000,Saitek P480 Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000a30600000901000000000000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b8,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b5,rightx:a3,righty:a2,x:b0,y:b1,platform:Windows, +03000000a30600000b04000000000000,Saitek P990,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Windows, +03000000a30600002106000000000000,Saitek PS1000 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000a306000020f6000000000000,Saitek PS2700 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Windows, +03000000300f00001101000000000000,Saitek Rumble,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000e804000000a0000000000000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000c01100000252000000000000,Sanwa Easy Grip,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000c01100004350000000000000,Sanwa Micro Grip P3,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,x:b3,y:b2,platform:Windows, +03000000411200004550000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a1,righty:a2,start:b9,x:b1,y:b3,platform:Windows, +03000000c01100004150000000000000,Sanwa Micro Grip Pro,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +03000000c01100004450000000000000,Sanwa Online Grip,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b11,righttrigger:b9,rightx:a3,righty:a2,start:b14,x:b3,y:b4,platform:Windows, +03000000730700000401000000000000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Windows, +03000000830500006120000000000000,Sanwa Smart Grip II,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,x:b1,y:b3,platform:Windows, +03000000c01100000051000000000000,Satechi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +030000004f04000028b3000000000000,Score A,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000952e00002577000000000000,Scuf PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000a30c00002500000000000000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Windows, +03000000a30c00002400000000000000,Sega Mega Drive Mini 6B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000d804000086e6000000000000,Sega Multi Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +0300000000050000289b000000000000,Sega Saturn Adapter,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b0,y:b3,platform:Windows, +0300000000f000000800000000000000,Sega Saturn Controller,a:b1,b:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b7,righttrigger:b3,start:b0,x:b5,y:b6,platform:Windows, +03000000730700000601000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Windows, +03000000b40400000a01000000000000,Sega Saturn Controller,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Windows, +030000003b07000004a1000000000000,SFX,a:b0,b:b2,back:b7,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Windows, +03000000f82100001900000000000000,Shogun Bros Chameleon X1,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000120c00001c1e000000000000,SnakeByte 4S PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +0300000081170000960a000000000000,SNES Controller,a:b4,b:b0,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b5,y:b1,platform:Windows, +03000000811700009d0a000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +030000008b2800000300000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000921200004653000000000000,SNES Controller,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Windows, +03000000ff000000cb01000000000000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000208000000000000,Speedlink 6555,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:-a4,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a3,righty:a2,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000908000000000000,Speedlink 6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000380700001722000000000000,Speedlink Competition Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,x:b2,y:b3,platform:Windows, +030000008f0e00000800000000000000,Speedlink Strike FX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000c01100000591000000000000,Speedlink Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000d11800000094000000000000,Stadia Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b11,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:Windows, +03000000de280000fc11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000de280000ff11000000000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c0000160e000000000000,Steel Play Metaltech PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000110100001914000000000000,SteelSeries,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b13,lefttrigger:b6,leftx:a0,lefty:a1,rightstick:b14,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000001214000000000000,SteelSeries Free,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Windows, +03000000110100003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000381000001814000000000000,SteelSeries Stratus XL,a:b0,b:b1,back:b18,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b19,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b2,y:b3,platform:Windows, +03000000790000001c18000000000000,STK 7024X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000380700003847000000000000,Street Fighter Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, +030000001f08000001e4000000000000,Super Famicom Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Windows, +03000000790000000418000000000000,Super Famicom Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b33,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000341200001300000000000000,Super Racer,a:b2,b:b3,back:b8,leftshoulder:b5,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b7,x:b0,y:b1,platform:Windows, +03000000457500002211000000000000,Szmy Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ab1000000000000,T16000M,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b10,x:b2,y:b3,platform:Windows, +030000000d0f00007b00000000000000,TAC GEAR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000e40a00000207000000000000,Taito Egret II Mini Controller,a:b4,b:b2,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,rightshoulder:b0,righttrigger:b1,start:b7,x:b8,y:b3,platform:Windows, +03000000d814000001a0000000000000,TE Kitty,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000fa1900000706000000000000,Team 5,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001203000000000000,Techmobility X6-38V,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000ba2200000701000000000000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b2,platform:Windows, +03000000c61100001000000000000000,Tencent Xianyou Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,x:b3,y:b4,platform:Windows, +03000000790000002601000000000000,TGZ,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000591c00002400000000000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000591c00002600000000000000,THEGamepad,a:b2,b:b1,back:b6,leftx:a0,lefty:a1,start:b7,x:b3,y:b0,platform:Windows, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000023b3000000000000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f0400000ed0000000000000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000008d0000000000000,ThrustMaster Ferrari 150 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Windows, +030000004f04000004b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Windows, +030000004f04000003d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:a3,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:a4,rightstick:b11,righttrigger:b5,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000004f04000009d0000000000000,ThrustMaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +030000006d04000088ca000000000000,Thunderpad,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000666600000288000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +03000000666600000488000000000000,TigerGame PlayStation Adapter,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000004f04000007d0000000000000,TMini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000571d00002100000000000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Windows, +03000000571d00002000000000000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000d62000006000000000000000,Tournament PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000c01100000055000000000000,Tronsmart,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000005f140000c501000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000b80500000210000000000000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000004f04000087b6000000000000,TWCS Throttle,dpdown:b8,dpleft:b9,dpright:b7,dpup:b6,leftstick:b5,lefttrigger:-a5,leftx:a0,lefty:a1,righttrigger:+a5,platform:Windows, +03000000411200000450000000000000,Twin Shock,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Windows, +03000000d90400000200000000000000,TwinShock PS2 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000151900005678000000000000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000101c0000171c000000000000,uRage Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +030000000b0400003065000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000242f00006e00000000000000,USB Controller,a:b1,b:b4,back:b10,leftshoulder:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b7,rightx:a2,righty:a5,start:b11,x:b0,y:b3,platform:Windows, +03000000300f00000701000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000341a00002308000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000666600000188000000000000,USB Controller,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Windows, +030000006b1400000203000000000000,USB Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000790000000a00000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b3,y:b0,platform:Windows, +03000000b404000081c6000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b3,y:b0,platform:Windows, +03000000b50700001503000000000000,USB Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b0,y:b1,platform:Windows, +03000000bd12000012d0000000000000,USB Controller,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Windows, +03000000ff1100004133000000000000,USB Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000632500002305000000000000,USB Vibration Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Windows, +03000000790000001a18000000000000,Venom,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +03000000790000001b18000000000000,Venom Arcade Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000302000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +030000006f0e00000702000000000000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Windows, +0300000034120000adbe000000000000,vJoy Device,a:b0,b:b1,back:b15,dpdown:b6,dpleft:b7,dpright:b8,dpup:b5,guide:b16,leftshoulder:b9,leftstick:b13,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b14,righttrigger:b12,rightx:a3,righty:a4,start:b4,x:b2,y:b3,platform:Windows, +03000000120c0000ab57000000000000,Warrior Joypad JS083,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000007e0500003003000000000000,Wii U Pro,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b6,leftstick:b11,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b12,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Windows, +0300000032150000030a000000000000,Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +0300000032150000140a000000000000,Wolverine,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000002e160000efbe000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,rightshoulder:b5,righttrigger:b11,start:b7,x:b2,y:b3,platform:Windows, +03000000380700001647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700002045000000000000,Xbox 360 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +03000000380700002644000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a5,start:b8,x:b2,y:b3,platform:Windows, +03000000380700002647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000003807000026b7000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700003647000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a7,righty:a5,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400001907000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400009102000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000000fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000001fd000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b000016f0000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000ad1b00008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400000053000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c6240000fdfa000000000000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700002847000000000000,Xbox 360 Fightpad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000a102000000000000,Xbox 360 Wireless Receiver,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000120c00000a88000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a2,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000120c00001088000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2~,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5~,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000002a0600002000000000000000,Xbox Controller,a:b0,b:b1,back:b13,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b5,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b15,righttrigger:b7,rightx:a2,righty:a5,start:b12,x:b2,y:b3,platform:Windows, +03000000300f00008888000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:b13,dpleft:b10,dpright:b11,dpup:b12,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700001645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700002645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000380700003645000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +03000000380700008645000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000202000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b11,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000005e0400008502000000000000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400008702000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000005e0400008902000000000000,Xbox Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b10,leftstick:b8,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b9,righttrigger:b4,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Windows, +030000000d0f00006300000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b9,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e0400000c0b000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000fd02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000ff02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:-a2,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e0000a802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000006f0e0000c802000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000c62400003a54000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000005e040000130b000000000000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +03000000341a00000608000000000000,Xeox,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +03000000450c00002043000000000000,Xeox SL6556BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +030000006f0e00000300000000000000,XGear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Windows, +03000000e0ff00000201000000000000,Xiaomi Black Shark (L),back:b0,dpdown:b11,dpleft:b9,dpright:b10,dpup:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,platform:Windows, +03000000172700004431000000000000,Xiaomi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a7,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Windows, +03000000172700003350000000000000,Xiaomi XMGP01YM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000bc2000005060000000000000,Xiaomi XMGP01YM,+lefty:+a2,+righty:+a5,-lefty:-a1,-righty:-a4,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,start:b11,x:b3,y:b4,platform:Windows, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Windows, +030000007d0400000340000000000000,Xterminator Digital Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:-a4,lefttrigger:+a4,leftx:a0,lefty:a1,paddle1:b7,paddle2:b6,rightshoulder:b5,rightstick:b9,righttrigger:b2,rightx:a3,righty:a5,start:b8,x:b3,y:b4,platform:Windows, +03000000790000004f18000000000000,ZDT Android Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b3,y:b4,platform:Windows, +03000000120c00000500000000000000,Zeroplus Adapter,a:b2,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b0,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, +03000000120c0000101e000000000000,Zeroplus P4 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +030000008f0e00000300000009010000,2 In 1 Joystick,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000031000001000000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000531000000020000,8BitDo Adapter 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00000090000001000000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001251000000020000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001151000000020000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000a30c00002400000006020000,8BitDo M30,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,guide:b9,leftshoulder:b6,lefttrigger:b5,rightshoulder:b4,righttrigger:b7,start:b8,x:b3,y:b0,platform:Mac OS X, +03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000650000001000000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00005106000000010000,8BitDo M30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,lefttrigger:a5,rightshoulder:b7,righttrigger:a4,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00001590000001000000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Mac OS X, +03000000c82d00002590000000010000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002690000000010000,8BitDo NEOGEOa:b0,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,b:b1,back:b10,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +030000003512000012ab000001000000,8BitDo NES30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d000012ab000001000000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00002028000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000022000000090000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000190000001000000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000660000000020000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000131000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000231000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000331000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000431000001000000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Mac OS X, +03000000102800000900000000000000,8BitDo SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001290000001000000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00004028000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000160000001000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a5,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000260000001000000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001530000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001630000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001730000001000000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001130000000020000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001330000001000000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001330000000020000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000a00500003232000009010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c82d00001890000001000000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a31,start:b11,x:b4,y:b3,platform:Mac OS X, +03000000491900001904000001010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000a30c00002700000003030000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000a30c00002800000003030000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a3,lefty:a4,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000050b00000579000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b42,paddle1:b9,paddle2:b11,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b23,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000503200000110000047010000,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b3,start:b2,platform:Mac OS X, +03000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c62400001a89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b14,leftshoulder:b6,leftstick:b15,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:a4,rightx:a2,righty:a3,start:b13,x:b3,y:b4,platform:Mac OS X, +03000000c62400001b89000000010000,BDA MOGA XP5-X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000d62000002a79000000010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000200e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000210e000000010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008305000031b0000000000000,Cideko AK08b,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d8140000cecf000000000000,Cthulhu,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000260900008888000088020000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000a306000022f6000001030000,Cyborg V3 Rumble Pad PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000791d00000103000009010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006e0500000720000010020000,Elecom JC-W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Mac OS X, +030000006f0e00008401000003010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000151900004000000001000000,Flydigi Vader 2,a:b14,b:b15,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Mac OS X, +03000000b40400001124000001040000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000b40400001224000003030000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000790000004618000000010000,GameCube Controller Adapter,a:b4,b:b0,dpdown:b56,dpleft:b60,dpright:b52,dpup:b48,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, +03000000ac0500001a06000002020000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000ad1b000001f9000000000000,Gamestop BB070 X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000c01100000140000000010000,GameStop PS4 Fun Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000102000000000000,GameStop Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000ff1100003133000007010000,GameWare PC Control Pad,a:b2,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b3,y:b0,platform:Mac OS X, +030000007d0400000540000001010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000280400000140000000020000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00000300000007010000,GreenAsia Joystick,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Mac OS X, +030000000d0f00002d00000000100000,Hori Fighting Commander 3 Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000000000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005f00000000010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000000000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00005e00000000010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008400000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008500000000010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000341a00000302000014010000,Hori Fighting Stick Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008800000000010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00008700000000010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00004d00000000000000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00003801000008010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Mac OS X, +030000000d0f00009200000000010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000aa00000072050000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000000d0f00000002000015010000,Hori Switch Split Pad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006e00000000010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f00006600000000000000,Horipad FPS Plus 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000000d0f0000ee00000000010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000242e0000ff0b000000010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Mac OS X, +03000000790000004e95000000010000,Hyperkin N64 Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a5,righty:a2,start:b9,platform:Mac OS X, +03000000830500006020000000000000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Mac OS X, +03000000ef0500000300000000020000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Mac OS X, +03000000fd0500000030000010010000,Interact GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Mac OS X, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Mac OS X, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000242f00002d00000007010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000006d04000019c2000000000000,Logitech Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000020000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000030000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000014040000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000016c2000000000000,Logitech F310,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000018c2000000000000,Logitech F510,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d04000019c2000005030000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006d0400001fc2000000000000,Logitech F710,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006d04000018c2000000010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3~,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005032000000010000,Mad Catz PS3 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008433000000010000,Mad Catz PS3 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700005082000000010000,Mad Catz PS4 Fightpad Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000380700008483000000010000,Mad Catz PS4 Fightstick TE S Plus,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000000600000007010000,Marvo GT-004,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000008f0e00001330000011010000,Mayflash Controller Adapter,a:b2,b:b4,back:b16,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b12,lefttrigger:b16,leftx:a0,lefty:a2,rightshoulder:b14,rightx:a6~,righty:a4,start:b18,x:b0,y:b6,platform:Mac OS X, +03000000790000004318000000010000,Mayflash GameCube Adapter,a:b4,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a12,leftx:a0,lefty:a4,rightshoulder:b28,righttrigger:a16,rightx:a20,righty:a8,start:b36,x:b8,y:b12,platform:Mac OS X, +03000000790000004418000000010000,Mayflash GameCube Controller,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000242f00007300000000020000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Mac OS X, +0300000079000000d218000026010000,Mayflash Magic NS,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000d620000010a7000003010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00001030000011010000,Mayflash Saturn Adapter,a:b0,b:b2,dpdown:b28,dpleft:b30,dpright:b26,dpup:b24,leftshoulder:b10,lefttrigger:b14,rightshoulder:b12,righttrigger:b4,start:b18,x:b6,y:b8,platform:Mac OS X, +0300000025090000e803000000000000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:b13,dpleft:b12,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Mac OS X, +03000000790000000318000000010000,Mayflash Wii DolphinBar,a:b8,b:b12,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b44,leftshoulder:b16,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b4,platform:Mac OS X, +03000000790000000018000000000000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +03000000790000000018000000010000,Mayflash Wii U Pro Adapter,a:b4,b:b8,back:b32,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b16,leftstick:b40,lefttrigger:b24,leftx:a0,lefty:a4,rightshoulder:b20,rightstick:b44,righttrigger:b28,rightx:a8,righty:a12,start:b36,x:b0,y:b12,platform:Mac OS X, +030000005e0400002800000002010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Mac OS X, +030000005e0400000300000006010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Mac OS X, +030000005e0400000700000006010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Mac OS X, +030000005e0400002700000001010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Mac OS X, +030000004523000015e0000072050000,Mobapad Chitu HD,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Mac OS X, +03000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400002b89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000632500007505000000020000,NeoGeo mini PAD Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000921200004b46000003020000,NES 2-port Adapter,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b11,platform:Mac OS X, +030000001008000001e5000006010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Mac OS X, +030000007e0500000920000000000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +030000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +050000007e05000009200000ff070000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b3,y:b2,platform:Mac OS X, +030000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Mac OS X, +030000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b15,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000550900001472000025050000,NVIDIA Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Mac OS X, +030000004b120000014d000000010000,Nyko Airflo EX,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000901000002010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008f0e00000300000000000000,Piranha Xtreme PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000666600006706000088020000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Mac OS X, +030000004c050000da0c000000010000,PlayStation Classic Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c0500003713000000010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d620000011a7000000020000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000d620000011a7000010050000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d62000006dca000000010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000100800000300000006010000,PS2 Adapter,a:b2,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a4,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c0500006802000072050000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +030000004c050000a00b000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Mac OS X, +030000005e040000e002000001000000,PXN P30 Pro Mobile,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000222c00000225000000010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000222c00000020000000010000,Qanba Drone Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000321500000204000000010000,Razer Panthera PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000104000000010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000010000000010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000507000001010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000321500000011000000010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000321500000009000000020000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +0300000032150000030a000000000000,Razer Wildcat,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000632500008005000000010000,Redgear,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +030000000d0f0000c100000072050000,Retro Bit Sega Genesis 6B Controller,a:b2,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b8,rightshoulder:b6,righttrigger:b7,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000921200004547000000020000,Retro Bit Sega Genesis Controller Adapter,a:b0,b:b2,dpdown:+a2,dpleft:-a0,dpright:+a0,dpup:-a2,lefttrigger:b14,rightshoulder:b10,righttrigger:b4,start:b12,x:b6,y:b8,platform:Mac OS X, +03000000790000001100000000000000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000001100000005010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000830500006020000000010000,Retro Controller,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b8,righttrigger:b9,start:b7,x:b2,y:b3,platform:Mac OS X, +0300000003040000c197000000000000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Mac OS X, +03000000790000001100000006010000,Retrolink SNES Controller,a:b2,b:b1,back:b8,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000341200000400000000000000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Mac OS X, +030000006b140000010d000000010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006b140000130d000000010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c0500006802000002100000,Rii RK707,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b3,righttrigger:b9,rightx:a2,righty:a3,start:b1,x:b15,y:b12,platform:Mac OS X, +030000006f0e00008701000005010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000c6240000fefa000000000000,Rock Candy PS3,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000e804000000a000001b010000,Samsung EIGP20,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b11,leftx:a1,lefty:a3,rightshoulder:b12,rightx:a4,righty:a5,start:b16,x:b7,y:b9,platform:Mac OS X, +03000000730700000401000000010000,Sanwa PlayOnline Mobile,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Mac OS X, +03000000a30c00002500000006020000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Mac OS X, +03000000811700007e05000000000000,Sega Saturn,a:b2,b:b4,dpdown:b16,dpleft:b15,dpright:b14,dpup:b17,leftshoulder:b8,lefttrigger:a5,leftx:a0,lefty:a2,rightshoulder:b9,righttrigger:a4,start:b13,x:b0,y:b6,platform:Mac OS X, +03000000b40400000a01000000000000,Sega Saturn,a:b0,b:b1,back:b5,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b2,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Mac OS X, +030000003512000021ab000000000000,SFC30 Joystick,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Mac OS X, +0300000000f00000f100000000000000,SNES RetroPort,a:b2,b:b3,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b5,rightshoulder:b7,start:b6,x:b0,y:b1,platform:Mac OS X, +030000004c050000a00b000000000000,Sony DualShock 4 Adapter,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004c050000cc09000000000000,Sony DualShock 4 V2,a:b1,b:b2,back:b13,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e0400008e02000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000000000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000110100002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +03000000381000002014000001000000,SteelSeries Nimbus,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,x:b2,y:b3,platform:Mac OS X, +05000000484944204465766963650000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, +050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b15,dpdown:b11,dpleft:b13,dpright:b12,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3~,start:b14,x:b2,y:b3,platform:Mac OS X, +03000000381000003014000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000381000003114000000000000,SteelSeries Stratus Duo,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000000000000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +03000000110100001714000020010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:b9,dpleft:b11,dpright:b10,dpup:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1~,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3~,start:b12,x:b2,y:b3,platform:Mac OS X, +030000000d0f0000f600000000010000,Switch Hori Pad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +03000000457500002211000000010000,SZMY Power PC Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000790000001c18000003100000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000591c00002400000021000000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, +03000000591c00002600000021000000,THEGamepad,a:b2,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Mac OS X, +030000004f04000015b3000000000000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Mac OS X, +030000004f0400000ed0000000020000,ThrustMaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000004f04000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Mac OS X, +03000000571d00002100000021000000,Tomee NES Controller Adapter,a:b1,b:b0,back:b2,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,start:b3,platform:Mac OS X, +03000000bd12000015d0000000010000,Tomee Retro Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000bd12000015d0000000000000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000571d00002000000021000000,Tomee SNES Controller Adapter,a:b0,b:b1,back:b6,dpdown:+a4,dpleft:-a0,dpright:+a0,dpup:-a4,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005f140000c501000000020000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Mac OS X, +03000000100800000100000000000000,Twin USB Joystick,a:b4,b:b2,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b12,leftstick:b20,lefttrigger:b8,leftx:a0,lefty:a2,rightshoulder:b14,rightstick:b22,righttrigger:b10,rightx:a6,righty:a4,start:b18,x:b6,y:b0,platform:Mac OS X, +03000000632500002605000000010000,Uberwith Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000151900005678000010010000,Uniplay U6,a:b3,b:b6,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,leftstick:b31,lefttrigger:b21,leftx:a1,lefty:a3,rightshoulder:b19,rightstick:b33,righttrigger:b23,rightx:a4,righty:a5,start:b27,x:b11,y:b13,platform:Mac OS X, +030000006f0e00000302000025040000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +030000006f0e00000702000003060000,Victrix PS4 Pro Fightstick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Mac OS X, +050000005769696d6f74652028303000,Wii Remote,a:b4,b:b5,back:b7,dpdown:b3,dpleft:b0,dpright:b1,dpup:b2,guide:b8,leftshoulder:b11,lefttrigger:b12,leftx:a0,lefty:a1,start:b6,x:b10,y:b9,platform:Mac OS X, +050000005769696d6f74652028313800,Wii U Pro Controller,a:b16,b:b15,back:b7,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b8,leftshoulder:b19,leftstick:b23,lefttrigger:b21,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b24,righttrigger:b22,rightx:a2,righty:a3,start:b6,x:b18,y:b17,platform:Mac OS X, +030000005e0400008e02000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000006f0e00000104000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +03000000c6240000045d000000000000,Xbox 360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e0400000a0b000000000000,Xbox Adaptive Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000050b000003090000,Xbox Elite Controller Series 2,a:b0,b:b1,back:b31,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b53,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000011050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000013050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000200b000015050000,Xbox One Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000d102000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000dd02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Mac OS X, +030000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000e302000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b16,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000c62400003a54000000000000,Xbox One PowerA Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +030000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +030000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Mac OS X, +03000000120c0000100e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +03000000120c0000101e000000010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Mac OS X, +030000005e0400008e02000020010000,8BitDo Adapter,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000031000011010000,8BitDo Adapter,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000951000000010000,8BitDo Dogbone,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux, +03000000021000000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000090000011010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001038000000010000,8BitDo FC30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001251000011010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001251000000010000,8BitDo Lite 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001151000011010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001151000000010000,8BitDo Lite SE,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000151000000010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000650000011010000,8BitDo M30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00005106000000010000,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00002090000011010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002090000000010000,8BitDo Micro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000451000000010000,8BitDo N30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b11,platform:Linux, +03000000c82d00001590000011010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006528000000010000,8BitDo N30 Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006928000000010000,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,platform:Linux, +05000000c82d00002590000001000000,8BitDo NEOGEO,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000008000000210000011010000,8BitDo NES30,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000c82d00000310000011010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00008010000000010000,8BitDo NES30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b9,righttrigger:b8,start:b11,x:b3,y:b4,platform:Linux, +03000000022000000090000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000190000011010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000203800000900000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00002038000000010000,8BitDo NES30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000751000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00000851000000010000,8BitDo P30,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:a8,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000660000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001030000011010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000660000000010000,8BitDo Pro 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000020000000000000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +06000000c82d00000020000006010000,8BitDo Pro 2 for Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000131000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000231000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000331000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000431000011010000,8BitDo Receiver,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00002867000000010000,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b8,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b3,y:b4,platform:Linux, +05000000c82d00000060000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000061000000010000,8BitDo SF30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +030000003512000012ab000010010000,8BitDo SFC30,a:b2,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, +030000003512000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d000021ab000010010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000102800000900000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00003028000000010000,8BitDo SFC30,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000351000000010000,8BitDo SN30,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000160000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000161000000000000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001290000011010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a3,righty:a4,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000161000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b2,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00006228000000010000,8BitDo SN30 Pro,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00000260000011010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00000261000000010000,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +05000000202800000900000000010000,8BitDo SNES30,a:b1,b:b0,back:b10,dpdown:b122,dpleft:b119,dpright:b120,dpup:b117,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +05000000c82d00001230000000010000,8BitDo Ultimate,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001530000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001630000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001730000011010000,8BitDo Ultimate C,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001130000011010000,8BitDo Ultimate Wired,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b24,paddle2:b25,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000760000011010000,8BitDo Ultimate Wireless,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c82d00001230000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001330000011010000,8BitDo Ultimate Wireless,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b26,paddle1:b23,paddle2:b19,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00000631000014010000,8BitDo Ultimate Wireless Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c82d00000121000011010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c82d00000121000000010000,8BitDo Xbox One SN30 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000001000000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +05000000a00500003232000008010000,8BitDo Zero,a:b0,b:b1,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b3,y:b4,platform:Linux, +03000000c82d00001890000011010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b11,x:b4,y:b3,platform:Linux, +050000005e040000e002000030110000,8BitDo Zero 2,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +05000000c82d00003032000000010000,8BitDo Zero 2,a:b1,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b4,y:b3,platform:Linux, +03000000c01100000355000011010000,Acrux Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008801000011010000,Afterglow Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00003901000000430000,Afterglow Prismatic Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000013020000,Afterglow Prismatic Controller 048-007-NA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00001302000000010000,Afterglow Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003901000020060000,Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100000008200000011010000,Akishop Customs PS360,a:b1,b:b2,back:b12,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000007c1800000006000010010000,Alienware Dual Compatible Game PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000491900000204000021000000,Amazon Fire Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b17,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000491900001904000011010000,Amazon Luna Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b9,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b7,x:b2,y:b3,platform:Linux, +05000000710100001904000000010000,Amazon Luna Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000790000003018000011010000,Arcade Fightstick F300,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000a30c00002700000011010000,Astro City Mini,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000a30c00002800000011010000,Astro City Mini,a:b2,b:b1,back:b8,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +05000000050b00000045000031000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +05000000050b00000045000040000000,ASUS Gamepad,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b10,x:b2,y:b3,platform:Linux, +03000000050b00000579000011010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b36,paddle1:b52,paddle2:b53,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000050b00000679000000010000,ASUS ROG Kunai 3,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b21,paddle1:b22,paddle2:b23,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000503200000110000000000000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +03000000503200000110000011010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000000000000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000044010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +05000000503200000110000046010000,Atari Classic Controller,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b4,start:b3,platform:Linux, +03000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, +03000000503200000210000011010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000000000000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000045010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000046010000,Atari Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +05000000503200000210000047010000,Atari VCS Modern Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:+a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:-a4,rightx:a2,righty:a3,start:b8,x:b2,y:b3,platform:Linux, +03000000c62400001b89000011010000,BDA MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000d62000002a79000011010000,BDA PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000c21100000791000011010000,Be1 GC101 Controller 1.03,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000c31100000791000011010000,Be1 GC101 Controller 1.03,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e0400008e02000003030000,Be1 GC101 Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000bc2000004d50000011010000,BEITONG A1T2 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000bc2000000055000001000000,BETOP AX1 BFM,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000bc2000006412000011010000,Betop Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b30,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006b1400000209000011010000,Bigben,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000200e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000210e000011010000,Brook Mars PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000f70e000011010000,Brook Universal Fighting Board,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000e82000006058000001010000,Cideko AK08b,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000b0400003365000000010000,Competition Pro,a:b0,b:b1,back:b2,leftx:a0,lefty:a1,start:b3,platform:Linux, +03000000260900008888000000010000,Cyber Gadget GameCube Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a2,righty:a3~,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000022f6000011010000,Cyborg V3 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:-a3,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000791d00000103000010010000,Dual Box Wii Classic Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00003001000001010000,EA Sports PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c11100000191000011010000,EasySMX,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00009100000000010000,EasySMX ESM-9101,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006e0500000320000010010000,Elecom U3613M,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +030000006e0500000720000010010000,Elecom W01U,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +030000007d0400000640000010010000,Eliminator AfterShock,a:b1,b:b2,back:b9,dpdown:+a3,dpleft:-a5,dpright:+a5,dpup:-a3,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a4,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000430b00000300000000010000,EMS Production PS2 Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a5,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00008401000011010000,Faceoff Deluxe Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008101000011010000,Faceoff Deluxe Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00008001000011010000,Faceoff Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03005036852100000201000010010000,Final Fantasy XIV Online Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b40400001124000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000b40400001224000011010000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b2,paddle1:b16,paddle2:b17,paddle3:b14,paddle4:b15,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000151900004000000001000000,Flydigi Vader 2,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b12,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b14,paddle1:b2,paddle2:b5,paddle3:b16,paddle4:b17,rightshoulder:b7,rightstick:b13,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000007e0500003703000000000000,GameCube Adapter,a:b0,b:b1,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b6,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b2,platform:Linux, +19000000030000000300000002030000,GameForce Controller,a:b1,b:b0,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a1,lefty:a0,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000ac0500005b05000010010000,GameSir G3w,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000011010000,GameSir G3w,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000558500001b06000010010000,GameSir G4 Pro,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000ac0500002d0200001b010000,GameSir G4s,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b33,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ac0500007a05000011010000,GameSir G5,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b16,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000bc2000005656000011010000,GameSir T4w,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ac0500001a06000011010000,GameSir-T3 2.02,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e00000104000000010000,Gamestop Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00000800000010010000,Gasia PlayStation Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000451300000010000010010000,Genius Maxfire Grandias 12,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +190000004b4800000010000000010000,GO-Advance Controller,a:b1,b:b0,back:b10,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,leftshoulder:b4,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b13,start:b15,x:b2,y:b3,platform:Linux, +190000004b4800000010000001010000,GO-Advance Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b13,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b16,righttrigger:b15,start:b17,x:b2,y:b3,platform:Linux, +190000004b4800000011000000010000,GO-Super Controller,a:b1,b:b0,back:b12,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b16,leftshoulder:b4,leftstick:b14,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b7,rightx:a2,righty:a3,start:b13,x:b2,y:b3,platform:Linux, +03000000f0250000c183000010010000,Goodbetterbest Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +0300000079000000d418000000010000,GPD Win 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000001010000,GPD Win Max 2 (6800U) Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000007d0400000540000000010000,Gravis Eliminator Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000280400000140000000010000,Gravis GamePad Pro,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000610000000010000,GreenAsia Electronics Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a3,righty:a2,start:b11,x:b3,y:b0,platform:Linux, +030000008f0e00001200000010010000,GreenAsia Joystick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +0500000047532067616d657061640000,GS gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000f0250000c383000010010000,GT VX2,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +06000000adde0000efbe000002010000,Hidromancer Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d81400000862000011010000,HitBox PS3 PC Analog Mode,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b12,x:b0,y:b3,platform:Linux, +03000000c9110000f055000011010000,HJC Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00000d00000000010000,Hori,a:b0,b:b6,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,rightshoulder:b7,start:b9,x:b1,y:b2,platform:Linux, +030000000d0f00006d00000020010000,Hori EDGE 301,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:+a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008400000011010000,Hori Fighting Commander,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005f00000011010000,Hori Fighting Commander 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005e00000011010000,Hori Fighting Commander 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00005001000009040000,Hori Fighting Commander OCTA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00008500000010010000,Hori Fighting Commander PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008600000002010000,Hori Fighting Commander Xbox 360,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00003701000013010000,Hori Fighting Stick Mini,a:b1,b:b0,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b3,y:b2,platform:Linux, +030000000d0f00008800000011010000,Hori Fighting Stick mini 4 (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,rightstick:b11,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00008700000011010000,Hori Fighting Stick mini 4 (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,rightstick:b11,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00001000000011010000,Hori Fightstick 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000003f5000033050000,Hori Fightstick VX,+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b8,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f00004d00000011010000,Hori Gem Pad 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00003801000011010000,Hori PC Engine Mini Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,platform:Linux, +030000000d0f00009200000011010000,Hori Pokken Tournament DX Pro,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00001100000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00002200000011010000,Hori Real Arcade Pro 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006a00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006b00000011010000,Hori Real Arcade Pro 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00001600000000010000,Hori Real Arcade Pro EXSE,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +030000000d0f0000aa00000011010000,Hori Real Arcade Pro for Nintendo Switch,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000000d0f00008501000015010000,Hori Switch Split Pad Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00006e00000011010000,Horipad 4 PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006600000011010000,Horipad 4 PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000ee00000011010000,Horipad Mini 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f0000c100000011010000,Horipad Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000000d0f00006700000001010000,Horipad One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000000d0f0000f600000001000000,Horipad Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000341a000005f7000010010000,HuiJia GameCube Controller Adapter,a:b1,b:b2,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +05000000242e00000b20000001000000,Hyperkin Admiral N64 Controller,+rightx:b11,+righty:b13,-rightx:b8,-righty:b12,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b14,leftx:a0,lefty:a1,rightshoulder:b5,start:b9,platform:Linux, +03000000242e0000ff0b000011010000,Hyperkin N64 Adapter,a:b1,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,platform:Linux, +03000000242e00006a38000010010000,Hyperkin Trooper 2,a:b0,b:b1,back:b4,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b3,start:b5,platform:Linux, +03000000242e00008816000001010000,Hyperkin X91,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000f00300008d03000011010000,HyperX Clutch,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000830500006020000010010000,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +050000006964726f69643a636f6e0000,idroidcon Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001503000010010000,Impact,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000d80400008200000003000000,IMS PCU0,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b5,x:b3,y:b2,platform:Linux, +03000000120c00000500000010010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +03000000ef0500000300000000010000,InterAct AxisPad,a:b2,b:b3,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b11,x:b0,y:b1,platform:Linux, +03000000fd0500000030000000010000,InterAct GoPad,a:b3,b:b4,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,x:b0,y:b1,platform:Linux, +03000000fd0500002a26000000010000,InterAct HammerHead FX,a:b3,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b2,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b1,platform:Linux, +0500000049190000020400001b010000,Ipega PG 9069,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b161,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000011010000,Ipega PG 9099,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +0500000049190000030400001b010000,Ipega PG9099,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000491900000204000000000000,Ipega PG9118,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000300f00001001000010010000,Jess Tech Dual Analog Rumble,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000300f00000b01000010010000,Jess Tech GGE909 PC Recoil,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000ba2200002010000001010000,Jess Technology Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +050000007e0500000620000001000000,Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b13,leftshoulder:b4,leftstick:b10,rightshoulder:b5,start:b8,x:b2,y:b3,platform:Linux, +030000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000720000001000000,Joy-Con (R),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b1,back:b12,leftshoulder:b4,leftstick:b11,rightshoulder:b5,start:b9,x:b2,y:b3,platform:Linux, +03000000bd12000003c0000010010000,Joypad Alpha Shock,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000242f00002d00000011010000,JYS Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000242f00008a00000011010000,JYS Adapter,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +030000006f0e00000103000000020000,Logic3 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d1ca000000000000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d040000d1ca000011010000,Logitech Chillstream,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000010010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000016c2000011010000,Logitech Dual Action,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000019200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000018c2000010010000,Logitech RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,back:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b6,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b10,rightx:a3,righty:a4,start:b8,x:b3,y:b4,platform:Linux, +030000006d0400000ac2000010010000,Logitech WingMan RumblePad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,rightx:a3,righty:a4,x:b3,y:b4,platform:Linux, +05000000380700006652000025010000,Mad Catz CTRLR,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008532000010010000,Mad Catz Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005032000011010000,Mad Catz Fightpad Pro PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700005082000011010000,Mad Catz Fightpad Pro PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b00002ef0000090040000,Mad Catz Fightpad SFxT,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +03000000380700008034000011010000,Mad Catz Fightstick PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008084000011010000,Mad Catz Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008433000011010000,Mad Catz Fightstick TE S PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700008483000011010000,Mad Catz Fightstick TE S PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700003888000010010000,Mad Catz Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:a0,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000380700001647000010040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000380700003847000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ad1b000016f0000090040000,Mad Catz Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c00000500000000010000,Manta Dualshock 2,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000008f0e00001330000010010000,Mayflash Controller Adapter,a:b1,b:b2,back:b8,dpdown:h0.8,dpleft:h0.2,dpright:h0.1,dpup:h0.4,leftshoulder:b6,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a3~,righty:a2,start:b9,x:b0,y:b3,platform:Linux, +03000000790000004318000010010000,Mayflash GameCube Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000790000004418000010010000,Mayflash GameCube Controller,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +03000000242f00007300000011010000,Mayflash Magic NS,a:b1,b:b4,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b0,y:b3,platform:Linux, +0300000079000000d218000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000010a7000011010000,Mayflash Magic NS,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000242f0000f700000001010000,Mayflash Magic S Pro,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000008f0e00001030000010010000,Mayflash Saturn Adapter,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, +0300000025090000e803000001010000,Mayflash Wii Classic Adapter,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:a4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:a5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +03000000790000000318000011010000,Mayflash Wii DolphinBar,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +03000000790000000018000011010000,Mayflash Wii U Pro Adapter,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700001203000010010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000b50700004f00000000010000,Mega World Logic 3 Controller,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b1,platform:Linux, +03000000780000000600000010010000,Microntek Joystick,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +030000005e0400002800000000010000,Microsoft Dual Strike,a:b3,b:b2,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,rightx:a0,righty:a1~,start:b5,x:b1,y:b0,platform:Linux, +030000005e0400000300000000010000,Microsoft SideWinder,a:b0,b:b1,back:b9,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400000700000000010000,Microsoft SideWinder,a:b0,b:b1,back:b8,leftshoulder:b6,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b2,start:b9,x:b3,y:b4,platform:Linux, +030000005e0400000e00000000010000,Microsoft SideWinder Freestyle Pro,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,rightshoulder:b7,start:b8,x:b3,y:b4,platform:Linux, +030000005e0400002700000000010000,Microsoft SideWinder Plug and Play,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,lefttrigger:b4,righttrigger:b5,x:b2,y:b3,platform:Linux, +030000005e0400008502000000010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008902000021010000,Microsoft Xbox,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000005e0400008e02000001000000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.1,dpleft:h0.2,dpright:h0.8,dpup:h0.4,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000004010000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000056210000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000062230000,Microsoft Xbox 360,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000001010000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000d102000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000dd02000003020000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000008040000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b000009050000,Microsoft Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000e302000003020000,Microsoft Xbox One Elite,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000000b000007040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000000b000008040000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b12,paddle2:b14,paddle3:b13,paddle4:b15,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000050b000003090000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e0400008e02000030110000,Microsoft Xbox One Elite 2,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000b050000,Microsoft Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000030000000300000002000000,Miroof,a:b1,b:b0,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b2,platform:Linux, +03000000790000001c18000010010000,Mobapad Chitu HD,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000004d4f435554452d3035335800,Mocute 053X,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +05000000e80400006e0400001b010000,Mocute 053X M59,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000004d4f435554452d3035305800,Mocute 054X,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000d6200000e589000001000000,Moga 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d6200000ad0d000001000000,Moga Pro,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +05000000d62000007162000001000000,Moga Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Linux, +03000000c62400002b89000011010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400002a89000000010000,MOGA XP5A Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b22,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000c62400001a89000000010000,MOGA XP5X Plus,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000250900006688000000010000,MP8866 Super Dual Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000010020000,MSI GC20 V2,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006b1400000906000014010000,Nacon Asymmetric Wireless PS4 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006b140000010c000010010000,Nacon GC 400ES,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000853200000706000012010000,Nacon GC-100,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000000d0f00000900000010010000,Natec Genesis P44,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f1f00000800000011010000,NeoGeo PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +0300000092120000474e000000010000,NeoGeo X Arcade Stick,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b3,y:b2,platform:Linux, +03000000790000004518000010010000,Nexilux GameCube Controller Adapter,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:a4,rightx:a5,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +030000001008000001e5000010010000,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Linux, +060000007e0500003713000000000000,Nintendo 3DS,a:b0,b:b1,back:b8,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000009b2800008000000020020000,Nintendo Classic Controller,a:b1,b:b4,back:b2,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b5,platform:Linux, +030000007e0500003703000000016800,Nintendo GameCube Controller,a:b0,b:b2,dpdown:b6,dpleft:b4,dpright:b5,dpup:b7,lefttrigger:a4,leftx:a0,lefty:a1~,rightshoulder:b9,righttrigger:a5,rightx:a2,righty:a3~,start:b8,x:b1,y:b3,platform:Linux, +03000000790000004618000010010000,Nintendo GameCube Controller Adapter,a:b1,b:b0,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,rightx:a5~,righty:a2~,start:b9,x:b2,y:b3,platform:Linux, +060000004e696e74656e646f20537700,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +060000007e0500000620000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +060000007e0500000820000000000000,Nintendo Switch Combined Joy-Cons,a:b0,b:b1,back:b9,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000004c69632050726f20436f6e00,Nintendo Switch Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000620000001800000,Nintendo Switch Left Joy-Con,a:b16,b:b15,back:b4,leftshoulder:b6,leftstick:b12,leftx:a1,lefty:a0~,rightshoulder:b8,start:b9,x:b14,y:b17,platform:Linux, +030000007e0500000920000000026803,Nintendo Switch Pro Controller,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Linux, +030000007e0500000920000011810000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500000920000001000000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500000920000001800000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b5,leftstick:b12,lefttrigger:b7,leftx:a0,lefty:a1,misc1:b4,rightshoulder:b6,rightstick:b13,righttrigger:b8,rightx:a2,righty:a3,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500000720000001800000,Nintendo Switch Right Joy-Con,a:b1,b:b2,back:b9,leftshoulder:b4,leftstick:b10,leftx:a1~,lefty:a0,rightshoulder:b6,start:b8,x:b0,y:b3,platform:Linux, +05000000010000000100000003000000,Nintendo Wii Remote,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000007e0500003003000001000000,Nintendo Wii U Pro Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000000d0500000308000010010000,Nostromo n45 Dual Analog,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,platform:Linux, +030000007e0500001920000011810000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +050000007e0500001920000001000000,NSO N64 Controller,+rightx:b8,+righty:b7,-rightx:b3,-righty:b2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,righttrigger:b10,start:b9,platform:Linux, +050000007e0500001920000001800000,NSO N64 Controller,+rightx:b10,+righty:b8,-rightx:b9,-righty:b7,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b11,leftshoulder:b3,lefttrigger:b2,leftx:a0,lefty:a1,misc1:b12,rightshoulder:b4,righttrigger:b5,start:b6,platform:Linux, +030000007e0500001720000011810000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +050000007e0500001720000001000000,NSO SNES Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:b7,rightshoulder:b6,righttrigger:b8,start:b10,x:b3,y:b2,platform:Linux, +050000007e0500001720000001800000,NSO SNES Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +03000000550900001072000011010000,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b8,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000550900001472000011010000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +05000000550900001472000001000000,NVIDIA Controller v01.04,a:b0,b:b1,back:b14,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b4,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Linux, +03000000451300000830000010010000,NYKO CORE,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +19000000010000000100000001010000,ODROID Go 2,a:b1,b:b0,dpdown:b7,dpleft:b8,dpright:b9,dpup:b6,guide:b10,leftshoulder:b4,leftstick:b12,lefttrigger:b11,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b13,righttrigger:b14,start:b15,x:b2,y:b3,platform:Linux, +19000000010000000200000011000000,ODROID Go 2,a:b1,b:b0,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b12,leftshoulder:b4,leftstick:b14,lefttrigger:b13,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b15,righttrigger:b16,start:b17,x:b2,y:b3,platform:Linux, +03000000c0160000dc27000001010000,OnyxSoft Dual JoyDivision,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:Linux, +05000000362800000100000002010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000003010000,OUYA Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,platform:Linux, +05000000362800000100000004010000,OUYA Controller,a:b0,b:b3,back:b14,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,leftshoulder:b4,leftstick:b6,lefttrigger:b12,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:b13,rightx:a3,righty:a4,start:b16,x:b1,y:b2,platform:Linux, +03000000830500005020000010010000,Padix Rockfire PlayStation Bridge,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b11,x:b2,y:b3,platform:Linux, +03000000ff1100003133000010010000,PC Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e0000b802000001010000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000b802000013020000,PDP Afterglow Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d702000006640000,PDP Black Camo Wired Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b13,dpup:b14,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00003101000000010000,PDP EA Sports Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008501000011010000,PDP Fightpad Pro Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e0000c802000012010000,PDP Kingdom Hearts Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00002801000011010000,PDP PS3 Rock Candy Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000901000011010000,PDP PS3 Versus Fighting,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +03000000ad1b000004f9000000010000,PDP Xbox 360 Versus Fighting,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000a802000023020000,PDP Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +030000006f0e0000a702000023020000,PDP Xbox One Raven Black,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000d802000006640000,PDP Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e0000ef02000007640000,PDP Xbox Series Kinetic Wired Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000666600006706000000010000,PlayStation Adapter,a:b2,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b9,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b10,righttrigger:b5,rightx:a2,righty:a3,start:b11,x:b3,y:b0,platform:Linux, +030000004c050000da0c000011010000,PlayStation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d9040000160f000000010000,PlayStation Controller Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400003a54000001010000,PowerA 1428124-01,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400001a53000000010000,PowerA Mini Pro Ex,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d620000013a7000011010000,PowerA Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d62000006dca000011010000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000d620000014a7000011010000,PowerA Spectra Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c62400001a58000001010000,PowerA Xbox One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000220000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +03000000d62000000228000001010000,PowerA Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c62400001a54000001010000,PowerA Xbox One Mini Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000240000001010000,PowerA Xbox One Spectra Infinity,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d62000000f20000001010000,PowerA Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b7,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d040000d2ca000011010000,Precision Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00003608000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000010810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c0500006802000011810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000005f1400003102000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000006f0e00001402000011010000,PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000008f0e00000300000010010000,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +050000004c0500006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +050000004c0500006802000000800000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c0500006802000000810000,PS3 Controller,a:b0,b:b1,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +05000000504c415953544154494f4e00,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +060000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000a00b000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000a00b000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000c405000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000c405000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004c050000cc09000011810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +03000000c01100000140000011010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000c405000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000c405000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +030000004c050000e60c000011810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +030000004c050000f20d000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b14,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +050000004c050000e60c000000810000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:Linux, +050000004c050000f20d000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000300f00001211000011010000,Qanba Arcade Joystick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,platform:Linux, +03000000222c00000225000011010000,Qanba Dragon Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000025000011010000,Qanba Dragon Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000020000011010000,Qanba Drone Arcade PS4 Joystick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,rightshoulder:b5,righttrigger:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000300f00001210000010010000,Qanba Joystick Plus,a:b0,b:b1,back:b8,leftshoulder:b5,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b4,righttrigger:b6,start:b9,x:b2,y:b3,platform:Linux, +03000000222c00000223000011010000,Qanba Obsidian Arcade Joystick (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000222c00000023000011010000,Qanba Obsidian Arcade Joystick (PS4),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000009b2800000300000001010000,Raphnet 4nes4snes,a:b0,b:b4,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +030000009b2800004200000001010000,Raphnet Dual NES Adapter,a:b0,b:b1,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b3,platform:Linux, +030000009b2800003200000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +030000009b2800006000000001010000,Raphnet GC and N64 Adapter,a:b0,b:b7,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b2,righttrigger:b5,rightx:a3,righty:a4,start:b3,x:b1,y:b8,platform:Linux, +03000000f8270000bf0b000011010000,Razer Kishi,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000008916000001fd000024010000,Razer Onza Classic Edition,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000204000011010000,Razer Panthera PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000104000011010000,Razer Panthera PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000810000011010000,Razer Panthera PS4 Evo Arcade Stick,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000010000011010000,Razer Raiju,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000507000000010000,Razer Raiju Mobile,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b21,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000321500000a10000001000000,Razer Raiju Tournament Edition,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b13,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000321500000011000011010000,Razer Raion PS4 Fightpad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000008916000000fe000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000024010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000045d000025010000,Razer Sabertooth,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000009000011010000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +050000003215000000090000163a0000,Razer Serval,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +0300000032150000030a000001010000,Razer Wildcat,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000321500000b10000011010000,Razer Wolverine PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,touchpad:b13,x:b0,y:b3,platform:Linux, +03000000790000001100000010010000,Retro Controller,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,start:b9,x:b0,y:b3,platform:Linux, +0300000003040000c197000011010000,Retrode Adapter,a:b0,b:b4,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b1,y:b5,platform:Linux, +190000004b4800000111000000010000,RetroGame Joypad,a:b1,b:b0,back:b8,dpdown:b14,dpleft:b15,dpright:b16,dpup:b13,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +0300000081170000990a000001010000,Retronic Adapter,a:b0,leftx:a0,lefty:a1,platform:Linux, +0300000000f000000300000000010000,RetroPad,a:b1,b:b5,back:b2,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +00000000526574726f53746f6e653200,RetroStone 2 Controller,a:b1,b:b0,back:b10,dpdown:b15,dpleft:b16,dpright:b17,dpup:b14,leftshoulder:b6,lefttrigger:b8,rightshoulder:b7,righttrigger:b9,start:b11,x:b4,y:b3,platform:Linux, +03000000341200000400000000010000,RetroUSB N64 RetroPort,+rightx:b8,+righty:b10,-rightx:b9,-righty:b11,a:b7,b:b6,dpdown:b2,dpleft:b1,dpright:b0,dpup:b3,leftshoulder:b13,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b12,start:b4,platform:Linux, +030000006b140000010d000011010000,Revolution Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006b140000130d000011010000,Revolution Pro Controller 3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001f01000000010000,Rock Candy,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00008701000011010000,Rock Candy Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00001e01000011010000,Rock Candy PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000c6240000fefa000000010000,Rock Candy Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006f0e00004601000001010000,Rock Candy Xbox One Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V1 PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000a30600001005000000010000,Saitek P150,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b7,lefttrigger:b6,rightshoulder:b2,righttrigger:b5,x:b3,y:b4,platform:Linux, +03000000a30600000701000000010000,Saitek P220,a:b2,b:b3,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b4,righttrigger:b5,x:b0,y:b1,platform:Linux, +03000000a30600000cff000010010000,Saitek P2500 Force Rumble,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b0,y:b1,platform:Linux, +03000000a30600000c04000011010000,Saitek P2900,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b12,x:b0,y:b3,platform:Linux, +03000000a306000018f5000010010000,Saitek P3200 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +03000000300f00001201000010010000,Saitek P380,a:b2,b:b3,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b0,y:b1,platform:Linux, +03000000a30600000901000000010000,Saitek P880,a:b2,b:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,platform:Linux, +03000000a30600000b04000000010000,Saitek P990 Dual Analog,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,platform:Linux, +03000000a306000020f6000011010000,Saitek PS2700 Rumble,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a4,start:b9,x:b0,y:b3,platform:Linux, +05000000e804000000a000001b010000,Samsung EIGP20,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b15,leftshoulder:b6,leftx:a0,lefty:a1,rightshoulder:b7,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000d81d00000e00000010010000,Savior,a:b0,b:b1,back:b8,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b11,righttrigger:b3,start:b9,x:b4,y:b5,platform:Linux, +03000000a30c00002500000011010000,Sega Genesis Mini 3B Controller,a:b2,b:b1,dpdown:+a4,dpleft:-a3,dpright:+a3,dpup:-a4,righttrigger:b5,start:b9,platform:Linux, +03000000790000001100000011010000,Sega Saturn,a:b1,b:b2,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b4,start:b9,x:b0,y:b3,platform:Linux, +03000000790000002201000011010000,Sega Saturn,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,start:b9,x:b2,y:b3,platform:Linux, +03000000b40400000a01000000010000,Sega Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b7,rightshoulder:b5,righttrigger:b2,start:b8,x:b3,y:b4,platform:Linux, +030000001f08000001e4000010010000,SFC Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002305000010010000,ShanWan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000632500002605000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000632500007505000010010000,Shanwan Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000bc2000000055000010010000,Shanwan Gamepad,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000f025000021c1000010010000,Shanwan Gioteck PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000341a00000908000010010000,SL6566,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +050000004c050000cc09000001000000,Sony DualShock 4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000ff000000cb01000010010000,Sony PlayStation Portable,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy Adapter,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +030000005e0400008e02000073050000,Speedlink Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000020200000,SpeedLink Xeox Pro Analog,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000d11800000094000011010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000d11800000094000000010000,Stadia Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000112000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:+a5,dpleft:-a4,dpright:+a4,dpup:-a5,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b15,paddle2:b16,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800004211000011010000,Steam Controller,a:b2,b:b3,back:b10,dpdown:b18,dpleft:b19,dpright:b20,dpup:b17,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,paddle1:b16,paddle2:b15,rightshoulder:b7,righttrigger:a6,rightx:a2,righty:a3,start:b11,x:b4,y:b5,platform:Linux, +03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b10,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Linux, +03000000de2800000512000010010000,Steam Deck,a:b3,b:b4,back:b11,dpdown:b17,dpleft:b18,dpright:b19,dpup:b16,guide:b13,leftshoulder:b7,leftstick:b14,lefttrigger:a9,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b15,righttrigger:a8,rightx:a2,righty:a3,start:b12,x:b5,y:b6,platform:Linux, +03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000004e696d6275732b0000000000,SteelSeries Nimbus Plus,a:b0,b:b1,back:b10,guide:b11,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a2,righty:a3,start:b12,x:b2,y:b3,platform:Linux, +03000000381000003014000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000381000003114000075010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +0500000011010000311400001b010000,SteelSeries Stratus Duo,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b32,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +05000000110100001914000009010000,SteelSeries Stratus XL,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000ad1b000038f0000090040000,Street Fighter IV Fightstick TE,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000003b07000004a1000000010000,Suncom SFX Plus,a:b0,b:b2,back:b7,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b9,righttrigger:b5,start:b8,x:b1,y:b3,platform:Linux, +03000000666600000488000000010000,Super Joy Box 5 Pro,a:b2,b:b1,back:b9,dpdown:b14,dpleft:b15,dpright:b13,dpup:b12,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b3,y:b0,platform:Linux, +0300000000f00000f100000000010000,Super RetroPort,a:b1,b:b5,back:b2,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b6,rightshoulder:b7,start:b3,x:b0,y:b4,platform:Linux, +030000008f0e00000d31000010010000,SZMY Power 3 Turbo,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000457500000401000011010000,SZMY Power DS4 Wired Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000457500002211000010010000,SZMY Power Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +030000008f0e00001431000010010000,SZMY Power PS3,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +03000000ba2200000701000001010000,Technology Innovation PS2 Adapter,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a5,righty:a2,start:b9,x:b3,y:b2,platform:Linux, +03000000790000001c18000011010000,TGZ Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:b9,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000591c00002400000010010000,THEC64 Joystick,a:b0,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000591c00002600000010010000,THEGamepad,a:b2,b:b1,back:b6,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b3,y:b0,platform:Linux, +030000004f04000015b3000001010000,Thrustmaster Dual Analog 3.2,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000015b3000010010000,Thrustmaster Dual Analog 4,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster Dual Trigger,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f0400000ed0000011010000,Thrustmaster eSwap Pro Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000b50700000399000000010000,Thrustmaster Firestorm Digital 2,a:b2,b:b4,back:b11,leftshoulder:b6,leftstick:b10,lefttrigger:b7,leftx:a0,lefty:a1,rightshoulder:b8,rightstick:b0,righttrigger:b9,start:b1,x:b3,y:b5,platform:Linux, +030000004f04000003b3000010010000,Thrustmaster Firestorm Dual Analog 2,a:b0,b:b2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b9,rightx:a2,righty:a3,x:b1,y:b3,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b11,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b10,x:b1,y:b3,platform:Linux, +030000004f04000004b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +030000004f04000026b3000002040000,Thrustmaster GP XID,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c6240000025b000002020000,Thrustmaster GPX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004f04000008d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000009d0000000010000,Thrustmaster Run N Drive PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000007d0000000010000,Thrustmaster T Mini,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000004f04000012b3000010010000,Thrustmaster Vibrating Gamepad,a:b0,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b1,y:b3,platform:Linux, +03000000571d00002000000010010000,Tomee SNES Adapter,a:b0,b:b1,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b2,y:b3,platform:Linux, +03000000bd12000015d0000010010000,Tomee SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b9,x:b3,y:b0,platform:Linux, +03000000d814000007cd000011010000,Toodles 2008 Chimp PC PS3,a:b0,b:b1,back:b8,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,start:b9,x:b3,y:b2,platform:Linux, +030000005e0400008e02000070050000,Torid,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000c01100000591000011010000,Torid,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +03000000680a00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000780300000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000e00d00000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +03000000f00600000300000003000000,TRBot Virtual Joypad,a:b11,b:b12,back:b15,dpdown:b6,dpleft:b3,dpright:b4,dpup:b5,leftshoulder:b17,leftstick:b21,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b22,righttrigger:a2,rightx:a3,righty:a4,start:b16,x:b13,y:b14,platform:Linux, +030000005f140000c501000010010000,Trust Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b0,platform:Linux, +06000000f51000000870000003010000,Turtle Beach Recon,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin PS2 Adapter,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000151900005678000010010000,Uniplay U6,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000100800000300000010010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +03000000790000000600000007010000,USB gamepad,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a4,start:b9,x:b3,y:b0,platform:Linux, +03000000790000001100000000010000,USB Gamepad,a:b2,b:b1,back:b8,dpdown:a0,dpleft:a1,dpright:a2,dpup:a4,start:b9,platform:Linux, +030000006f0e00000302000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +030000006f0e00000702000011010000,Victrix Pro Fightstick PS4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,start:b9,x:b0,y:b3,platform:Linux, +05000000ac0500003232000001000000,VR Box Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b2,y:b3,platform:Linux, +05000000434f4d4d414e440000000000,VX Gaming Command Series,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +0000000058626f782033363020576900,Xbox 360 Controller,a:b0,b:b1,back:b14,dpdown:b11,dpleft:b12,dpright:b13,dpup:b10,guide:b7,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400009102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000000010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000007010000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000030060000,Xbox 360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000000010000,Xbox 360 EasySMX,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000a102000014010000,Xbox 360 Receiver,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400000202000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +030000006f0e00001304000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000ffff0000ffff000000010000,Xbox Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b5,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b2,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b3,y:b4,platform:Linux, +0000000058626f782047616d65706100,Xbox Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a4,rightx:a2,righty:a3,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400000a0b000005040000,Xbox One Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b11,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b3,y:b2,platform:Linux, +030000005e040000d102000002010000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000000000000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000ea02000001030000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e002000003090000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000fd02000003090000,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b16,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000fd02000030110000,Xbox One Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000e302000002090000,Xbox One Elite,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000220b000013050000,Xbox One Elite 2 Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b13,lefttrigger:a6,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a5,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +030000005e040000ea02000011050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000ea0200000b050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000ea0200000d050000,Xbox One S Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000001050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000005050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b000009050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000d050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000001050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000005050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000007050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000009050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000011050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000013050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +050000005e040000130b000015050000,Xbox Series Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,misc1:b15,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +060000005e040000120b000007050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000b050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000f050000,Xbox Series Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +060000005e040000120b00000d050000,Xbox Series X Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +050000005e040000200b000013050000,Xbox Wireless Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b13,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux, +03000000450c00002043000010010000,XEOX SL6556 BK,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +05000000172700004431000029010000,XiaoMi Controller,a:b0,b:b1,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b20,leftshoulder:b6,leftstick:b13,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b14,righttrigger:a6,rightx:a2,righty:a5,start:b11,x:b3,y:b4,platform:Linux, +03000000c0160000e105000001010000,XinMo Dual Arcade,a:b4,b:b3,back:b6,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b9,leftshoulder:b2,leftx:a0,lefty:a1,rightshoulder:b5,start:b7,x:b1,y:b0,platform:Linux, +xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000120c0000100e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +03000000120c0000101e000011010000,Zeroplus P4,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +38653964633230666463343334313533,8BitDo Adapter,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36666264316630653965636634386234,8BitDo Adapter 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f20417263616465205374,8BitDo Arcade Stick,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b5,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61393962646434393836356631636132,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +64323139346131306233636562663738,8BitDo Arcade Stick,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +64643565386136613265663236636564,8BitDo Arcade Stick,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +33313433353539306634656436353432,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f20446f67626f6e65204d,8BitDo Dogbone,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +34343439373236623466343934376233,8BitDo FC30 Pro,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b28,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b4,rightstick:b29,righttrigger:b7,start:b5,x:b30,y:b2,platform:Android, +38426974446f2038426974446f204c69,8BitDo Lite,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +30643332373663313263316637356631,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f204c6974652032000000,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +62656331626461363634633735353032,8BitDo Lite 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38393936616436383062666232653338,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f204c6974652053450000,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +39356430616562366466646636643435,8BitDo Lite SE,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000006500000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a5,rightshoulder:b10,righttrigger:a4,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000051060000ffff3f00,8BitDo M30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,guide:b17,leftshoulder:b9,lefttrigger:a4,rightshoulder:b10,righttrigger:a5,start:b6,x:b3,y:b2,platform:Android, +32323161363037623637326438643634,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33656266353630643966653238646264,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:a5,start:b10,x:b19,y:b2,platform:Android, +38426974446f204d3330204d6f646b69,8BitDo M30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39366630663062373237616566353437,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,start:b6,x:b2,y:b3,platform:Android, +64653533313537373934323436343563,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,start:b6,x:b2,y:b3,platform:Android, +66356438346136366337386437653934,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,start:b18,x:b19,y:b2,platform:Android, +66393064393162303732356665666366,8BitDo M30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,start:b6,x:b2,y:b3,platform:Android, +38426974446f204d6963726f2067616d,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +61653365323561356263373333643266,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +62613137616239666338343866326336,8BitDo Micro,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:a4,leftx:b0,lefty:b1,rightshoulder:b10,righttrigger:a5,rightx:b2,righty:b3,start:b6,x:b3,y:b2,platform:Android, +33663431326134333366393233616633,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +38426974446f204e3330204d6f646b69,8BitDo N30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,rightx:a2,righty:a3,start:b6,platform:Android, +05000000c82d000015900000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000065280000ffff3f00,8BitDo N30 Pro 2,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38323035343766666239373834336637,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android, +38426974446f204e3634204d6f646b69,8BitDo N64,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,platform:Android, +32363135613966656338666638666237,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35363534633333373639386466346631,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f204e454f47454f204750,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39383963623932353561633733306334,8BitDo NEOGEO,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000000220000000900000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002038000009000000ffff3f00,8BitDo NES30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38313433643131656262306631373166,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38326536643339353865323063616339,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38426974446f2050333020636c617373,8BitDo P30,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35376664343164386333616535333434,8BitDo Pro 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,start:b10,x:b19,y:b2,platform:Android, +38426974446f2038426974446f205072,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f2050726f203200000000,8BitDo Pro 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +62373739366537363166326238653463,8BitDo Pro 2,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b3,y:b2,platform:Android, +38386464613034326435626130396565,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f2038426974446f205265,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +66303230343038613365623964393766,8BitDo Receiver,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20533330204d6f646b69,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66316462353561376330346462316137,8BitDo S30,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:a4,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b9,righttrigger:b10,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000000600000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000000610000ffff3f00,8BitDo SF30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974646f20534633302050726f00,8BitDo SF30 Pro,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b17,platform:Android, +61623334636338643233383735326439,8BitDo SFC30,a:b0,b:b1,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b31,start:b5,x:b30,y:b2,platform:Android, +05000000c82d000012900000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000062280000ffff3f00,8BitDo SN30,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +38316230613931613964356666353839,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20534e3330204d6f646b,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +65323563303231646531383162646335,8BitDo SN30,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +35383531346263653330306238353131,8BitDo SN30 PP,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000001600000ffff3f00,8BitDo SN30 Pro,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000002600000ffff0f00,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b17,leftshoulder:b9,leftstick:b7,lefttrigger:b15,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b16,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +36653638656632326235346264663661,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +38303232393133383836366330346462,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +38346630346135363335366265656666,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38426974446f20534e33302050726f2b,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +536f6e7920436f6d707574657220456e,8BitDo SN30 Pro Plus,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66306331643531333230306437353936,8BitDo SN30 Pro Plus,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000002028000009000000ffff3f00,8BitDo SNES30,a:b1,b:b0,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +050000003512000020ab000000780f00,8BitDo SNES30,a:b21,b:b20,back:b30,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b26,rightshoulder:b27,start:b31,x:b24,y:b23,platform:Android, +33666663316164653937326237613331,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +38426974646f205a65726f2047616d65,8BitDo Zero,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +05000000c82d000018900000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +05000000c82d000030320000ffff0f00,8BitDo Zero 2,a:b1,b:b0,back:b4,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +33663434393362303033616630346337,8BitDo Zero 2,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +34656330626361666438323266633963,8BitDo Zero 2,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +63396666386564393334393236386630,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +63633435623263373466343461646430,8BitDo Zero 2,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftx:a0,lefty:a1,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +32333634613735616163326165323731,Amazon Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +417374726f2063697479206d696e6920,Astro City Mini,a:b23,b:b22,back:b29,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, +35643263313264386134376362363435,Atari VCS Classic Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,start:b6,platform:Android, +32353831643566306563643065356239,Atari VCS Modern Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +32303165626138343962363666346165,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +38383337343564366131323064613561,Brook Mars PS4 Controller,a:b1,b:b19,back:b17,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +34313430343161653665353737323365,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +4875694a6961204a432d573031550000,Elecom JC-W01U,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +30363230653635633863366338623265,Evo VR,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftx:a0,lefty:a1,x:b2,y:b3,platform:Android, +05000000b404000011240000dfff3f00,Flydigi Vader 2,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000bc20000000550000ffff3f00,GameSir G3w,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34323662653333636330306631326233,Google Nexus,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35383633353935396534393230616564,Google Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000d6020000e5890000dfff3f00,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +05000000d6020000e5890000dfff3f80,GPD XD Plus,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android, +66633030656131663837396562323935,Hori Battle,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +35623466343433653739346434636330,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c54442e203130,Hori Fighting Commander 3 Pro,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +484f524920434f2e2c4c544420205041,Hori Gem Pad 3,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, +65656436646661313232656661616130,Hori PC Engine Mini Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b18,platform:Android, +31303433326562636431653534636633,Hori Real Arcade Pro 3,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +32656664353964393561366362333636,Hori Switch Split Pad Pro,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +30306539356238653637313730656134,HORIPAD Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +48797065726b696e2050616400000000,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android, +62333331353131353034386136626636,Hyperkin Admiral N64 Controller,+rightx:b6,+righty:b7,-rightx:b17,-righty:b5,a:b1,b:b0,leftshoulder:b3,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b20,start:b18,platform:Android, +31306635363562663834633739396333,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +5368616e57616e202020202048797065,Hyperkin N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +0500000083050000602000000ffe0000,iBuffalo SNES Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b15,rightshoulder:b16,start:b10,x:b2,y:b3,platform:Android, +5553422c322d6178697320382d627574,iBuffalo Super Famicom Controller,a:b1,b:b0,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b3,y:b2,platform:Android, +64306137363261396266353433303531,InterAct GoPad,a:b24,b:b25,leftshoulder:b23,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,x:b21,y:b22,platform:Android, +532e542e442e20496e74657261637420,InterAct HammerHead FX,a:b23,b:b24,back:b30,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b22,lefttrigger:b28,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b25,righttrigger:b29,rightx:a2,righty:a3,start:b31,x:b20,y:b21,platform:Android, +65346535636333663931613264643164,Joy-Con,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b23,y:b24,platform:Android, +33346566643039343630376565326335,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +35313531613435623366313835326238,Joy-Con (L),a:b0,b:b1,back:b7,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +4a6f792d436f6e20284c290000000000,Joy-Con (L),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b17,x:b19,y:b2,platform:Android, +38383665633039363066383334653465,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39363561613936303237333537383931,Joy-Con (R),a:b0,b:b1,back:b5,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +4a6f792d436f6e202852290000000000,Joy-Con (R),a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +39656136363638323036303865326464,JYS Aapter,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +63316564383539663166353034616434,JYS Adapter,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, +64623163333561643339623235373232,Logitech F310,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35623364393661626231343866613337,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4c6f6769746563682047616d65706164,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64396331333230326333313330336533,Logitech F710,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39653365373864633935383236363438,Logitech G Cloud,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +416d617a6f6e2047616d6520436f6e74,Luna Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +4c756e612047616d6570616400000000,Luna Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30363066623539323534363639323363,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +31353762393935386662336365626334,Magic NS,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +39623565346366623931666633323530,Magic NS,a:b1,b:b3,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b0,y:b2,platform:Android, +6d6179666c617368206c696d69746564,Mayflash GameCube Adapter,a:b22,b:b21,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a5,righty:a2,start:b30,x:b23,y:b24,platform:Android, +436f6e74726f6c6c6572000000000000,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +65666330633838383061313633326461,Mayflash N64 Adapter,a:b1,b:b19,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a2,righty:a3,start:b18,platform:Android, +37316565396364386635383230353365,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +4875694a696120205553422047616d65,Mayflash Saturn Adapter,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +535a4d792d706f776572204c54442043,Mayflash Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b31,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +30653962643666303631376438373532,Mayflash Wii DolphinBar,a:b23,b:b24,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b0,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b22,platform:Android, +39346131396233376535393665363161,Mayflash Wii U Pro Adapter,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftstick:b31,lefttrigger:b27,rightshoulder:b26,rightstick:b0,righttrigger:b28,rightx:a0,righty:a1,start:b30,x:b21,y:b24,platform:Android, +31323564663862633234646330373138,Mega Drive,a:b23,b:b22,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,rightshoulder:b25,righttrigger:b26,start:b30,x:b24,y:b21,platform:Android, +37333564393261653735306132613061,Mega Drive,a:b21,b:b22,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,lefttrigger:b28,rightshoulder:b27,righttrigger:b23,start:b30,x:b24,y:b25,platform:Android, +64363363336633363736393038313464,Mega Drive,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b9,x:b2,y:b3,platform:Android, +33323763323132376537376266393366,Microsoft Dual Strike,a:b24,b:b23,back:b25,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b29,rightshoulder:b78,rightx:a0,righty:a1~,start:b26,x:b22,y:b21,platform:Android, +30306461613834333439303734316539,Microsoft SideWinder Pro,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b20,lefttrigger:b9,rightshoulder:b19,righttrigger:b10,start:b17,x:b2,y:b3,platform:Android, +32386235353630393033393135613831,Microsoft Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d4f42415041442050726f2d48440000,Mobapad Chitu HD,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d4f435554452d303533582d4d35312d,Mocute 053X,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33343361376163623438613466616531,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39306635663061636563316166303966,Mocute M053,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +7573622067616d657061642020202020,NEXT SNES Controller,a:b2,b:b1,back:b8,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,righttrigger:b6,start:b9,x:b3,y:b0,platform:Android, +050000007e05000009200000ffff0f00,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b17,y:b2,platform:Android, +34323437396534643531326161633738,Nintendo Switch Pro Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,misc1:b5,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +50726f20436f6e74726f6c6c65720000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b2,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b10,rightx:a2,righty:a3,start:b18,y:b3,platform:Android, +36326533353166323965623661303933,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, +4e363420436f6e74726f6c6c65720000,NSO N64 Controller,+rightx:b17,+righty:b10,-rightx:b2,-righty:b19,a:b1,b:b0,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,righttrigger:b15,start:b18,platform:Android, +534e455320436f6e74726f6c6c657200,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +64623863346133633561626136366634,NSO SNES Controller,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,rightshoulder:b20,start:b18,x:b19,y:b2,platform:Android, +050000005509000003720000cf7f3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000010720000ffff3f00,NVIDIA Controller,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f00,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +050000005509000014720000df7f3f80,NVIDIA Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a3,rightx:a4,righty:a5,start:b6,x:b2,y:b3,platform:Android, +37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +39383335313438623439373538343266,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b16,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +4f5559412047616d6520436f6e74726f,OUYA Controller,a:b0,b:b2,dpdown:b18,dpleft:b15,dpright:b6,dpup:b17,leftshoulder:b3,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b19,platform:Android, +506572666f726d616e63652044657369,PDP PS3 Rock Candy Controller,a:b1,b:b17,back:h0.2,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b16,x:b0,y:b2,platform:Android, +62653335326261303663356263626339,PlayStation Classic Controller,a:b19,b:b1,back:b17,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b3,rightshoulder:b10,righttrigger:b20,start:b18,x:b2,y:b0,platform:Android, +536f6e7920496e746572616374697665,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +576972656c65737320436f6e74726f6c,PlayStation Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61653962353232366130326530363061,Pokken,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,rightshoulder:b20,righttrigger:b10,start:b18,x:b0,y:b2,platform:Android, +32666633663735353234363064386132,PS2,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a3,righty:a2,start:b30,x:b24,y:b21,platform:Android, +050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +536f6e7920504c415953544154494f4e,PS3 Controller,a:b0,b:b1,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +61363034663839376638653463633865,PS3 Controller,a:b0,b:b1,back:b15,dpdown:a14,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66366539656564653432353139356536,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66383132326164626636313737373037,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000c405000000783f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000c4050000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000c4050000fffe3f80,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000c4050000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000cc090000fffe3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000004c050000cc090000ffff3f00,PS4 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30303839663330346632363232623138,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +31326235383662333266633463653332,PS4 Controller,a:b1,b:b16,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b17,x:b0,y:b2,platform:Android, +31373231336561636235613666323035,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31663838336334393132303338353963,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34613139376634626133336530386430,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +37626233336235343937333961353732,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +37626464343430636562316661643863,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38393161636261653636653532386639,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63313733393535663339656564343962,PS4 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +63393662363836383439353064663939,PS4 Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65366465656364636137653363376531,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +66613532303965383534396638613230,PS4 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f00,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000fffe3f80,PS5 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a3,rightx:a4,righty:a5,start:b16,x:b0,y:b2,platform:Android, +050000004c050000e60c0000ffff3f00,PS5 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +32346465346533616263386539323932,PS5 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +32633532643734376632656664383733,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +37363764353731323963323639666565,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +61303162353165316365336436343139,PS5 Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b8,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a5,start:b18,x:b0,y:b2,platform:Android, +64336263393933626535303339616332,Qanba 4RAF,a:b0,b:b1,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b20,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:b3,righttrigger:b9,rightx:a2,righty:a3,start:b18,x:b19,y:b2,platform:Android, +36626666353861663864336130363137,Razer Junglecat,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000f8270000bf0b0000ffff3f00,Razer Kishi,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +62653861643333663663383332396665,Razer Kishi,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000005070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000007070000ffff3f00,Razer Raiju Mobile,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000003215000000090000bf7f3f00,Razer Serval,a:b0,b:b1,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +5a6869587520526574726f2042697420,Retro Bit Saturn Controller,a:b21,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b26,rightshoulder:b27,righttrigger:b28,start:b30,x:b23,y:b24,platform:Android, +32417865732031314b6579732047616d,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +36313938306539326233393732613361,Retro Bit SNES Controller,a:b0,b:b1,back:b15,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b2,y:b3,platform:Android, +526574726f466c616720576972656420,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,rightshoulder:b18,start:b10,x:b2,y:b3,platform:Android, +61343739353764363165343237303336,Retro Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b17,lefttrigger:b18,leftx:a0,lefty:a1,start:b10,x:b2,y:b3,platform:Android, +526574726f696420506f636b65742043,Retroid Pocket,a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +582d426f7820436f6e74726f6c6c6572,Retroid Pocket,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,paddle1:b17,paddle2:b18,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38653130373365613538333235303036,Retroid Pocket 2,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64363363336633363736393038313463,Retrolink,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,start:b6,platform:Android, +37393234373533633333323633646531,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, +5365616c6965436f6d707574696e6720,RetroUSB N64 RetroPort,+rightx:b17,+righty:b15,-rightx:b18,-righty:b6,a:b10,b:b9,dpdown:b19,dpleft:b1,dpright:b0,dpup:b2,leftshoulder:b7,lefttrigger:b20,leftx:a0,lefty:a1,rightshoulder:b5,start:b3,platform:Android, +526574726f5553422e636f6d20534e45,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android, +64643037633038386238303966376137,RetroUSB SNES RetroPort,a:b1,b:b20,back:b19,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,rightshoulder:b10,start:b2,x:b0,y:b3,platform:Android, +37656564346533643138636436356230,Rock Candy Switch Controller,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b15,lefttrigger:b9,leftx:a0,lefty:a1,misc1:b7,rightshoulder:b20,rightstick:b6,righttrigger:b10,rightx:a2,righty:a3,start:b18,x:b0,y:b2,platform:Android, +33373336396634316434323337666361,RumblePad 2,a:b22,b:b23,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,lefttrigger:b27,leftx:a0,lefty:a1,rightshoulder:b26,righttrigger:b28,rightx:a2,righty:a3,start:b30,x:b21,y:b24,platform:Android, +36363537303435333566386638366333,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +53616d73756e672047616d6520506164,Samsung EIGP20,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +66386565396238363534313863353065,Sanwa PlayOnline Mobile,a:b21,b:b22,back:b23,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,start:b24,platform:Android, +32383165316333383766336338373261,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, +38613865396530353338373763623431,Saturn,a:b0,b:b1,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b9,lefttrigger:b10,rightshoulder:b20,righttrigger:b19,start:b17,x:b2,y:b3,platform:Android, +61316232336262373631343137633631,Saturn,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,lefttrigger:b10,leftx:a0,lefty:a1,rightshoulder:a4,righttrigger:a5,x:b2,y:b3,platform:Android, +30353835333338613130373363646337,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +66386262366536653765333235343634,SG H510,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,platform:Android, +66633132393363353531373465633064,SG H510,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftstick:b17,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b20,rightstick:b18,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b19,y:b2,platform:Android, +62653761636366393366613135366338,SN30 PP,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b3,y:b2,platform:Android, +38376662666661636265313264613039,SNES,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5346432f555342205061640000000000,SNES Adapter,a:b0,b:b1,back:b9,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b3,rightshoulder:b20,start:b10,x:b19,y:b2,platform:Android, +5553422047616d657061642000000000,SNES Controller,a:b1,b:b0,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,rightshoulder:b10,start:b6,x:b3,y:b2,platform:Android, +63303964303462366136616266653561,Sony PSP,a:b21,b:b22,back:b27,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b23,y:b24,platform:Android, +63376637643462343766333462383235,Sony Vita,a:b1,b:b19,back:b17,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,leftx:a0,lefty:a1,rightshoulder:b20,rightx:a3,righty:a4,start:b18,x:b0,y:b2,platform:Android, +476f6f676c65204c4c43205374616469,Stadia Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5374616469614e3848532d6532633400,Stadia Controller,a:b0,b:b1,back:b15,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:Android, +0500000011010000201400000f7e0f00,SteelSeries Nimbus,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b3,lefttrigger:b9,leftx:a0,lefty:a1,rightshoulder:b20,righttrigger:b10,rightx:a2,righty:a3,x:b19,y:b2,platform:Android, +35306436396437373135383665646464,SteelSeries Nimbus Plus,a:b0,b:b1,leftshoulder:b3,leftstick:b17,lefttrigger:b9,leftx:a0,rightshoulder:b20,rightstick:b18,righttrigger:b10,rightx:a2,x:b19,y:b2,platform:Android, +54475a20436f6e74726f6c6c65720000,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +62363434353532386238336663643836,TGZ Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:b17,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:b18,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +37323236633763666465316365313236,THEC64 Joystick,a:b21,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b27,x:b23,y:b24,platform:Android, +38346162326232346533316164363336,THEGamepad,a:b23,b:b22,back:b27,leftshoulder:b25,leftx:a0,lefty:a1,rightshoulder:b26,start:b28,x:b24,y:b21,platform:Android, +050000004f0400000ed00000fffe3f00,ThrustMaster eSwap Pro Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +5477696e20555342204a6f7973746963,Twin Joystick,a:b22,b:b21,back:b28,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b26,leftstick:b30,lefttrigger:b24,leftx:a0,lefty:a1,rightshoulder:b27,rightstick:b31,righttrigger:b25,rightx:a3,righty:a2,start:b29,x:b23,y:b20,platform:Android, +30623739343039643830333266346439,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +31643365666432386133346639383937,Valve Steam Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,leftx:a0,lefty:a1,paddle1:b24,paddle2:b23,rightshoulder:b10,rightstick:b8,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30386438313564306161393537333663,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +33333034646336346339646538643633,Wii Classic Adapter,a:b23,b:b22,back:b29,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b27,lefttrigger:b25,leftx:a0,lefty:a1,rightshoulder:b28,righttrigger:b26,rightx:a2,righty:a3,start:b30,x:b24,y:b21,platform:Android, +050000005e0400008e02000000783f00,Xbox 360 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +30396232393162346330326334636566,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +38313038323730383864666463383533,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f782033363020576972656c6573,Xbox 360 Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65353331386662343338643939643636,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65613532386633373963616462363038,Xbox 360 Controller,a:b0,b:b1,back:b4,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +47656e6572696320582d426f78207061,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +4d6963726f736f667420582d426f7820,Xbox Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a4,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +64633436313965656664373634323364,Xbox Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b19,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f00,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e04000091020000ff073f80,Xbox One Controller,a:b0,b:b1,back:b4,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e00200000ffe3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e00200000ffe3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b3,leftstick:b15,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e0020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b17,y:b2,platform:Android, +050000005e040000e0020000ffff3f80,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b4,leftshoulder:b3,leftstick:b8,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b17,y:b2,platform:Android, +050000005e040000fd020000ffff3f00,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +33356661323266333733373865656366,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +34356136633366613530316338376136,Xbox One Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,platform:Android, +35623965373264386238353433656138,Xbox One Controller,a:b0,b:b1,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +36616131643361333337396261666433,Xbox One Controller,a:b0,b:b1,back:b15,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +58626f7820576972656c65737320436f,Xbox One Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000000b000000783f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e040000000b000000783f80,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000050b0000ffff3f00,Xbox One Elite 2 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a5,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000e002000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000ea02000000783f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000fd020000ff7f3f00,Xbox One S Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000120b000000783f00,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:Android, +050000005e040000120b000000783f80,Xbox Series Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000005e040000130b0000ffff3f00,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +65633038363832353634653836396239,Xbox Series Controller,a:b0,b:b1,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,platform:Android, +050000001727000044310000ffff3f00,XiaoMi Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a7,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a6,rightx:a2,righty:a5,start:b6,x:b2,y:b3,platform:Android, +05000000ac0500000100000000006d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac050000010000004f066d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000cf076d01,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b2,y:b3,platform:iOS, +05000000ac05000001000000df076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +05000000ac05000001000000ff076d01,*,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +05000000ac0500000200000000006d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +05000000ac050000020000004f066d02,*,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b2,y:b3,platform:iOS, +050000008a35000003010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000008a35000004010000ff070000,Backbone One,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,platform:iOS, +4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,platform:iOS, +050000007e050000062000000f060000,Nintendo Switch Joy-Con (L),+leftx:h0.2,+lefty:h0.4,-leftx:h0.8,-lefty:h0.1,a:b0,b:b2,leftshoulder:b4,rightshoulder:b5,x:b1,y:b3,platform:iOS, +050000007e050000062000004f060000,Nintendo Switch Joy-Con (L),+leftx:h0.1,+lefty:h0.2,-leftx:h0.4,-lefty:h0.8,dpdown:b2,dpleft:b0,dpright:b3,dpup:b1,leftshoulder:b4,misc1:b6,rightshoulder:b5,platform:iOS, +050000007e05000008200000df070000,Nintendo Switch Joy-Con (L/R),a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000007e0500000e200000df070000,Nintendo Switch Joy-Con (L/R),a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, +050000007e050000072000004f060000,Nintendo Switch Joy-Con (R),+rightx:h0.4,+righty:h0.8,-rightx:h0.1,-righty:h0.2,a:b1,b:b0,guide:b6,leftshoulder:b4,rightshoulder:b5,x:b3,y:b2,platform:iOS, +050000007e05000009200000df870000,Nintendo Switch Pro Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,platform:iOS, +050000007e05000009200000ff870000,Nintendo Switch Pro Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000cc090000df070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000004c050000cc090000df870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff070000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff870001,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS, +050000004c050000cc090000ff876d01,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000004c050000e60c0000df870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,touchpad:b10,x:b2,y:b3,platform:iOS, +050000004c050000e60c0000ff870000,PS5 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,touchpad:b11,x:b2,y:b3,platform:iOS, +05000000ac0500000300000000006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000ac0500000300000043006d03,Remote,a:b0,b:b2,leftx:a0,lefty:a1,platform:iOS, +05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +05000000de2800000611000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,platform:iOS, +050000005e040000050b0000df070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b10,paddle2:b12,paddle3:b11,paddle4:b13,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000050b0000ff070001,Xbox Elite Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,paddle1:b11,paddle2:b13,paddle3:b12,paddle4:b14,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000e0020000df070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000e0020000ff070000,Xbox One Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, +050000005e040000130b0000df870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b10,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b2,y:b3,platform:iOS, +050000005e040000130b0000ff870001,Xbox Series X Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,misc1:b11,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b10,x:b2,y:b3,platform:iOS, diff --git a/testing/resources/pixel.png b/testing/resources/pixel.png new file mode 100644 index 000000000..e8b825eae Binary files /dev/null and b/testing/resources/pixel.png differ diff --git a/testing/resources/pop.ogg b/testing/resources/pop.ogg new file mode 100644 index 000000000..fb0a82a7b Binary files /dev/null and b/testing/resources/pop.ogg differ diff --git a/testing/resources/sample.ogv b/testing/resources/sample.ogv new file mode 100644 index 000000000..f145489c2 Binary files /dev/null and b/testing/resources/sample.ogv differ diff --git a/testing/resources/test.txt b/testing/resources/test.txt new file mode 100644 index 000000000..620ffd0fd --- /dev/null +++ b/testing/resources/test.txt @@ -0,0 +1 @@ +helloworld \ No newline at end of file diff --git a/testing/resources/test.zip b/testing/resources/test.zip new file mode 100644 index 000000000..46cfaba97 Binary files /dev/null and b/testing/resources/test.zip differ diff --git a/testing/resources/tone.ogg b/testing/resources/tone.ogg new file mode 100644 index 000000000..1e7156e47 Binary files /dev/null and b/testing/resources/tone.ogg differ diff --git a/testing/tests/audio.lua b/testing/tests/audio.lua new file mode 100644 index 000000000..7554eed12 --- /dev/null +++ b/testing/tests/audio.lua @@ -0,0 +1,536 @@ +-- love.audio + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- RecordingDevice (love.audio.getRecordingDevices) +love.test.audio.RecordingDevice = function(test) + + -- skip recording device on runners, they cant emulate it + if GITHUB_RUNNER then + return test:skipTest('cant emulate recording devices in CI') + end + + -- check devices first + local devices = love.audio.getRecordingDevices() + if #devices == 0 then + return test:skipTest('cant test this works: no recording devices found') + end + + -- check object created and basics + local device = devices[1] + test:assertObject(device) + test:assertMatch({1, 2}, device:getChannelCount(), 'check channel count is 1 or 2') + test:assertNotEquals(nil, device:getName(), 'check has name') + + -- check initial data is empty as we haven't recorded anything yet + test:assertNotNil(device:getBitDepth()) + test:assertEquals(nil, device:getData(), 'check initial data empty') + test:assertEquals(0, device:getSampleCount(), 'check initial sample empty') + test:assertNotNil(device:getSampleRate()) + test:assertFalse(device:isRecording(), 'check not recording') + + -- start recording for a short time + local startrecording = device:start(32000, 4000, 16, 1) + test:waitFrames(10) + test:assertTrue(startrecording, 'check recording started') + test:assertTrue(device:isRecording(), 'check now recording') + test:assertEquals(4000, device:getSampleRate(), 'check sample rate set') + test:assertEquals(16, device:getBitDepth(), 'check bit depth set') + test:assertEquals(1, device:getChannelCount(), 'check channel count set') + local recording = device:stop() + test:waitFrames(10) + + -- after recording + test:assertFalse(device:isRecording(), 'check not recording') + test:assertEquals(nil, device:getData(), 'using stop should clear buffer') + test:assertObject(recording) + +end + + +-- Source (love.audio.newSource) +love.test.audio.Source = function(test) + + -- create stereo source + local stereo = love.audio.newSource('resources/click.ogg', 'static') + test:assertObject(stereo) + + -- check stereo props + test:assertEquals(2, stereo:getChannelCount(), 'check stereo src') + test:assertRange(stereo:getDuration("seconds"), 0, 0.1, 'check stereo seconds') + test:assertNotNil(stereo:getFreeBufferCount()) + test:assertEquals('static', stereo:getType(), 'check stereo type') + + -- check cloning a stereo + local clone = stereo:clone() + test:assertEquals(2, clone:getChannelCount(), 'check clone stereo src') + test:assertRange(clone:getDuration("seconds"), 0, 0.1, 'check clone stereo seconds') + test:assertNotNil(clone:getFreeBufferCount()) + test:assertEquals('static', clone:getType(), 'check cloned stereo type') + + -- mess with stereo playing + test:assertFalse(stereo:isPlaying(), 'check not playing') + stereo:setLooping(true) + stereo:play() + test:assertTrue(stereo:isPlaying(), 'check now playing') + test:assertTrue(stereo:isLooping(), 'check now playing') + stereo:pause() + stereo:seek(0.01, 'seconds') + test:assertEquals(0.01, stereo:tell('seconds'), 'check seek/tell') + stereo:stop() + test:assertFalse(stereo:isPlaying(), 'check stopped playing') + + -- check volume limits + stereo:setVolumeLimits(0.1, 0.5) + local min, max = stereo:getVolumeLimits() + test:assertRange(min, 0.1, 0.2, 'check min limit') + test:assertRange(max, 0.5, 0.6, 'check max limit') + + -- check setting volume + stereo:setVolume(1) + test:assertEquals(1, stereo:getVolume(), 'check set volume') + stereo:setVolume(0) + test:assertEquals(0, stereo:getVolume(), 'check set volume') + + -- change some get/set props that can apply to stereo + stereo:setPitch(2) + test:assertEquals(2, stereo:getPitch(), 'check pitch change') + + -- create mono source + local mono = love.audio.newSource('resources/clickmono.ogg', 'stream') + test:assertObject(mono) + test:assertEquals(1, mono:getChannelCount(), 'check mono src') + test:assertEquals(2927, mono:getDuration("samples"), 'check mono seconds') + test:assertEquals('stream', mono:getType(), 'check mono type') + + -- air absorption + test:assertEquals(0, mono:getAirAbsorption(), 'get air absorption') + mono:setAirAbsorption(1) + test:assertEquals(1, mono:getAirAbsorption(), 'set air absorption') + + -- cone + mono:setCone(0, 90*(math.pi/180), 1) + local ia, oa, ov = mono:getCone() + test:assertEquals(0, ia, 'check cone ia') + test:assertEquals(math.floor(9000*(math.pi/180)), math.floor(oa*100), 'check cone oa') + test:assertEquals(1, ov, 'check cone ov') + + -- direction + mono:setDirection(3, 1, -1) + local x, y, z = mono:getDirection() + test:assertEquals(3, x, 'check direction x') + test:assertEquals(1, y, 'check direction y') + test:assertEquals(-1, z, 'check direction z') + + -- relative + mono:setRelative(true) + test:assertTrue(mono:isRelative(), 'check set relative') + + -- position + mono:setPosition(1, 2, 3) + x, y, z = mono:getPosition() + test:assertEquals(x, 1, 'check pos x') + test:assertEquals(y, 2, 'check pos y') + test:assertEquals(z, 3, 'check pos z') + + -- velocity + mono:setVelocity(1, 3, 4) + x, y, z = mono:getVelocity() + test:assertEquals(x, 1, 'check velocity x') + test:assertEquals(y, 3, 'check velocity x') + test:assertEquals(z, 4, 'check velocity x') + + -- rolloff + mono:setRolloff(1) + test:assertEquals(1, mono:getRolloff(), 'check rolloff set') + + -- create queue source + local queue = love.audio.newQueueableSource(44100, 16, 1, 3) + local sdata = love.sound.newSoundData(1024, 44100, 16, 1) + test:assertObject(queue) + local run = queue:queue(sdata) + test:assertTrue(run, 'check queued sound') + queue:stop() + + -- check making a filer + local setfilter = stereo:setFilter({ + type = 'lowpass', + volume = 0.5, + highgain = 0.3 + }) + test:assertTrue(setfilter, 'check filter applied') + local filter = stereo:getFilter() + test:assertEquals('lowpass', filter.type, 'check filter type') + test:assertEquals(0.5, filter.volume, 'check filter volume') + test:assertRange(filter.highgain, 0.3, 0.4, 'check filter highgain') + test:assertEquals(nil, filter.lowgain, 'check filter lowgain') + + -- add an effect + local effsource = love.audio.newSource('resources/click.ogg', 'static') + love.audio.setEffect('testeffect', { + type = 'flanger', + volume = 0.75 + }) + local seteffect, err = effsource:setEffect('testeffect', { + type = 'highpass', + volume = 0.3, + lowgain = 0.1 + }) + + -- both these fail on 12 using stereo or mono, no err + test:assertTrue(seteffect, 'check effect was applied') + local filtersettings = effsource:getEffect('effectthatdoesntexist', {}) + test:assertNotNil(filtersettings) + + love.audio.stop(stereo) + love.audio.stop(mono) + love.audio.stop(effsource) + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.audio.getActiveEffects +love.test.audio.getActiveEffects = function(test) + -- check we get a value + test:assertNotNil(love.audio.getActiveEffects()) + -- check setting an effect active + love.audio.setEffect('testeffect', { + type = 'chorus', + volume = 0.75 + }) + test:assertEquals(1, #love.audio.getActiveEffects(), 'check 1 effect running') + test:assertEquals('testeffect', love.audio.getActiveEffects()[1], 'check effect details') +end + + +-- love.audio.getActiveSourceCount +love.test.audio.getActiveSourceCount = function(test) + -- check we get a value + test:assertNotNil(love.audio.getActiveSourceCount()) + -- check source isn't active by default + local testsource = love.audio.newSource('resources/click.ogg', 'static') + love.audio.stop(testsource) + test:assertEquals(0, love.audio.getActiveSourceCount(), 'check not active') + -- check playing a source marks it as active + love.audio.play(testsource) + test:assertEquals(1, love.audio.getActiveSourceCount(), 'check now active') + love.audio.pause() +end + + +-- love.audio.getDistanceModel +love.test.audio.getDistanceModel = function(test) + -- check we get a value + test:assertNotNil(love.audio.getDistanceModel()) + -- check default value from documentation + test:assertEquals('inverseclamped', love.audio.getDistanceModel(), 'check default value') + -- check get correct value after setting + love.audio.setDistanceModel('inverse') + test:assertEquals('inverse', love.audio.getDistanceModel(), 'check setting model') +end + + +-- love.audio.getDopplerScale +love.test.audio.getDopplerScale = function(test) + -- check default value + test:assertEquals(1, love.audio.getDopplerScale(), 'check default 1') + -- check correct value after setting to 0 + love.audio.setDopplerScale(0) + test:assertEquals(0, love.audio.getDopplerScale(), 'check setting to 0') + love.audio.setDopplerScale(1) +end + + +-- love.audio.getEffect +love.test.audio.getEffect = function(test) + -- check getting a non-existent effect + test:assertEquals(nil, love.audio.getEffect('madeupname'), 'check wrong name') + -- check getting a valid effect + love.audio.setEffect('testeffect', { + type = 'chorus', + volume = 0.75 + }) + test:assertNotNil(love.audio.getEffect('testeffect')) + -- check effect values match creation values + test:assertEquals('chorus', love.audio.getEffect('testeffect').type, 'check effect type') + test:assertEquals(0.75, love.audio.getEffect('testeffect').volume, 'check effect volume') +end + + +-- love.audio.getMaxSceneEffects +-- @NOTE feel like this is platform specific number so best we can do is a nil? +love.test.audio.getMaxSceneEffects = function(test) + test:assertNotNil(love.audio.getMaxSceneEffects()) +end + + +-- love.audio.getMaxSourceEffects +-- @NOTE feel like this is platform specific number so best we can do is a nil? +love.test.audio.getMaxSourceEffects = function(test) + test:assertNotNil(love.audio.getMaxSourceEffects()) +end + + +-- love.audio.getOrientation +-- @NOTE is there an expected default listener pos? +love.test.audio.getOrientation = function(test) + -- checking getting values matches what was set + love.audio.setOrientation(1, 2, 3, 4, 5, 6) + local fx, fy, fz, ux, uy, uz = love.audio.getOrientation() + test:assertEquals(1, fx, 'check fx orientation') + test:assertEquals(2, fy, 'check fy orientation') + test:assertEquals(3, fz, 'check fz orientation') + test:assertEquals(4, ux, 'check ux orientation') + test:assertEquals(5, uy, 'check uy orientation') + test:assertEquals(6, uz, 'check uz orientation') +end + + +-- love.audio.getPlaybackDevice +love.test.audio.getPlaybackDevice = function(test) + test:assertNotNil(love.audio.getPlaybackDevice) + test:assertNotNil(love.audio.getPlaybackDevice()) +end + + +-- love.audio.getPlaybackDevices +love.test.audio.getPlaybackDevices = function(test) + test:assertNotNil(love.audio.getPlaybackDevices) + test:assertGreaterEqual(0, #love.audio.getPlaybackDevices(), 'check table') +end + + +-- love.audio.getPosition +-- @NOTE is there an expected default listener pos? +love.test.audio.getPosition = function(test) + -- check getting values matches what was set + love.audio.setPosition(1, 2, 3) + local x, y, z = love.audio.getPosition() + test:assertEquals(1, x, 'check x position') + test:assertEquals(2, y, 'check y position') + test:assertEquals(3, z, 'check z position') +end + + +-- love.audio.getRecordingDevices +-- @NOTE hardware dependent so best can do is not nil check +love.test.audio.getRecordingDevices = function(test) + test:assertNotNil(love.audio.getRecordingDevices()) +end + + +-- love.audio.getVelocity +love.test.audio.getVelocity = function(test) + -- check getting values matches what was set + love.audio.setVelocity(1, 2, 3) + local x, y, z = love.audio.getVelocity() + test:assertEquals(1, x, 'check x velocity') + test:assertEquals(2, y, 'check y velocity') + test:assertEquals(3, z, 'check z velocity') +end + + +-- love.audio.getVolume +love.test.audio.getVolume = function(test) + -- check getting values matches what was set + love.audio.setVolume(0.5) + test:assertEquals(0.5, love.audio.getVolume(), 'check matches set') +end + + +-- love.audio.isEffectsSupported +love.test.audio.isEffectsSupported = function(test) + test:assertNotNil(love.audio.isEffectsSupported()) +end + + +-- love.audio.newQueueableSource +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.audio.newQueueableSource = function(test) + test:assertObject(love.audio.newQueueableSource(32, 8, 1, 8)) +end + + +-- love.audio.newSource +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.audio.newSource = function(test) + test:assertObject(love.audio.newSource('resources/click.ogg', 'static')) + test:assertObject(love.audio.newSource('resources/click.ogg', 'stream')) +end + + +-- love.audio.pause +love.test.audio.pause = function(test) + -- check nothing paused (as should be nothing playing) + local nopauses = love.audio.pause() + test:assertEquals(0, #nopauses, 'check nothing paused') + -- check 1 source paused after playing/pausing 1 + local source = love.audio.newSource('resources/click.ogg', 'static') + love.audio.play(source) + local onepause = love.audio.pause() + test:assertEquals(1, #onepause, 'check 1 paused') + love.audio.stop(source) +end + + +-- love.audio.play +love.test.audio.play = function(test) + -- check playing source is detected + local source = love.audio.newSource('resources/click.ogg', 'static') + love.audio.play(source) + test:assertTrue(source:isPlaying(), 'check something playing') + love.audio.stop() +end + + +-- love.audio.setDistanceModel +love.test.audio.setDistanceModel = function(test) + -- check setting each of the distance models is accepted and val returned + local distancemodel = { + 'none', 'inverse', 'inverseclamped', 'linear', 'linearclamped', + 'exponent', 'exponentclamped' + } + for d=1,#distancemodel do + love.audio.setDistanceModel(distancemodel[d]) + test:assertEquals(distancemodel[d], love.audio.getDistanceModel(), + 'check model set to ' .. distancemodel[d]) + end +end + + +-- love.audio.setDopplerScale +love.test.audio.setDopplerScale = function(test) + -- check setting value is returned properly + love.audio.setDopplerScale(0) + test:assertEquals(0, love.audio.getDopplerScale(), 'check set to 0') + love.audio.setDopplerScale(1) + test:assertEquals(1, love.audio.getDopplerScale(), 'check set to 1') +end + + +-- love.audio.setEffect +love.test.audio.setEffect = function(test) + -- check effect is set correctly + local effect = love.audio.setEffect('testeffect', { + type = 'chorus', + volume = 0.75 + }) + test:assertTrue(effect, 'check effect created') + -- check values set match + local settings = love.audio.getEffect('testeffect') + test:assertEquals('chorus', settings.type, 'check effect type') + test:assertEquals(0.75, settings.volume, 'check effect volume') +end + + +-- love.audio.setMixWithSystem +love.test.audio.setMixWithSystem = function(test) + test:assertNotNil(love.audio.setMixWithSystem(true)) +end + + +-- love.audio.setOrientation +love.test.audio.setOrientation = function(test) + -- check setting orientation vals are returned + love.audio.setOrientation(1, 2, 3, 4, 5, 6) + local fx, fy, fz, ux, uy, uz = love.audio.getOrientation() + test:assertEquals(1, fx, 'check fx orientation') + test:assertEquals(2, fy, 'check fy orientation') + test:assertEquals(3, fz, 'check fz orientation') + test:assertEquals(4, ux, 'check ux orientation') + test:assertEquals(5, uy, 'check uy orientation') + test:assertEquals(6, uz, 'check uz orientation') +end + + +-- love.audio.setPlaybackDevice +love.test.audio.setPlaybackDevice = function(test) + -- check method + test:assertNotNil(love.audio.setPlaybackDevice) + + -- check blank string name + test:assertTrue(love.audio.setPlaybackDevice(''), 'check blank device is fine') + + -- check invalid name + test:assertFalse(love.audio.setPlaybackDevice('loveFM'), 'check invalid device fails') + + -- check setting already set + test:assertTrue(love.audio.setPlaybackDevice(love.audio.getPlaybackDevice()), 'check existing device is fine') + + -- if other devices to play with lets set a different one + local devices = love.audio.getPlaybackDevices() + if #devices > 1 then + local another = '' + local current = love.audio.getPlaybackDevice() + for a=1,#devices do + if devices[a] ~= current then + another = devices[a] + break + end + end + if another ~= '' then + -- check setting new device + local success4, msg4 = love.audio.setPlaybackDevice(another) + test:assertTrue(success4, 'check setting different device') + -- check resetting to default + local success5, msg5 = love.audio.setPlaybackDevice() + test:assertTrue(success5, 'check resetting') + test:assertEquals(current, love.audio.getPlaybackDevice()) + end + end +end + + +-- love.audio.setPosition +love.test.audio.setPosition = function(test) + -- check setting position vals are returned + love.audio.setPosition(1, 2, 3) + local x, y, z = love.audio.getPosition() + test:assertEquals(1, x, 'check x position') + test:assertEquals(2, y, 'check y position') + test:assertEquals(3, z, 'check z position') +end + + +-- love.audio.setVelocity +love.test.audio.setVelocity = function(test) + -- check setting velocity vals are returned + love.audio.setVelocity(1, 2, 3) + local x, y, z = love.audio.getVelocity() + test:assertEquals(1, x, 'check x velocity') + test:assertEquals(2, y, 'check y velocity') + test:assertEquals(3, z, 'check z velocity') +end + + +-- love.audio.setVolume +love.test.audio.setVolume = function(test) + -- check setting volume works + love.audio.setVolume(0.5) + test:assertEquals(0.5, love.audio.getVolume(), 'check set to 0.5') +end + + +-- love.audio.stop +love.test.audio.stop = function(test) + -- check source is playing first + local source = love.audio.newSource('resources/click.ogg', 'static') + love.audio.play(source) + test:assertTrue(source:isPlaying(), 'check is playing') + -- check source is then stopped + love.audio.stop() + test:assertFalse(source:isPlaying(), 'check stopped playing') +end diff --git a/testing/tests/data.lua b/testing/tests/data.lua new file mode 100644 index 000000000..073ca63fa --- /dev/null +++ b/testing/tests/data.lua @@ -0,0 +1,276 @@ +-- love.data + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- ByteData (love.data.newByteData) +love.test.data.ByteData = function(test) + + -- create new obj + local data = love.data.newByteData('helloworld') + test:assertObject(data) + + -- check properties match expected + test:assertEquals('helloworld', data:getString(), 'check data string') + test:assertEquals(10, data:getSize(), 'check data size') + + -- check cloning the bytedata + local cloneddata = data:clone() + test:assertObject(cloneddata) + test:assertEquals('helloworld', cloneddata:getString(), 'check cloned data') + test:assertEquals(10, cloneddata:getSize(), 'check cloned size') + + -- check pointer access if allowed + if data:getFFIPointer() ~= nil and ffi ~= nil then + local pointer = data:getFFIPointer() + local ptr = ffi.cast('uint8_t*', pointer) + local byte5 = ptr[4] + test:assertEquals('o', byte5) + end + + -- check overwriting the byte data string + data:setString('love!', 5) + test:assertEquals('hellolove!', data:getString(), 'check change string') + +end + + +-- CompressedData (love.data.compress) +love.test.data.CompressedData = function(test) + + -- create new compressed data + local cdata = love.data.compress('data', 'zlib', 'helloworld', -1) + test:assertObject(cdata) + test:assertEquals('zlib', cdata:getFormat(), 'check format used') + + -- check properties match expected + test:assertEquals(18, cdata:getSize()) + test:assertEquals('helloworld', love.data.decompress('data', cdata):getString()) + + -- check cloning the data + local clonedcdata = cdata:clone() + test:assertObject(clonedcdata) + test:assertEquals('zlib', clonedcdata:getFormat()) + test:assertEquals(18, clonedcdata:getSize()) + test:assertEquals('helloworld', love.data.decompress('data', clonedcdata):getString()) + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.data.compress +love.test.data.compress = function(test) + -- here just testing each combo 'works' - in decompress's test method + -- we actually check the compress + decompress give the right value back + local compressions = { + { love.data.compress('string', 'lz4', 'helloworld', -1), 'string'}, + { love.data.compress('string', 'lz4', 'helloworld', 0), 'string'}, + { love.data.compress('string', 'lz4', 'helloworld', 9), 'string'}, + { love.data.compress('string', 'zlib', 'helloworld', -1), 'string'}, + { love.data.compress('string', 'zlib', 'helloworld', 0), 'string'}, + { love.data.compress('string', 'zlib', 'helloworld', 9), 'string'}, + { love.data.compress('string', 'gzip', 'helloworld', -1), 'string'}, + { love.data.compress('string', 'gzip', 'helloworld', 0), 'string'}, + { love.data.compress('string', 'gzip', 'helloworld', 9), 'string'}, + { love.data.compress('string', 'deflate', 'aaaaaa', 1), 'string'}, + { love.data.compress('string', 'deflate', 'heloworld', -1), 'string'}, + { love.data.compress('string', 'deflate', 'heloworld', 0), 'string'}, + { love.data.compress('string', 'deflate', 'heloworld', 9), 'string'}, + { love.data.compress('data', 'lz4', 'helloworld', -1), 'userdata'}, + { love.data.compress('data', 'lz4', 'helloworld', 0), 'userdata'}, + { love.data.compress('data', 'lz4', 'helloworld', 9), 'userdata'}, + { love.data.compress('data', 'zlib', 'helloworld', -1), 'userdata'}, + { love.data.compress('data', 'zlib', 'helloworld', 0), 'userdata'}, + { love.data.compress('data', 'zlib', 'helloworld', 9), 'userdata'}, + { love.data.compress('data', 'gzip', 'helloworld', -1), 'userdata'}, + { love.data.compress('data', 'gzip', 'helloworld', 0), 'userdata'}, + { love.data.compress('data', 'gzip', 'helloworld', 9), 'userdata'}, + { love.data.compress('data', 'deflate', 'heloworld', -1), 'userdata'}, + { love.data.compress('data', 'deflate', 'heloworld', 0), 'userdata'}, + { love.data.compress('data', 'deflate', 'heloworld', 9), 'userdata'}, + } + for c=1,#compressions do + test:assertNotNil(compressions[c][1]) + -- sense check return type and make sure bytedata returns are an object + test:assertEquals(compressions[c][2], type(compressions[c][1]), 'check is userdata') + if compressions[c][2] == 'userdata' then + test:assertNotEquals(nil, compressions[c][1]:type(), 'check has :type()') + end + end +end + + +-- love.data.decode +love.test.data.decode = function(test) + -- setup encoded strings + local str1 = love.data.encode('string', 'base64', 'helloworld', 0) + local str2 = love.data.encode('string', 'hex', 'helloworld') + local str3 = love.data.encode('data', 'base64', 'helloworld', 0) + local str4 = love.data.encode('data', 'hex', 'helloworld') + -- check value matches expected when decoded back + test:assertEquals('helloworld', love.data.decode('string', 'base64', str1), 'check string base64 decode') + test:assertEquals('helloworld', love.data.decode('string', 'hex', str2), 'check string hex decode') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decode('data', 'base64', str3):getString(), 'check data base64 decode') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decode('data', 'hex', str4):getString(), 'check data hex decode') +end + + +-- love.data.decompress +love.test.data.decompress = function(test) + -- setup compressed data for each combination + local str1 = love.data.compress('string', 'lz4', 'helloworld', -1) + local str2 = love.data.compress('string', 'lz4', 'helloworld', 0) + local str3 = love.data.compress('string', 'lz4', 'helloworld', 9) + local str4 = love.data.compress('string', 'zlib', 'helloworld', -1) + local str5 = love.data.compress('string', 'zlib', 'helloworld', 0) + local str6 = love.data.compress('string', 'zlib', 'helloworld', 9) + local str7 = love.data.compress('string', 'gzip', 'helloworld', -1) + local str8 = love.data.compress('string', 'gzip', 'helloworld', 0) + local str9 = love.data.compress('string', 'gzip', 'helloworld', 9) + local str10 = love.data.compress('data', 'lz4', 'helloworld', -1) + local str11 = love.data.compress('data', 'lz4', 'helloworld', 0) + local str12 = love.data.compress('data', 'lz4', 'helloworld', 9) + local str13 = love.data.compress('data', 'zlib', 'helloworld', -1) + local str14 = love.data.compress('data', 'zlib', 'helloworld', 0) + local str15 = love.data.compress('data', 'zlib', 'helloworld', 9) + local str16 = love.data.compress('data', 'gzip', 'helloworld', -1) + local str17 = love.data.compress('data', 'gzip', 'helloworld', 0) + local str18 = love.data.compress('data', 'gzip', 'helloworld', 9) + -- check decompressed value matches whats expected + test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str1), 'check string lz4 decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str2), 'check string lz4 decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'lz4', str3), 'check string lz4 decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str4), 'check string zlib decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str5), 'check string zlib decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'zlib', str6), 'check string zlib decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str7), 'check string glib decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str8), 'check string glib decompress') + test:assertEquals('helloworld', love.data.decompress('string', 'gzip', str9), 'check string glib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str10):getString(), 'check data lz4 decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str11):getString(), 'check data lz4 decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'lz4', str12):getString(), 'check data lz4 decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str13):getString(), 'check data zlib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str14):getString(), 'check data zlib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'zlib', str15):getString(), 'check data zlib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str16):getString(), 'check data glib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str17):getString(), 'check data glib decompress') + test:assertEquals(love.data.newByteData('helloworld'):getString(), love.data.decompress('data', 'gzip', str18):getString(), 'check data glib decompress') +end + + +-- love.data.encode +love.test.data.encode = function(test) + -- here just testing each combo 'works' - in decode's test method + -- we actually check the encode + decode give the right value back + local encodes = { + { love.data.encode('string', 'base64', 'helloworld', 0), 'string'}, + { love.data.encode('string', 'base64', 'helloworld', 2), 'string'}, + { love.data.encode('string', 'hex', 'helloworld'), 'string'}, + { love.data.encode('data', 'base64', 'helloworld', 0), 'userdata'}, + { love.data.encode('data', 'base64', 'helloworld', 2), 'userdata'}, + { love.data.encode('data', 'hex', 'helloworld'), 'userdata'} + } + for e=1,#encodes do + test:assertNotNil(encodes[e][1]) + -- sense check return type and make sure bytedata returns are an object + test:assertEquals(encodes[e][2], type(encodes[e][1]), 'check is usedata') + if encodes[e][2] == 'userdata' then + test:assertNotEquals(nil, encodes[e][1]:type(), 'check has :type()') + end + end + +end + + +-- love.data.getPackedSize +love.test.data.getPackedSize = function(test) + local pack1 = love.data.getPackedSize('>xI3b') + local pack2 = love.data.getPackedSize('>I2B') + local pack3 = love.data.getPackedSize('>I4I4I4I4x') + test:assertEquals(5, pack1, 'check pack size 1') + test:assertEquals(3, pack2, 'check pack size 2') + test:assertEquals(17, pack3, 'check pack size 3') +end + + +-- love.data.hash +love.test.data.hash = function(test) + -- setup all the different hashing types + local str1 = love.data.hash('string', 'md5', 'helloworld') + local str2 = love.data.hash('string', 'sha1', 'helloworld') + local str3 = love.data.hash('string', 'sha224', 'helloworld') + local str4 = love.data.hash('string', 'sha256', 'helloworld') + local str5 = love.data.hash('string', 'sha384', 'helloworld') + local str6 = love.data.hash('string', 'sha512', 'helloworld') + local data1 = love.data.hash('data', 'md5', 'helloworld') + local data2 = love.data.hash('data', 'sha1', 'helloworld') + local data3 = love.data.hash('data', 'sha224', 'helloworld') + local data4 = love.data.hash('data', 'sha256', 'helloworld') + local data5 = love.data.hash('data', 'sha384', 'helloworld') + local data6 = love.data.hash('data', 'sha512', 'helloworld') + -- check encoded hash value matches what's expected for that algo + -- test container string + test:assertEquals('fc5e038d38a57032085441e7fe7010b0', love.data.encode("string", "hex", str1), 'check string md5 encode') + test:assertEquals('6adfb183a4a2c94a2f92dab5ade762a47889a5a1', love.data.encode("string", "hex", str2), 'check string sha1 encode') + test:assertEquals('b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc', love.data.encode("string", "hex", str3), 'check string sha224 encode') + test:assertEquals('936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af', love.data.encode("string", "hex", str4), 'check string sha256 encode') + test:assertEquals('97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9', love.data.encode("string", "hex", str5), 'check string sha384 encode') + test:assertEquals('1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60', love.data.encode("string", "hex", str6), 'check string sha512 encode') + -- test container data + test:assertEquals('fc5e038d38a57032085441e7fe7010b0', love.data.encode("string", "hex", data1), 'check data md5 encode') + test:assertEquals('6adfb183a4a2c94a2f92dab5ade762a47889a5a1', love.data.encode("string", "hex", data2), 'check data sha1 encode') + test:assertEquals('b033d770602994efa135c5248af300d81567ad5b59cec4bccbf15bcc', love.data.encode("string", "hex", data3), 'check data sha224 encode') + test:assertEquals('936a185caaa266bb9cbe981e9e05cb78cd732b0b3280eb944412bb6f8f8f07af', love.data.encode("string", "hex", data4), 'check data sha256 encode') + test:assertEquals('97982a5b1414b9078103a1c008c4e3526c27b41cdbcf80790560a40f2a9bf2ed4427ab1428789915ed4b3dc07c454bd9', love.data.encode("string", "hex", data5), 'check data sha384 encode') + test:assertEquals('1594244d52f2d8c12b142bb61f47bc2eaf503d6d9ca8480cae9fcf112f66e4967dc5e8fa98285e36db8af1b8ffa8b84cb15e0fbcf836c3deb803c13f37659a60', love.data.encode("string", "hex", data6), 'check data sha512 encode') +end + + +-- love.data.newByteData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.data.newByteData = function(test) + test:assertObject(love.data.newByteData('helloworld')) +end + + +-- love.data.newDataView +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.data.newDataView = function(test) + test:assertObject(love.data.newDataView(love.data.newByteData('helloworld'), 0, 10)) +end + + +-- love.data.pack +love.test.data.pack = function(test) + local packed1 = love.data.pack('string', '>I4I4I4I4', 9999, 1000, 1010, 2030) + local packed2 = love.data.pack('data', '>I4I4I4I4', 9999, 1000, 1010, 2030) + local a, b, c, d = love.data.unpack('>I4I4I4I4', packed1) + local e, f, g, h = love.data.unpack('>I4I4I4I4', packed2) + test:assertEquals(9999+9999, a+e, 'check packed 1') + test:assertEquals(1000+1000, b+f, 'check packed 2') + test:assertEquals(1010+1010, c+g, 'check packed 3') + test:assertEquals(2030+2030, d+h, 'check packed 4') +end + + +-- love.data.unpack +love.test.data.unpack = function(test) + local packed1 = love.data.pack('string', '>s5s4I3', 'hello', 'love', 100) + local packed2 = love.data.pack('data', '>s5I2', 'world', 20) + local a, b, c = love.data.unpack('>s5s4I3', packed1) + local d, e = love.data.unpack('>s5I2', packed2) + test:assertEquals(a .. ' ' .. d, 'hello world', 'check unpack 1') + test:assertEquals(b, 'love', 'check unpack 2') + test:assertEquals(c - e, 80, 'check unpack 3') +end diff --git a/testing/tests/event.lua b/testing/tests/event.lua new file mode 100644 index 000000000..50d347a87 --- /dev/null +++ b/testing/tests/event.lua @@ -0,0 +1,80 @@ +-- love.event + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.event.clear +love.test.event.clear = function(test) + -- push some events first + love.event.push('test', 1, 2, 3) + love.event.push('test', 1, 2, 3) + love.event.push('test', 1, 2, 3) + -- check after calling clear there are no events left + love.event.clear() + local count = 0 + for n, a, b, c, d, e, f in love.event.poll() do + count = count + 1 + end + test:assertEquals(0, count, 'check no events') +end + + +-- love.event.poll +love.test.event.poll = function(test) + -- push some events first + love.event.push('test', 1, 2, 3) + love.event.push('test', 1, 2, 3) + love.event.push('test', 1, 2, 3) + -- check poll recieves all events + local count = 0 + for n, a, b, c, d, e, f in love.event.poll() do + count = count + 1 + end + test:assertEquals(3, count, 'check 3 events') +end + + +-- love.event.pump +-- @NOTE dont think can really test as internally used +love.test.event.pump = function(test) + test:skipTest('used internally') +end + + +-- love.event.push +love.test.event.push = function(test) + -- check pushing some different types + love.event.push('add', 1, 2, 3) + love.event.push('ignore', 1, 2, 3) + love.event.push('add', 1, 2, 3) + love.event.push('ignore', 1, 2, 3) + local count = 0 + for n, a, b, c, d, e, f in love.event.poll() do + if n == 'add' then + count = count + a + b + c + end + end + test:assertEquals(12, count, 'check total events') +end + + +-- love.event.quit +love.test.event.quit = function(test) + -- setting this overrides the quit hook to prevent actually quitting + love.test.module.fakequit = true + love.event.quit(0) + -- if it failed we'd have quit here + test:assertTrue(true, 'check quit hook called') +end + + +-- love.event.wait +-- @NOTE not sure best way to test this one +love.test.event.wait = function(test) + test:skipTest('used internally') +end diff --git a/testing/tests/filesystem.lua b/testing/tests/filesystem.lua new file mode 100644 index 000000000..1b8948a27 --- /dev/null +++ b/testing/tests/filesystem.lua @@ -0,0 +1,570 @@ +-- love.filesystem + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- File (love.filesystem.newFile) +love.test.filesystem.File = function(test) + + -- setup a file to play with + local file1 = love.filesystem.openFile('data.txt', 'w') + file1:write('helloworld') + test:assertObject(file1) + file1:close() + + -- test read mode + file1:open('r') + test:assertEquals('r', file1:getMode(), 'check read mode') + local contents, size = file1:read() + test:assertEquals('helloworld', contents) + test:assertEquals(10, size, 'check file read') + test:assertEquals(10, file1:getSize()) + local ok1, err1 = file1:write('hello') + test:assertNotEquals(nil, err1, 'check cant write in read mode') + local iterator = file1:lines() + test:assertNotEquals(nil, iterator, 'check can read lines') + test:assertEquals('data.txt', file1:getFilename(), 'check filename matches') + file1:close() + + -- test write mode + file1:open('w') + test:assertEquals('w', file1:getMode(), 'check write mode') + contents, size = file1:read() + test:assertEquals(nil, contents, 'check cant read file in write mode') + test:assertEquals('string', type(size), 'check err message shown') + local ok2, err2 = file1:write('helloworld') + test:assertTrue(ok2, 'check file write') + test:assertEquals(nil, err2, 'check no err writing') + + -- test open/closing + file1:open('r') + test:assertTrue(file1:isOpen(), 'check file is open') + file1:close() + test:assertFalse(file1:isOpen(), 'check file gets closed') + file1:close() + + -- test buffering and flushing + file1:open('w') + local ok3, err3 = file1:setBuffer('full', 10000) + test:assertTrue(ok3) + test:assertEquals('full', file1:getBuffer()) + file1:write('replacedcontent') + file1:flush() + file1:close() + file1:open('r') + contents, size = file1:read() + test:assertEquals('replacedcontent', contents, 'check buffered content was written') + file1:close() + + -- loop through file data with seek/tell until EOF + file1:open('r') + local counter = 0 + for i=1,100 do + file1:seek(i) + test:assertEquals(i, file1:tell()) + if file1:isEOF() == true then + counter = i + break + end + end + test:assertEquals(counter, 15) + file1:close() + +end + + +-- FileData (love.filesystem.newFileData) +love.test.filesystem.FileData = function(test) + + -- create new obj + local fdata = love.filesystem.newFileData('helloworld', 'test.txt') + test:assertObject(fdata) + test:assertEquals('test.txt', fdata:getFilename()) + test:assertEquals('txt', fdata:getExtension()) + + -- check properties match expected + test:assertEquals('helloworld', fdata:getString(), 'check data string') + test:assertEquals(10, fdata:getSize(), 'check data size') + + -- check cloning the bytedata + local clonedfdata = fdata:clone() + test:assertObject(clonedfdata) + test:assertEquals('helloworld', clonedfdata:getString(), 'check cloned data') + test:assertEquals(10, clonedfdata:getSize(), 'check cloned size') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.filesystem.append +love.test.filesystem.append = function(test) + -- create a new file to test with + love.filesystem.write('filesystem.append.txt', 'foo') + -- try appending text and check new file contents/size matches + local success, message = love.filesystem.append('filesystem.append.txt', 'bar') + test:assertNotEquals(false, success, 'check success') + test:assertEquals(nil, message, 'check no error msg') + local contents, size = love.filesystem.read('filesystem.append.txt') + test:assertEquals(contents, 'foobar', 'check file contents') + test:assertEquals(size, 6, 'check file size') + -- check appending a specific no. of bytes + love.filesystem.append('filesystem.append.txt', 'foobarfoobarfoo', 6) + contents, size = love.filesystem.read('filesystem.append.txt') + test:assertEquals(contents, 'foobarfoobar', 'check appended contents') + test:assertEquals(size, 12, 'check appended size') + -- cleanup + love.filesystem.remove('filesystem.append.txt') +end + + +-- love.filesystem.areSymlinksEnabled +-- @NOTE best can do here is just check not nil +love.test.filesystem.areSymlinksEnabled = function(test) + test:assertNotNil(love.filesystem.areSymlinksEnabled()) +end + + +-- love.filesystem.createDirectory +love.test.filesystem.createDirectory = function(test) + -- try creating a dir + subdir and check both exist + local success = love.filesystem.createDirectory('foo/bar') + test:assertNotEquals(false, success, 'check success') + test:assertNotEquals(nil, love.filesystem.getInfo('foo', 'directory'), 'check directory created') + test:assertNotEquals(nil, love.filesystem.getInfo('foo/bar', 'directory'), 'check subdirectory created') + -- cleanup + love.filesystem.remove('foo/bar') + love.filesystem.remove('foo') +end + + +-- love.filesystem.getAppdataDirectory +-- @NOTE i think this is too platform dependent to be tested nicely +love.test.filesystem.getAppdataDirectory = function(test) + test:assertNotNil(love.filesystem.getAppdataDirectory()) +end + + +-- love.filesystem.getCRequirePath +love.test.filesystem.getCRequirePath = function(test) + -- check default value from documentation + test:assertEquals('??', love.filesystem.getCRequirePath(), 'check default value') +end + + +-- love.filesystem.getDirectoryItems +love.test.filesystem.getDirectoryItems = function(test) + -- create a dir + subdir with 2 files + love.filesystem.createDirectory('foo/bar') + love.filesystem.write('foo/file1.txt', 'file1') + love.filesystem.write('foo/bar/file2.txt', 'file2') + -- check both the file + subdir exist in the item list + local files = love.filesystem.getDirectoryItems('foo') + local hasfile = false + local hasdir = false + for _,v in ipairs(files) do + local info = love.filesystem.getInfo('foo/'..v) + if v == 'bar' and info.type == 'directory' then hasdir = true end + if v == 'file1.txt' and info.type == 'file' then hasfile = true end + end + test:assertTrue(hasfile, 'check file exists') + test:assertTrue(hasdir, 'check directory exists') + -- cleanup + love.filesystem.remove('foo/file1.txt') + love.filesystem.remove('foo/bar/file2.txt') + love.filesystem.remove('foo/bar') + love.filesystem.remove('foo') +end + + +-- love.filesystem.getFullCommonPath +love.test.filesystem.getFullCommonPath = function(test) + -- check standard paths + local appsavedir = love.filesystem.getFullCommonPath('appsavedir') + local appdocuments = love.filesystem.getFullCommonPath('appdocuments') + local userhome = love.filesystem.getFullCommonPath('userhome') + local userappdata = love.filesystem.getFullCommonPath('userappdata') + local userdesktop = love.filesystem.getFullCommonPath('userdesktop') + local userdocuments = love.filesystem.getFullCommonPath('userdocuments') + test:assertNotNil(appsavedir) + test:assertNotNil(appdocuments) + test:assertNotNil(userhome) + test:assertNotNil(userappdata) + test:assertNotNil(userdesktop) + test:assertNotNil(userdocuments) + -- check invalid path + local ok = pcall(love.filesystem.getFullCommonPath, 'fakepath') + test:assertFalse(ok, 'check invalid common path') +end + + +-- love.filesystem.getIdentity +love.test.filesystem.getIdentity = function(test) + -- check setting identity matches + local original = love.filesystem.getIdentity() + love.filesystem.setIdentity('lover') + test:assertEquals('lover', love.filesystem.getIdentity(), 'check identity matches') + -- put back to original value + love.filesystem.setIdentity(original) +end + + +-- love.filesystem.getRealDirectory +love.test.filesystem.getRealDirectory = function(test) + -- make a test dir + file first + love.filesystem.createDirectory('foo') + love.filesystem.write('foo/test.txt', 'test') + -- check save dir matches the real dir we just wrote to + test:assertEquals(love.filesystem.getSaveDirectory(), + love.filesystem.getRealDirectory('foo/test.txt'), 'check directory matches') + -- cleanup + love.filesystem.remove('foo/test.txt') + love.filesystem.remove('foo') +end + + +-- love.filesystem.getRequirePath +love.test.filesystem.getRequirePath = function(test) + test:assertEquals('?.lua;?/init.lua', + love.filesystem.getRequirePath(), 'check default value') +end + + +-- love.filesystem.getSource +-- @NOTE i dont think we can test this cos love calls it first +love.test.filesystem.getSource = function(test) + test:skipTest('used internally') +end + + +-- love.filesystem.getSourceBaseDirectory +-- @NOTE i think this is too platform dependent to be tested nicely +love.test.filesystem.getSourceBaseDirectory = function(test) + test:assertNotNil(love.filesystem.getSourceBaseDirectory()) +end + + +-- love.filesystem.getUserDirectory +-- @NOTE i think this is too platform dependent to be tested nicely +love.test.filesystem.getUserDirectory = function(test) + test:assertNotNil(love.filesystem.getUserDirectory()) +end + + +-- love.filesystem.getWorkingDirectory +-- @NOTE i think this is too platform dependent to be tested nicely +love.test.filesystem.getWorkingDirectory = function(test) + test:assertNotNil(love.filesystem.getWorkingDirectory()) +end + + +-- love.filesystem.getSaveDirectory +-- @NOTE i think this is too platform dependent to be tested nicely +love.test.filesystem.getSaveDirectory = function(test) + test:assertNotNil(love.filesystem.getSaveDirectory()) +end + + +-- love.filesystem.getInfo +love.test.filesystem.getInfo = function(test) + -- create a dir and subdir with a file + love.filesystem.createDirectory('foo/bar') + love.filesystem.write('foo/bar/file2.txt', 'file2') + -- check getinfo returns the correct values + test:assertEquals(nil, love.filesystem.getInfo('foo/bar/file2.txt', 'directory'), 'check not directory') + test:assertNotEquals(nil, love.filesystem.getInfo('foo/bar/file2.txt'), 'check info not nil') + test:assertEquals(love.filesystem.getInfo('foo/bar/file2.txt').size, 5, 'check info size match') + test:assertFalse(love.filesystem.getInfo('foo/bar/file2.txt').readonly, 'check readonly') + -- @TODO test modified timestamp from info.modtime? + -- cleanup + love.filesystem.remove('foo/bar/file2.txt') + love.filesystem.remove('foo/bar') + love.filesystem.remove('foo') +end + + +-- love.filesystem.isFused +love.test.filesystem.isFused = function(test) + -- kinda assuming you'd run the testsuite in a non-fused game + test:assertEquals(love.filesystem.isFused(), false, 'check not fused') +end + + +-- love.filesystem.lines +love.test.filesystem.lines = function(test) + -- check lines returns the 3 lines expected + love.filesystem.write('file.txt', 'line1\nline2\nline3') + local linenum = 1 + for line in love.filesystem.lines('file.txt') do + test:assertEquals('line' .. tostring(linenum), line, 'check line matches') + -- also check it removes newlines like the docs says it does + test:assertEquals(nil, string.find(line, '\n'), 'check newline removed') + linenum = linenum + 1 + end + -- cleanup + love.filesystem.remove('file.txt') +end + + +-- love.filesystem.load +love.test.filesystem.load = function(test) + -- setup some fake lua files + love.filesystem.write('test1.lua', 'function test()\nreturn 1\nend\nreturn test()') + love.filesystem.write('test2.lua', 'function test()\nreturn 1') + + if test:isAtLeastLuaVersion(5.2) or test:isLuaJITEnabled() then + -- check file that doesn't exist + local chunk1, errormsg1 = love.filesystem.load('faker.lua', 'b') + test:assertEquals(nil, chunk1, 'check file doesnt exist') + -- check valid lua file (text load) + local chunk2, errormsg2 = love.filesystem.load('test1.lua', 't') + test:assertEquals(nil, errormsg2, 'check no error message') + test:assertEquals(1, chunk2(), 'check lua file runs') + else + local _, errormsg3 = love.filesystem.load('test1.lua', 'b') + test:assertNotEquals(nil, errormsg3, 'check for an error message') + + local _, errormsg4 = love.filesystem.load('test1.lua', 't') + test:assertNotEquals(nil, errormsg4, 'check for an error message') + end + + -- check valid lua file (any load) + local chunk5, errormsg5 = love.filesystem.load('test1.lua', 'bt') + test:assertEquals(nil, errormsg5, 'check no error message') + test:assertEquals(1, chunk5(), 'check lua file runs') + + -- check invalid lua file + local ok, chunk, err = pcall(love.filesystem.load, 'test2.lua') + test:assertFalse(ok, 'check invalid lua file') + -- cleanup + love.filesystem.remove('test1.lua') + love.filesystem.remove('test2.lua') +end + + +-- love.filesystem.mount +love.test.filesystem.mount = function(test) + -- write an example zip to savedir to use + local contents, size = love.filesystem.read('resources/test.zip') -- contains test.txt + love.filesystem.write('test.zip', contents, size) + -- check mounting file and check contents are mounted + local success = love.filesystem.mount('test.zip', 'test') + test:assertTrue(success, 'check success') + test:assertNotEquals(nil, love.filesystem.getInfo('test'), 'check mount not nil') + test:assertEquals('directory', love.filesystem.getInfo('test').type, 'check directory made') + test:assertNotEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check file not nil') + test:assertEquals('file', love.filesystem.getInfo('test/test.txt').type, 'check file type') + -- cleanup + love.filesystem.remove('test/test.txt') + love.filesystem.remove('test') + love.filesystem.remove('test.zip') +end + + +-- love.filesystem.mountFullPath +love.test.filesystem.mountFullPath = function(test) + -- mount something in the working directory + local mount = love.filesystem.mountFullPath(love.filesystem.getSource() .. '/tests', 'tests', 'read') + test:assertTrue(mount, 'check can mount') + -- check reading file through mounted path label + local contents, _ = love.filesystem.read('tests/audio.lua') + test:assertNotEquals(nil, contents) + local unmount = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/tests') + test:assertTrue(unmount, 'reset mount') +end + + +-- love.filesystem.unmountFullPath +love.test.filesystem.unmountFullPath = function(test) + -- try unmounting something we never mounted + local unmount1 = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/faker') + test:assertFalse(unmount1, 'check not mounted to start with') + -- mount something to unmount after + love.filesystem.mountFullPath(love.filesystem.getSource() .. '/tests', 'tests', 'read') + local unmount2 = love.filesystem.unmountFullPath(love.filesystem.getSource() .. '/tests') + test:assertTrue(unmount2, 'check unmounted') +end + + +-- love.filesystem.mountCommonPath +love.test.filesystem.mountCommonPath = function(test) + -- check if we can mount all the expected paths + local mount1 = love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'readwrite') + local mount2 = love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'readwrite') + local mount3 = love.filesystem.mountCommonPath('userhome', 'userhome', 'readwrite') + local mount4 = love.filesystem.mountCommonPath('userappdata', 'userappdata', 'readwrite') + -- userdesktop isnt valid on linux + if not test:isOS('Linux') then + local mount5 = love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'readwrite') + test:assertTrue(mount5, 'check mount userdesktop') + end + local mount6 = love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'readwrite') + local ok = pcall(love.filesystem.mountCommonPath, 'fakepath', 'fake', 'readwrite') + test:assertTrue(mount1, 'check mount appsavedir') + test:assertTrue(mount2, 'check mount appdocuments') + test:assertTrue(mount3, 'check mount userhome') + test:assertTrue(mount4, 'check mount userappdata') + test:assertTrue(mount6, 'check mount userdocuments') + test:assertFalse(ok, 'check mount invalid common path fails') +end + + +-- love.filesystem.unmountCommonPath +--love.test.filesystem.unmountCommonPath = function(test) +-- -- check unmounting invalid +-- local ok = pcall(love.filesystem.unmountCommonPath, 'fakepath') +-- test:assertFalse(ok, 'check unmount invalid common path') +-- -- check mounting valid paths +-- love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'read') +-- love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'read') +-- love.filesystem.mountCommonPath('userhome', 'userhome', 'read') +-- love.filesystem.mountCommonPath('userappdata', 'userappdata', 'read') +-- love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'read') +-- love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'read') +-- local unmount1 = love.filesystem.unmountCommonPath('appsavedir') +-- local unmount2 = love.filesystem.unmountCommonPath('appdocuments') +-- local unmount3 = love.filesystem.unmountCommonPath('userhome') +-- local unmount4 = love.filesystem.unmountCommonPath('userappdata') +-- local unmount5 = love.filesystem.unmountCommonPath('userdesktop') +-- local unmount6 = love.filesystem.unmountCommonPath('userdocuments') +-- test:assertTrue(unmount1, 'check unmount appsavedir') +-- test:assertTrue(unmount2, 'check unmount appdocuments') +-- test:assertTrue(unmount3, 'check unmount userhome') +-- test:assertTrue(unmount4, 'check unmount userappdata') +-- test:assertTrue(unmount5, 'check unmount userdesktop') +-- test:assertTrue(unmount6, 'check unmount userdocuments') +-- -- remount or future tests fail +-- love.filesystem.mountCommonPath('appsavedir', 'appsavedir', 'readwrite') +-- love.filesystem.mountCommonPath('appdocuments', 'appdocuments', 'readwrite') +-- love.filesystem.mountCommonPath('userhome', 'userhome', 'readwrite') +-- love.filesystem.mountCommonPath('userappdata', 'userappdata', 'readwrite') +-- love.filesystem.mountCommonPath('userdesktop', 'userdesktop', 'readwrite') +-- love.filesystem.mountCommonPath('userdocuments', 'userdocuments', 'readwrite') +--end + + +-- love.filesystem.openFile +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.filesystem.openFile = function(test) + test:assertNotNil(love.filesystem.openFile('file2.txt', 'w')) + test:assertNotNil(love.filesystem.openFile('file2.txt', 'r')) + test:assertNotNil(love.filesystem.openFile('file2.txt', 'a')) + test:assertNotNil(love.filesystem.openFile('file2.txt', 'c')) + love.filesystem.remove('file2.txt') +end + + +-- love.filesystem.newFileData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.filesystem.newFileData = function(test) + test:assertNotNil(love.filesystem.newFileData('helloworld', 'file1')) +end + + +-- love.filesystem.read +love.test.filesystem.read = function(test) + -- check reading a full file + local content, size = love.filesystem.read('resources/test.txt') + test:assertNotEquals(nil, content, 'check not nil') + test:assertEquals('helloworld', content, 'check content match') + test:assertEquals(10, size, 'check size match') + -- check reading partial file + content, size = love.filesystem.read('resources/test.txt', 5) + test:assertNotEquals(nil, content, 'check not nil') + test:assertEquals('hello', content, 'check content match') + test:assertEquals(5, size, 'check size match') +end + + +-- love.filesystem.remove +love.test.filesystem.remove = function(test) + -- create a dir + subdir with a file + love.filesystem.createDirectory('foo/bar') + love.filesystem.write('foo/bar/file2.txt', 'helloworld') + -- check removing files + dirs (should fail to remove dir if file inside) + test:assertFalse(love.filesystem.remove('foo'), 'check fail when file inside') + test:assertFalse(love.filesystem.remove('foo/bar'), 'check fail when file inside') + test:assertTrue(love.filesystem.remove('foo/bar/file2.txt'), 'check file removed') + test:assertTrue(love.filesystem.remove('foo/bar'), 'check subdirectory removed') + test:assertTrue(love.filesystem.remove('foo'), 'check directory removed') + -- cleanup not needed here hopefully... +end + + +-- love.filesystem.setCRequirePath +love.test.filesystem.setCRequirePath = function(test) + -- check setting path val is returned + love.filesystem.setCRequirePath('/??') + test:assertEquals('/??', love.filesystem.getCRequirePath(), 'check crequirepath value') + love.filesystem.setCRequirePath('??') +end + + +-- love.filesystem.setIdentity +love.test.filesystem.setIdentity = function(test) + -- check setting identity val is returned + local original = love.filesystem.getIdentity() + love.filesystem.setIdentity('lover') + test:assertEquals('lover', love.filesystem.getIdentity(), 'check indentity value') + -- return value to original + love.filesystem.setIdentity(original) +end + + +-- love.filesystem.setRequirePath +love.test.filesystem.setRequirePath = function(test) + -- check setting path val is returned + love.filesystem.setRequirePath('?.lua;?/start.lua') + test:assertEquals('?.lua;?/start.lua', love.filesystem.getRequirePath(), 'check require path') + -- reset to default + love.filesystem.setRequirePath('?.lua;?/init.lua') +end + + +-- love.filesystem.setSource +love.test.filesystem.setSource = function(test) + test:skipTest('used internally') +end + + +-- love.filesystem.unmount +love.test.filesystem.unmount = function(test) + -- create a zip file mounted to use + local contents, size = love.filesystem.read('resources/test.zip') -- contains test.txt + love.filesystem.write('test.zip', contents, size) + love.filesystem.mount('test.zip', 'test') + -- check mounted, unmount, then check its unmounted + test:assertNotEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check mount exists') + love.filesystem.unmount('test.zip') + test:assertEquals(nil, love.filesystem.getInfo('test/test.txt'), 'check unmounted') + -- cleanup + love.filesystem.remove('test/test.txt') + love.filesystem.remove('test') + love.filesystem.remove('test.zip') +end + + +-- love.filesystem.write +love.test.filesystem.write = function(test) + -- check writing a bunch of files matches whats read back + love.filesystem.write('test1.txt', 'helloworld') + love.filesystem.write('test2.txt', 'helloworld', 10) + love.filesystem.write('test3.txt', 'helloworld', 5) + test:assertEquals('helloworld', love.filesystem.read('test1.txt'), 'check read file') + test:assertEquals('helloworld', love.filesystem.read('test2.txt'), 'check read all') + test:assertEquals('hello', love.filesystem.read('test3.txt'), 'check read partial') + -- cleanup + love.filesystem.remove('test1.txt') + love.filesystem.remove('test2.txt') + love.filesystem.remove('test3.txt') +end diff --git a/testing/tests/font.lua b/testing/tests/font.lua new file mode 100644 index 000000000..acd7eed12 --- /dev/null +++ b/testing/tests/font.lua @@ -0,0 +1,131 @@ +-- love.font + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- GlyphData (love.font.newGlyphData) +love.test.font.GlyphData = function(test) + + -- create obj + local rasterizer = love.font.newRasterizer('resources/font.ttf') + local gdata = love.font.newGlyphData(rasterizer, 97) -- 'a' + test:assertObject(gdata) + + -- check properties match expected + test:assertNotNil(gdata:getString()) + test:assertEquals(128, gdata:getSize(), 'check data size') + test:assertEquals(9, gdata:getAdvance(), 'check advance') + test:assertEquals('la8', gdata:getFormat(), 'check format') + + -- @TODO + --[[ + currently these will return 0 and '' respectively as not implemented + https://github.com/love2d/love/blob/12.0-development/src/modules/font/freetype/TrueTypeRasterizer.cpp#L140-L141 + "basically I haven't decided what to do here yet, because of the more + advanced text shaping that happens in love 12 having a unicode codepoint + associated with a glyph probably doesn't make sense in the first place" + ]]-- + --test:assertEquals(97, gdata:getGlyph(), 'check glyph number') - returns 0 + --test:assertEquals('a', gdata:getGlyphString(), 'check glyph string') - returns '' + + -- check height + width + test:assertEquals(8, gdata:getHeight(), 'check height') + test:assertEquals(8, gdata:getWidth(), 'check width') + + -- check boundary / dimensions + local x, y, w, h = gdata:getBoundingBox() + local dw, dh = gdata:getDimensions() + test:assertEquals(0, x, 'check bbox x') + test:assertEquals(-3, y, 'check bbox y') + test:assertEquals(8, w, 'check bbox w') + test:assertEquals(14, h, 'check bbox h') + test:assertEquals(8, dw, 'check dim width') + test:assertEquals(8, dh, 'check dim height') + + -- check bearing + local bw, bh = gdata:getBearing() + test:assertEquals(0, bw, 'check bearing w') + test:assertEquals(11, bh, 'check bearing h') + +end + + +-- Rasterizer (love.font.newRasterizer) +love.test.font.Rasterizer = function(test) + + -- create obj + local rasterizer = love.font.newRasterizer('resources/font.ttf') + test:assertObject(rasterizer) + + -- check advance + test:assertEquals(9, rasterizer:getAdvance(), 'check advance') + + -- check ascent/descent + test:assertEquals(9, rasterizer:getAscent(), 'check ascent') + test:assertEquals(-3, rasterizer:getDescent(), 'check descent') + + -- check glyphcount + test:assertEquals(77, rasterizer:getGlyphCount(), 'check glyph count') + + -- check specific glyphs + test:assertObject(rasterizer:getGlyphData('L')) + test:assertTrue(rasterizer:hasGlyphs('L', 'O', 'V', 'E'), 'check LOVE') + + -- check height + lineheight + test:assertEquals(12, rasterizer:getHeight(), 'check height') + test:assertEquals(15, rasterizer:getLineHeight(), 'check line height') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.font.newBMFontRasterizer +love.test.font.newBMFontRasterizer = function(test) + local rasterizer = love.font.newBMFontRasterizer('resources/love.png'); + test:assertObject(rasterizer) +end + + +-- love.font.newGlyphData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.font.newGlyphData = function(test) + local img = love.image.newImageData('resources/love.png') + local rasterizer = love.font.newImageRasterizer(img, 'ABC', 0, 1); + local glyphdata = love.font.newGlyphData(rasterizer, 65) + test:assertObject(glyphdata) +end + + +-- love.font.newImageRasterizer +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.font.newImageRasterizer = function(test) + local img = love.image.newImageData('resources/love.png') + local rasterizer = love.font.newImageRasterizer(img, 'ABC', 0, 1); + test:assertObject(rasterizer) +end + + +-- love.font.newRasterizer +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.font.newRasterizer = function(test) + test:assertObject(love.font.newRasterizer('resources/font.ttf')) +end + + +-- love.font.newTrueTypeRasterizer +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.font.newTrueTypeRasterizer = function(test) + test:assertObject(love.font.newTrueTypeRasterizer(12, "normal", 1)) + test:assertObject(love.font.newTrueTypeRasterizer('resources/font.ttf', 8, "normal", 1)) +end diff --git a/testing/tests/graphics.lua b/testing/tests/graphics.lua new file mode 100644 index 000000000..34d74410c --- /dev/null +++ b/testing/tests/graphics.lua @@ -0,0 +1,2846 @@ +-- love.graphics + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- GraphicsBuffer (love.graphics.newBuffer) +love.test.graphics.Buffer = function(test) + + -- setup vertex data and create some buffers + local vertexformat = { + {name="VertexPosition", format="floatvec2"}, + {name="VertexTexCoord", format="floatvec2"}, + {name="VertexColor", format="unorm8vec4"}, + } + local vertexdata = { + {0, 0, 0, 0, 1, 0, 1, 1}, + {10, 0, 1, 0, 0, 1, 1, 1}, + {10, 10, 1, 1, 0, 0, 1, 1}, + {0, 10, 0, 1, 1, 0, 0, 1}, + } + local flatvertexdata = {} + for i, vert in ipairs(vertexdata) do + for j, v in ipairs(vert) do + table.insert(flatvertexdata, v) + end + end + local vertexbuffer1 = love.graphics.newBuffer(vertexformat, 4, {vertex=true, debugname='testvertexbuffer'}) + local vertexbuffer2 = love.graphics.newBuffer(vertexformat, vertexdata, {vertex=true}) + test:assertObject(vertexbuffer1) + test:assertObject(vertexbuffer2) + + -- check buffer properties + test:assertEquals(4, vertexbuffer1:getElementCount(), 'check vertex count 1') + test:assertEquals(4, vertexbuffer2:getElementCount(), 'check vertex count 2') + -- vertex buffers have their elements tightly packed. + test:assertEquals(20, vertexbuffer1:getElementStride(), 'check vertex array stride') + test:assertEquals(20 * 4, vertexbuffer1:getSize(), 'check vertex buffer size') + vertexbuffer1:setArrayData(vertexdata) + vertexbuffer1:setArrayData(flatvertexdata) + vertexbuffer1:clear(8, 8) -- partial clear (the first texcoord) + + -- check buffer types + test:assertTrue(vertexbuffer1:isBufferType('vertex'), 'check is vertex buffer') + test:assertFalse(vertexbuffer1:isBufferType('index'), 'check is not index buffer') + test:assertFalse(vertexbuffer1:isBufferType('texel'), 'check is not texel buffer') + test:assertFalse(vertexbuffer1:isBufferType('shaderstorage'), 'check is not shader storage buffer') + + -- check debug name + test:assertEquals('testvertexbuffer', vertexbuffer1:getDebugName(), 'check buffer debug name') + + -- check buffer format and format properties + local format = vertexbuffer1:getFormat() + test:assertEquals('table', type(format), 'check buffer format is table') + test:assertEquals(#vertexformat, #format, 'check buffer format length') + for i, v in ipairs(vertexformat) do + test:assertEquals(v.name, format[i].name, string.format('check buffer format %d name', i)) + test:assertEquals(v.format, format[i].format, string.format('check buffer format %d format', i)) + test:assertEquals(0, format[i].arraylength, string.format('check buffer format %d array length', i)) + test:assertNotNil(format[i].offset) + end + + -- check index buffer + local indexbuffer = love.graphics.newBuffer('uint16', 128, {index=true}) + test:assertTrue(indexbuffer:isBufferType('index'), 'check is index buffer') + +end + + +-- Shader Storage GraphicsBuffer (love.graphics.newBuffer) +-- Separated from the above test so we can skip it when they aren't supported. +love.test.graphics.ShaderStorageBuffer = function(test) + if not love.graphics.getSupported().glsl4 then + test:skipTest('GLSL 4 and shader storage buffers are not supported on this system') + return + end + + -- setup buffer + local format = { + { name="1", format="float" }, + { name="2", format="floatmat4x4" }, + { name="3", format="floatvec2" } + } + local buffer = love.graphics.newBuffer(format, 1, {shaderstorage = true}) + test:assertEquals(96, buffer:getElementStride(), 'check shader storage buffer element stride') + + -- set new data + local data = {} + for i = 1, 19 do + data[i] = 0 + end + buffer:setArrayData(data) + +end + + +-- Canvas (love.graphics.newCanvas) +love.test.graphics.Canvas = function(test) + + -- create canvas with defaults + local canvas = love.graphics.newCanvas(100, 100, { + type = '2d', + format = 'normal', + readable = true, + msaa = 0, + dpiscale = love.graphics.getDPIScale(), + mipmaps = 'auto', + debugname = 'testcanvas' + }) + test:assertObject(canvas) + test:assertTrue(canvas:isCanvas(), 'check is canvas') + test:assertFalse(canvas:isComputeWritable(), 'check not compute writable') + + -- check dpi + test:assertEquals(love.graphics.getDPIScale(), canvas:getDPIScale(), 'check dpi scale') + + -- check depth + test:assertEquals(1, canvas:getDepth(), 'check depth is 2d') + test:assertEquals(nil, canvas:getDepthSampleMode(), 'check depth sample nil') + + local maxanisotropy = love.graphics.getSystemLimits().anisotropy + + -- check fliter + local min1, mag1, ani1 = canvas:getFilter() + test:assertEquals('nearest', min1, 'check filter def min') + test:assertEquals('nearest', mag1, 'check filter def mag') + test:assertEquals(1, ani1, 'check filter def ani') + canvas:setFilter('linear', 'linear', 2) + local min2, mag2, ani2 = canvas:getFilter() + test:assertEquals('linear', min2, 'check filter changed min') + test:assertEquals('linear', mag2, 'check filter changed mag') + test:assertEquals(math.min(maxanisotropy, 2), ani2, 'check filter changed ani') + + -- check layer + test:assertEquals(1, canvas:getLayerCount(), 'check 1 layer for 2d') + + -- check texture type + test:assertEquals('2d', canvas:getTextureType(), 'check 2d') + + -- check texture wrap + local horiz1, vert1 = canvas:getWrap() + test:assertEquals('clamp', horiz1, 'check def wrap h') + test:assertEquals('clamp', vert1, 'check def wrap v') + canvas:setWrap('repeat', 'repeat') + local horiz2, vert2 = canvas:getWrap() + test:assertEquals('repeat', horiz2, 'check changed wrap h') + test:assertEquals('repeat', vert2, 'check changed wrap v') + + -- check readable + test:assertTrue(canvas:isReadable(), 'check canvas readable') + + -- check msaa + test:assertEquals(1, canvas:getMSAA(), 'check samples match') + + -- check dimensions + local cw, ch = canvas:getDimensions() + test:assertEquals(100, cw, 'check canvas dim w') + test:assertEquals(100, ch, 'check canvas dim h') + test:assertEquals(cw, canvas:getWidth(), 'check canvas w matches dim') + test:assertEquals(ch, canvas:getHeight(), 'check canvas h matches dim') + local pw, ph = canvas:getPixelDimensions() + test:assertEquals(100*love.graphics.getDPIScale(), pw, 'check pixel dim w') + test:assertEquals(100*love.graphics.getDPIScale(), ph, 'check pixel dim h') + test:assertEquals(pw, canvas:getPixelWidth(), 'check pixel w matches dim') + test:assertEquals(ph, canvas:getPixelHeight(), 'check pixel h matches dim') + + -- check mipmaps + local mode, sharpness = canvas:getMipmapFilter() + test:assertEquals('linear', mode, 'check def minmap filter mode') + test:assertEquals(0, sharpness, 'check def minmap filter sharpness') + local name, version, vendor, device = love.graphics.getRendererInfo() + canvas:setMipmapFilter('nearest', 1) + mode, sharpness = canvas:getMipmapFilter() + test:assertEquals('nearest', mode, 'check changed minmap filter mode') + -- @NOTE mipmap sharpness wont work on opengl/metal + if string.match(name, 'OpenGL ES') == nil and string.match(name, 'Metal') == nil then + test:assertEquals(1, sharpness, 'check changed minmap filter sharpness') + end + test:assertGreaterEqual(2, canvas:getMipmapCount()) -- docs say no mipmaps should return 1 + test:assertEquals('auto', canvas:getMipmapMode()) + + -- check debug name + test:assertEquals('testcanvas', canvas:getDebugName()) + + -- check basic rendering + canvas:renderTo(function() + love.graphics.setColor(1, 0, 0) + love.graphics.rectangle('fill', 0, 0, 200, 200) + love.graphics.setColor(1, 1, 1, 1) + end) + local imgdata1 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata1) + + -- check using canvas in love.graphics.draw() + local xcanvas = love.graphics.newCanvas() + love.graphics.setCanvas(xcanvas) + love.graphics.draw(canvas, 0, 0) + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata2) + + -- check y-down + local shader1 = love.graphics.newShader[[ + vec4 effect(vec4 c, Image tex, vec2 tc, vec2 pc) { + return tc.y > 0.5 ? vec4(1.0, 0.0, 0.0, 1.0) : vec4(0.0, 1.0, 0.0, 1.0); + } + ]] + local shader2 = love.graphics.newShader[[ + vec4 effect(vec4 c, Image tex, vec2 tc, vec2 pc) { + // rounding during quantization from float to unorm8 doesn't seem to be + // totally consistent across devices, lets do it ourselves. + highp vec2 value = pc / love_ScreenSize.xy; + highp vec2 quantized = (floor(255.0 * value + 0.5) + 0.1) / 255.0; + return vec4(quantized, 0.0, 1.0); + } + ]] + local img = love.graphics.newImage(love.image.newImageData(1, 1)) + + love.graphics.push("all") + love.graphics.setCanvas(canvas) + love.graphics.setShader(shader1) + love.graphics.draw(img, 0, 0, 0, canvas:getDimensions()) + love.graphics.pop() + local imgdata3 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata3) + + love.graphics.push("all") + love.graphics.setCanvas(canvas) + love.graphics.setShader(shader2) + love.graphics.draw(img, 0, 0, 0, canvas:getDimensions()) + love.graphics.pop() + local imgdata4 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata4) + + + -- check depth samples + local dcanvas = love.graphics.newCanvas(100, 100, { + type = '2d', + format = 'depth16', + readable = true + }) + test:assertEquals(nil, dcanvas:getDepthSampleMode(), 'check depth sample mode nil by def') + dcanvas:setDepthSampleMode('equal') + test:assertEquals('equal', dcanvas:getDepthSampleMode(), 'check depth sample mode set') + + -- check compute writeable (wont work on opengl mac) + if love.graphics.getSupported().glsl4 then + local ccanvas = love.graphics.newCanvas(100, 100, { + type = '2d', + format = 'rgba8', + computewrite = true + }) + test:assertTrue(ccanvas:isComputeWritable()) + end + +end + + +-- Font (love.graphics.newFont) +love.test.graphics.Font = function(test) + + -- create obj + local font = love.graphics.newFont('resources/font.ttf', 8) + test:assertObject(font) + + -- check ascent/descent + test:assertEquals(6, font:getAscent(), 'check ascent') + test:assertEquals(-2, font:getDescent(), 'check descent') + + -- check baseline + test:assertEquals(6, font:getBaseline(), 'check baseline') + + -- check dpi + test:assertEquals(1, font:getDPIScale(), 'check dpi') + + -- check filter + test:assertEquals('nearest', font:getFilter(), 'check filter def') + font:setFilter('linear', 'linear') + test:assertEquals('linear', font:getFilter(), 'check filter change') + font:setFilter('nearest', 'nearest') + + -- check height + lineheight + test:assertEquals(8, font:getHeight(), 'check height') + test:assertEquals(1, font:getLineHeight(), 'check line height') + font:setLineHeight(2) + test:assertEquals(2, font:getLineHeight(), 'check changed line height') + font:setLineHeight(1) -- reset for drawing + wrap later + + -- check width + kerning + test:assertEquals(0, font:getKerning('a', 'b'), 'check kerning') + test:assertEquals(24, font:getWidth('test'), 'check data size') + + -- check specific glyphs + test:assertTrue(font:hasGlyphs('test'), 'check data size') + + -- check font wrapping + local width, wrappedtext = font:getWrap('LÖVE is an *awesome* framework you can use to make 2D games in Lua.', 50) + test:assertEquals(48, width, 'check actual wrap width') + test:assertEquals(8, #wrappedtext, 'check wrapped lines') + test:assertEquals('LÖVE is an ', wrappedtext[1], 'check wrapped line') + + -- check drawing font + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.setFont(font) + love.graphics.print('Aa', 0, 5) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) + + -- check font substitution + local fontab = love.graphics.newImageFont('resources/font-letters-ab.png', 'AB') + local fontcd = love.graphics.newImageFont('resources/font-letters-cd.png', 'CD') + fontab:setFallbacks(fontcd) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 0) + love.graphics.setFont(fontab) + love.graphics.print('AB', 0, 0) -- should come from fontab + love.graphics.print('CD', 0, 9) -- should come from fontcd + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata2) + +end + + +-- Image (love.graphics.newImage) +love.test.graphics.Image = function(test) + + -- create object + local image = love.graphics.newImage('resources/love.png', { + dpiscale = 1, + mipmaps = true + }) + test:assertObject(image) + test:assertFalse(image:isCanvas(), 'check not canvas') + test:assertFalse(image:isComputeWritable(), 'check not compute writable') + + -- check dpi + test:assertEquals(love.graphics.getDPIScale(), image:getDPIScale(), 'check dpi scale') + + -- check depth + test:assertEquals(1, image:getDepth(), 'check depth is 2d') + test:assertEquals(nil, image:getDepthSampleMode(), 'check depth sample nil') + + local maxanisotropy = love.graphics.getSystemLimits().anisotropy + + -- check filter + local min1, mag1, ani1 = image:getFilter() + test:assertEquals('nearest', min1, 'check filter def min') + test:assertEquals('nearest', mag1, 'check filter def mag') + test:assertEquals(1, ani1, 'check filter def ani') + image:setFilter('linear', 'linear', 2) + local min2, mag2, ani2 = image:getFilter() + test:assertEquals('linear', min2, 'check filter changed min') + test:assertEquals('linear', mag2, 'check filter changed mag') + test:assertEquals(math.min(maxanisotropy, 2), ani2, 'check filter changed ani') + image:setFilter('nearest', 'nearest', 1) + + -- check layers + test:assertEquals(1, image:getLayerCount(), 'check 1 layer for 2d') + + -- check texture type + test:assertEquals('2d', image:getTextureType(), 'check 2d') + + -- check texture wrapping + local horiz1, vert1 = image:getWrap() + test:assertEquals('clamp', horiz1, 'check def wrap h') + test:assertEquals('clamp', vert1, 'check def wrap v') + image:setWrap('repeat', 'repeat') + local horiz2, vert2 = image:getWrap() + test:assertEquals('repeat', horiz2, 'check changed wrap h') + test:assertEquals('repeat', vert2, 'check changed wrap v') + + -- check readable + test:assertTrue(image:isReadable(), 'check canvas readable') + + -- check msaa + test:assertEquals(1, image:getMSAA(), 'check samples match') + + -- check dimensions + local cw, ch = image:getDimensions() + test:assertEquals(64, cw, 'check canvas dim w') + test:assertEquals(64, ch, 'check canvas dim h') + test:assertEquals(cw, image:getWidth(), 'check canvas w matches dim') + test:assertEquals(ch, image:getHeight(), 'check canvas h matches dim') + local pw, ph = image:getPixelDimensions() + test:assertEquals(64*love.graphics.getDPIScale(), pw, 'check pixel dim w') + test:assertEquals(64*love.graphics.getDPIScale(), ph, 'check pixel dim h') + test:assertEquals(pw, image:getPixelWidth(), 'check pixel w matches dim') + test:assertEquals(ph, image:getPixelHeight(), 'check pixel h matches dim') + + -- check mipmaps + local mode, sharpness = image:getMipmapFilter() + test:assertEquals('linear', mode, 'check def minmap filter mode') + test:assertEquals(0, sharpness, 'check def minmap filter sharpness') + local name, version, vendor, device = love.graphics.getRendererInfo() + -- @note mipmap sharpness wont work on opengl/metal + image:setMipmapFilter('nearest', 1) + mode, sharpness = image:getMipmapFilter() + test:assertEquals('nearest', mode, 'check changed minmap filter mode') + if string.match(name, 'OpenGL ES') == nil and string.match(name, 'Metal') == nil then + test:assertEquals(1, sharpness, 'check changed minmap filter sharpness') + end + test:assertGreaterEqual(2, image:getMipmapCount()) -- docs say no mipmaps should return 1? + + -- check image properties + test:assertFalse(image:isCompressed(), 'check not compressed') + test:assertFalse(image:isFormatLinear(), 'check not linear') + local cimage = love.graphics.newImage('resources/love.dxt1') + test:assertObject(cimage) + test:assertTrue(cimage:isCompressed(), 'check is compressed') + + -- check pixel replacement + local rimage = love.image.newImageData('resources/loveinv.png') + image:replacePixels(rimage) + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.draw(image, 0, 0) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + local r1, g1, b1 = imgdata:getPixel(25, 25) + test:assertEquals(3, r1+g1+b1, 'check back to white') + test:compareImg(imgdata) + +end + + +-- Mesh (love.graphics.newMesh) +love.test.graphics.Mesh = function(test) + + -- create 2d mesh with pretty colors + local image = love.graphics.newImage('resources/love.png') + local vertices = { + { 0, 0, 0, 0, 1, 0, 0 }, + { image:getWidth(), 0, 1, 0, 0, 1, 0 }, + { image:getWidth(), image:getHeight(), 1, 1, 0, 0, 1 }, + { 0, image:getHeight(), 0, 1, 1, 1, 0 }, + } + local mesh1 = love.graphics.newMesh(vertices, 'fan') + test:assertObject(mesh1) + + -- check draw mode + test:assertEquals('fan', mesh1:getDrawMode(), 'check draw mode') + mesh1:setDrawMode('triangles') + test:assertEquals('triangles', mesh1:getDrawMode(), 'check draw mode set') + + -- check draw range + local min1, max1 = mesh1:getDrawRange() + test:assertEquals(nil, min1, 'check draw range not set') + mesh1:setDrawRange(1, 10) + local min2, max2 = mesh1:getDrawRange() + test:assertEquals(1, min2, 'check draw range set min') + test:assertEquals(10, max2, 'check draw range set max') + + -- check texture pointer + test:assertEquals(nil, mesh1:getTexture(), 'check no texture') + mesh1:setTexture(image) + test:assertEquals(image:getHeight(), mesh1:getTexture():getHeight(), 'check texture match w') + test:assertEquals(image:getWidth(), mesh1:getTexture():getWidth(), 'check texture match h') + + -- check vertext count + test:assertEquals(4, mesh1:getVertexCount(), 'check vertex count') + + -- check def vertex format + local format = mesh1:getVertexFormat() + test:assertEquals('floatvec2', format[2].format, 'check def vertex format 2') + test:assertEquals('VertexColor', format[3].name, 'check def vertex format 3') + + -- check vertext attributes + test:assertTrue(mesh1:isAttributeEnabled('VertexPosition'), 'check def attribute VertexPosition') + test:assertTrue(mesh1:isAttributeEnabled('VertexTexCoord'), 'check def attribute VertexTexCoord') + test:assertTrue(mesh1:isAttributeEnabled('VertexColor'), 'check def attribute VertexColor') + mesh1:setAttributeEnabled('VertexPosition', false) + mesh1:setAttributeEnabled('VertexTexCoord', false) + mesh1:setAttributeEnabled('VertexColor', false) + test:assertFalse(mesh1:isAttributeEnabled('VertexPosition'), 'check disable attribute VertexPosition') + test:assertFalse(mesh1:isAttributeEnabled('VertexTexCoord'), 'check disable attribute VertexTexCoord') + test:assertFalse(mesh1:isAttributeEnabled('VertexColor'), 'check disable attribute VertexColor') + + -- check vertex itself + local x1, y1, u1, v1, r1, g1, b1, a1 = mesh1:getVertex(1) + test:assertEquals(0, x1, 'check vertex props x') + test:assertEquals(0, y1, 'check vertex props y') + test:assertEquals(0, u1, 'check vertex props u') + test:assertEquals(0, v1, 'check vertex props v') + test:assertEquals(1, r1, 'check vertex props r') + test:assertEquals(0, g1, 'check vertex props g') + test:assertEquals(0, b1, 'check vertex props b') + test:assertEquals(1, a1, 'check vertex props a') + + -- check setting a specific vertex + mesh1:setVertex(2, image:getWidth(), 0, 1, 0, 0, 1, 1, 1) + local x2, y2, u2, v2, r2, g2, b2, a2 = mesh1:getVertex(2) + test:assertEquals(image:getWidth(), x2, 'check changed vertex props x') + test:assertEquals(0, y2, 'check changed vertex props y') + test:assertEquals(1, u2, 'check changed vertex props u') + test:assertEquals(0, v2, 'check changed vertex props v') + test:assertEquals(0, r2, 'check changed vertex props r') + test:assertEquals(1, g2, 'check changed vertex props g') + test:assertEquals(1, b2, 'check changed vertex props b') + test:assertEquals(1, a2, 'check changed vertex props a') + + -- check setting a specific vertex attribute + local r3, g3, b3, a3 = mesh1:getVertexAttribute(3, 3) + test:assertEquals(1, b3, 'check specific vertex color') + mesh1:setVertexAttribute(4, 3, 1, 0, 1) + local r4, g4, b4, a4 = mesh1:getVertexAttribute(4, 3) + test:assertEquals(0, g4, 'check changed vertex color') + + -- check setting a vertice + mesh1:setVertices(vertices) + local r5, g5, b5, a5 = mesh1:getVertexAttribute(4, 3) + local x6, y6, u6, v6, r6, g6, b6, a6 = mesh1:getVertex(2) + test:assertEquals(1, g5, 'check reset vertex color 1') + test:assertEquals(0, b5, 'check reset vertex color 2') + + -- check setting the vertex map + local vmap1 = mesh1:getVertexMap() + test:assertEquals(nil, vmap1, 'check no map by def') + mesh1:setVertexMap({4, 1, 2, 3}) + local vmap2 = mesh1:getVertexMap() + test:assertEquals(4, #vmap2, 'check set map len') + test:assertEquals(2, vmap2[3], 'check set map val') + + -- check using custom attributes + local mesh2 = love.graphics.newMesh({ + { name = 'VertexPosition', format = 'floatvec2'}, + { name = 'VertexTexCoord', format = 'floatvec2'}, + { name = 'VertexColor', format = 'floatvec4'}, + { name = 'CustomValue1', format = 'floatvec2'}, + { name = 'CustomValue2', format = 'uint16'} + }, { + { 0, 0, 0, 0, 1, 0, 0, 1, 2, 1, 1005 }, + { image:getWidth(), 0, 1, 0, 0, 1, 0, 0, 2, 2, 2005 }, + { image:getWidth(), image:getHeight(), 1, 1, 0, 0, 1, 0, 2, 3, 3005 }, + { 0, image:getHeight(), 0, 1, 1, 1, 0, 0, 2, 4, 4005 }, + }, 'fan') + local c1, c2 = mesh2:getVertexAttribute(1, 4) + local c3 = mesh2:getVertexAttribute(1, 5) + test:assertEquals(2, c1, 'check custom attribute val 1') + test:assertEquals(1, c2, 'check custom attribute val 2') + test:assertEquals(1005, c3, 'check custom attribute val 3') + + -- check attaching custom attribute + detaching + mesh1:attachAttribute('CustomValue1', mesh2) + test:assertTrue(mesh1:isAttributeEnabled('CustomValue1'), 'check custom attribute attached') + mesh1:detachAttribute('CustomValue1') + local obj, err = pcall(mesh1.isAttributeEnabled, mesh1, 'CustomValue1') + test:assertNotEquals(nil, err, 'check attribute detached') + mesh1:detachAttribute('VertexPosition') + test:assertTrue(mesh1:isAttributeEnabled('VertexPosition'), 'check cant detach def attribute') + +end + + +-- ParticleSystem (love.graphics.newParticleSystem) +love.test.graphics.ParticleSystem = function(test) + + -- create new system + local image = love.graphics.newImage('resources/pixel.png') + local quad1 = love.graphics.newQuad(0, 0, 1, 1, image) + local quad2 = love.graphics.newQuad(0, 0, 1, 1, image) + local psystem = love.graphics.newParticleSystem(image, 1000) + test:assertObject(psystem) + + -- check psystem state properties + psystem:start() + psystem:update(1) + test:assertTrue(psystem:isActive(), 'check active') + test:assertFalse(psystem:isPaused(), 'checked not paused by def') + test:assertFalse(psystem:hasRelativeRotation(), 'check rel rot def') + psystem:pause() + test:assertTrue(psystem:isPaused(), 'check now paused') + test:assertFalse(psystem:isStopped(), 'check not stopped by def') + psystem:stop() + test:assertTrue(psystem:isStopped(), 'check now stopped') + psystem:start() + psystem:reset() + + -- check emitting some particles + -- need to set a lifespan at minimum or none will be counted + local min, max = psystem:getParticleLifetime() + test:assertEquals(0, min, 'check def lifetime min') + test:assertEquals(0, max, 'check def lifetime max') + psystem:setParticleLifetime(1, 2) + psystem:emit(10) + psystem:update(1) + test:assertEquals(10, psystem:getCount(), 'check added particles') + psystem:reset() + test:assertEquals(0, psystem:getCount(), 'check reset') + + -- check setting colors + local colors1 = {psystem:getColors()} + test:assertEquals(1, #colors1, 'check 1 color by def') + psystem:setColors(1, 1, 1, 1, 1, 0, 0, 1) + local colors2 = {psystem:getColors()} + test:assertEquals(2, #colors2, 'check set colors') + test:assertEquals(1, colors2[2][1], 'check set color') + + -- check setting direction + test:assertEquals(0, psystem:getDirection(), 'check def direction') + psystem:setDirection(90 * (math.pi/180)) + test:assertEquals(math.floor(math.pi/2*100), math.floor(psystem:getDirection()*100), 'check set direction') + + -- check emission area options + psystem:setEmissionArea('normal', 100, 50) + psystem:setEmissionArea('ellipse', 100, 50) + psystem:setEmissionArea('borderellipse', 100, 50) + psystem:setEmissionArea('borderrectangle', 100, 50) + psystem:setEmissionArea('none', 100, 50) + psystem:setEmissionArea('uniform', 100, 50) + local dist, dx, dy, angle, rel = psystem:getEmissionArea() + test:assertEquals('uniform', dist, 'check emission area dist') + test:assertEquals(100, dx, 'check emission area dx') + test:assertEquals(50, dy, 'check emission area dy') + test:assertEquals(0, angle, 'check emission area angle') + test:assertFalse(rel, 'check emission area rel') + + -- check emission rate + test:assertEquals(0, psystem:getEmissionRate(), 'check def emission rate') + psystem:setEmissionRate(1) + test:assertEquals(1, psystem:getEmissionRate(), 'check changed emission rate') + + -- check emission lifetime + test:assertEquals(-1, psystem:getEmitterLifetime(), 'check def emitter life') + psystem:setEmitterLifetime(10) + test:assertEquals(10, psystem:getEmitterLifetime(), 'check changed emitter life') + + -- check insert mode + test:assertEquals('top', psystem:getInsertMode(), 'check def insert mode') + psystem:setInsertMode('bottom') + psystem:setInsertMode('random') + test:assertEquals('random', psystem:getInsertMode(), 'check change insert mode') + + -- check linear acceleration + local xmin1, ymin1, xmax1, ymax1 = psystem:getLinearAcceleration() + test:assertEquals(0, xmin1, 'check def lin acceleration xmin') + test:assertEquals(0, ymin1, 'check def lin acceleration ymin') + test:assertEquals(0, xmax1, 'check def lin acceleration xmax') + test:assertEquals(0, ymax1, 'check def lin acceleration ymax') + psystem:setLinearAcceleration(1, 2, 3, 4) + local xmin2, ymin2, xmax2, ymax2 = psystem:getLinearAcceleration() + test:assertEquals(1, xmin2, 'check change lin acceleration xmin') + test:assertEquals(2, ymin2, 'check change lin acceleration ymin') + test:assertEquals(3, xmax2, 'check change lin acceleration xmax') + test:assertEquals(4, ymax2, 'check change lin acceleration ymax') + + -- check linear damping + local min3, max3 = psystem:getLinearDamping() + test:assertEquals(0, min3, 'check def lin damping min') + test:assertEquals(0, max3, 'check def lin damping max') + psystem:setLinearDamping(1, 2) + local min4, max4 = psystem:getLinearDamping() + test:assertEquals(1, min4, 'check change lin damping min') + test:assertEquals(2, max4, 'check change lin damping max') + + -- check offset + local ox1, oy1 = psystem:getOffset() + test:assertEquals(0.5, ox1, 'check def offset x') -- 0.5 cos middle of pixel image which is 1x1 + test:assertEquals(0.5, oy1, 'check def offset y') + psystem:setOffset(0, 10) + local ox2, oy2 = psystem:getOffset() + test:assertEquals(0, ox2, 'check change offset x') + test:assertEquals(10, oy2, 'check change offset y') + + -- check lifetime (we set it earlier) + local min5, max5 = psystem:getParticleLifetime() + test:assertEquals(1, min5, 'check p lifetime min') + test:assertEquals(2, max5, 'check p lifetime max') + + -- check position + local x1, y1 = psystem:getPosition() + test:assertEquals(0, x1, 'check emitter x') + test:assertEquals(0, y1, 'check emitter y') + psystem:setPosition(10, 12) + local x2, y2 = psystem:getPosition() + test:assertEquals(10, x2, 'check set emitter x') + test:assertEquals(12, y2, 'check set emitter y') + + -- check quads + test:assertEquals(0, #psystem:getQuads(), 'check def quads') + psystem:setQuads({quad1}) + psystem:setQuads(quad1, quad2) + test:assertEquals(2, #psystem:getQuads(), 'check set quads') + + -- check radial acceleration + local min6, max6 = psystem:getRadialAcceleration() + test:assertEquals(0, min6, 'check def rad accel min') + test:assertEquals(0, max6, 'check def rad accel max') + psystem:setRadialAcceleration(1, 2) + local min7, max7 = psystem:getRadialAcceleration() + test:assertEquals(1, min7, 'check change rad accel min') + test:assertEquals(2, max7, 'check change rad accel max') + + -- check rotation + local min8, max8 = psystem:getRotation() + test:assertEquals(0, min8, 'check def rot min') + test:assertEquals(0, max8, 'check def rot max') + psystem:setRotation(90 * (math.pi/180), 180 * (math.pi/180)) + local min8, max8 = psystem:getRotation() + test:assertEquals(math.floor(math.pi/2*100), math.floor(min8*100), 'check set rot min') + test:assertEquals(math.floor(math.pi*100), math.floor(max8*100), 'check set rot max') + + -- check variation + test:assertEquals(0, psystem:getSizeVariation(), 'check def variation') + psystem:setSizeVariation(1) + test:assertEquals(1, psystem:getSizeVariation(), 'check change variation') + + -- check sizes + test:assertEquals(1, #{psystem:getSizes()}, 'check def size') + psystem:setSizes(1, 2, 4, 1, 3, 2) + local sizes = {psystem:getSizes()} + test:assertEquals(6, #sizes, 'check set sizes') + test:assertEquals(3, sizes[5], 'check set size') + + -- check speed + local min9, max9 = psystem:getSpeed() + test:assertEquals(0, min9, 'check def speed min') + test:assertEquals(0, max9, 'check def speed max') + psystem:setSpeed(1, 10) + local min10, max10 = psystem:getSpeed() + test:assertEquals(1, min10, 'check change speed min') + test:assertEquals(10, max10, 'check change speed max') + + -- check variation + spin + local variation = psystem:getSpinVariation() + test:assertEquals(0, variation, 'check def spin variation') + psystem:setSpinVariation(1) + test:assertEquals(1, psystem:getSpinVariation(), 'check change spin variation') + psystem:setSpin(1, 2) + local min11, max11 = psystem:getSpin() + test:assertEquals(1, min11, 'check change spin min') + test:assertEquals(2, max11, 'check change spin max') + + -- check spread + test:assertEquals(0, psystem:getSpread(), 'check def spread') + psystem:setSpread(90 * (math.pi/180)) + test:assertEquals(math.floor(math.pi/2*100), math.floor(psystem:getSpread()*100), 'check change spread') + + -- tangential acceleration + local min12, max12 = psystem:getTangentialAcceleration() + test:assertEquals(0, min12, 'check def tan accel min') + test:assertEquals(0, max12, 'check def tan accel max') + psystem:setTangentialAcceleration(1, 2) + local min13, max13 = psystem:getTangentialAcceleration() + test:assertEquals(1, min13, 'check change tan accel min') + test:assertEquals(2, max13, 'check change tan accel max') + + -- check texture + test:assertNotEquals(nil, psystem:getTexture(), 'check texture obj') + test:assertObject(psystem:getTexture()) + psystem:setTexture(love.graphics.newImage('resources/love.png')) + test:assertObject(psystem:getTexture()) + + -- try a graphics test! + -- hard to get exactly because of the variation but we can use some pixel + -- tolerance and volume to try and cover the randomness + local psystem2 = love.graphics.newParticleSystem(image, 5000) + psystem2:setEmissionArea('uniform', 2, 64) + psystem2:setColors(1, 0, 0, 1) + psystem2:setDirection(0 * math.pi/180) + psystem2:setEmitterLifetime(100) + psystem2:setEmissionRate(5000) + local psystem3 = psystem2:clone() + psystem3:setPosition(64, 0) + psystem3:setColors(0, 1, 0, 1) + psystem3:setDirection(180 * (math.pi/180)) + psystem2:start() + psystem3:start() + psystem2:update(1) + psystem3:update(1) + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(psystem2, 0, 0) + love.graphics.draw(psystem3, 0, 0) + love.graphics.setCanvas() + -- this should result in a bunch of red pixels on the left 2px of the canvas + -- and a bunch of green pixels on the right 2px of the canvas + local imgdata = love.graphics.readbackTexture(canvas) + test.pixel_tolerance = 1 + test:compareImg(imgdata) + +end + + +-- Quad (love.graphics.newQuad) +love.test.graphics.Quad = function(test) + + -- create quad obj + local texture = love.graphics.newImage('resources/love.png') + local quad = love.graphics.newQuad(0, 0, 32, 32, texture) + test:assertObject(quad) + + -- check properties + test:assertEquals(1, quad:getLayer(), 'check default layer') + quad:setLayer(2) + test:assertEquals(2, quad:getLayer(), 'check changed layer') + local sw, sh = quad:getTextureDimensions() + test:assertEquals(64, sw, 'check texture w') + test:assertEquals(64, sh, 'check texture h') + + -- check drawing and viewport changes + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.draw(texture, quad, 0, 0) + quad:setViewport(32, 32, 32, 32, 64, 64) + love.graphics.draw(texture, quad, 32, 32) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) + +end + + +-- Shader (love.graphics.newShader) +love.test.graphics.Shader = function(test) + + -- check valid shader + local pixelcode1 = [[ + uniform Image tex2; + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texturecolor = Texel(tex2, texture_coords); + return texturecolor * color; + } + ]] + local vertexcode1 = [[ + vec4 position(mat4 transform_projection, vec4 vertex_position) { + return transform_projection * vertex_position; + } + ]] + local shader1 = love.graphics.newShader(pixelcode1, vertexcode1, {debugname = 'testshader'}) + test:assertObject(shader1) + test:assertEquals('', shader1:getWarnings(), 'check shader valid') + test:assertFalse(shader1:hasUniform('tex1'), 'check invalid uniform') + test:assertTrue(shader1:hasUniform('tex2'), 'check valid uniform') + test:assertEquals('testshader', shader1:getDebugName()) + + -- check invalid shader + local pixelcode2 = [[ + uniform float ww; + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texturecolor = Texel(tex, texture_coords); + float unused = ww * 3 * color; + return texturecolor * color; + } + ]] + local res, err = pcall(love.graphics.newShader, pixelcode2, vertexcode1) + test:assertNotEquals(nil, err, 'check shader compile fails') + + -- check using a shader to draw + sending uniforms + -- shader will return a given color if overwrite set to 1, otherwise def. draw + local pixelcode3 = [[ + uniform vec4 col; + uniform float overwrite; + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texcol = Texel(tex, texture_coords); + if (overwrite == 1.0) { + return col; + } else { + return texcol * color; + } + } + ]] + local shader3 = love.graphics.newShader(pixelcode3, vertexcode1) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.push("all") + love.graphics.setCanvas(canvas) + -- set color to yellow + love.graphics.setColor(1, 1, 0, 1) + -- turn shader 'on' and use red to draw + shader3:send('overwrite', 1) + shader3:sendColor('col', {1, 0, 0, 1}) + love.graphics.setShader(shader3) + love.graphics.rectangle('fill', 0, 0, 8, 8) + love.graphics.setShader() + -- turn shader 'off' and draw again + shader3:send('overwrite', 0) + love.graphics.setShader(shader3) + love.graphics.rectangle('fill', 8, 8, 8, 8) + love.graphics.pop() + + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) + + -- test some uncommon paths for shader uniforms + local shader4 = love.graphics.newShader[[ + uniform bool booleans[5]; + vec4 effect(vec4 vcolor, Image tex, vec2 tc, vec2 pc) { + return booleans[3] ? vec4(0, 1, 0, 0) : vec4(1, 0, 0, 0); + } + ]] + + shader4:send("booleans", false, true, true) + + local shader5 = love.graphics.newShader[[ + uniform sampler2D textures[5]; + vec4 effect(vec4 vcolor, Image tex, vec2 tc, vec2 pc) { + return Texel(textures[2], tc) + Texel(textures[3], tc); + } + ]] + + local canvas2 = love.graphics.newCanvas(1, 1) + love.graphics.setCanvas(canvas2) + love.graphics.clear(0, 0.5, 0, 1) + love.graphics.setCanvas() + + shader5:send("textures", canvas2, canvas2, canvas2, canvas2, canvas2) + + local shader6 = love.graphics.newShader[[ + struct Data { + bool boolValue; + float floatValue; + sampler2D tex; + }; + + uniform Data data; + uniform Data dataArray[3]; + + vec4 effect(vec4 vcolor, Image tex, vec2 tc, vec2 pc) { + return (data.boolValue && dataArray[1].boolValue) ? Texel(dataArray[0].tex, tc) : vec4(0.0, 0.0, 0.0, 0.0); + } + ]] + + shader6:send("data.boolValue", true) + shader6:send("dataArray[1].boolValue", true) + shader6:send("dataArray[0].tex", canvas2) + + local shader7 = love.graphics.newShader[[ + uniform vec3 vec3s[3]; + + vec4 effect(vec4 vcolor, Image tex, vec2 tc, vec2 pc) { + return vec4(vec3s[1], 1.0); + } + ]] + + shader7:send("vec3s", {0, 0, 1}, {0, 1, 0}, {1, 0, 0}) + + local canvas3 = love.graphics.newCanvas(16, 16) + love.graphics.push("all") + love.graphics.setCanvas(canvas3) + love.graphics.setShader(shader7) + love.graphics.rectangle("fill", 0, 0, 16, 16) + love.graphics.pop() + local imgdata2 = love.graphics.readbackTexture(canvas3) + test:compareImg(imgdata2) + + if love.graphics.getSupported().glsl3 then + local shader8 = love.graphics.newShader[[ + #pragma language glsl3 + #ifdef GL_ES + precision highp float; + #endif + + varying vec4 VaryingUnused1; + varying mat3 VaryingMatrix; + flat varying ivec4 VaryingInt; + + #ifdef VERTEX + in vec4 VertexPosition; + in ivec4 IntAttributeUnused; + + void vertexmain() + { + VaryingMatrix = mat3(vec3(1, 0, 0), vec3(0, 1, 0), vec3(0, 0, 1)); + VaryingInt = ivec4(1, 1, 1, 1); + love_Position = TransformProjectionMatrix * VertexPosition; + } + #endif + + #ifdef PIXEL + out ivec4 outData; + + void pixelmain() + { + outData = ivec4(VaryingMatrix[1][1] > 0.0 ? 1 : 0, 1, VaryingInt.x, 1); + } + #endif + ]] + + local canvas4 = love.graphics.newCanvas(16, 16, {format="rgba8i"}) + love.graphics.push("all") + love.graphics.setBlendMode("none") + love.graphics.setCanvas(canvas4) + love.graphics.setShader(shader8) + love.graphics.rectangle("fill", 0, 0, 16, 16) + love.graphics.pop() + + local intimagedata = love.graphics.readbackTexture(canvas4) + local imgdata3 = love.image.newImageData(16, 16, "rgba8") + for y=0, 15 do + for x=0, 15 do + local ir, ig, ib, ia = intimagedata:getInt8(4 * (y * 16 + x), 4) + imgdata3:setPixel(x, y, ir, ig, ib, ia) + end + end + test:compareImg(imgdata3) + else + test:assertTrue(true, "skip shader IO test") + end +end + + +-- SpriteBatch (love.graphics.newSpriteBatch) +love.test.graphics.SpriteBatch = function(test) + + -- create batch + local texture1 = love.graphics.newImage('resources/cubemap.png') + local texture2 = love.graphics.newImage('resources/love.png') + local quad1 = love.graphics.newQuad(32, 12, 1, 1, texture2) -- lovepink + local quad2 = love.graphics.newQuad(32, 32, 1, 1, texture2) -- white + local sbatch = love.graphics.newSpriteBatch(texture1, 5000) + test:assertObject(sbatch) + + -- check initial count + test:assertEquals(0, sbatch:getCount(), 'check batch size') + + -- check buffer size + test:assertEquals(5000, sbatch:getBufferSize(), 'check batch size') + + -- check height/width/texture + test:assertEquals(texture1:getWidth(), sbatch:getTexture():getWidth(), 'check texture match w') + test:assertEquals(texture1:getHeight(), sbatch:getTexture():getHeight(), 'check texture match h') + sbatch:setTexture(texture2) + test:assertEquals(texture2:getWidth(), sbatch:getTexture():getWidth(), 'check texture change w') + test:assertEquals(texture2:getHeight(), sbatch:getTexture():getHeight(), 'check texture change h') + + -- check colors + local r1, g1, b1, a1 = sbatch:getColor() + test:assertEquals(1, r1, 'check initial color r') + test:assertEquals(1, g1, 'check initial color g') + test:assertEquals(1, b1, 'check initial color b') + test:assertEquals(1, a1, 'check initial color a') + sbatch:setColor(1, 0, 0, 1) + local r2, g2, b2, a2 = sbatch:getColor() + test:assertEquals(1, r2, 'check set color r') + test:assertEquals(0, g2, 'check set color g') + test:assertEquals(0, b2, 'check set color b') + test:assertEquals(1, a2, 'check set color a') + + -- check adding sprites + local offset_x = 0 + local offset_y = 0 + local color = 'white' + sbatch:setColor(1, 1, 1, 1) + local sprites = {} + for s=1,4096 do + local spr = sbatch:add(quad1, offset_x, offset_y, 0, 1, 1) + table.insert(sprites, {spr, offset_x, offset_y}) + offset_x = offset_x + 1 + if s % 64 == 0 then + -- alternate row colors + if color == 'white' then + color = 'red' + sbatch:setColor(1, 0, 0, 1) + else + color = 'white' + sbatch:setColor(1, 1, 1, 1) + end + offset_y = offset_y + 1 + offset_x = 0 + end + end + test:assertEquals(4096, sbatch:getCount()) + + -- test drawing and setting + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(sbatch, 0, 0) + love.graphics.setCanvas() + local imgdata1 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata1) + + -- use set to change some sprites + for s=1,2048 do + sbatch:set(sprites[s][1], quad2, sprites[s][2], sprites[s][3]+1, 0, 1, 1) + end + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(sbatch, 0, 0) + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata2) + + -- set drawRange and redraw + sbatch:setDrawRange(1025, 2048) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(sbatch, 0, 0) + love.graphics.setCanvas() + local imgdata3 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata3) + + -- clear and redraw + sbatch:clear() + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(sbatch, 0, 0) + love.graphics.setCanvas() + local imgdata4 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata4) + + -- array texture sbatch + local texture3 = love.graphics.newArrayImage({ + 'resources/love.png', + 'resources/loveinv.png' + }) + local asbatch = love.graphics.newSpriteBatch(texture3, 4096) + local quad3 = love.graphics.newQuad(32, 52, 1, 1, texture3) -- loveblue + sprites = {} + for s=1,4096 do + local spr = asbatch:addLayer(1, quad3, 0, s, math.floor(s/64), 1, 1) + table.insert(sprites, {spr, s, math.floor(s/64)}) + end + test:assertEquals(4096, asbatch:getCount(), 'check max batch size applies') + for s=1,2048 do + asbatch:setLayer(sprites[s][1], 2, sprites[s][2], sprites[s][3], 0, 1, 1) + end + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(asbatch, 0, 0) + love.graphics.setCanvas() + local imgdata5 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata5) + +end + + +-- Text (love.graphics.newTextBatch) +love.test.graphics.Text = function(test) + + -- setup text object + local font = love.graphics.newFont('resources/font.ttf', 8) + local plaintext = love.graphics.newTextBatch(font, 'test') + test:assertObject(plaintext) + + -- check height/width/dimensions + test:assertEquals(font:getHeight(), plaintext:getFont():getHeight(), 'check font matches') + local tw, th = plaintext:getDimensions() + test:assertEquals(24, tw, 'check initial dim w') + test:assertEquals(8, th, 'check initial dim h') + test:assertEquals(tw, plaintext:getWidth(), 'check initial dim w') + test:assertEquals(th, plaintext:getHeight(), 'check initial dim h') + + -- check changing text effects dimensions + plaintext:add('more text', 100, 0, 0) + test:assertEquals(49, plaintext:getDimensions(), 'check adding text') + plaintext:set('test') + test:assertEquals(24, plaintext:getDimensions(), 'check resetting text') + plaintext:clear() + test:assertEquals(0, plaintext:getDimensions(), 'check clearing text') + + -- check drawing + setting more complex text + local colortext = love.graphics.newTextBatch(font, {{1, 0, 0, 1}, 'test'}) + test:assertObject(colortext) + colortext:setf('LÖVE is an *awesome* framework you can use to make 2D games in Lua', 60, 'right') + colortext:addf({{1, 1, 0}, 'overlap'}, 1000, 'left') + local font2 = love.graphics.newFont('resources/font.ttf', 8) + colortext:setFont(font2) + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.draw(colortext, 0, 10) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) + +end + + +-- Video (love.graphics.newVideo) +love.test.graphics.Video = function(test) + + -- create video obj + local video = love.graphics.newVideo('resources/sample.ogv') + test:assertObject(video) + + -- check dimensions + local w, h = video:getDimensions() + test:assertEquals(496, w, 'check vid dim w') + test:assertEquals(502, h, 'check vid dim h') + test:assertEquals(w, video:getWidth(), 'check vid width match') + test:assertEquals(h, video:getHeight(), 'check vid height match') + + -- check filters + local min1, mag1, ani1 = video:getFilter() + test:assertEquals('nearest', min1, 'check def filter min') + test:assertEquals('nearest', mag1, 'check def filter mag') + test:assertEquals(1, ani1, 'check def filter ani') + video:setFilter('linear', 'linear', 2) + local min2, mag2, ani2 = video:getFilter() + test:assertEquals('linear', min2, 'check changed filter min') + test:assertEquals('linear', mag2, 'check changed filter mag') + test:assertEquals(2, ani2, 'check changed filter ani') + + -- check video playing + test:assertFalse(video:isPlaying(), 'check paused by default') + test:assertEquals(0, video:tell(), 'check 0:00 by default') + + -- covered by their own obj tests in video but check returns obj + local source = video:getSource() + test:assertObject(source) + local stream = video:getStream() + test:assertObject(stream) + + -- check playing / pausing / seeking states + video:play() + test:waitSeconds(0.25) + video:pause() + -- runners can be a bit funny and just not play anything sometimes + if not GITHUB_RUNNER then + test:assertRange(video:tell(), 0.2, 0.35, 'check video playing for 0.25s') + end + video:seek(0.2) + test:assertEquals(0.2, video:tell(), 'check video seeking') + video:rewind() + test:assertEquals(0, video:tell(), 'check video rewind') + video:setFilter('nearest', 'nearest', 1) + + -- check actuall drawing with the vid + local canvas = love.graphics.newCanvas(500, 500) + love.graphics.setCanvas(canvas) + love.graphics.clear(1, 0, 0, 1) + love.graphics.draw(video, 0, 0) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------DRAWING------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.arc +love.test.graphics.arc = function(test) + -- draw some arcs using pi format + local canvas = love.graphics.newCanvas(32, 32) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.arc('line', "pie", 16, 16, 16, 0 * (math.pi/180), 360 * (math.pi/180), 10) + love.graphics.arc('fill', "pie", 16, 16, 16, 270 * (math.pi/180), 45 * (math.pi/180), 10) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.arc('line', "pie", 16, 16, 16, 0 * (math.pi/180), 90 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.arc('line', "pie", 16, 16, 16, 180 * (math.pi/180), 135 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata1 = love.graphics.readbackTexture(canvas) + -- draw some arcs with open format + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.arc('line', "open", 16, 16, 16, 0 * (math.pi/180), 315 * (math.pi/180), 10) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.arc('fill', "open", 16, 16, 16, 0 * (math.pi/180), 180 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.arc('fill', "open", 16, 16, 16, 180 * (math.pi/180), 270 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + -- draw some arcs with closed format + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.arc('line', "closed", 16, 16, 16, 0 * (math.pi/180), 315 * (math.pi/180), 10) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.arc('fill', "closed", 16, 16, 16, 0 * (math.pi/180), 180 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.arc('line', "closed", 16, 16, 16, 180 * (math.pi/180), 90 * (math.pi/180), 10) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata3 = love.graphics.readbackTexture(canvas) + if GITHUB_RUNNER and test:isOS('OS X') then + -- on macosx runners, the arcs are not drawn as accurately at low res + -- there's a couple pixels different in the curve of the arc but as we + -- are at such a low resolution I think that can be expected + -- on real hardware the test passes fine though + test:assertTrue(true, 'skip test') + else + test:compareImg(imgdata1) + test:compareImg(imgdata2) + test:compareImg(imgdata3) + end +end + + +-- love.graphics.circle +love.test.graphics.circle = function(test) + -- draw some circles + local canvas = love.graphics.newCanvas(32, 32) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.circle('fill', 16, 16, 16) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.circle('line', 16, 16, 16) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.circle('fill', 16, 16, 8) + love.graphics.setColor(0, 1, 0, 1) + love.graphics.circle('fill', 16, 16, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + + +-- love.graphics.clear +love.test.graphics.clear = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.clear(1, 1, 0, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.discard +love.test.graphics.discard = function(test) + -- from the docs: "on some desktops this may do nothing" + test:skipTest('cant test this worked') +end + + +-- love.graphics.draw +love.test.graphics.draw = function(test) + local canvas1 = love.graphics.newCanvas(32, 32) + local canvas2 = love.graphics.newCanvas(32, 32) + local transform = love.math.newTransform( ) + transform:translate(16, 0) + transform:scale(0.5, 0.5) + love.graphics.setCanvas(canvas1) + love.graphics.clear(0, 0, 0, 1) + -- img, offset + love.graphics.draw(Logo.texture, Logo.img, 0, 0, 0, 1, 1, 16, 16) + love.graphics.setCanvas() + love.graphics.setCanvas(canvas2) + love.graphics.clear(1, 0, 0, 1) + -- canvas, scale, shear, transform obj + love.graphics.draw(canvas1, 0, 0, 0, 1, 1, 0, 0, 2, 2) + love.graphics.draw(canvas1, 0, 16, 0, 0.5, 0.5) + love.graphics.draw(canvas1, 16, 16, 0, 0.5, 0.5) + love.graphics.draw(canvas1, transform) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas2) + test:compareImg(imgdata) +end + + +-- love.graphics.drawInstanced +love.test.graphics.drawInstanced = function(test) + local image = love.graphics.newImage('resources/love.png') + local vertices = { + { 0, 0, 0, 0, 1, 0, 0 }, + { image:getWidth(), 0, 1, 0, 0, 1, 0 }, + { image:getWidth(), image:getHeight(), 1, 1, 0, 0, 1 }, + { 0, image:getHeight(), 0, 1, 1, 1, 0 }, + } + local mesh = love.graphics.newMesh(vertices, 'fan') + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.drawInstanced(mesh, 1000, 0, 0, 0, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + -- need 1 tolerance here just cos of the amount of colors + test.rgba_tolerance = 1 + test:compareImg(imgdata) +end + + +-- love.graphics.drawLayer +love.test.graphics.drawLayer = function(test) + local image = love.graphics.newArrayImage({ + 'resources/love.png', 'resources/loveinv.png', + 'resources/love.png', 'resources/loveinv.png' + }) + local canvas = love.graphics.newCanvas(64, 64) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.drawLayer(image, 1, 0, 0, 0, 1, 1) + love.graphics.drawLayer(image, 2, 32, 0, 0, 0.5, 0.5) + love.graphics.drawLayer(image, 4, 0, 32, 0, 0.5, 0.5) + love.graphics.drawLayer(image, 3, 32, 32, 0, 2, 2, 16, 16) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.ellipse +love.test.graphics.ellipse = function(test) + local canvas = love.graphics.newCanvas(32, 32) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.ellipse('fill', 16, 16, 16, 8) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.ellipse('fill', 24, 24, 10, 24) + love.graphics.setColor(1, 0, 1, 1) + love.graphics.ellipse('fill', 16, 0, 8, 16) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.flushBatch +love.test.graphics.flushBatch = function(test) + love.graphics.flushBatch() + local initial = love.graphics.getStats()['drawcalls'] + local canvas = love.graphics.newCanvas(32, 32) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 32, 32) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + love.graphics.flushBatch() + local after = love.graphics.getStats()['drawcalls'] + test:assertEquals(initial+1, after, 'check drawcalls increased') +end + + +-- love.graphics.line +love.test.graphics.line = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.line(1,1,16,1,16,16,1,16,1,1) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.line({0,0,8,8,16,0,8,8,16,16,8,8,0,16}) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.points +love.test.graphics.points = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.push("all") + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.translate(0.5, 0.5) -- draw points at the center of pixels + love.graphics.setColor(1, 0, 0, 1) + love.graphics.points(0,0,15,0,15,15,0,15,0,0) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.points({1,1,7,7,14,1,7,8,14,14,8,8,1,14,8,7}) + love.graphics.pop() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.polygon +love.test.graphics.polygon = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.polygon("fill", 1, 1, 4, 5, 8, 10, 16, 2, 7, 3, 5, 16, 16, 16, 1, 8) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.polygon("line", {2, 2, 4, 5, 3, 7, 8, 15, 12, 4, 5, 10}) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.print +love.test.graphics.print = function(test) + love.graphics.setFont(Font) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.print('love', 0, 3, 0, 1, 1, 0, 0) + love.graphics.setColor(0, 1, 0, 1) + love.graphics.print('ooo', 0, 3, 0, 2, 2, 0, 0) + love.graphics.setColor(0, 0, 1, 1) + love.graphics.print('hello', 0, 3, 90*(math.pi/180), 1, 1, 0, 8) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.printf +love.test.graphics.printf = function(test) + love.graphics.setFont(Font) + local canvas = love.graphics.newCanvas(32, 32) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.printf('love', 0, 0, 8, "left") + love.graphics.setColor(0, 1, 0, 1) + love.graphics.printf('love', 0, 5, 16, "right") + love.graphics.setColor(0, 0, 1, 1) + love.graphics.printf('love', 0, 7, 32, "center") + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.rectangle +love.test.graphics.rectangle = function(test) + -- setup, draw a 16x16 red rectangle with a blue central square + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setColor(0, 0, 1, 1) + love.graphics.rectangle('fill', 6, 6, 4, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata1 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata1) + -- clear canvas to do some line testing + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('line', 1, 1, 15, 15) -- red border + love.graphics.setColor(0, 0, 1, 1) + love.graphics.rectangle('line', 1, 1, 2, 15) -- 3x16 left aligned blue outline + love.graphics.setColor(0, 1, 0, 1) + love.graphics.rectangle('line', 11, 1, 5, 15) -- 6x16 right aligned green outline + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata2) +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +--------------------------------OBJECT CREATION--------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.captureScreenshot +love.test.graphics.captureScreenshot = function(test) + love.graphics.captureScreenshot('example-screenshot.png') + test:waitFrames(1) + -- need to wait until end of the frame for the screenshot + test:assertTrue(love.filesystem.exists('example-screenshot.png')) + love.filesystem.remove('example-screenshot.png') + -- test callback version + local cbdata = nil + local prevtextcommand = TextCommand + TextCommand = "Capturing screenshot" + love.graphics.captureScreenshot(function (idata) + test:assertNotEquals(nil, idata, 'check we have image data') + cbdata = idata + end) + test:waitFrames(1) + TextCommand = prevtextcommand + test:assertNotNil(cbdata) + + if test:isOS('iOS', 'Android') then + -- Mobile operating systems don't let us control the window resolution, + -- so we can't compare the reference image properly. + test:assertTrue(true, 'skip test') + else + test:compareImg(cbdata) + end +end + + +-- love.graphics.newArrayImage +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newArrayImage = function(test) + test:assertObject(love.graphics.newArrayImage({ + 'resources/love.png', 'resources/love2.png', 'resources/love3.png' + })) +end + +-- love.graphics.newCanvas +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newCanvas = function(test) + test:assertObject(love.graphics.newCanvas(16, 16, { + type = '2d', + format = 'normal', + readable = true, + msaa = 0, + dpiscale = 1, + mipmaps = 'none' + })) + test:assertObject(love.graphics.newCanvas(1000, 1000)) +end + + +-- love.graphics.newCubeImage +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newCubeImage = function(test) + test:assertObject(love.graphics.newCubeImage('resources/cubemap.png', { + mipmaps = false, + linear = false + })) +end + + +-- love.graphics.newFont +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newFont = function(test) + test:assertObject(love.graphics.newFont('resources/font.ttf')) + test:assertObject(love.graphics.newFont('resources/font.ttf', 8, "normal", 1)) +end + + +-- love.graphics.newImage +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newImage = function(test) + test:assertObject(love.graphics.newImage('resources/love.png', { + mipmaps = false, + linear = false, + dpiscale = 1 + })) +end + + +-- love.graphics.newImageFont +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newImageFont = function(test) + test:assertObject(love.graphics.newImageFont('resources/love.png', 'ABCD', 1)) +end + + +-- love.graphics.newMesh +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newMesh = function(test) + test:assertObject(love.graphics.newMesh({{1, 1, 0, 0, 1, 1, 1, 1}}, 'fan', 'dynamic')) +end + + +-- love.graphics.newParticleSystem +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newParticleSystem = function(test) + local imgdata = love.graphics.newImage('resources/love.png') + test:assertObject(love.graphics.newParticleSystem(imgdata, 1000)) +end + + +-- love.graphics.newQuad +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newQuad = function(test) + local imgdata = love.graphics.newImage('resources/love.png') + test:assertObject(love.graphics.newQuad(0, 0, 16, 16, imgdata)) +end + + +-- love.graphics.newShader +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newShader = function(test) + local pixelcode = [[ + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texturecolor = Texel(tex, texture_coords); + return texturecolor * color; + } + ]] + local vertexcode = [[ + vec4 position(mat4 transform_projection, vec4 vertex_position) { + return transform_projection * vertex_position; + } + ]] + test:assertObject(love.graphics.newShader(pixelcode, vertexcode)) +end + + +-- love.graphics.newSpriteBatch +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newSpriteBatch = function(test) + local imgdata = love.graphics.newImage('resources/love.png') + test:assertObject(love.graphics.newSpriteBatch(imgdata, 1000)) +end + + +-- love.graphics.newTextBatch +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newTextBatch = function(test) + local font = love.graphics.newFont('resources/font.ttf') + test:assertObject(love.graphics.newTextBatch(font, 'helloworld')) +end + + +-- love.graphics.newTexture +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newTexture = function(test) + local imgdata = love.image.newImageData('resources/love.png') + test:assertObject(love.graphics.newTexture(imgdata)) +end + + +-- love.graphics.newVideo +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newVideo = function(test) + test:assertObject(love.graphics.newVideo('resources/sample.ogv', { + audio = false, + dpiscale = 1 + })) +end + + +-- love.graphics.newVolumeImage +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.graphics.newVolumeImage = function(test) + test:assertObject(love.graphics.newVolumeImage({ + 'resources/love.png', 'resources/love2.png', 'resources/love3.png' + }, { + mipmaps = false, + linear = false + })) +end + + +-- love.graphics.validateShader +love.test.graphics.validateShader = function(test) + local pixelcode = [[ + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texturecolor = Texel(tex, texture_coords); + return texturecolor * color; + } + ]] + local vertexcode = [[ + vec4 position(mat4 transform_projection, vec4 vertex_position) { + return transform_projection * vertex_position; + } + ]] + -- check made up code first + local status, _ = love.graphics.validateShader(true, 'nothing here', 'or here') + test:assertFalse(status, 'check invalid shader code') + -- check real code + status, _ = love.graphics.validateShader(true, pixelcode, vertexcode) + test:assertTrue(status, 'check valid shader code') +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +---------------------------------GRAPHICS STATE--------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.getBackgroundColor +love.test.graphics.getBackgroundColor = function(test) + -- check default bg is black + local r, g, b, a = love.graphics.getBackgroundColor() + test:assertEquals(0, r, 'check default background r') + test:assertEquals(0, g, 'check default background g') + test:assertEquals(0, b, 'check default background b') + test:assertEquals(1, a, 'check default background a') + -- check set value returns correctly + love.graphics.setBackgroundColor(1, 1, 1, 0) + r, g, b, a = love.graphics.getBackgroundColor() + test:assertEquals(1, r, 'check updated background r') + test:assertEquals(1, g, 'check updated background g') + test:assertEquals(1, b, 'check updated background b') + test:assertEquals(0, a, 'check updated background a') + love.graphics.setBackgroundColor(0, 0, 0, 1) -- reset +end + + +-- love.graphics.getBlendMode +love.test.graphics.getBlendMode = function(test) + -- check default blend mode + local mode, alphamode = love.graphics.getBlendMode() + test:assertEquals('alpha', mode, 'check default blend mode') + test:assertEquals('alphamultiply', alphamode, 'check default alpha blend') + -- check set mode returns correctly + love.graphics.setBlendMode('add', 'premultiplied') + mode, alphamode = love.graphics.getBlendMode() + test:assertEquals('add', mode, 'check changed blend mode') + test:assertEquals('premultiplied', alphamode, 'check changed alpha blend') + love.graphics.setBlendMode('alpha', 'alphamultiply') -- reset +end + + +-- love.graphics.getCanvas +love.test.graphics.getCanvas = function(test) + -- by default should be nil if drawing to real screen + test:assertEquals(nil, love.graphics.getCanvas(), 'check no canvas set') + -- should return not nil when we target a canvas + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + test:assertObject(love.graphics.getCanvas()) + love.graphics.setCanvas() +end + + +-- love.graphics.getColor +love.test.graphics.getColor = function(test) + -- by default should be white + local r, g, b, a = love.graphics.getColor() + test:assertEquals(1, r, 'check default color r') + test:assertEquals(1, g, 'check default color g') + test:assertEquals(1, b, 'check default color b') + test:assertEquals(1, a, 'check default color a') + -- check set color is returned correctly + love.graphics.setColor(0, 0, 0, 0) + r, g, b, a = love.graphics.getColor() + test:assertEquals(0, r, 'check changed color r') + test:assertEquals(0, g, 'check changed color g') + test:assertEquals(0, b, 'check changed color b') + test:assertEquals(0, a, 'check changed color a') + love.graphics.setColor(1, 1, 1, 1) -- reset +end + + +-- love.graphics.getColorMask +love.test.graphics.getColorMask = function(test) + -- by default should all be active + local r, g, b, a = love.graphics.getColorMask() + test:assertTrue(r, 'check default color mask r') + test:assertTrue(g, 'check default color mask g') + test:assertTrue(b, 'check default color mask b') + test:assertTrue(a, 'check default color mask a') + -- check set color mask is returned correctly + love.graphics.setColorMask(false, false, true, false) + r, g, b, a = love.graphics.getColorMask() + test:assertFalse(r, 'check changed color mask r') + test:assertFalse(g, 'check changed color mask g') + test:assertTrue( b, 'check changed color mask b') + test:assertFalse(a, 'check changed color mask a') + love.graphics.setColorMask(true, true, true, true) -- reset +end + + +-- love.graphics.getDefaultFilter +love.test.graphics.getDefaultFilter = function(test) + -- we set this already for testsuite so we know what it should be + local min, mag, anisotropy = love.graphics.getDefaultFilter() + test:assertEquals('nearest', min, 'check default filter min') + test:assertEquals('nearest', mag, 'check default filter mag') + test:assertEquals(1, anisotropy, 'check default filter mag') +end + + +-- love.graphics.getDepthMode +love.test.graphics.getDepthMode = function(test) + -- by default should be always/write + local comparemode, write = love.graphics.getDepthMode() + test:assertEquals('always', comparemode, 'check default compare depth') + test:assertFalse(write, 'check default depth buffer write') +end + + +-- love.graphics.getFont +love.test.graphics.getFont = function(test) + test:assertObject(love.graphics.getFont()) +end + + +-- love.graphics.getFrontFaceWinding +love.test.graphics.getFrontFaceWinding = function(test) + -- check default winding + test:assertEquals('ccw', love.graphics.getFrontFaceWinding()) + -- check setting value changes it correctly + love.graphics.setFrontFaceWinding('cw') + test:assertEquals('cw', love.graphics.getFrontFaceWinding()) + love.graphics.setFrontFaceWinding('ccw') -- reset +end + + +-- love.graphics.getLineJoin +love.test.graphics.getLineJoin = function(test) + -- check default line join + test:assertEquals('miter', love.graphics.getLineJoin()) + -- check set value returned correctly + love.graphics.setLineJoin('none') + test:assertEquals('none', love.graphics.getLineJoin()) + love.graphics.setLineJoin('miter') -- reset +end + + +-- love.graphics.getLineStyle +love.test.graphics.getLineStyle = function(test) + -- we know this should be as testsuite sets it! + test:assertEquals('rough', love.graphics.getLineStyle()) + -- check set value returned correctly + love.graphics.setLineStyle('smooth') + test:assertEquals('smooth', love.graphics.getLineStyle()) + love.graphics.setLineStyle('rough') -- reset +end + + +-- love.graphics.getLineWidth +love.test.graphics.getLineWidth = function(test) + -- we know this should be as testsuite sets it! + test:assertEquals(1, love.graphics.getLineWidth()) + -- check set value returned correctly + love.graphics.setLineWidth(10) + test:assertEquals(10, love.graphics.getLineWidth()) + love.graphics.setLineWidth(1) -- reset +end + + +-- love.graphics.getMeshCullMode +love.test.graphics.getMeshCullMode = function(test) + -- get default mesh culling + test:assertEquals('none', love.graphics.getMeshCullMode()) + -- check set value returned correctly + love.graphics.setMeshCullMode('front') + test:assertEquals('front', love.graphics.getMeshCullMode()) + love.graphics.setMeshCullMode('back') -- reset +end + + +-- love.graphics.getPointSize +love.test.graphics.getPointSize = function(test) + -- get default point size + test:assertEquals(1, love.graphics.getPointSize()) + -- check set value returned correctly + love.graphics.setPointSize(10) + test:assertEquals(10, love.graphics.getPointSize()) + love.graphics.setPointSize(1) -- reset +end + + +-- love.graphics.getScissor +love.test.graphics.getScissor = function(test) + -- should be no scissor atm + local x, y, w, h = love.graphics.getScissor() + test:assertEquals(nil, x, 'check no scissor') + test:assertEquals(nil, y, 'check no scissor') + test:assertEquals(nil, w, 'check no scissor') + test:assertEquals(nil, h, 'check no scissor') + -- check set value returned correctly + love.graphics.setScissor(0, 0, 16, 16) + x, y, w, h = love.graphics.getScissor() + test:assertEquals(0, x, 'check scissor set') + test:assertEquals(0, y, 'check scissor set') + test:assertEquals(16, w, 'check scissor set') + test:assertEquals(16, h, 'check scissor set') + love.graphics.setScissor() -- reset +end + + +-- love.graphics.getShader +love.test.graphics.getShader = function(test) + -- should be no shader active + test:assertEquals(nil, love.graphics.getShader(), 'check no active shader') +end + + +-- love.graphics.getStackDepth +love.test.graphics.getStackDepth = function(test) + -- by default should be none + test:assertEquals(0, love.graphics.getStackDepth(), 'check no transforms in stack') + -- now add 3 + love.graphics.push() + love.graphics.push() + love.graphics.push() + test:assertEquals(3, love.graphics.getStackDepth(), 'check 3 transforms in stack') + -- now remove 2 + love.graphics.pop() + love.graphics.pop() + test:assertEquals(1, love.graphics.getStackDepth(), 'check 1 transforms in stack') + -- now back to 0 + love.graphics.pop() + test:assertEquals(0, love.graphics.getStackDepth(), 'check no transforms in stack') +end + + +-- love.graphics.getStencilState +love.test.graphics.getStencilState = function(test) + -- check default vals + local action, comparemode, value = love.graphics.getStencilState( ) + test:assertEquals('keep', action, 'check default stencil action') + test:assertEquals('always', comparemode, 'check default stencil compare') + test:assertEquals(0, value, 'check default stencil value') + -- check set stencil values is returned + love.graphics.setStencilState('replace', 'less', 255) + local action, comparemode, value = love.graphics.getStencilState() + test:assertEquals('replace', action, 'check changed stencil action') + test:assertEquals('less', comparemode, 'check changed stencil compare') + test:assertEquals(255, value, 'check changed stencil value') + love.graphics.setStencilState() -- reset +end + + +-- love.graphics.intersectScissor +love.test.graphics.intersectScissor = function(test) + -- make a scissor for the left half, then interset to make the top half + -- then we should be able to fill the canvas with red and only top 4x4 is filled + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.origin() + love.graphics.setScissor(0, 0, 8, 16) + love.graphics.intersectScissor(0, 0, 4, 4) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setScissor() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.isActive +love.test.graphics.isActive = function(test) + test:assertTrue(love.graphics.isActive(), 'check graphics is active') -- i mean if you got this far +end + + +-- love.graphics.isGammaCorrect +love.test.graphics.isGammaCorrect = function(test) + -- we know the config so know this is false + test:assertNotNil(love.graphics.isGammaCorrect()) +end + + +-- love.graphics.isWireframe +love.test.graphics.isWireframe = function(test) + local name, version, vendor, device = love.graphics.getRendererInfo() + if string.match(name, 'OpenGL ES') then + test:skipTest('Wireframe not supported on OpenGL ES') + else + -- check off by default + test:assertFalse(love.graphics.isWireframe(), 'check no wireframe by default') + -- check on when enabled + love.graphics.setWireframe(true) + test:assertTrue(love.graphics.isWireframe(), 'check wireframe is set') + love.graphics.setWireframe(false) -- reset + end +end + + +-- love.graphics.reset +love.test.graphics.reset = function(test) + -- reset should reset current canvas and any colors/scissor + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setBackgroundColor(0, 0, 1, 1) + love.graphics.setColor(0, 1, 0, 1) + love.graphics.setCanvas(canvas) + love.graphics.reset() + local r, g, b, a = love.graphics.getBackgroundColor() + test:assertEquals(1, r+g+b+a, 'check background reset') + r, g, b, a = love.graphics.getColor() + test:assertEquals(4, r+g+b+a, 'check color reset') + test:assertEquals(nil, love.graphics.getCanvas(), 'check canvas reset') + love.graphics.setDefaultFilter("nearest", "nearest") + love.graphics.setLineStyle('rough') + love.graphics.setPointSize(1) + love.graphics.setLineWidth(1) +end + + +-- love.graphics.setBackgroundColor +love.test.graphics.setBackgroundColor = function(test) + -- check background is set + love.graphics.setBackgroundColor(1, 0, 0, 1) + local r, g, b, a = love.graphics.getBackgroundColor() + test:assertEquals(1, r, 'check set bg r') + test:assertEquals(0, g, 'check set bg g') + test:assertEquals(0, b, 'check set bg b') + test:assertEquals(1, a, 'check set bg a') + love.graphics.setBackgroundColor(0, 0, 0, 1) +end + + +-- love.graphics.setBlendMode +love.test.graphics.setBlendMode = function(test) + -- create fully white canvas, then draw diff. pixels through blendmodes + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0.5, 0.5, 0.5, 1) + love.graphics.setBlendMode('add', 'alphamultiply') + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setBlendMode('subtract', 'alphamultiply') + love.graphics.setColor(1, 1, 1, 0.5) + love.graphics.rectangle('fill', 15, 0, 1, 1) + love.graphics.setBlendMode('multiply', 'premultiplied') + love.graphics.setColor(0, 1, 0, 1) + love.graphics.rectangle('fill', 15, 15, 1, 1) + love.graphics.setBlendMode('replace', 'premultiplied') + love.graphics.setColor(0, 0, 1, 0.5) + love.graphics.rectangle('fill', 0, 15, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + love.graphics.setBlendMode('alpha', 'alphamultiply') -- reset + -- need 1rgba tolerance here on some machines + test.rgba_tolerance = 1 + test:compareImg(imgdata) +end + + +-- love.graphics.setCanvas +love.test.graphics.setCanvas = function(test) + -- make 2 canvas, set to each, draw one to the other, check output + local canvas1 = love.graphics.newCanvas(16, 16) + local canvas2 = love.graphics.newCanvas(16, 16, {mipmaps = "auto"}) + love.graphics.setCanvas(canvas1) + test:assertEquals(canvas1, love.graphics.getCanvas(), 'check canvas 1 set') + love.graphics.clear(1, 0, 0, 1) + love.graphics.setCanvas(canvas2) + test:assertEquals(canvas2, love.graphics.getCanvas(), 'check canvas 2 set') + love.graphics.clear(0, 0, 0, 1) + love.graphics.draw(canvas1, 0, 0) + love.graphics.setCanvas() + test:assertEquals(nil, love.graphics.getCanvas(), 'check no canvas set') + local imgdata = love.graphics.readbackTexture(canvas2) + test:compareImg(imgdata) + local imgdata2 = love.graphics.readbackTexture(canvas2, 1, 2) -- readback mipmap + test:compareImg(imgdata2) +end + + +-- love.graphics.setColor +love.test.graphics.setColor = function(test) + -- set colors, draw rect, check color + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + local r, g, b, a = love.graphics.getColor() + test:assertEquals(1, r, 'check r set') + test:assertEquals(0, g, 'check g set') + test:assertEquals(0, b, 'check b set') + test:assertEquals(1, a, 'check a set') + + love.graphics.rectangle('fill', 0, 0, 16, 1) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.rectangle('fill', 0, 1, 16, 1) + love.graphics.setColor(0, 1, 0, 0.5) + love.graphics.rectangle('fill', 0, 2, 16, 1) + love.graphics.setColor(0, 0, 1, 1) + love.graphics.rectangle('fill', 0, 3, 16, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setColorMask +love.test.graphics.setColorMask = function(test) + -- set mask, draw stuff, check output pixels + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + -- mask off blue + love.graphics.setColorMask(true, true, false, true) + local r, g, b, a = love.graphics.getColorMask() + test:assertEquals(r, true, 'check r mask') + test:assertEquals(g, true, 'check g mask') + test:assertEquals(b, false, 'check b mask') + test:assertEquals(a, true, 'check a mask') + -- draw "black" which should then turn to yellow + love.graphics.setColor(1, 1, 1, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setColorMask(true, true, true, true) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setDefaultFilter +love.test.graphics.setDefaultFilter = function(test) + -- check setting filter val works + love.graphics.setDefaultFilter('linear', 'linear', 1) + local min, mag, anisotropy = love.graphics.getDefaultFilter() + test:assertEquals('linear', min, 'check default filter min') + test:assertEquals('linear', mag, 'check default filter mag') + test:assertEquals(1, anisotropy, 'check default filter mag') + love.graphics.setDefaultFilter('nearest', 'nearest', 1) -- reset +end + + +-- love.graphics.setDepthMode +love.test.graphics.setDepthMode = function(test) + -- check documented modes are valid + local comparemode, write = love.graphics.getDepthMode() + local modes = { + 'equal', 'notequal', 'less', 'lequal', 'gequal', + 'greater', 'never', 'always' + } + for m=1,#modes do + love.graphics.setDepthMode(modes[m], true) + test:assertEquals(modes[m], love.graphics.getDepthMode(), 'check depth mode ' .. modes[m] .. ' set') + end + love.graphics.setDepthMode(comparemode, write) + -- @TODO better graphics drawing specific test +end + + +-- love.graphics.setFont +love.test.graphics.setFont = function(test) + -- set font doesnt return anything so draw with the test font + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setFont(Font) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.print('love', 0, 3) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setFrontFaceWinding +love.test.graphics.setFrontFaceWinding = function(test) + -- check documented modes are valid + local original = love.graphics.getFrontFaceWinding() + love.graphics.setFrontFaceWinding('cw') + test:assertEquals('cw', love.graphics.getFrontFaceWinding(), 'check ffw cw set') + love.graphics.setFrontFaceWinding('ccw') + test:assertEquals('ccw', love.graphics.getFrontFaceWinding(), 'check ffw ccw set') + love.graphics.setFrontFaceWinding(original) + -- @TODO better graphics drawing specific test + + local shader = love.graphics.newShader[[ +vec4 effect(vec4 c, Image tex, vec2 tc, vec2 pc) { + return gl_FrontFacing ? vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0); +} + ]] + local dummyimg = love.graphics.newImage(love.image.newImageData(1, 1)) + + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.push("all") + love.graphics.setCanvas(canvas) + love.graphics.setShader(shader) + love.graphics.draw(dummyimg, 0, 0, 0, 16, 16) + love.graphics.pop() + + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setLineJoin +love.test.graphics.setLineJoin = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setFont(Font) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + local line = {0,1,8,1,8,8} + love.graphics.setLineStyle('rough') + love.graphics.setLineWidth(2) + love.graphics.setColor(1, 0, 0) + love.graphics.setLineJoin('bevel') + love.graphics.line(line) + love.graphics.translate(0, 4) + love.graphics.setColor(1, 1, 0) + love.graphics.setLineJoin('none') + love.graphics.line(line) + love.graphics.translate(0, 4) + love.graphics.setColor(0, 0, 1) + love.graphics.setLineJoin('miter') + love.graphics.line(line) + love.graphics.setColor(1, 1, 1) + love.graphics.setLineWidth(1) + love.graphics.origin() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setLineStyle +love.test.graphics.setLineStyle = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setFont(Font) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0) + local line = {0,1,16,1} + love.graphics.setLineStyle('rough') + love.graphics.line(line) + love.graphics.translate(0, 4) + love.graphics.setLineStyle('smooth') + love.graphics.line(line) + love.graphics.setLineStyle('rough') + love.graphics.setColor(1, 1, 1) + love.graphics.origin() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + -- linux runner needs a 1/255 tolerance for the blend between a rough line + bg + if GITHUB_RUNNER and test:isOS('Linux') then + test.rgba_tolerance = 1 + end + test:compareImg(imgdata) +end + + +-- love.graphics.setLineWidth +love.test.graphics.setLineWidth = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setFont(Font) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + local line = {0,1,8,1,8,8} + love.graphics.setColor(1, 0, 0) + love.graphics.setLineWidth(2) + love.graphics.line(line) + love.graphics.translate(0, 4) + love.graphics.setColor(1, 1, 0) + love.graphics.setLineWidth(3) + love.graphics.line(line) + love.graphics.translate(0, 4) + love.graphics.setColor(0, 0, 1) + love.graphics.setLineWidth(4) + love.graphics.line(line) + love.graphics.setColor(1, 1, 1) + love.graphics.setLineWidth(1) + love.graphics.origin() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setMeshCullMode +love.test.graphics.setMeshCullMode = function(test) + -- check documented modes are valid + local original = love.graphics.getMeshCullMode() + local modes = {'back', 'front', 'none'} + for m=1,#modes do + love.graphics.setMeshCullMode(modes[m]) + test:assertEquals(modes[m], love.graphics.getMeshCullMode(), 'check mesh cull mode ' .. modes[m] .. ' was set') + end + love.graphics.setMeshCullMode(original) + -- @TODO better graphics drawing specific test +end + + +-- love.graphics.setScissor +love.test.graphics.setScissor = function(test) + -- make a scissor for the left half + -- then we should be able to fill the canvas with red and only left is filled + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.origin() + love.graphics.setScissor(0, 0, 8, 16) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setScissor() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setShader +love.test.graphics.setShader = function(test) + -- make a shader that will only ever draw yellow + local pixelcode = [[ + vec4 effect(vec4 color, Image tex, vec2 texture_coords, vec2 screen_coords) { + vec4 texturecolor = Texel(tex, texture_coords); + return vec4(1.0,1.0,0.0,1.0); + } + ]] + local vertexcode = [[ + vec4 position(mat4 transform_projection, vec4 vertex_position) { + return transform_projection * vertex_position; + } + ]] + local shader = love.graphics.newShader(pixelcode, vertexcode) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setShader(shader) + -- draw red rectangle + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setShader() + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setStencilState +love.test.graphics.setStencilState = function(test) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas({canvas, stencil=true}) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setStencilState('replace', 'always', 1) + love.graphics.circle('fill', 8, 8, 6) + love.graphics.setStencilState('keep', 'greater', 0) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 16, 16) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setStencilState() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.setWireframe +love.test.graphics.setWireframe = function(test) + local name, version, vendor, device = love.graphics.getRendererInfo() + if string.match(name, 'OpenGL ES') then + test:skipTest('Wireframe not supported on OpenGL ES') + else + -- check wireframe outlines + love.graphics.setWireframe(true) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 1, 0, 1) + love.graphics.rectangle('fill', 2, 2, 13, 13) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + love.graphics.setWireframe(false) + local imgdata = love.graphics.readbackTexture(canvas) + -- on macOS runners wireframes are drawn 1px off from the target + if GITHUB_RUNNER and test:isOS('OS X') then + test.pixel_tolerance = 1 + end + test:compareImg(imgdata) + end +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------COORDINATE SYSTEM-------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.applyTransform +love.test.graphics.applyTransform = function(test) + -- use transform object to translate the drawn rectangle + local transform = love.math.newTransform() + transform:translate(10, 0) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.applyTransform(transform) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.inverseTransformPoint +love.test.graphics.inverseTransformPoint = function(test) + -- start with 0, 0 + local sx, sy = love.graphics.inverseTransformPoint(0, 0) + test:assertEquals(0, sx, 'check starting x is 0') + test:assertEquals(0, sy, 'check starting y is 0') + -- check translation effects the point + love.graphics.translate(1, 5) + sx, sy = love.graphics.inverseTransformPoint(1, 5) + test:assertEquals(0, sx, 'check transformed x is 0') + test:assertEquals(0, sy, 'check transformed y is 0') + love.graphics.origin() +end + + +-- love.graphics.origin +love.test.graphics.origin = function(test) + -- if we do some translations and scaling + -- using .origin() should reset it all and draw the pixel at 0,0 + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.origin() + love.graphics.translate(10, 10) + love.graphics.scale(1, 1) + love.graphics.shear(20, 20) + love.graphics.origin() + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.pop +love.test.graphics.pop = function(test) + -- if we push at the start, and then run a pop + -- it should reset it all and draw the pixel at 0,0 + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.push() + love.graphics.translate(10, 10) + love.graphics.scale(1, 1) + love.graphics.shear(20, 20) + love.graphics.pop() + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.push +love.test.graphics.push = function(test) + -- if we push at the start, do some stuff, then another push + -- 1 pop should only go back 1 push and draw the pixel at 1, 1 + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.push() + love.graphics.scale(1, 1) + love.graphics.shear(20, 20) + love.graphics.push() + love.graphics.translate(1, 1) + love.graphics.pop() + love.graphics.setColor(1, 0, 0, 1) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.pop() + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.replaceTransform +love.test.graphics.replaceTransform = function(test) + -- if use transform object to translate + -- set some normal transforms first which should get overwritten + local transform = love.math.newTransform() + transform:translate(10, 0) + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.scale(2, 2) + love.graphics.translate(10, 10) + love.graphics.replaceTransform(transform) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.rotate +love.test.graphics.rotate = function(test) + -- starting at 0,0, we rotate by 90deg and then draw + -- we can then check the drawn rectangle is rotated + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.translate(4, 0) + love.graphics.rotate(90 * (math.pi/180)) + love.graphics.rectangle('fill', 0, 0, 4, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.scale +love.test.graphics.scale = function(test) + -- starting at 0,0, we scale by 4x and then draw + -- we can then check the drawn rectangle covers the whole canvas + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.scale(4, 4) + love.graphics.rectangle('fill', 0, 0, 4, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-- love.graphics.shear +love.test.graphics.shear = function(test) + -- starting at 0,0, we shear by 2x and then draw + -- we can then check the drawn rectangle has moved over + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.origin() + love.graphics.setColor(1, 0, 0, 1) + love.graphics.shear(2, 0) + love.graphics.rectangle('fill', 0, 0, 4, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata1 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata1) + -- same again at 0,0, we shear by 2y and then draw + -- we can then check the drawn rectangle has moved down + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.origin() + love.graphics.setColor(1, 0, 0, 1) + love.graphics.shear(0, 2) + love.graphics.rectangle('fill', 0, 0, 4, 4) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata2 = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata2) +end + + +-- love.graphics.transformPoint +love.test.graphics.transformPoint = function(test) + -- start with 0, 0 + local sx, sy = love.graphics.transformPoint(0, 0) + test:assertEquals(0, sx, 'check starting x is 0') + test:assertEquals(0, sy, 'check starting y is 0') + -- check translation effects the point + love.graphics.translate(1, 5) + sx, sy = love.graphics.transformPoint(0, 0) + test:assertEquals(1, sx, 'check transformed x is 0') + test:assertEquals(5, sy, 'check transformed y is 10') +end + + +-- love.graphics.translate +love.test.graphics.translate = function(test) + -- starting at 0,0, we translate 4 times and draw a pixel at each point + -- we can then check the 4 points are now red + local canvas = love.graphics.newCanvas(16, 16) + love.graphics.setCanvas(canvas) + love.graphics.clear(0, 0, 0, 1) + love.graphics.setColor(1, 0, 0, 1) + love.graphics.translate(5, 0) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.translate(0, 5) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.translate(-5, 0) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.translate(0, -5) + love.graphics.rectangle('fill', 0, 0, 1, 1) + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setCanvas() + local imgdata = love.graphics.readbackTexture(canvas) + test:compareImg(imgdata) +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------WINDOW------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.getDPIScale +-- @NOTE hardware dependent so can't check result +love.test.graphics.getDPIScale = function(test) + test:assertNotNil(love.graphics.getDPIScale()) +end + + +-- love.graphics.getDimensions +love.test.graphics.getDimensions = function(test) + -- check graphics dimensions match window dimensions + local gwidth, gheight = love.graphics.getDimensions() + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wwidth, gwidth, 'check graphics dimension w matches window w') + test:assertEquals(wheight, gheight, 'check graphics dimension h matches window h') +end + + +-- love.graphics.getHeight +love.test.graphics.getHeight = function(test) + -- check graphics height match window height + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wheight, love.graphics.getHeight(), 'check graphics h matches window h') +end + + +-- love.graphics.getPixelDimensions +love.test.graphics.getPixelDimensions = function(test) + -- check graphics dimensions match window dimensions relative to dpi + local dpi = love.graphics.getDPIScale() + local gwidth, gheight = love.graphics.getPixelDimensions() + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wwidth, gwidth/dpi, 'check graphics pixel dpi w matches window w') + test:assertEquals(wheight, gheight/dpi, 'check graphics pixel dpi h matches window h') +end + + +-- love.graphics.getPixelHeight +love.test.graphics.getPixelHeight = function(test) + -- check graphics height match window height relative to dpi + local dpi = love.graphics.getDPIScale() + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wheight,love.graphics.getPixelHeight()/dpi, 'check graphics pixel dpi h matches window h') +end + + +-- love.graphics.getPixelWidth +love.test.graphics.getPixelWidth = function(test) + -- check graphics width match window width relative to dpi + local dpi = love.graphics.getDPIScale() + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wwidth, love.graphics.getWidth()/dpi, 'check graphics pixel dpi w matches window w') +end + + +-- love.graphics.getWidth +love.test.graphics.getWidth = function(test) + -- check graphics width match window width + local wwidth, wheight, _ = love.window.getMode() + test:assertEquals(wwidth, love.graphics.getWidth(), 'check graphics w matches window w') +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------SYSTEM INFORMATION------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.graphics.getTextureFormats +love.test.graphics.getTextureFormats = function(test) + local formats = { + 'hdr', 'r8i', 'r8ui', 'r16i', 'r16ui', 'r32i', 'r32ui', 'rg8i', 'rg8ui', + 'rg16i', 'rg16ui', 'rg32i', 'rg32ui', 'bgra8', 'r8', 'rgba8i', 'rgba8ui', + 'rgba16i', 'rg8', 'rgba32i', 'rgba32ui', 'rgba8', 'DXT1', 'r16', 'DXT5', + 'rg16', 'BC4s', 'rgba16', 'BC5s', 'r16f', 'BC6hs', 'BC7', 'PVR1rgb2', + 'rg16f', 'PVR1rgba2', 'rgba16f', 'ETC1', 'r32f', 'ETC2rgba', 'rg32f', + 'EACr', 'rgba32f', 'EACrg', 'rgba4', 'ASTC4x4', 'ASTC5x4', 'rgb5a1', + 'ASTC6x5', 'rgb565', 'ASTC8x5', 'ASTC8x6', 'rgb10a2', 'ASTC10x5', + 'rg11b10f', 'ASTC10x8', 'ASTC10x10', 'ASTC12x10', 'ASTC12x12', 'normal', + 'srgba8', 'la8', 'ASTC10x6', 'ASTC8x8', 'ASTC6x6', 'ASTC5x5', 'EACrgs', + 'EACrs', 'ETC2rgba1', 'ETC2rgb', 'PVR1rgba4', 'PVR1rgb4', 'BC6h', + 'BC5', 'BC4', 'DXT3', 'rgba16ui', 'bgra8srgb', + 'depth16', 'depth24', 'depth32f', 'depth24stencil8', 'depth32fstencil8', 'stencil8' + } + local supported = love.graphics.getTextureFormats({ canvas = true }) + test:assertNotNil(supported) + for f=1,#formats do + test:assertNotEquals(nil, supported[formats[f] ], 'expected a key for format: ' .. formats[f]) + end +end + + +-- love.graphics.getRendererInfo +-- @NOTE hardware dependent so best can do is nil checking +love.test.graphics.getRendererInfo = function(test) + local name, version, vendor, device = love.graphics.getRendererInfo() + test:assertNotNil(name) + test:assertNotNil(version) + test:assertNotNil(vendor) + test:assertNotNil(device) +end + + +-- love.graphics.getStats +-- @NOTE cant really predict some of these so just nil check for most +love.test.graphics.getStats = function(test) + local stattypes = { + 'drawcalls', 'canvasswitches', 'texturememory', 'shaderswitches', + 'drawcallsbatched', 'textures', 'fonts' + } + local stats = love.graphics.getStats() + for s=1,#stattypes do + test:assertNotEquals(nil, stats[stattypes[s] ], 'expected a key for stat: ' .. stattypes[s]) + end +end + + +-- love.graphics.getSupported +love.test.graphics.getSupported = function(test) + -- cant check values as hardware dependent but we can check the keys in the + -- table match what the documentation lists + local gfs = { + 'clampzero', 'lighten', 'glsl3', 'instancing', 'fullnpot', + 'pixelshaderhighp', 'shaderderivatives', 'indirectdraw', + 'copytexturetobuffer', 'multirendertargetformats', + 'clampone', 'glsl4' + } + local features = love.graphics.getSupported() + for g=1,#gfs do + test:assertNotEquals(nil, features[gfs[g] ], 'expected a key for graphic feature: ' .. gfs[g]) + end +end + + +-- love.graphics.getSystemLimits +love.test.graphics.getSystemLimits = function(test) + -- cant check values as hardware dependent but we can check the keys in the + -- table match what the documentation lists + local glimits = { + 'texelbuffersize', 'shaderstoragebuffersize', 'threadgroupsx', + 'threadgroupsy', 'pointsize', 'texturesize', 'texturelayers', 'volumetexturesize', + 'cubetexturesize', 'anisotropy', 'texturemsaa', 'rendertargets', 'threadgroupsz' + } + local limits = love.graphics.getSystemLimits() + for g=1,#glimits do + test:assertNotEquals(nil, limits[glimits[g] ], 'expected a key for system limit: ' .. glimits[g]) + end +end + + +-- love.graphics.getTextureTypes +love.test.graphics.getTextureTypes = function(test) + -- cant check values as hardware dependent but we can check the keys in the + -- table match what the documentation lists + local ttypes = { + '2d', 'array', 'cube', 'volume' + } + local types = love.graphics.getTextureTypes() + for t=1,#ttypes do + test:assertNotEquals(nil, types[ttypes[t] ], 'expected a key for texture type: ' .. ttypes[t]) + end +end diff --git a/testing/tests/image.lua b/testing/tests/image.lua new file mode 100644 index 000000000..db98882d4 --- /dev/null +++ b/testing/tests/image.lua @@ -0,0 +1,136 @@ +-- love.image + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- CompressedImageData (love.image.newCompressedImageData) +love.test.image.CompressedImageData = function(test) + + -- create obj + local idata = love.image.newCompressedData('resources/love.dxt1') + test:assertObject(idata) + + -- check string + size + test:assertNotEquals(nil, idata:getString(), 'check data string') + test:assertEquals(2744, idata:getSize(), 'check data size') + + -- check img dimensions + local iw, ih = idata:getDimensions() + test:assertEquals(64, iw, 'check image dimension w') + test:assertEquals(64, ih, 'check image dimension h') + test:assertEquals(64, idata:getWidth(), 'check image direct w') + test:assertEquals(64, idata:getHeight(), 'check image direct h') + + -- check format + test:assertEquals('DXT1', idata:getFormat(), 'check image format') + + -- check mipmap count + test:assertEquals(7, idata:getMipmapCount(), 'check mipmap count') + + -- check linear + test:assertFalse(idata:isLinear(), 'check not linear') + idata:setLinear(true) + test:assertTrue(idata:isLinear(), 'check now linear') + +end + + +-- ImageData (love.image.newImageData) +love.test.image.ImageData = function(test) + + -- create obj + local idata = love.image.newImageData('resources/love.png') + test:assertObject(idata) + + -- check string + size + test:assertNotEquals(nil, idata:getString(), 'check data string') + test:assertEquals(16384, idata:getSize(), 'check data size') + + -- check img dimensions + local iw, ih = idata:getDimensions() + test:assertEquals(64, iw, 'check image dimension w') + test:assertEquals(64, ih, 'check image dimension h') + test:assertEquals(64, idata:getWidth(), 'check image direct w') + test:assertEquals(64, idata:getHeight(), 'check image direct h') + + -- check format + test:assertEquals('rgba8', idata:getFormat(), 'check image format') + + -- manipulate image data so white heart is black + local mapdata = function(x, y, r, g, b, a) + if r == 1 and g == 1 and b == 1 then + r = 0; g = 0; b = 0 + end + return r, g, b, a + end + idata:mapPixel(mapdata, 0, 0, 64, 64) + local r1, g1, b1 = idata:getPixel(25, 25) + test:assertEquals(0, r1+g1+b1, 'check mapped black') + + -- map some other data into the idata + local idata2 = love.image.newImageData('resources/loveinv.png') + idata:paste(idata2, 0, 0, 0, 0) + r1, g1, b1 = idata:getPixel(25, 25) + test:assertEquals(3, r1+g1+b1, 'check back to white') + + -- set pixels directly + idata:setPixel(25, 25, 1, 0, 0, 1) + local r2, g2, b2 = idata:getPixel(25, 25) + test:assertEquals(1, r2+g2+b2, 'check set to red') + + -- check encoding to an image (png) + idata:encode('png', 'test-encode.png') + local read1 = love.filesystem.openFile('test-encode.png', 'r') + test:assertNotNil(read1) + love.filesystem.remove('test-encode.png') + + -- check encoding to an image (exr) + local edata = love.image.newImageData(100, 100, 'r16f') + edata:encode('exr', 'test-encode.exr') + local read2 = love.filesystem.openFile('test-encode.exr', 'r') + test:assertNotNil(read2) + love.filesystem.remove('test-encode.exr') + + -- check linear + test:assertFalse(idata:isLinear(), 'check not linear') + idata:setLinear(true) + test:assertTrue(idata:isLinear(), 'check now linear') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.image.isCompressed +-- @NOTE really we need to test each of the files listed here: +-- https://love2d.org/wiki/CompressedImageFormat +-- also need to be platform dependent (e.g. dxt not suppored on phones) +love.test.image.isCompressed = function(test) + test:assertTrue(love.image.isCompressed('resources/love.dxt1'), + 'check dxt1 valid compressed image') +end + + +-- love.image.newCompressedData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.image.newCompressedData = function(test) + test:assertObject(love.image.newCompressedData('resources/love.dxt1')) +end + + +-- love.image.newImageData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.image.newImageData = function(test) + test:assertObject(love.image.newImageData('resources/love.png')) + test:assertObject(love.image.newImageData(16, 16, 'rgba8', nil)) +end diff --git a/testing/tests/joystick.lua b/testing/tests/joystick.lua new file mode 100644 index 000000000..584422ef8 --- /dev/null +++ b/testing/tests/joystick.lua @@ -0,0 +1,81 @@ +-- love.joystick +-- @NOTE we can't test this module fully as it's hardware dependent +-- however we can test methods do what is expected and can handle certain params + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.joystick.getGamepadMappingString +love.test.joystick.getGamepadMappingString = function(test) + local mapping = love.joystick.getGamepadMappingString('faker') + test:assertEquals(nil, mapping, 'check no mapping for fake gui') +end + + +-- love.joystick.getJoystickCount +love.test.joystick.getJoystickCount = function(test) + local count = love.joystick.getJoystickCount() + test:assertGreaterEqual(0, count, 'check number') +end + + +-- love.joystick.getJoysticks +love.test.joystick.getJoysticks = function(test) + local joysticks = love.joystick.getJoysticks() + test:assertGreaterEqual(0, #joysticks, 'check is count') +end + + +-- love.joystick.loadGamepadMappings +love.test.joystick.loadGamepadMappings = function(test) + local ok, err = pcall(love.joystick.loadGamepadMappings, 'fakefile.txt') + test:assertEquals(false, ok, 'check invalid file') + love.joystick.loadGamepadMappings('resources/mappings.txt') +end + + +-- love.joystick.saveGamepadMappings +love.test.joystick.saveGamepadMappings = function(test) + love.joystick.loadGamepadMappings('resources/mappings.txt') + local mapping = love.joystick.saveGamepadMappings() + test:assertGreaterEqual(0, #mapping, 'check something mapped') +end + + +-- love.joystick.setGamepadMapping +love.test.joystick.setGamepadMapping = function(test) + local guid = '030000005e040000130b000011050000' + local mappings = { + love.joystick.setGamepadMapping(guid, 'a', 'button', 1, nil), + love.joystick.setGamepadMapping(guid, 'b', 'button', 2, nil), + love.joystick.setGamepadMapping(guid, 'x', 'button', 3, nil), + love.joystick.setGamepadMapping(guid, 'y', 'button', 4, nil), + love.joystick.setGamepadMapping(guid, 'back', 'button', 5, nil), + love.joystick.setGamepadMapping(guid, 'start', 'button', 6, nil), + love.joystick.setGamepadMapping(guid, 'guide', 'button', 7, nil), + love.joystick.setGamepadMapping(guid, 'leftstick', 'button', 8, nil), + love.joystick.setGamepadMapping(guid, 'leftshoulder', 'button', 9, nil), + love.joystick.setGamepadMapping(guid, 'rightstick', 'button', 10, nil), + love.joystick.setGamepadMapping(guid, 'rightshoulder', 'button', 11, nil), + love.joystick.setGamepadMapping(guid, 'dpup', 'button', 12, nil), + love.joystick.setGamepadMapping(guid, 'dpdown', 'button', 13, nil), + love.joystick.setGamepadMapping(guid, 'dpleft', 'button', 14, nil), + love.joystick.setGamepadMapping(guid, 'dpright', 'button', 15, nil), + love.joystick.setGamepadMapping(guid, 'dpup', 'button', 12, 'u'), + love.joystick.setGamepadMapping(guid, 'dpdown', 'button', 13, 'd'), + love.joystick.setGamepadMapping(guid, 'dpleft', 'button', 14, 'l'), + love.joystick.setGamepadMapping(guid, 'dpright', 'button', 15, 'r'), + love.joystick.setGamepadMapping(guid, 'dpup', 'hat', 12, 'lu'), + love.joystick.setGamepadMapping(guid, 'dpdown', 'hat', 13, 'ld'), + love.joystick.setGamepadMapping(guid, 'dpleft', 'hat', 14, 'ru'), + love.joystick.setGamepadMapping(guid, 'dpright', 'hat', 15, 'rd'), + love.joystick.setGamepadMapping(guid, 'leftstick', 'axis', 8, 'c') + } + for m=1,#mappings do + test:assertEquals(true, mappings[m], 'check mapping #' .. tostring(m)) + end +end diff --git a/testing/tests/keyboard.lua b/testing/tests/keyboard.lua new file mode 100644 index 000000000..c8f9748c9 --- /dev/null +++ b/testing/tests/keyboard.lua @@ -0,0 +1,84 @@ +-- love.keyboard +-- @NOTE we can't test this module fully as it's hardware dependent +-- however we can test methods do what is expected and can handle certain params + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.keyboard.getKeyFromScancode +love.test.keyboard.getKeyFromScancode = function(test) + test:assertEquals('function', type(love.keyboard.getKeyFromScancode)) +end + + +-- love.keyboard.getScancodeFromKey +love.test.keyboard.getScancodeFromKey = function(test) + test:assertEquals('function', type(love.keyboard.getScancodeFromKey)) +end + + +-- love.keyboard.hasKeyRepeat +love.test.keyboard.hasKeyRepeat = function(test) + local enabled = love.keyboard.hasKeyRepeat() + test:assertNotNil(enabled) +end + + +-- love.keyboard.hasScreenKeyboard +love.test.keyboard.hasScreenKeyboard = function(test) + local enabled = love.keyboard.hasScreenKeyboard() + test:assertNotNil(enabled) +end + + +-- love.keyboard.hasTextInput +love.test.keyboard.hasTextInput = function(test) + local enabled = love.keyboard.hasTextInput() + test:assertNotNil(enabled) +end + + +-- love.keyboard.isDown +love.test.keyboard.isDown = function(test) + local keydown = love.keyboard.isDown('a') + test:assertNotNil(keydown) +end + + +-- love.keyboard.isScancodeDown +love.test.keyboard.isScancodeDown = function(test) + local keydown = love.keyboard.isScancodeDown('a') + test:assertNotNil(keydown) +end + + +-- love.keyboard.setKeyRepeat +love.test.keyboard.setKeyRepeat = function(test) + love.keyboard.setKeyRepeat(true) + local enabled = love.keyboard.hasKeyRepeat() + test:assertEquals(true, enabled, 'check key repeat set') +end + + +-- love.keyboard.isModifierActive +love.test.keyboard.isModifierActive = function(test) + local active1 = love.keyboard.isModifierActive('numlock') + local active2 = love.keyboard.isModifierActive('capslock') + local active3 = love.keyboard.isModifierActive('scrolllock') + local active4 = love.keyboard.isModifierActive('mode') + test:assertNotNil(active1) + test:assertNotNil(active2) + test:assertNotNil(active3) + test:assertNotNil(active4) +end + + +-- love.keyboard.setTextInput +love.test.keyboard.setTextInput = function(test) + love.keyboard.setTextInput(false) + test:assertEquals(false, love.keyboard.hasTextInput(), 'check disable text input') +end diff --git a/testing/tests/love.lua b/testing/tests/love.lua new file mode 100644 index 000000000..36b70f1f7 --- /dev/null +++ b/testing/tests/love.lua @@ -0,0 +1,54 @@ +-- love +-- tests for the main love hooks + methods, mainly just that they exist + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.getVersion +love.test.love.getVersion = function(test) + local major, minor, revision, codename = love.getVersion() + test:assertGreaterEqual(0, major, 'check major is number') + test:assertGreaterEqual(0, minor, 'check minor is number') + test:assertGreaterEqual(0, revision, 'check revision is number') + test:assertTrue(codename ~= nil, 'check has codename') +end + + +-- love.hasDeprecationOutput +love.test.love.hasDeprecationOutput = function(test) + local enabled = love.hasDeprecationOutput() + test:assertEquals(true, enabled, 'check enabled by default') +end + + +-- love.isVersionCompatible +love.test.love.isVersionCompatible = function(test) + local major, minor, revision, _ = love.getVersion() + test:assertTrue(love.isVersionCompatible(major, minor, revision), 'check own version') +end + + +-- love.setDeprecationOutput +love.test.love.setDeprecationOutput = function(test) + local enabled = love.hasDeprecationOutput() + test:assertEquals(true, enabled, 'check enabled by default') + love.setDeprecationOutput(false) + test:assertEquals(false, love.hasDeprecationOutput(), 'check disable') + love.setDeprecationOutput(true) +end + + +-- love.errhand +love.test.love.errhand = function(test) + test:assertTrue(type(love.errhand) == 'function', 'check defined') +end + + +-- love.run +love.test.love.run = function(test) + test:assertTrue(type(love.run) == 'function', 'check defined') +end diff --git a/testing/tests/math.lua b/testing/tests/math.lua new file mode 100644 index 000000000..dbc92e714 --- /dev/null +++ b/testing/tests/math.lua @@ -0,0 +1,368 @@ +-- love.math + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- BezierCurve (love.math.newBezierCurve) +love.test.math.BezierCurve = function(test) + + -- create obj + local curve = love.math.newBezierCurve(1, 1, 2, 2, 3, 1) + local px, py = curve:getControlPoint(2) + test:assertObject(curve) + + -- check initial properties + test:assertCoords({2, 2}, {px, py}, 'check point x/y') + test:assertEquals(3, curve:getControlPointCount(), 'check 3 points') + test:assertEquals(2, curve:getDegree(), 'check degree is points-1') + + -- check some values on the curve + test:assertEquals(1, curve:evaluate(0), 'check curve evaluation 0') + test:assertRange(curve:evaluate(0.1), 1.2, 1.3, 'check curve evaluation 0.1') + test:assertRange(curve:evaluate(0.2), 1.4, 1.5, 'check curve evaluation 0.2') + test:assertRange(curve:evaluate(0.5), 2, 2.1, 'check curve evaluation 0.5') + test:assertEquals(3, curve:evaluate(1), 'check curve evaluation 1') + + -- check derivative + local deriv = curve:getDerivative() + test:assertObject(deriv) + test:assertEquals(2, deriv:getControlPointCount(), 'check deriv points') + test:assertRange(deriv:evaluate(0.1), 2, 2.1, 'check deriv evaluation 0.1') + + -- check segment + local segment = curve:getSegment(0, 0.5) + test:assertObject(segment) + test:assertEquals(3, segment:getControlPointCount(), 'check segment points') + test:assertRange(segment:evaluate(0.1), 1, 1.1, 'check segment evaluation 0.1') + + -- mess with control points + curve:removeControlPoint(2) + curve:insertControlPoint(4, 1, -1) + curve:insertControlPoint(5, 3, -1) + curve:insertControlPoint(6, 2, -1) + curve:setControlPoint(2, 3, 2) + test:assertEquals(5, curve:getControlPointCount(), 'check 3 points still') + local px1, py1 = curve:getControlPoint(1) + local px2, py2 = curve:getControlPoint(3) + local px3, py3 = curve:getControlPoint(5) + test:assertCoords({1, 1}, {px1, py1}, 'check modified point 1') + test:assertCoords({5, 3}, {px2, py2}, 'check modified point 1') + test:assertCoords({3, 1}, {px3, py3}, 'check modified point 1') + + -- check render lists + local coords1 = curve:render(5) + local coords2 = curve:renderSegment(0, 0.1, 5) + test:assertEquals(196, #coords1, 'check coords') + test:assertEquals(20, #coords2, 'check segment coords') + + -- check translation values + px, py = curve:getControlPoint(2) + test:assertCoords({3, 2}, {px, py}, 'check pretransform x/y') + curve:rotate(90 * (math.pi/180), 0, 0) + px, py = curve:getControlPoint(2) + test:assertCoords({-2, 3}, {px, py}, 'check rotated x/y') + curve:scale(2, 0, 0) + px, py = curve:getControlPoint(2) + test:assertCoords({-4, 6}, {px, py}, 'check scaled x/y') + curve:translate(5, -5) + px, py = curve:getControlPoint(2) + test:assertCoords({1, 1}, {px, py}, 'check translated x/y') + +end + + +-- RandomGenerator (love.math.RandomGenerator) +-- @NOTE as this checks random numbers the chances this fails is very unlikely, but not 0... +-- if you've managed to proc it congrats! your prize is to rerun the testsuite again +love.test.math.RandomGenerator = function(test) + + -- create object + local rng1 = love.math.newRandomGenerator(3418323524, 20529293) + test:assertObject(rng1) + + -- check set properties + local low, high = rng1:getSeed() + test:assertEquals(3418323524, low, 'check seed low') + test:assertEquals(20529293, high, 'check seed high') + + -- check states + local rng2 = love.math.newRandomGenerator(1448323524, 10329293) + test:assertNotEquals(rng1:random(), rng2:random(), 'check not matching states') + test:assertNotEquals(rng1:randomNormal(), rng2:randomNormal(), 'check not matching states') + + -- check setting state works + rng2:setState(rng1:getState()) + test:assertEquals(rng1:random(), rng2:random(), 'check now matching') + + -- check overwriting seed works, should change output + rng1:setSeed(os.time()) + test:assertNotEquals(rng1:random(), rng2:random(), 'check not matching states') + test:assertNotEquals(rng1:randomNormal(), rng2:randomNormal(), 'check not matching states') + +end + + +-- Transform (love.math.Transform) +love.test.math.Transform = function(test) + + -- create obj + local transform = love.math.newTransform(0, 0, 0, 1, 1, 0, 0, 0, 0) + test:assertObject(transform) + + -- set some values and check the matrix and transformPoint values + transform:translate(10, 8) + transform:scale(2, 3) + transform:rotate(90*(math.pi/180)) + transform:shear(1, 2) + local px, py = transform:transformPoint(1, 1) + test:assertCoords({4, 14}, {px, py}, 'check transformation methods') + transform:reset() + px, py = transform:transformPoint(1, 1) + test:assertCoords({1, 1}, {px, py}, 'check reset') + + -- apply a transform to another transform + local transform2 = love.math.newTransform() + transform2:translate(5, 3) + transform:apply(transform2) + px, py = transform:transformPoint(1, 1) + test:assertCoords({6, 4}, {px, py}, 'check apply other transform') + + -- check cloning a transform + local transform3 = transform:clone() + px, py = transform3:transformPoint(1, 1) + test:assertCoords({6, 4}, {px, py}, 'check clone transform') + + -- check inverse and inverseTransform + transform:reset() + transform:translate(-14, 6) + local ipx, ipy = transform:inverseTransformPoint(0, 0) + transform:inverse() + px, py = transform:transformPoint(0, 0) + test:assertCoords({-px, -py}, {ipx, ipy}, 'check inverse points transform') + + -- check matrix manipulation + transform:setTransformation(0, 0, 0, 1, 1, 0, 0, 0, 0) + transform:translate(4, 4) + local m1, m2, m3, m4, m5, m6, m7, m8, + m9, m10, m11, m12, m13, m14, m15, m16 = transform:getMatrix() + test:assertEquals(4, m4, 'check translate matrix x') + test:assertEquals(4, m8, 'check translate matrix y') + transform:setMatrix(m1, m2, m3, 3, m5, m6, m7, 1, m9, m10, m11, m12, m13, m14, m15, m16) + px, py = transform:transformPoint(1, 1) + test:assertCoords({4, 2}, {px, py}, 'check set matrix') + + -- check affine vs non affine + transform:reset() + test:assertTrue(transform:isAffine2DTransform(), 'check affine 1') + transform:translate(4, 3) + test:assertTrue(transform:isAffine2DTransform(), 'check affine 2') + transform:setMatrix(1, 3, 4, 5.5, 1, 4.5, 2, 1, 3.4, 5.1, 4.1, 13, 1, 1, 2, 3) + test:assertFalse(transform:isAffine2DTransform(), 'check not affine') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.math.colorFromBytes +love.test.math.colorFromBytes = function(test) + -- check random value + local r1, g1, b1, a1 = love.math.colorFromBytes(51, 51, 51, 51) + test:assertEquals(r1, 0.2, 'check r from bytes') + test:assertEquals(g1, 0.2, 'check g from bytes') + test:assertEquals(b1, 0.2, 'check b from bytes') + test:assertEquals(a1, 0.2, 'check a from bytes') + -- check "max" value + local r2, g2, b2, a2 = love.math.colorFromBytes(255, 255, 255, 255) + test:assertEquals(r2, 1, 'check r from bytes') + test:assertEquals(g2, 1, 'check g from bytes') + test:assertEquals(b2, 1, 'check b from bytes') + test:assertEquals(a2, 1, 'check a from bytes') + -- check "min" value + local r3, g3, b3, a3 = love.math.colorFromBytes(0, 0, 0, 0) + test:assertEquals(r3, 0, 'check r from bytes') + test:assertEquals(g3, 0, 'check g from bytes') + test:assertEquals(b3, 0, 'check b from bytes') + test:assertEquals(a3, 0, 'check a from bytes') +end + + +-- love.math.colorToBytes +love.test.math.colorToBytes = function(test) + -- check random value + local r1, g1, b1, a1 = love.math.colorToBytes(0.2, 0.2, 0.2, 0.2) + test:assertEquals(r1, 51, 'check bytes from r') + test:assertEquals(g1, 51, 'check bytes from g') + test:assertEquals(b1, 51, 'check bytes from b') + test:assertEquals(a1, 51, 'check bytes from a') + -- check "max" value + local r2, g2, b2, a2 = love.math.colorToBytes(1, 1, 1, 1) + test:assertEquals(r2, 255, 'check bytes from r') + test:assertEquals(g2, 255, 'check bytes from g') + test:assertEquals(b2, 255, 'check bytes from b') + test:assertEquals(a2, 255, 'check bytes from a') + -- check "min" value + local r3, g3, b3, a3 = love.math.colorToBytes(0, 0, 0, 0) + test:assertEquals(r3, 0, 'check bytes from r') + test:assertEquals(g3, 0, 'check bytes from g') + test:assertEquals(b3, 0, 'check bytes from b') + test:assertEquals(a3, 0, 'check bytes from a') +end + + +-- love.math.gammaToLinear +-- @NOTE I tried doing the same formula as the source from MathModule.cpp +-- but get test failues due to slight differences +love.test.math.gammaToLinear = function(test) + local lr, lg, lb = love.math.gammaToLinear(1, 0.8, 0.02) + --local eg = ((0.8 + 0.055) / 1.055)^2.4 + --local eb = 0.02 / 12.92 + test:assertGreaterEqual(0, lr, 'check gamma r to linear') + test:assertGreaterEqual(0, lg, 'check gamma g to linear') + test:assertGreaterEqual(0, lb, 'check gamma b to linear') +end + + +-- love.math.getRandomSeed +-- @NOTE whenever i run this high is always 0, is that intended? +love.test.math.getRandomSeed = function(test) + local low, high = love.math.getRandomSeed() + test:assertGreaterEqual(0, low, 'check random seed low') + test:assertGreaterEqual(0, high, 'check random seed high') +end + + +-- love.math.getRandomState +love.test.math.getRandomState = function(test) + test:assertNotNil(love.math.getRandomState()) +end + + +-- love.math.isConvex +love.test.math.isConvex = function(test) + local isconvex = love.math.isConvex({0, 0, 1, 0, 1, 1, 1, 0, 0, 0}) -- square + local notconvex = love.math.isConvex({1, 2, 2, 4, 3, 4, 2, 1, 3, 1}) -- weird shape + test:assertTrue(isconvex, 'check polygon convex') + test:assertFalse(notconvex, 'check polygon not convex') +end + + +-- love.math.linearToGammer +-- @NOTE I tried doing the same formula as the source from MathModule.cpp +-- but get test failues due to slight differences +love.test.math.linearToGamma = function(test) + local gr, gg, gb = love.math.linearToGamma(1, 0.8, 0.001) + --local eg = 1.055 * (0.8^1/2.4) - 0.055 + --local eb = 0.001 * 12.92 + test:assertGreaterEqual(0, gr, 'check linear r to gamme') + test:assertGreaterEqual(0, gg, 'check linear g to gamme') + test:assertGreaterEqual(0, gb, 'check linear b to gamme') +end + + +-- love.math.newBezierCurve +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.math.newBezierCurve = function(test) + test:assertObject(love.math.newBezierCurve({0, 0, 0, 1, 1, 1, 2, 1})) +end + + +-- love.math.newRandomGenerator +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.math.newRandomGenerator = function(test) + test:assertObject(love.math.newRandomGenerator()) +end + + +-- love.math.newTransform +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.math.newTransform = function(test) + test:assertObject(love.math.newTransform()) +end + + +-- love.math.perlinNoise +love.test.math.perlinNoise = function(test) + -- check some noise values + -- output should be consistent if given the same input + local noise1 = love.math.perlinNoise(100) + local noise2 = love.math.perlinNoise(1, 10) + local noise3 = love.math.perlinNoise(1043, 31.123, 999) + local noise4 = love.math.perlinNoise(99.222, 10067, 8, 1843) + test:assertRange(noise1, 0.5, 0.51, 'check noise 1 dimension') + test:assertRange(noise2, 0.5, 0.51, 'check noise 2 dimensions') + test:assertRange(noise3, 0.56, 0.57, 'check noise 3 dimensions') + test:assertRange(noise4, 0.52, 0.53, 'check noise 4 dimensions') +end + + +-- love.math.simplexNoise +love.test.math.simplexNoise = function(test) + -- check some noise values + -- output should be consistent if given the same input + local noise1 = love.math.simplexNoise(100) + local noise2 = love.math.simplexNoise(1, 10) + local noise3 = love.math.simplexNoise(1043, 31.123, 999) + local noise4 = love.math.simplexNoise(99.222, 10067, 8, 1843) + -- rounded to avoid floating point issues + test:assertRange(noise1, 0.5, 0.51, 'check noise 1 dimension') + test:assertRange(noise2, 0.47, 0.48, 'check noise 2 dimensions') + test:assertRange(noise3, 0.26, 0.27, 'check noise 3 dimensions') + test:assertRange(noise4, 0.53, 0.54, 'check noise 4 dimensions') +end + + +-- love.math.random +love.test.math.random = function(test) + -- check some random ranges + love.math.setRandomSeed(123) + test:assertRange(love.math.random(), 0.37068322251462, 0.37068322251464, "check random algorithm") + test:assertEquals(love.math.random(10), 4, "check single random param") + test:assertEquals(love.math.random(15, 100), 92, "check two random params") +end + + +-- love.math.randomNormal +love.test.math.randomNormal = function(test) + love.math.setRandomSeed(1234) + test:assertRange(love.math.randomNormal(1, 2), 1.0813614997253, 1.0813614997255, 'check randomNormal two params') +end + + +-- love.math.setRandomSeed +-- @NOTE same with getRandomSeed, high is always 0 when I tested it? +love.test.math.setRandomSeed = function(test) + love.math.setRandomSeed(9001) + local low, high = love.math.getRandomSeed() + test:assertEquals(9001, low, 'check seed low set') + test:assertEquals(0, high, 'check seed high set') +end + + +-- love.math.setRandomState +love.test.math.setRandomState = function(test) + -- check setting state matches value returned + local rs1 = love.math.getRandomState() + love.math.setRandomState(rs1) + local rs2 = love.math.getRandomState() + test:assertEquals(rs1, rs2, 'check random state set') +end + + +-- love.math.triangulate +love.test.math.triangulate = function(test) + local triangles1 = love.math.triangulate({0, 0, 1, 0, 1, 1, 1, 0, 0, 0}) -- square + local triangles2 = love.math.triangulate({1, 2, 2, 4, 3, 4, 2, 1, 3, 1}) -- weird shape + test:assertEquals(3, #triangles1, 'check polygon triangles') + test:assertEquals(3, #triangles2, 'check polygon triangles') +end diff --git a/testing/tests/mouse.lua b/testing/tests/mouse.lua new file mode 100644 index 000000000..8b5a5a66d --- /dev/null +++ b/testing/tests/mouse.lua @@ -0,0 +1,187 @@ +-- love.mouse +-- @NOTE we can't test this module fully as it's hardware dependent +-- however we can test methods do what is expected and can handle certain params + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.mouse.getCursor +love.test.mouse.getCursor = function(test) + local cursor = love.mouse.getCursor() + test:assertEquals(nil, cursor, 'check nil initially') + -- try setting a cursor to check return if supported + if love.mouse.isCursorSupported() then + love.mouse.setCursor(love.mouse.getSystemCursor("hand")) + local newcursor = love.mouse.getCursor() + test:assertObject(newcursor) + love.mouse.setCursor() + end +end + + +-- love.mouse.getPosition +love.test.mouse.getPosition = function(test) + love.mouse.setPosition(0, 0) -- cant predict + local x, y = love.mouse.getPosition() + test:assertEquals(0, x, 'check x pos') + test:assertEquals(0, y, 'check y pos') +end + + +-- love.mouse.getRelativeMode +love.test.mouse.getRelativeMode = function(test) + local enabled = love.mouse.getRelativeMode() + test:assertEquals(false, enabled, 'check relative mode') + love.mouse.setRelativeMode(true) + test:assertEquals(true, love.mouse.getRelativeMode(), 'check enabling') +end + + +-- love.mouse.getSystemCursor +love.test.mouse.getSystemCursor = function(test) + local hand = love.mouse.getSystemCursor('hand') + test:assertObject(hand) + local ok, err = pcall(love.mouse.getSystemCursor, 'love') + test:assertEquals(false, ok, 'check invalid cursor') +end + + +-- love.mouse.getX +love.test.mouse.getX = function(test) + love.mouse.setPosition(0, 0) -- cant predict + local x = love.mouse.getX() + test:assertEquals(0, x, 'check x pos') + love.mouse.setX(10) + test:assertEquals(10, love.mouse.getX(), 'check set x') +end + + +-- love.mouse.getY +love.test.mouse.getY = function(test) + love.mouse.setPosition(0, 0) -- cant predict + local y = love.mouse.getY() + test:assertEquals(0, y, 'check x pos') + love.mouse.setY(10) + test:assertEquals(10, love.mouse.getY(), 'check set y') +end + + +-- love.mouse.isCursorSupported +love.test.mouse.isCursorSupported = function(test) + test:assertNotNil(love.mouse.isCursorSupported()) +end + + +-- love.mouse.isDown +love.test.mouse.isDown = function(test) + test:assertNotNil(love.mouse.isDown()) +end + + +-- love.mouse.isGrabbed +love.test.mouse.isGrabbed = function(test) + test:assertNotNil(love.mouse.isGrabbed()) +end + + +-- love.mouse.isVisible +love.test.mouse.isVisible = function(test) + local visible = love.mouse.isVisible() + test:assertEquals(true, visible, 'check visible default') + love.mouse.setVisible(false) + test:assertEquals(false, love.mouse.isVisible(), 'check invisible') + love.mouse.setVisible(true) +end + + +-- love.mouse.newCursor +love.test.mouse.newCursor = function(test) + -- new cursor might fail if not supported + if love.mouse.isCursorSupported() then + local cursor = love.mouse.newCursor('resources/love.png', 0, 0) + test:assertObject(cursor) + else + test:skipTest('cursor not supported on this system') + end +end + + +-- love.mouse.setCursor +love.test.mouse.setCursor = function(test) + -- cant set cursor if not supported + if love.mouse.isCursorSupported() then + love.mouse.setCursor() + test:assertEquals(nil, love.mouse.getCursor(), 'check reset') + love.mouse.setCursor(love.mouse.getSystemCursor('hand')) + test:assertObject(love.mouse.getCursor()) + else + test:skipTest('cursor not supported on this system') + end +end + + +-- love.mouse.setGrabbed +-- @NOTE can fail if you move the mouse a bunch while the test runs +love.test.mouse.setGrabbed = function(test) + test:assertEquals(false, love.mouse.isGrabbed(), 'check not grabbed') + love.mouse.setGrabbed(true) + test:assertEquals(true, love.mouse.isGrabbed(), 'check now grabbed') + love.mouse.setGrabbed(false) +end + + +-- love.mouse.setPosition +love.test.mouse.setPosition = function(test) + love.mouse.setPosition(10, 10) + local x, y = love.mouse.getPosition() + test:assertEquals(10, x, 'check x position') + test:assertEquals(10, y, 'check y position') + love.mouse.setPosition(15, 20) + local x2, y2 = love.mouse.getPosition() + test:assertEquals(15, x2, 'check new x position') + test:assertEquals(20, y2, 'check new y position') +end + + +-- love.mouse.setRelativeMode +love.test.mouse.setRelativeMode = function(test) + love.mouse.setRelativeMode(true) + local enabled = love.mouse.getRelativeMode() + test:assertEquals(true, enabled, 'check relative mode') + love.mouse.setRelativeMode(false) + test:assertEquals(false, love.mouse.getRelativeMode(), 'check disabling') +end + + +-- love.mouse.setVisible +love.test.mouse.setVisible = function(test) + local visible = love.mouse.isVisible() + test:assertEquals(true, visible, 'check visible default') + love.mouse.setVisible(false) + test:assertEquals(false, love.mouse.isVisible(), 'check invisible') + love.mouse.setVisible(true) +end + + +-- love.mouse.setX +love.test.mouse.setX = function(test) + love.mouse.setX(30) + local x = love.mouse.getX() + test:assertEquals(30, x, 'check x pos') + love.mouse.setX(10) + test:assertEquals(10, love.mouse.getX(), 'check set x') +end + + +-- love.mouse.setY +love.test.mouse.setY = function(test) + love.mouse.setY(12) + local y = love.mouse.getY() + test:assertEquals(12, y, 'check x pos') + love.mouse.setY(10) + test:assertEquals(10, love.mouse.getY(), 'check set y') +end diff --git a/testing/tests/physics.lua b/testing/tests/physics.lua new file mode 100644 index 000000000..5e4662526 --- /dev/null +++ b/testing/tests/physics.lua @@ -0,0 +1,839 @@ +-- love.physics + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------OBJECTS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- Body (love.physics.newBody) +love.test.physics.Body = function(test) + + -- create body + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 0, 0, 'static') + local body2 = love.physics.newBody(world, 30, 30, 'dynamic') + love.physics.newRectangleShape(body1, 5, 5, 10, 10) + love.physics.newRectangleShape(body2, 5, 5, 10, 10) + test:assertObject(body1) + + -- check shapes + test:assertEquals(1, #body1:getShapes(), 'check shapes total 1') + test:assertEquals(1, #body2:getShapes(), 'check shapes total 2') + test:assertNotEquals(nil, body1:getShape(), 'check shape 1') + test:assertNotEquals(nil, body2:getShape(), 'check shape 2') + + -- check body active + test:assertTrue(body1:isActive(), 'check active by def') + + -- check body bullet + test:assertFalse(body1:isBullet(), 'check not bullet by def') + body1:setBullet(true) + test:assertTrue(body1:isBullet(), 'check set bullet') + + -- check fixed rotation + test:assertFalse(body1:isFixedRotation(), 'check fix rot def') + body1:setFixedRotation(true) + test:assertTrue(body1:isFixedRotation(), 'check set fix rot') + + -- check sleeping/waking + test:assertTrue(body1:isSleepingAllowed(), 'check sleep def') + body1:setSleepingAllowed(false) + test:assertFalse(body1:isSleepingAllowed(), 'check set sleep') + body1:setSleepingAllowed(true) + world:update(1) + test:assertFalse(body1:isAwake(), 'check fell asleep') + body1:setSleepingAllowed(false) + body1:setType('dynamic') + test:assertTrue(body1:isAwake(), 'check waking up') + + -- check touching + test:assertFalse(body1:isTouching(body2)) + body2:setPosition(5, 5) + world:update(1) + test:assertTrue(body1:isTouching(body2)) + + -- check children lists + test:assertEquals(1, #body1:getContacts(), 'check contact list') + test:assertEquals(0, #body1:getJoints(), 'check joints list') + love.physics.newDistanceJoint(body1, body2, 5, 5, 10, 10, true) + test:assertEquals(1, #body1:getJoints(), 'check joints list') + + -- check local points + local x, y = body1:getLocalCenter() + test:assertRange(x, 5, 6, 'check local center x') + test:assertRange(y, 5, 6, 'check local center y') + local lx, ly = body1:getLocalPoint(10, 10) + test:assertRange(lx, 10, 11, 'check local point x') + test:assertRange(ly, 9, 10, 'check local point y') + local lx1, ly1, lx2, ly2 = body1:getLocalPoints(0, 5, 5, 10) + test:assertRange(lx1, 0, 1, 'check local points x 1') + test:assertRange(ly1, 3, 4, 'check local points y 1') + test:assertRange(lx2, 5, 6, 'check local points x 2') + test:assertRange(ly2, 9, 10, 'check local points y 2') + + -- check world points + local wx, wy = body1:getWorldPoint(10.4, 9) + test:assertRange(wx, 10, 11, 'check world point x') + test:assertRange(wy, 10, 11, 'check world point y') + local wx1, wy1, wx2, wy2 = body1:getWorldPoints(0.4, 4, 5.4, 9) + test:assertRange(wx1, 0, 1, 'check world points x 1') + test:assertRange(wy1, 5, 6, 'check world points y 1') + test:assertRange(wx2, 5, 6, 'check world points x 2') + test:assertRange(wy2, 10, 11, 'check world points y 2') + + -- check angular damping + velocity + test:assertEquals(0, body1:getAngularDamping(), 'check angular damping') + test:assertEquals(0, body1:getAngularVelocity(), 'check angular velocity') + + -- check world props + test:assertObject(body1:getWorld()) + test:assertEquals(2, body1:getWorld():getBodyCount(), 'check world count') + local cx, cy = body1:getWorldCenter() + test:assertRange(cx, 4, 5, 'check world center x') + test:assertRange(cy, 6, 7, 'check world center y') + local vx, vy = body1:getWorldVector(5, 10) + test:assertEquals(5, vx, 'check vector x') + test:assertEquals(10, vy, 'check vector y') + + -- check inertia + test:assertRange(body1:getInertia(), 5, 6, 'check inertia') + + -- check angle + test:assertEquals(0, body1:getAngle(), 'check def angle') + body1:setAngle(90 * (math.pi/180)) + test:assertEquals(math.floor(math.pi/2*100), math.floor(body1:getAngle()*100), 'check set angle') + + -- check gravity scale + test:assertEquals(1, body1:getGravityScale(), 'check def grav') + body1:setGravityScale(2) + test:assertEquals(2, body1:getGravityScale(), 'check change grav') + + -- check damping + test:assertEquals(0, body1:getLinearDamping(), 'check def lin damping') + body1:setLinearDamping(0.1) + test:assertRange(body1:getLinearDamping(), 0, 0.2, 'check change lin damping') + + -- check velocity + local x2, y2 = body1:getLinearVelocity() + test:assertEquals(1, x2, 'check def lin velocity x') + test:assertEquals(1, y2, 'check def lin velocity y') + body1:setLinearVelocity(4, 5) + local x3, y3 = body1:getLinearVelocity() + test:assertEquals(4, x3, 'check change lin velocity x') + test:assertEquals(5, y3, 'check change lin velocity y') + + -- check mass + test:assertRange(body1:getMass(), 0.1, 0.2, 'check def mass') + body1:setMass(10) + test:assertEquals(10, body1:getMass(), 'check change mass') + body1:setMassData(3, 5, 10, 1) + local x4, y4, mass4, inertia4 = body1:getMassData() + test:assertEquals(3, x4, 'check mass data change x') + test:assertEquals(5, y4, 'check mass data change y') + test:assertEquals(10, mass4, 'check mass data change mass') + test:assertRange(inertia4, 340, 341, 'check mass data change inertia') + body1:resetMassData() + local x5, y5, mass5, inertia5 = body1:getMassData() + test:assertRange(x5, 5, 6, 'check mass data reset x') + test:assertRange(y5, 5, 6, 'check mass data reset y') + test:assertRange(mass5, 0.1, 0.2, 'check mass data reset mass') + test:assertRange(inertia5, 5, 6, 'check mass data reset inertia') + test:assertFalse(body1:hasCustomMassData()) + + -- check position + local x6, y6 = body1:getPosition() + test:assertRange(x6, -1, 0, 'check position x') + test:assertRange(y6, 0, 1, 'check position y') + body1:setPosition(10, 4) + local x7, y7 = body1:getPosition() + test:assertEquals(x7, 10, 'check set position x') + test:assertEquals(y7, 4, 'check set position y') + + -- check type + test:assertEquals('dynamic', body1:getType(), 'check type match') + body1:setType('kinematic') + body1:setType('static') + test:assertEquals('static', body1:getType(), 'check type change') + + -- check userdata + test:assertEquals(nil, body1:getUserData(), 'check user data') + body1:setUserData({ love = 'cool' }) + test:assertEquals('cool', body1:getUserData().love, 'check set user data') + + -- check x/y direct + test:assertEquals(10, math.floor(body1:getX()), 'check get x') + test:assertEquals(4, math.floor(body1:getY()), 'check get y') + body1:setX(0) + body1:setY(0) + test:assertEquals(0, body1:getX(), 'check get x') + test:assertEquals(0, body1:getY(), 'check get y') + + -- apply angular impulse + local vel = body2:getAngularVelocity() + test:assertRange(vel, 0, 0, 'check velocity before') + body2:applyAngularImpulse(10) + local vel1 = body2:getAngularVelocity() + test:assertRange(vel1, 5, 6, 'check velocity after 1') + + -- apply standard force + local ang1 = body2:getAngle() + test:assertRange(ang1, 0.1, 0.2, 'check initial angle 1') + body2:applyForce(2, 3) + world:update(2) + local vel2 = body2:getAngularVelocity() + local ang2 = body2:getAngle() + test:assertRange(ang2, -0.1, 0, 'check angle after 2') + test:assertRange(vel2, 1, 2, 'check velocity after 2') + + -- apply linear impulse + body2:applyLinearImpulse(-4, -59) + world:update(1) + local ang3 = body2:getAngle() + local vel3 = body2:getAngularVelocity() + test:assertRange(ang3, -2, -1, 'check angle after 3') + test:assertRange(vel3, 0, 1, 'check velocity after 3') + + -- apply torque + body2:applyTorque(4) + world:update(2) + local ang4 = body2:getAngle() + local vel4 = body2:getAngularVelocity() + test:assertRange(ang4, -1, 0, 'check angle after 4') + test:assertRange(vel4, 0, 1, 'check velocity after 4') + + -- check destroy + test:assertFalse(body1:isDestroyed(), 'check not destroyed') + body1:destroy() + test:assertTrue(body1:isDestroyed(), 'check destroyed') + +end + + +-- Contact (love.physics.World:getContacts) +love.test.physics.Contact = function(test) + + -- create a setup so we can access some contact objects + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 0, 0, 'dynamic') + local body2 = love.physics.newBody(world, 10, 10, 'dynamic') + local rectangle1 = love.physics.newRectangleShape(body1, 0, 0, 10, 10) + local rectangle2 = love.physics.newRectangleShape(body2, 0, 0, 10, 10) + rectangle1:setUserData('rec1') + rectangle2:setUserData('rec2') + + -- used to check for collisions + no. of collisions + local collided = false + local pass = 1 + + -- set callback for contact start + world:setCallbacks( + function(shape_a, shape_b, contact) + collided = true + + -- check contact object + test:assertObject(contact) + + -- check child indices + local indexA, indexB = contact:getChildren() + test:assertEquals(1, indexA, 'check child indice a') + test:assertEquals(1, indexB, 'check child indice b') + + -- check shapes match using userdata + local shapeA, shapeB = contact:getShapes() + test:assertEquals(shape_a:getUserData(), shapeA:getUserData(), 'check shape a matches') + test:assertEquals(shape_b:getUserData(), shapeB:getUserData(), 'check shape b matches') + + -- check normal pos + local nx, ny = contact:getNormal() + test:assertEquals(1, nx, 'check normal x') + test:assertEquals(0, ny, 'check normal y') + + -- check actual pos + local px1, py1, px2, py2 = contact:getPositions() + test:assertRange(px1, 5, 6, 'check collide x 1') + test:assertRange(py1, 5, 6, 'check collide y 1') + test:assertRange(px2, 5, 6, 'check collide x 2') + test:assertRange(py2, 5, 6, 'check collide y 2') + + -- check touching + test:assertTrue(contact:isTouching(), 'check touching') + + -- check enabled (we pass through twice to test on/off) + test:assertEquals(pass == 1, contact:isEnabled(), 'check enabled for pass ' .. tostring(pass)) + + -- check friction + test:assertRange(contact:getFriction(), 0.2, 0.3, 'check def friction') + contact:setFriction(0.1) + test:assertRange(contact:getFriction(), 0.1, 0.2, 'check set friction') + contact:resetFriction() + test:assertRange(contact:getFriction(), 0.2, 0.3, 'check reset friction') + + -- check restitution + test:assertEquals(0, contact:getRestitution(), 'check def restitution') + contact:setRestitution(1) + test:assertEquals(1, contact:getRestitution(), 'check set restitution') + contact:resetRestitution() + test:assertEquals(0, contact:getRestitution(), 'check reset restitution') + pass = pass + 1 + + end, function() end, function(shape_a, shape_b, contact) + if pass > 2 then + contact:setEnabled(false) + end + end, function() end + ) + + -- check bodies collided + world:update(1) + test:assertTrue(collided, 'check bodies collided') + + -- update again for enabled check + world:update(1) + test:assertEquals(2, pass, 'check ran twice') + +end + + +-- Joint (love.physics.newDistanceJoint) +love.test.physics.Joint = function(test) + + -- make joint + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'dynamic') + local body2 = love.physics.newBody(world, 20, 20, 'dynamic') + local joint = love.physics.newDistanceJoint(body1, body2, 10, 10, 20, 20, true) + test:assertObject(joint) + + -- check type + test:assertEquals('distance', joint:getType(), 'check joint type') + + -- check not destroyed + test:assertFalse(joint:isDestroyed(), 'check not destroyed') + + + -- check reaction props + world:update(1) + local rx1, ry1 = joint:getReactionForce(1) + test:assertEquals(0, rx1, 'check reaction force x') + test:assertEquals(0, ry1, 'check reaction force y') + local rx2, ry2 = joint:getReactionTorque(1) + test:assertEquals(0, rx2, 'check reaction torque x') + test:assertEquals(nil, ry2, 'check reaction torque y') + + -- check body pointer + local b1, b2 = joint:getBodies() + test:assertEquals(body1:getX(), b1:getX(), 'check body 1') + test:assertEquals(body2:getX(), b2:getX(), 'check body 2') + + -- check joint anchors + local x1, y1, x2, y2 = joint:getAnchors() + test:assertRange(x1, 10, 11, 'check anchor x1') + test:assertRange(y1, 10, 11, 'check anchor y1') + test:assertRange(x2, 20, 21, 'check anchor x2') + test:assertRange(y2, 20, 21, 'check anchor y2') + test:assertTrue(joint:getCollideConnected(), 'check not colliding') + + -- test userdata + test:assertEquals(nil, joint:getUserData(), 'check no data by def') + joint:setUserData('hello') + test:assertEquals('hello', joint:getUserData(), 'check set userdata') + + -- destroy + joint:destroy() + test:assertTrue(joint:isDestroyed(), 'check destroyed') + +end + + +-- Shape (love.physics.newCircleShape) +-- @NOTE in 12.0 fixtures have been merged into shapes +love.test.physics.Shape = function(test) + + -- create shape + local world = love.physics.newWorld(0, 0, false) + local body1 = love.physics.newBody(world, 0, 0, 'dynamic') + local shape1 = love.physics.newRectangleShape(body1, 5, 5, 10, 10) + test:assertObject(shape1) + + -- check child count + test:assertEquals(1, shape1:getChildCount(), 'check child count') + + -- check radius + test:assertRange(shape1:getRadius(), 0, 0.4, 'check radius') + + -- check type match + test:assertEquals('polygon', shape1:getType(), 'check rectangle type') + + -- check body pointer + test:assertEquals(0, shape1:getBody():getX(), 'check body link') + + -- check category + test:assertEquals(1, shape1:getCategory(), 'check def category') + shape1:setCategory(3, 5, 6) + local categories = {shape1:getCategory()} + test:assertEquals(14, categories[1] + categories[2] + categories[3], 'check set category') + + -- check sensor prop + test:assertFalse(shape1:isSensor(), 'check sensor def') + shape1:setSensor(true) + test:assertTrue(shape1:isSensor(), 'check set sensor') + shape1:setSensor(false) + + -- check not destroyed + test:assertFalse(shape1:isDestroyed(), 'check not destroyed') + + -- check user data + test:assertEquals(nil, shape1:getUserData(), 'check no user data') + shape1:setUserData({ test = 14 }) + test:assertEquals(14, shape1:getUserData().test, 'check user data set') + + -- check bounding box + -- polygons have an additional skin radius to help with collisions + -- so this wont be 0, 0, 10, 10 as you'd think but has an additional 0.3 padding + local topLeftX, topLeftY, bottomRightX, bottomRightY = shape1:computeAABB(0, 0, 0, 1) + local tlx, tly, brx, bry = shape1:getBoundingBox(1) + test:assertEquals(topLeftX, tlx, 'check bbox methods match tlx') + test:assertEquals(topLeftY, tly, 'check bbox methods match tly') + test:assertEquals(bottomRightX, brx, 'check bbox methods match brx') + test:assertEquals(bottomRightY, bry, 'check bbox methods match bry') + test:assertEquals(topLeftX, topLeftY, 'check bbox tl 1') + test:assertRange(topLeftY, -0.3, -0.2, 'check bbox tl 2') + test:assertEquals(bottomRightX, bottomRightY, 'check bbox br 1') + test:assertRange(bottomRightX, 10.3, 10.4, 'check bbox br 2') + + -- check density + test:assertEquals(1, shape1:getDensity(), 'check def density') + shape1:setDensity(5) + test:assertEquals(5, shape1:getDensity(), 'check set density') + + -- check mass + local x1, y1, mass1, inertia1 = shape1:getMassData() + test:assertRange(x1, 5, 5.1, 'check shape mass pos x') + test:assertRange(y1, 5, 5.1, 'check shape mass pos y') + test:assertRange(mass1, 0.5, 0.6, 'check mass at 1 density') + test:assertRange(inertia1, 0, 0.1, 'check intertia at 1 density') + local x2, y2, mass2, inertia2 = shape1:computeMass(1000) + test:assertRange(mass2, 111, 112, 'check mass at 1000 density') + test:assertRange(inertia2, 7407, 7408, 'check intertia at 1000 density') + + -- check friction + test:assertRange(shape1:getFriction(), 0.2, 0.3, 'check def friction') + shape1:setFriction(1) + test:assertEquals(1, shape1:getFriction(), 'check set friction') + + -- check restitution + test:assertEquals(0, shape1:getRestitution(), 'check def restitution') + shape1:setRestitution(0.5) + test:assertRange(shape1:getRestitution(), 0.5, 0.6, 'check set restitution') + + -- check points + local bodyp = love.physics.newBody(world, 0, 0, 'dynamic') + local shape2 = love.physics.newRectangleShape(bodyp, 5, 5, 10, 10) + test:assertTrue(shape2:testPoint(5, 5), 'check point 5,5') + test:assertTrue(shape2:testPoint(10, 10, 0, 15, 15), 'check point 15,15 after translate 10,10') + test:assertFalse(shape2:testPoint(5, 5, 90, 10, 10), 'check point 10,10 after translate 5,5,90') + test:assertFalse(shape2:testPoint(10, 10, 90, 5, 5), 'check point 5,5 after translate 10,10,90') + test:assertFalse(shape2:testPoint(15, 15), 'check point 15,15') + + -- check ray cast + local xn1, yn1, fraction1 = shape2:rayCast(-20, -20, 20, 20, 100, 0, 0, 0, 1) + test:assertNotEquals(nil, xn1, 'check ray 1 x') + test:assertNotEquals(nil, xn1, 'check ray 1 y') + local xn2, yn2, fraction2 = shape2:rayCast(10, 10, -150, -150, 100, 0, 0, 0, 1) + test:assertEquals(nil, xn2, 'check ray 2 x') + test:assertEquals(nil, yn2, 'check ray 2 y') + + -- check filtering + test:assertEquals(nil, shape2:getMask(), 'check no mask') + shape2:setMask(1, 2, 3) + test:assertEquals(3, #{shape2:getMask()}, 'check set mask') + test:assertEquals(0, shape2:getGroupIndex(), 'check no index') + shape2:setGroupIndex(-1) + test:assertEquals(-1, shape2:getGroupIndex(), 'check set index') + local cat, mask, group = shape2:getFilterData() + test:assertEquals(1, cat, 'check filter cat') + test:assertEquals(65528, mask, 'check filter mask') + test:assertEquals(-1, group, 'check filter group') + + -- check destroyed + shape1:destroy() + test:assertTrue(shape1:isDestroyed(), 'check destroyed') + shape2:destroy() + + -- run some collision checks using filters, setup new shapes + local body2 = love.physics.newBody(world, 5, 5, 'dynamic') + local shape3 = love.physics.newRectangleShape(body1, 0, 0, 10, 10) + local shape4 = love.physics.newRectangleShape(body2, 0, 0, 10, 10) + local collisions = 0 + world:setCallbacks( + function() collisions = collisions + 1 end, + function() end, + function() end, + function() end + ) + + -- same positive group do collide + shape3:setGroupIndex(1) + shape4:setGroupIndex(1) + world:update(1) + test:assertEquals(1, collisions, 'check positive group collide') + + -- check negative group dont collide + shape3:setGroupIndex(-1) + shape4:setGroupIndex(-1) + body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1) + test:assertEquals(1, collisions, 'check negative group collide') + + -- check masks do collide + shape3:setGroupIndex(0) + shape4:setGroupIndex(0) + shape3:setCategory(2) + shape4:setMask(3) + body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1) + test:assertEquals(2, collisions, 'check mask collide') + + -- check masks not colliding + shape3:setCategory(2) + shape4:setMask(2, 4, 6) + body2:setPosition(20, 20); world:update(1); body2:setPosition(0, 0); world:update(1) + test:assertEquals(2, collisions, 'check mask not collide') + +end + + +-- World (love.physics.newWorld) +love.test.physics.World = function(test) + + -- create new world + local world = love.physics.newWorld(0, 0, false) + local body1 = love.physics.newBody(world, 0, 0, 'dynamic') + local rectangle1 = love.physics.newRectangleShape(body1, 0, 0, 10, 10) + test:assertObject(world) + + -- check bodies in world + test:assertEquals(1, #world:getBodies(), 'check 1 body') + test:assertEquals(0, world:getBodies()[1]:getX(), 'check body prop x') + test:assertEquals(0, world:getBodies()[1]:getY(), 'check body prop y') + world:translateOrigin(-10, -10) -- check affects bodies + test:assertRange(world:getBodies()[1]:getX(), 9, 11, 'check body prop change x') + test:assertRange(world:getBodies()[1]:getY(), 9, 11, 'check body prop change y') + test:assertEquals(1, world:getBodyCount(), 'check 1 body count') + + -- check shapes in world + test:assertEquals(1, #world:getShapesInArea(0, 0, 10, 10), 'check shapes in area #1') + test:assertEquals(0, #world:getShapesInArea(20, 20, 30, 30), 'check shapes in area #1') + + -- check world status + test:assertFalse(world:isLocked(), 'check not updating') + test:assertFalse(world:isSleepingAllowed(), 'check no sleep (till brooklyn)') + world:setSleepingAllowed(true) + test:assertTrue(world:isSleepingAllowed(), 'check can sleep') + + -- check world objects + test:assertEquals(0, #world:getJoints(), 'check no joints') + test:assertEquals(0, world:getJointCount(), 'check no joints count') + test:assertEquals(0, world:getGravity(), 'check def gravity') + test:assertEquals(0, #world:getContacts(), 'check no contacts') + test:assertEquals(0, world:getContactCount(), 'check no contact count') + + -- check callbacks are called + local beginContact, endContact, preSolve, postSolve = world:getCallbacks() + test:assertEquals(nil, beginContact, 'check no begin contact callback') + test:assertEquals(nil, endContact, 'check no end contact callback') + test:assertEquals(nil, preSolve, 'check no pre solve callback') + test:assertEquals(nil, postSolve, 'check no post solve callback') + local beginContactCheck = false + local endContactCheck = false + local preSolveCheck = false + local postSolveCheck = false + local collisions = 0 + world:setCallbacks( + function() beginContactCheck = true; collisions = collisions + 1 end, + function() endContactCheck = true end, + function() preSolveCheck = true end, + function() postSolveCheck = true end + ) + + -- setup so we can collide stuff to call the callbacks + local body2 = love.physics.newBody(world, 10, 10, 'dynamic') + local rectangle2 = love.physics.newRectangleShape(body2, 0, 0, 10, 10) + test:assertFalse(beginContactCheck, 'check world didnt update after adding body') + world:update(1) + test:assertTrue(beginContactCheck, 'check contact start') + test:assertTrue(preSolveCheck, 'check pre solve') + test:assertTrue(postSolveCheck, 'check post solve') + body2:setPosition(100, 100) + world:update(1) + test:assertTrue(endContactCheck, 'check contact end') + + -- check point checking + local shapes = 0 + world:queryShapesInArea(0, 0, 10, 10, function(x) + shapes = shapes + 1 + end) + test:assertEquals(1, shapes, 'check shapes in area') + + -- check raycast + world:rayCast(0, 0, 200, 200, function(x) + shapes = shapes + 1 + return 1 + end) + test:assertEquals(3, shapes, 'check shapes in raycast') + test:assertEquals(world:rayCastClosest(0, 0, 200, 200), rectangle1, 'check closest raycast') + test:assertNotEquals(nil, world:rayCastAny(0, 0, 200, 200), 'check any raycast') + + -- change collision logic + test:assertEquals(nil, world:getContactFilter(), 'check def filter') + world:update(1) + world:setContactFilter(function(s1, s2) + return false -- nothing collides + end) + body2:setPosition(10, 10) + world:update(1) + test:assertEquals(1, collisions, 'check collision logic change') + + -- check gravity + world:setGravity(1, 1) + test:assertEquals(1, world:getGravity(), 'check grav change') + + -- check destruction + test:assertFalse(world:isDestroyed(), 'check not destroyed') + world:destroy() + test:assertTrue(world:isDestroyed(), 'check world destroyed') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.physics.getDistance +love.test.physics.getDistance = function(test) + -- setup two fixtues to check + local world = love.physics.newWorld(0, 0, false) + local body = love.physics.newBody(world, 10, 10, 'static') + local shape1 = love.physics.newEdgeShape(body, 0, 0, 5, 5) + local shape2 = love.physics.newEdgeShape(body, 10, 10, 15, 15) + -- check distance between them + test:assertRange(love.physics.getDistance(shape1, shape2), 6, 7, 'check distance matches') +end + + +-- love.physics.getMeter +love.test.physics.getMeter = function(test) + -- check value set is returned + love.physics.setMeter(30) + test:assertEquals(30, love.physics.getMeter(), 'check meter matches') +end + + +-- love.physics.newBody +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newBody = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + test:assertObject(body) +end + + +-- love.physics.newChainShape +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newChainShape = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + test:assertObject(love.physics.newChainShape(body, true, 0, 0, 1, 0, 1, 1, 0, 1)) +end + + +-- love.physics.newCircleShape +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newCircleShape = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + test:assertObject(love.physics.newCircleShape(body, 10)) +end + + +-- love.physics.newDistanceJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newDistanceJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newDistanceJoint(body1, body2, 10, 10, 20, 20, true) + test:assertObject(obj) +end + + +-- love.physics.newEdgeShape +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newEdgeShape = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + local obj = love.physics.newEdgeShape(body, 0, 0, 10, 10) + test:assertObject(obj) +end + + +-- love.physics.newFrictionJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newFrictionJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newFrictionJoint(body1, body2, 15, 15, true) + test:assertObject(obj) +end + + +-- love.physics.newGearJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newGearJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'dynamic') + local body2 = love.physics.newBody(world, 20, 20, 'dynamic') + local body3 = love.physics.newBody(world, 30, 30, 'dynamic') + local body4 = love.physics.newBody(world, 40, 40, 'dynamic') + local joint1 = love.physics.newPrismaticJoint(body1, body2, 10, 10, 20, 20, true) + local joint2 = love.physics.newPrismaticJoint(body3, body4, 30, 30, 40, 40, true) + local obj = love.physics.newGearJoint(joint1, joint2, 1, true) + test:assertObject(obj) +end + + +-- love.physics.newMotorJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newMotorJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newMotorJoint(body1, body2, 1) + test:assertObject(obj) +end + + +-- love.physics.newMouseJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newMouseJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + local obj = love.physics.newMouseJoint(body, 10, 10) + test:assertObject(obj) +end + + +-- love.physics.newPolygonShape +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newPolygonShape = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + local obj = love.physics.newPolygonShape(body, {0, 0, 2, 3, 2, 1, 3, 1, 5, 1}) + test:assertObject(obj) +end + + +-- love.physics.newPrismaticJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newPrismaticJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newPrismaticJoint(body1, body2, 10, 10, 20, 20, true) + test:assertObject(obj) +end + + +-- love.physics.newPulleyJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newPulleyJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newPulleyJoint(body1, body2, 10, 10, 20, 20, 15, 15, 25, 25, 1, true) + test:assertObject(obj) +end + + +-- love.physics.newRectangleShape +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newRectangleShape = function(test) + local world = love.physics.newWorld(1, 1, true) + local body = love.physics.newBody(world, 10, 10, 'static') + local shape1 = love.physics.newRectangleShape(body, 10, 20) + local shape2 = love.physics.newRectangleShape(body, 10, 10, 40, 30, 10) + test:assertObject(shape1) + test:assertObject(shape2) +end + + +-- love.physics.newRevoluteJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newRevoluteJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newRevoluteJoint(body1, body2, 10, 10, true) + test:assertObject(obj) +end + + +-- love.physics.newRopeJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newRopeJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newRopeJoint(body1, body2, 10, 10, 20, 20, 50, true) + test:assertObject(obj) +end + + +-- love.physics.newWeldJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newWeldJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newWeldJoint(body1, body2, 10, 10, true) + test:assertObject(obj) +end + + +-- love.physics.newWheelJoint +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newWheelJoint = function(test) + local world = love.physics.newWorld(1, 1, true) + local body1 = love.physics.newBody(world, 10, 10, 'static') + local body2 = love.physics.newBody(world, 20, 20, 'static') + local obj = love.physics.newWheelJoint(body1, body2, 10, 10, 5, 5, true) + test:assertObject(obj) +end + + +-- love.physics.newWorld +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.physics.newWorld = function(test) + local world = love.physics.newWorld(1, 1, true) + test:assertObject(world) +end + + +-- love.physics.setMeter +love.test.physics.setMeter = function(test) + -- set initial meter + local world = love.physics.newWorld(1, 1, true) + love.physics.setMeter(30) + local body = love.physics.newBody(world, 300, 300, "dynamic") + -- check changing meter changes pos value relatively + love.physics.setMeter(10) + local x, y = body:getPosition() + test:assertEquals(100, x, 'check pos x') + test:assertEquals(100, y, 'check pos y') +end diff --git a/testing/tests/sensor.lua b/testing/tests/sensor.lua new file mode 100644 index 000000000..56c5da7b5 --- /dev/null +++ b/testing/tests/sensor.lua @@ -0,0 +1,102 @@ +-- love.sensor +-- @NOTE we can't test this module fully as it's hardware dependent +-- however we can test methods do what is expected and can handle certain params + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------HELPERS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + +local function testIsEnabled(test, sensorType) + love.sensor.setEnabled(sensorType, true) + test:assertTrue(love.sensor.isEnabled(sensorType), 'check ' .. sensorType .. ' enabled') + love.sensor.setEnabled(sensorType, false) + test:assertFalse(love.sensor.isEnabled(sensorType), 'check ' .. sensorType .. ' disabled') +end + + +local function testGetName(test, sensorType) + love.sensor.setEnabled(sensorType, true) + local ok, name = pcall(love.sensor.getName, sensorType) + test:assertTrue(ok, 'check sensor.getName("' .. sensorType .. '") success') + test:assertEquals(type(name), 'string', 'check sensor.getName("' .. sensorType .. '") return value type') + + love.sensor.setEnabled(sensorType, false) + ok, name = pcall(love.sensor.getName, sensorType) + test:assertFalse(ok, 'check sensor.getName("' .. sensorType .. '") errors when disabled') +end + + +local function testGetData(test, sensorType) + love.sensor.setEnabled(sensorType, true) + local ok, x, y, z = pcall(love.sensor.getData, sensorType) + test:assertTrue(ok, 'check sensor.getData("' .. sensorType .. '") success') + if ok then + test:assertNotNil(x) + test:assertNotNil(y) + test:assertNotNil(z) + end + + love.sensor.setEnabled(sensorType, false) + ok, x, y, z = pcall(love.sensor.getData, sensorType) + test:assertFalse(ok, 'check sensor.getData("' .. sensorType .. '") errors when disabled') +end + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.sensor.hasSensor +love.test.sensor.hasSensor = function(test) + -- but we can make sure that the SensorTypes can be passed + local accelerometer = love.sensor.hasSensor('accelerometer') + local gyroscope = love.sensor.hasSensor('gyroscope') + test:assertNotNil(accelerometer) + test:assertNotNil(gyroscope) +end + + +-- love.sensor.isEnabled and love.sensor.setEnabled +love.test.sensor.isEnabled = function(test) + local accelerometer = love.sensor.hasSensor('accelerometer') + local gyroscope = love.sensor.hasSensor('gyroscope') + + if accelerometer or gyroscope then + if accelerometer then testIsEnabled(test, 'accelerometer') end + if gyroscope then testIsEnabled(test, 'gyroscope') end + else + test:skipTest('neither accelerometer nor gyroscope are supported in this system') + end +end + + +-- love.sensor.getName +love.test.sensor.getName = function(test) + local accelerometer = love.sensor.hasSensor('accelerometer') + local gyroscope = love.sensor.hasSensor('gyroscope') + + if accelerometer or gyroscope then + if accelerometer then testGetName(test, 'accelerometer') end + if gyroscope then testGetName(test, 'gyroscope') end + else + test:skipTest('neither accelerometer nor gyroscope are supported in this system') + end +end + + +-- love.sensor.getData +love.test.sensor.getData = function(test) + local accelerometer = love.sensor.hasSensor('accelerometer') + local gyroscope = love.sensor.hasSensor('gyroscope') + + if accelerometer or gyroscope then + if accelerometer then testGetData(test, 'accelerometer') end + if gyroscope then testGetData(test, 'gyroscope') end + else + test:skipTest('neither accelerometer nor gyroscope are supported in this system') + end +end diff --git a/testing/tests/sound.lua b/testing/tests/sound.lua new file mode 100644 index 000000000..d5032cb30 --- /dev/null +++ b/testing/tests/sound.lua @@ -0,0 +1,118 @@ +-- love.sound + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------OBJECTS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- Decoder (love.sound.newDecoder) +love.test.sound.Decoder = function(test) + + -- create obj + local decoder = love.sound.newDecoder('resources/click.ogg') + test:assertObject(decoder) + + -- check bit depth + test:assertMatch({8, 16}, decoder:getBitDepth(), 'check bit depth') + + -- check channel count + test:assertMatch({1, 2}, decoder:getChannelCount(), 'check channel count') + + -- check duration + test:assertRange(decoder:getDuration(), 0.06, 0.07, 'check duration') + + -- check sample rate + test:assertEquals(44100, decoder:getSampleRate(), 'check sample rate') + + -- check makes sound data (test in method below) + test:assertObject(decoder:decode()) + + -- check cloning sound + local clone = decoder:clone() + test:assertMatch({8, 16}, clone:getBitDepth(), 'check cloned bit depth') + test:assertMatch({1, 2}, clone:getChannelCount(), 'check cloned channel count') + test:assertRange(clone:getDuration(), 0.06, 0.07, 'check cloned duration') + test:assertEquals(44100, clone:getSampleRate(), 'check cloned sample rate') + +end + + +-- SoundData (love.sound.newSoundData) +love.test.sound.SoundData = function(test) + + -- create obj + local sdata = love.sound.newSoundData('resources/click.ogg') + test:assertObject(sdata) + + -- check data size + string + test:assertEquals(11708, sdata:getSize(), 'check size') + test:assertNotNil(sdata:getString()) + + -- check bit depth + test:assertMatch({8, 16}, sdata:getBitDepth(), 'check bit depth') + + -- check channel count + test:assertMatch({1, 2}, sdata:getChannelCount(), 'check channel count') + + -- check duration + test:assertRange(sdata:getDuration(), 0.06, 0.07, 'check duration') + + -- check samples + test:assertEquals(44100, sdata:getSampleRate(), 'check sample rate') + test:assertEquals(2927, sdata:getSampleCount(), 'check sample count') + + -- check cloning + local clone = sdata:clone() + test:assertEquals(11708, clone:getSize(), 'check clone size') + test:assertNotNil(clone:getString()) + test:assertMatch({8, 16}, clone:getBitDepth(), 'check clone bit depth') + test:assertMatch({1, 2}, clone:getChannelCount(), 'check clone channel count') + test:assertRange(clone:getDuration(), 0.06, 0.07, 'check clone duration') + test:assertEquals(44100, clone:getSampleRate(), 'check clone sample rate') + test:assertEquals(2927, clone:getSampleCount(), 'check clone sample count') + + -- check sample setting + test:assertRange(sdata:getSample(0.001), -0.1, 0, 'check sample 1') + test:assertRange(sdata:getSample(0.005), -0.1, 0, 'check sample 1') + sdata:setSample(0.002, 1) + test:assertEquals(1, sdata:getSample(0.002), 'check setting sample manually') + + -- check copying from another sound + local copy1 = love.sound.newSoundData('resources/tone.ogg') + local copy2 = love.sound.newSoundData('resources/pop.ogg') + local before = copy2:getSample(0.02) + copy2:copyFrom(copy1, 0.01, 1, 0.02) + test:assertNotEquals(before, copy2:getSample(0.02), 'check changed') + + -- check slicing + local count = math.floor(copy1:getSampleCount()/2) + local slice = copy1:slice(0, count) + test:assertEquals(count, slice:getSampleCount(), 'check slice length') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + + +-- love.sound.newDecoder +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.sound.newDecoder = function(test) + test:assertObject(love.sound.newDecoder('resources/click.ogg')) +end + + +-- love.sound.newSoundData +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.sound.newSoundData = function(test) + test:assertObject(love.sound.newSoundData('resources/click.ogg')) + test:assertObject(love.sound.newSoundData(math.floor((1/32)*44100), 44100, 16, 1)) +end diff --git a/testing/tests/system.lua b/testing/tests/system.lua new file mode 100644 index 000000000..88912d525 --- /dev/null +++ b/testing/tests/system.lua @@ -0,0 +1,91 @@ +-- love.system + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------METHODS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.system.getClipboardText +love.test.system.getClipboardText = function(test) + -- ignore if not using window + if love.test.windowmode == false then + return test:skipTest('clipboard only available in window mode') + end + -- check clipboard value is set + love.system.setClipboardText('helloworld') + test:assertEquals('helloworld', love.system.getClipboardText(), 'check clipboard match') +end + + +-- love.system.getOS +love.test.system.getOS = function(test) + -- check os is in documented values + local os = love.system.getOS() + local options = {'OS X', 'Windows', 'Linux', 'Android', 'iOS'} + test:assertMatch(options, os, 'check value matches') +end + + +-- love.system.getPreferredLocales +love.test.system.getPreferredLocales = function(test) + local locale = love.system.getPreferredLocales() + test:assertNotNil(locale) + test:assertEquals('table', type(locale), 'check returns table') +end + + +-- love.system.getPowerInfo +love.test.system.getPowerInfo = function(test) + -- check battery state is one of the documented states + local state, percent, seconds = love.system.getPowerInfo() + local states = {'unknown', 'battery', 'nobattery', 'charging', 'charged'} + test:assertMatch(states, state, 'check value matches') + -- if percent/seconds check within expected range + if percent ~= nil then + test:assertRange(percent, 0, 100, 'check battery percent within range') + end + if seconds ~= nil then + test:assertNotNil(seconds) + end +end + + +-- love.system.getProcessorCount +love.test.system.getProcessorCount = function(test) + test:assertNotNil(love.system.getProcessorCount()) -- youd hope right +end + + +-- love.system.hasBackgroundMusic +love.test.system.hasBackgroundMusic = function(test) + test:assertNotNil(love.system.hasBackgroundMusic()) +end + + +-- love.system.openURL +love.test.system.openURL = function(test) + test:skipTest('cant test this worked') + --test:assertNotEquals(nil, love.system.openURL('https://love2d.org'), 'check open URL') +end + + +-- love.system.getClipboardText +love.test.system.setClipboardText = function(test) + -- ignore if not using window + if love.test.windowmode == false then + return test:skipTest('clipboard only available in window mode') + end + -- check value returned is what was set + love.system.setClipboardText('helloworld') + test:assertEquals('helloworld', love.system.getClipboardText(), 'check set text') +end + + +-- love.system.vibrate +-- @NOTE cant really test this +love.test.system.vibrate = function(test) + test:skipTest('cant test this worked') +end diff --git a/testing/tests/thread.lua b/testing/tests/thread.lua new file mode 100644 index 000000000..6bf03d358 --- /dev/null +++ b/testing/tests/thread.lua @@ -0,0 +1,137 @@ +-- love.thread + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------OBJECTS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- Channel (love.thread.newChannel) +love.test.thread.Channel = function(test) + + -- create channel + local channel = love.thread.getChannel('test') + test:assertObject(channel) + + -- setup thread to use + local threadcode1 = [[ + require("love.timer") + love.timer.sleep(0.1) + love.thread.getChannel('test'):push('hello world') + love.timer.sleep(0.1) + love.thread.getChannel('test'):push('me again') + ]] + local thread1 = love.thread.newThread(threadcode1) + thread1:start() + + -- check message sent from thread to channel + local msg1 = channel:demand() + test:assertEquals('hello world', msg1, 'check 1st message was sent') + thread1:wait() + test:assertEquals(1, channel:getCount(), 'check still another message') + test:assertEquals('me again', channel:peek(), 'check 2nd message pending') + local msg2 = channel:pop() + test:assertEquals('me again', msg2, 'check 2nd message was sent') + channel:clear() + + -- setup another thread for some ping pong + local threadcode2 = [[ + local function setChannel(channel, value) + channel:clear() + return channel:push(value) + end + local channel = love.thread.getChannel('test') + local waiting = true + local sent = nil + while waiting == true do + if sent == nil then + sent = channel:performAtomic(setChannel, 'ping') + end + if channel:hasRead(sent) then + local msg = channel:demand() + if msg == 'pong' then + channel:push(msg) + waiting = false + end + end + end + ]] + + -- first we run a thread that will send 1 ping + local thread2 = love.thread.newThread(threadcode2) + thread2:start() + + -- we wait for that ping to be sent and then send a pong back + local msg3 = channel:demand() + test:assertEquals('ping', msg3, 'check message recieved 1') + + -- thread should be waiting for us, and checking is the ping was read + channel:supply('pong', 1) + + -- if it was then it should send back our pong and thread should die + thread2:wait() + local msg4 = channel:pop() + test:assertEquals('pong', msg4, 'check message recieved 2') + test:assertEquals(0, channel:getCount()) + +end + + +-- Thread (love.thread.newThread) +love.test.thread.Thread = function(test) + + -- create thread + local threadcode = [[ + local b = 0 + for a=1,100000 do + b = b + a + end + ]] + local thread = love.thread.newThread(threadcode) + test:assertObject(thread) + + -- check thread runs + thread:start() + test:assertTrue(thread:isRunning(), 'check started') + thread:wait() + test:assertFalse(thread:isRunning(), 'check finished') + test:assertEquals(nil, thread:getError(), 'check no errors') + + -- check an invalid thread + local badthreadcode = 'local b = 0\nreturn b + "string" .. 10' + local badthread = love.thread.newThread(badthreadcode) + badthread:start() + badthread:wait() + test:assertNotNil(badthread:getError()) + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------METHODS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.thread.getChannel +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.thread.getChannel = function(test) + test:assertObject(love.thread.getChannel('test')) +end + + +-- love.thread.newChannel +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.thread.newChannel = function(test) + test:assertObject(love.thread.newChannel()) +end + + +-- love.thread.newThread +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.thread.newThread = function(test) + test:assertObject(love.thread.newThread('classes/TestSuite.lua')) +end diff --git a/testing/tests/timer.lua b/testing/tests/timer.lua new file mode 100644 index 000000000..33de52447 --- /dev/null +++ b/testing/tests/timer.lua @@ -0,0 +1,52 @@ +-- love.timer + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------METHODS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.timer.getAverageDelta +-- @NOTE not sure if you could reliably get a specific delta? +love.test.timer.getAverageDelta = function(test) + test:assertNotNil(love.timer.getAverageDelta()) +end + +-- love.timer.getDelta +-- @NOTE not sure if you could reliably get a specific delta? +love.test.timer.getDelta = function(test) + test:assertNotNil(love.timer.getDelta()) +end + + +-- love.timer.getFPS +-- @NOTE not sure if you could reliably get a specific FPS? +love.test.timer.getFPS = function(test) + test:assertNotNil(love.timer.getFPS()) +end + + +-- love.timer.getTime +love.test.timer.getTime = function(test) + local starttime = love.timer.getTime() + love.timer.sleep(0.1) + local endtime = love.timer.getTime() - starttime + test:assertRange(endtime, 0.05, 1, 'check 0.1s passes') +end + + +-- love.timer.sleep +love.test.timer.sleep = function(test) + local starttime = love.timer.getTime() + love.timer.sleep(0.1) + test:assertRange(love.timer.getTime() - starttime, 0.05, 1, 'check 0.1s passes') +end + + +-- love.timer.step +-- @NOTE not sure if you could reliably get a specific step val? +love.test.timer.step = function(test) + test:assertNotNil(love.timer.step()) +end diff --git a/testing/tests/touch.lua b/testing/tests/touch.lua new file mode 100644 index 000000000..b3e804687 --- /dev/null +++ b/testing/tests/touch.lua @@ -0,0 +1,31 @@ +-- love.touch +-- @NOTE we can't test this module fully as it's hardware dependent +-- however we can test methods do what is expected and can handle certain params + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +------------------------------------METHODS------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.touch.getPosition +-- @TODO is there a way to fake the touchid pointer? +love.test.touch.getPosition = function(test) + test:assertNotNil(love.touch.getPosition) + test:assertEquals('function', type(love.touch.getPosition)) +end + + +-- love.touch.getPressure +-- @TODO is there a way to fake the touchid pointer? +love.test.touch.getPressure = function(test) + test:assertNotNil(love.touch.getPressure) + test:assertEquals('function', type(love.touch.getPressure)) +end + + +-- love.touch.getTouches +love.test.touch.getTouches = function(test) + test:assertEquals('function', type(love.touch.getTouches)) +end diff --git a/testing/tests/video.lua b/testing/tests/video.lua new file mode 100644 index 000000000..169e0dd8d --- /dev/null +++ b/testing/tests/video.lua @@ -0,0 +1,46 @@ +-- love.video + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------OBJECTS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- VideoStream (love.thread.newVideoStream) +love.test.video.VideoStream = function(test) + + -- create obj + local video = love.video.newVideoStream('resources/sample.ogv') + test:assertObject(video) + + -- check def properties + test:assertEquals('resources/sample.ogv', video:getFilename(), 'check filename') + test:assertFalse(video:isPlaying(), 'check not playing by def') + + -- check playing and pausing states + video:play() + test:assertTrue(video:isPlaying(), 'check now playing') + video:seek(0.3) + test:assertRange(video:tell(), 0.3, 0.4, 'check seek/tell') + video:rewind() + test:assertRange(video:tell(), 0, 0.1, 'check rewind') + video:pause() + test:assertFalse(video:isPlaying(), 'check paused') + +end + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------METHODS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.video.newVideoStream +-- @NOTE this is just basic nil checking, objs have their own test method +love.test.video.newVideoStream = function(test) + test:assertObject(love.video.newVideoStream('resources/sample.ogv')) +end diff --git a/testing/tests/window.lua b/testing/tests/window.lua new file mode 100644 index 000000000..98cfc2f43 --- /dev/null +++ b/testing/tests/window.lua @@ -0,0 +1,361 @@ +-- love.window + + +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- +----------------------------------METHODS--------------------------------------- +-------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- + + +-- love.window.focus +love.test.window.focus = function(test) + -- cant test as doesnt return anything + test:assertEquals('function', type(love.window.focus), 'check method exists') +end + + +-- love.window.fromPixels +love.test.window.fromPixels = function(test) + -- check dpi/pixel ratio as expected + local dpi = love.window.getDPIScale() + local pixels = love.window.fromPixels(100) + test:assertEquals(100/dpi, pixels, 'check dpi ratio') +end + + +-- love.window.getDPIScale +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getDPIScale = function(test) + test:assertNotNil(test) +end + + +-- love.window.getDesktopDimensions +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getDesktopDimensions = function(test) + local w, h = love.window.getDesktopDimensions() + test:assertNotNil(w) + test:assertNotNil(h) +end + + +-- love.window.getDisplayCount +-- @NOTE cant wait for the test suite to be run headless and fail here +love.test.window.getDisplayCount = function(test) + test:assertGreaterEqual(1, love.window.getDisplayCount(), 'check 1 display') +end + + +-- love.window.getDisplayName +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getDisplayName = function(test) + test:assertNotNil(love.window.getDisplayName(1)) +end + + +-- love.window.getDisplayOrientation +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getDisplayOrientation = function(test) + test:assertNotNil(love.window.getDisplayOrientation(1)) +end + + +-- love.window.getFullscreen +love.test.window.getFullscreen = function(test) + -- check not fullscreen to start + test:assertFalse(love.window.getFullscreen(), 'check not fullscreen') + love.window.setFullscreen(true) + -- check now fullscreen + test:assertTrue(love.window.getFullscreen(), 'check now fullscreen') + love.window.setFullscreen(false) -- reset +end + + +-- love.window.getFullscreenModes +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getFullscreenModes = function(test) + test:assertNotNil(love.window.getFullscreenModes(1)) +end + + +-- love.window.getIcon +love.test.window.getIcon = function(test) + -- check icon nil by default if not set + test:assertEquals(nil, love.window.getIcon(), 'check nil by default') + local icon = love.image.newImageData('resources/love.png') + -- check getting icon not nil after setting + love.window.setIcon(icon) + test:assertNotNil(love.window.getIcon()) +end + + +-- love.window.getMode +-- @NOTE could prob add more checks on the flags here based on conf.lua +love.test.window.getMode = function(test) + local w, h, flags = love.window.getMode() + test:assertEquals(360, w, 'check w') + test:assertEquals(240, h, 'check h') + test:assertFalse(flags["fullscreen"], 'check fullscreen') +end + + +-- love.window.getPosition +-- @NOTE anything we could check display index agaisn't in getPosition return? +love.test.window.getPosition = function(test) + love.window.setPosition(100, 100, 1) + local x, y, _ = love.window.getPosition() + test:assertEquals(100, x, 'check position x') + test:assertEquals(100, y, 'check position y') +end + + +-- love.window.getSafeArea +-- @NOTE dependent on hardware so best can do is not nil +love.test.window.getSafeArea = function(test) + local x, y, w, h = love.window.getSafeArea() + test:assertNotNil(x) + test:assertNotNil(y) + test:assertNotNil(w) + test:assertNotNil(h) +end + + +-- love.window.getTitle +love.test.window.getTitle = function(test) + -- check title returned is what was set + love.window.setTitle('love.testing') + test:assertEquals('love.testing', love.window.getTitle(), 'check title match') + love.window.setTitle('love.test') +end + + +-- love.window.getVSync +love.test.window.getVSync = function(test) + test:assertNotNil(love.window.getVSync()) +end + + +-- love.window.hasFocus +-- @NOTE cant really test as cant force focus +love.test.window.hasFocus = function(test) + test:assertNotNil(love.window.hasFocus()) +end + + +-- love.window.hasMouseFocus +-- @NOTE cant really test as cant force focus +love.test.window.hasMouseFocus = function(test) + test:assertNotNil(love.window.hasMouseFocus()) +end + + +-- love.window.isDisplaySleepEnabled +love.test.window.isDisplaySleepEnabled = function(test) + test:assertNotNil(love.window.isDisplaySleepEnabled()) + -- check disabled + love.window.setDisplaySleepEnabled(false) + test:assertFalse(love.window.isDisplaySleepEnabled(), 'check sleep disabled') + -- check enabled + love.window.setDisplaySleepEnabled(true) + test:assertTrue(love.window.isDisplaySleepEnabled(), 'check sleep enabled') +end + + +-- love.window.isMaximized +love.test.window.isMaximized = function(test) + test:assertFalse(love.window.isMaximized(), 'check window not maximized') + love.window.maximize() + test:waitFrames(10) + -- on MACOS maximize wont get recognised immedietely so wait a few frames + test:assertTrue(love.window.isMaximized(), 'check window now maximized') + love.window.restore() +end + + +-- love.window.isMinimized +love.test.window.isMinimized = function(test) + -- check not minimized to start + test:assertFalse(love.window.isMinimized(), 'check window not minimized') + -- try to minimize + love.window.minimize() + test:waitFrames(10) + -- on linux minimize won't get recognized immediately, so wait a few frames + test:assertTrue(love.window.isMinimized(), 'check window minimized') + love.window.restore() +end + + +-- love.window.isOpen +love.test.window.isOpen = function(test) + -- check open initially + test:assertTrue(love.window.isOpen(), 'check window open') + -- we check closing in test.window.close +end + + +-- love.window.isVisible +love.test.window.isVisible = function(test) + -- check visible initially + test:assertTrue(love.window.isVisible(), 'check window visible') + -- we check closing in test.window.close +end + + +-- love.window.maximize +love.test.window.maximize = function(test) + test:assertFalse(love.window.isMaximized(), 'check window not maximized') + -- check maximizing is set + love.window.maximize() + test:waitFrames(10) + -- on macos we need to wait a few frames + test:assertTrue(love.window.isMaximized(), 'check window maximized') + love.window.restore() +end + + +-- love.window.minimize +love.test.window.minimize = function(test) + test:assertFalse(love.window.isMinimized(), 'check window not minimized') + -- check minimizing is set + love.window.minimize() + test:waitFrames(10) + -- on linux we need to wait a few frames + test:assertTrue(love.window.isMinimized(), 'check window maximized') + love.window.restore() +end + + +-- love.window.requestAttention +love.test.window.requestAttention = function(test) + test:skipTest('cant test this worked') +end + + +-- love.window.restore +love.test.window.restore = function(test) + -- check minimized to start + love.window.minimize() + test:waitFrames(10) + love.window.restore() + test:waitFrames(10) + -- check restoring the state of the window + test:assertFalse(love.window.isMinimized(), 'check window restored') +end + + +-- love.window.setDisplaySleepEnabled +love.test.window.setDisplaySleepEnabled = function(test) + -- check disabling sleep + love.window.setDisplaySleepEnabled(false) + test:assertFalse(love.window.isDisplaySleepEnabled(), 'check sleep disabled') + -- check setting it back to enabled + love.window.setDisplaySleepEnabled(true) + test:assertTrue(love.window.isDisplaySleepEnabled(), 'check sleep enabled') +end + + +-- love.window.setFullscreen +love.test.window.setFullscreen = function(test) + -- check fullscreen is set + love.window.setFullscreen(true) + test:assertTrue(love.window.getFullscreen(), 'check fullscreen') + -- check setting back to normal + love.window.setFullscreen(false) + test:assertFalse(love.window.getFullscreen(), 'check not fullscreen') +end + + +-- love.window.setIcon +-- @NOTE could check the image data itself? +love.test.window.setIcon = function(test) + -- check setting an icon returns the val + local icon = love.image.newImageData('resources/love.png') + love.window.setIcon(icon) + test:assertNotEquals(nil, love.window.getIcon(), 'check icon not nil') +end + + +-- love.window.setMode +-- @NOTE same as getMode could be checking more flag properties +love.test.window.setMode = function(test) + -- set window mode + love.window.setMode(512, 512, { + fullscreen = false, + resizable = false + }) + -- check what we set is returned + local width, height, flags = love.window.getMode() + test:assertEquals(512, width, 'check window w match') + test:assertEquals(512, height, 'check window h match') + test:assertFalse(flags["fullscreen"], 'check window not fullscreen') + test:assertFalse(flags["resizable"], 'check window not resizeable') + love.window.setMode(360, 240, { + fullscreen = false, + resizable = true + }) +end + +-- love.window.setPosition +love.test.window.setPosition = function(test) + -- check position is returned + love.window.setPosition(100, 100, 1) + test:waitFrames(10) + local x, y, _ = love.window.getPosition() + test:assertEquals(100, x, 'check position x') + test:assertEquals(100, y, 'check position y') +end + + +-- love.window.setTitle +love.test.window.setTitle = function(test) + -- check setting title val is returned + love.window.setTitle('love.testing') + test:assertEquals('love.testing', love.window.getTitle(), 'check title matches') + love.window.setTitle('love.test') +end + + +-- love.window.setVSync +love.test.window.setVSync = function(test) + love.window.setVSync(0) + test:assertNotNil(love.window.getVSync()) +end + + +-- love.window.showMessageBox +-- @NOTE if running headless would need to skip anyway cos can't press it +love.test.window.showMessageBox = function(test) + test:skipTest('cant test this worked') +end + + +-- love.window.toPixels +love.test.window.toPixels = function(test) + -- check dpi/pixel ratio is as expected + local dpi = love.window.getDPIScale() + local pixels = love.window.toPixels(50) + test:assertEquals(50*dpi, pixels, 'check dpi ratio') +end + + +-- love.window.updateMode +love.test.window.updateMode = function(test) + -- set initial mode + love.window.setMode(512, 512, { + fullscreen = false, + resizable = false + }) + -- update mode with some props but not others + love.window.updateMode(360, 240, nil) + -- check only changed values changed + local width, height, flags = love.window.getMode() + test:assertEquals(360, width, 'check window w match') + test:assertEquals(240, height, 'check window h match') + test:assertFalse(flags["fullscreen"], 'check window not fullscreen') + test:assertFalse(flags["resizable"], 'check window not resizeable') + love.window.setMode(360, 240, { -- reset + fullscreen = false, + resizable = true + }) +end diff --git a/testing/todo.md b/testing/todo.md new file mode 100644 index 000000000..ba589fb75 --- /dev/null +++ b/testing/todo.md @@ -0,0 +1,28 @@ +# TODO +These are all the outstanding methods that require test coverage, along with a few bits that still need doing / discussion. + +## General +- ability to test loading different combinations of modules if needed? +- check expected behaviour of mount + unmount with common path + try uncommenting love.filesystem.unmountCommonPath and you'll see the issues +- revisit love.audio.setPlaybackDevice when we update openal soft for MacOS + +## Graphics +- love.graphics.copyBuffer() +- love.graphics.copyBufferToTexture() +- love.graphics.copyTextureToBuffer() +- love.graphics.readbackTexture() +- love.graphics.readbackTextureAsync() +- love.graphics.readbackBuffer() +- love.graphics.readbackBufferAsync() +- love.graphics.newComputeShader() +- love.graphics.dispatchThreadgroups() +- love.graphics.dispatchIndirect() +- love.graphics.drawFromShader() +- love.graphics.drawFromShaderIndirect() +- love.graphics.drawIndirect() +- love.graphics.getQuadIndexBuffer() +- love.graphics.setBlendState() +- love.graphics.resetProjection() +- love.graphics.Mesh:getAttachedAttributes() +- love.graphics.Shader:hasStage()