diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..b1a0d2b7de --- /dev/null +++ b/.clang-format @@ -0,0 +1,41 @@ +BasedOnStyle: LLVM + +# Whitespace +MaxEmptyLinesToKeep: 2 +IndentWidth: 4 +ColumnLimit: 100 + +# Preprocessor +AlignEscapedNewlines: Left +IncludeBlocks: Regroup + +# Functions +AllowAllArgumentsOnNextLine: false +BinPackArguments: false +BinPackParameters: false +AllowAllParametersOfDeclarationOnNextLine: false +PenaltyReturnTypeOnItsOwnLine: 9999999 +PenaltyBreakBeforeFirstCallParameter: 6 +AllowShortFunctionsOnASingleLine: Inline + +# Brackets and braces +AlignAfterOpenBracket: AlwaysBreak +BreakBeforeBraces: Allman + +# Pointers +PointerAlignment: Left + +# Classes +PackConstructorInitializers: NextLineOnly +BreakConstructorInitializers: BeforeComma +AccessModifierOffset: -4 + +# Switch statements +IndentCaseBlocks: true + +# Templates +SpaceAfterTemplateKeyword: false +AlwaysBreakTemplateDeclarations: true + +# Misc +SortUsingDeclarations: false diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..b2e758e0c1 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,2 @@ +* @shader-slang/dev +/docs/proposals @tangent-vector @csyonghe @expipiplus1 diff --git a/.github/actions/common-setup/action.yml b/.github/actions/common-setup/action.yml index 712a74df52..68a47e707e 100644 --- a/.github/actions/common-setup/action.yml +++ b/.github/actions/common-setup/action.yml @@ -16,6 +16,13 @@ inputs: runs: using: composite steps: + - name: Add bash to PATH + shell: pwsh + if: ${{inputs.os == 'windows'}} + run: | + Add-Content -Path $env:GITHUB_PATH -Value "C:\\Program Files\\Git\\bin" + Add-Content -Path $env:GITHUB_PATH -Value "C:\\Program Files\\Git\\usr\\bin" + - name: Set up MSVC dev tools on Windows uses: ilammy/msvc-dev-cmd@v1 with: @@ -59,14 +66,20 @@ runs: # Some useful variables config=${{inputs.config}} - Config=$(echo "${{inputs.config}}" | sed 's/debug/Debug/;s/release/Release/') - bin_dir=$(pwd)/build/$Config/bin - lib_dir=$(pwd)/build/$Config/lib + cmake_config=$(echo "${{inputs.config}}" | sed ' + s/^debug$/Debug/ + s/^release$/Release/ + s/^releaseWithDebugInfo$/RelWithDebInfo/ + s/^minSizeRelease$/MinSizeRel/ + ') + bin_dir=$(pwd)/build/$cmake_config/bin + lib_dir=$(pwd)/build/$cmake_config/lib echo "config=$config" >> "$GITHUB_ENV" + echo "cmake_config=$cmake_config" >> "$GITHUB_ENV" echo "bin_dir=$bin_dir" >> "$GITHUB_ENV" echo "lib_dir=$lib_dir" >> "$GITHUB_ENV" - # Try to restore a LLVM install, and build it otherwise + # Try to restore an LLVM install, and build it otherwise - uses: actions/cache/restore@v4 id: cache-llvm if: inputs.build-llvm == 'true' @@ -77,25 +90,17 @@ runs: - name: Build LLVM if: inputs.build-llvm == 'true' && steps.cache-llvm.outputs.cache-hit != 'true' shell: bash - run: ./external/build-llvm.sh --install-prefix "${{ github.workspace }}/build/llvm-project-install" + run: | + ./external/build-llvm.sh \ + --install-prefix "${{github.workspace}}/build/llvm-project-install" \ + --repo "https://${{github.token}}@github.com/llvm/llvm-project" - uses: actions/cache/save@v4 if: inputs.build-llvm == 'true' && steps.cache-llvm.outputs.cache-hit != 'true' with: path: ${{ github.workspace }}/build/llvm-project-install key: ${{ steps.cache-llvm.outputs.cache-primary-key }} - # Run this after building llvm, it's pointless to fill the caches with - # infrequent llvm build products - - name: Set up sccache - uses: hendrikmuhs/ccache-action@v1.2 - with: - key: ${{inputs.os}}-${{inputs.compiler}}-${{inputs.platform}}-${{inputs.config}} - variant: sccache - # Opportunistically use sccache, it's not available for example on self - # hosted runners or ARM - continue-on-error: true - - - name: Set environment variable for CMake + - name: Set environment variable for CMake and sccache shell: bash run: | if [ "${{inputs.build-llvm}}" == "true" ]; then @@ -108,9 +113,10 @@ runs: echo "CMAKE_CXX_COMPILER_LAUNCHER=sccache" >> "$GITHUB_ENV" echo "CMAKE_C_COMPILER_LAUNCHER=sccache" >> "$GITHUB_ENV" fi + echo SCCACHE_IGNORE_SERVER_IO_ERROR=1 >> "$GITHUB_ENV" # Install swiftshader - - uses: robinraju/release-downloader@v1.8 + - uses: robinraju/release-downloader@v1.11 continue-on-error: true with: latest: true diff --git a/.github/actions/format-setup/action.yml b/.github/actions/format-setup/action.yml new file mode 100644 index 0000000000..1028ce6bb9 --- /dev/null +++ b/.github/actions/format-setup/action.yml @@ -0,0 +1,37 @@ +name: Formatting tools setup + +description: Performs setup common to the code formatting actions + +runs: + using: composite + steps: + - name: install gersemi + shell: bash + run: | + pip3 install gersemi colorama + + - name: install clang-format + shell: bash + run: | + tmpdir=$(mktemp -d) + curl -L -H "Authorization: token ${{github.token}}" \ + -o "$tmpdir/clang-format" \ + https://github.com/shader-slang/slang-binaries/raw/306d22efc0f5f72c7230b0b6b7c99f03c46995bd/clang-format/x86_64-linux/bin/clang-format + chmod +x "$tmpdir/clang-format" + echo "$tmpdir" >> $GITHUB_PATH + + - name: install prettier + shell: bash + run: | + npm install -g prettier@3.3.3 + echo "$(npm bin -g)" >> $GITHUB_PATH + + - name: install shfmt + shell: bash + run: | + tmpdir=$(mktemp -d) + curl -L -H "Authorization: token ${{github.token}}" \ + -o "$tmpdir/shfmt" \ + https://github.com/mvdan/sh/releases/download/v3.10.0/shfmt_v3.10.0_linux_amd64 + chmod +x "$tmpdir/shfmt" + echo "$tmpdir" >> $GITHUB_PATH diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index eb90492f38..3398c8425d 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -4,17 +4,19 @@ on: push: branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" pull_request: branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -23,10 +25,10 @@ jobs: build: runs-on: [Windows, self-hosted] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - submodules: 'recursive' - fetch-depth: '0' + submodules: "recursive" + fetch-depth: "0" - name: Common setup uses: ./.github/actions/common-setup with: @@ -39,10 +41,10 @@ jobs: run: | cmake --preset default --fresh -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM -DCMAKE_COMPILE_WARNING_AS_ERROR=false cmake --workflow --preset release - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - repository: 'shader-slang/MDL-SDK' - path: 'external/MDL-SDK' + repository: "shader-slang/MDL-SDK" + path: "external/MDL-SDK" - name: Run benchmark run: | cd tools/benchmark diff --git a/.github/workflows/check-formatting.yml b/.github/workflows/check-formatting.yml new file mode 100644 index 0000000000..f4226cd8c4 --- /dev/null +++ b/.github/workflows/check-formatting.yml @@ -0,0 +1,14 @@ +name: Check Formatting (comment /format to auto-fix) + +on: + push: + branches: [master] + pull_request: + branches: [master] +jobs: + check-formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/format-setup + - run: ./extras/formatting.sh --check-only diff --git a/.github/workflows/check-toc.yml b/.github/workflows/check-toc.yml new file mode 100644 index 0000000000..2b478cb632 --- /dev/null +++ b/.github/workflows/check-toc.yml @@ -0,0 +1,13 @@ +name: Check Table of Contents (comment /regenerate-toc to auto-fix) + +on: + push: + branches: [master] + pull_request: + branches: [master] +jobs: + check-formatting: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: ./docs/build_toc.sh --check-only diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4d9fb06b9..ce7c821fd2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,18 +3,8 @@ name: CI on: push: branches: [master] - paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' pull_request: branches: [master] - paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -23,14 +13,17 @@ jobs: strategy: matrix: os: [linux, macos, windows] - config: [debug, release] + config: [debug, releaseWithDebugInfo] compiler: [gcc, clang, cl] - platform: [x86_64, aarch64] + platform: [x86_64, aarch64, wasm] exclude: # Default to x64, but aarch64 on osx - { os: linux, platform: aarch64 } - { os: windows, platform: aarch64 } - { os: macos, platform: x86_64 } + - { os: linux, config: debug, platform: wasm } + - { os: windows, platform: wasm } + - { os: macos, platform: wasm } # Unused compiler configs - { os: linux, compiler: clang } - { os: linux, compiler: cl } @@ -51,14 +44,14 @@ jobs: # quick or full conditionally otherwise - test-category: smoke - { os: windows, test-category: quick } - - { config: release, test-category: full } + - { config: releaseWithDebugInfo, test-category: full } # default not full gpu tests - full-gpu-tests: false # The runners don't have a GPU by default except for the self-hosted ones - has-gpu: false # Self-hosted aarch64 build - os: linux - config: release + config: releaseWithDebugInfo compiler: gcc platform: aarch64 test-category: smoke @@ -67,7 +60,7 @@ jobs: has-gpu: true # Self-hosted full gpu build - os: windows - config: release + config: releaseWithDebugInfo compiler: cl platform: x86_64 test-category: full @@ -82,40 +75,83 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - name: Add bash to PATH + shell: pwsh + if: ${{matrix.os == 'windows'}} + run: | + Add-Content -Path $env:GITHUB_PATH -Value "C:\\Program Files\\Git\\bin" + Add-Content -Path $env:GITHUB_PATH -Value "C:\\Program Files\\Git\\usr\\bin" + + - uses: actions/checkout@v4 with: - submodules: 'recursive' - fetch-depth: '0' + submodules: "recursive" + fetch-depth: "0" + - id: filter + run: | + # This step prevents subsequent steps from running if only documentation was changed + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + git fetch origin ${{ github.base_ref }} + BASE=origin/${{ github.base_ref }} + else + BASE=HEAD^1 + fi + if git diff --name-only -z $BASE...HEAD | + grep --null-data -qvE '^(docs/|LICENSES/|LICENSE$|CONTRIBUTING\.md$|README\.md$)'; then + echo "should-run=true" >> $GITHUB_OUTPUT + else + echo "Only documentation files changed, skipping remaining steps" + echo "should-run=false" >> $GITHUB_OUTPUT + fi - name: Setup + if: steps.filter.outputs.should-run == 'true' uses: ./.github/actions/common-setup with: os: ${{matrix.os}} compiler: ${{matrix.compiler}} platform: ${{matrix.platform}} config: ${{matrix.config}} - build-llvm: true + build-llvm: ${{ matrix.platform != 'wasm' }} - name: Build Slang + if: steps.filter.outputs.should-run == 'true' run: | - if [[ "${{ matrix.os }}" =~ "windows" && "${{ matrix.config }}" != "release" ]]; then - # Doing a debug build will try to link against a release built llvm, this - # is a problem on Windows, so make slang-llvm in release build and use - # that as though it's a fetched binary via these presets. - cmake --workflow --preset slang-llvm - # Configure, pointing to our just-generated slang-llvm archive - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=FETCH_BINARY \ - "-DSLANG_SLANG_LLVM_BINARY_URL=$(pwd)/build/dist-release/slang-llvm.zip" \ - "-DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}}" - cmake --workflow --preset "${{matrix.config}}" + if [[ "${{ matrix.platform }}" = "wasm" ]]; then + git clone https://github.com/emscripten-core/emsdk.git + pushd emsdk + ./emsdk install latest + ./emsdk activate latest + source ./emsdk_env.sh + popd + cmake --workflow --preset generators --fresh + mkdir generators + cmake --install build --prefix generators --component generators + emcmake cmake -DSLANG_GENERATORS_PATH=generators/bin --preset emscripten -DSLANG_SLANG_LLVM_FLAVOR=DISABLE + cmake --build --preset emscripten --config "$cmake_config" --target slang + [ -f "build.em/$cmake_config/lib/libslang.a" ] + [ -f "build.em/$cmake_config/lib/libcompiler-core.a" ] + [ -f "build.em/$cmake_config/lib/libcore.a" ] else - # Otherwise, use the system llvm we have just build or got from the - # cache in the setup phase - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} - cmake --workflow --preset "${{matrix.config}}" + if [[ "${{ matrix.os }}" =~ "windows" && "${{ matrix.config }}" != "release" && "${{ matrix.config }}" != "releaseWithDebugInfo" ]]; then + # Doing a debug build will try to link against a release built llvm, this + # is a problem on Windows, so make slang-llvm in release build and use + # that as though it's a fetched binary via these presets. + cmake --workflow --preset slang-llvm + # Configure, pointing to our just-generated slang-llvm archive + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=FETCH_BINARY \ + "-DSLANG_SLANG_LLVM_BINARY_URL=$(pwd)/build/dist-release/slang-llvm.zip" \ + "-DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}}" + cmake --workflow --preset "${{matrix.config}}" + else + # Otherwise, use the "system" llvm we have just build or got from the + # cache in the setup phase + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} + cmake --workflow --preset "${{matrix.config}}" + fi fi - name: Test Slang + if: steps.filter.outputs.should-run == 'true' && matrix.platform != 'wasm' run: | export SLANG_RUN_SPIRV_VALIDATION=1 export SLANG_USE_SPV_SOURCE_LANGUAGE_UNKNOWN=1 @@ -124,7 +160,8 @@ jobs: -use-test-server \ -server-count 8 \ -category ${{ matrix.test-category }} \ - -api all-cpu + -api all-cpu \ + -expected-failure-list tests/expected-failure-github.txt elif [[ "${{matrix.has-gpu}}" == "true" ]]; then "$bin_dir/slang-test" \ -use-test-server \ @@ -140,7 +177,7 @@ jobs: -expected-failure-list tests/expected-failure-record-replay-tests.txt fi - name: Test Slang via glsl - if: ${{matrix.full-gpu-tests}} + if: steps.filter.outputs.should-run == 'true' && matrix.full-gpu-tests && matrix.platform != 'wasm' run: | export SLANG_RUN_SPIRV_VALIDATION=1 export SLANG_USE_SPV_SOURCE_LANGUAGE_UNKNOWN=1 @@ -152,7 +189,7 @@ jobs: -api vk \ -expected-failure-list tests/expected-failure.txt - uses: actions/upload-artifact@v3 - if: ${{ ! matrix.full-gpu-tests }} + if: steps.filter.outputs.should-run == 'true' && ! matrix.full-gpu-tests with: name: slang-build-${{matrix.os}}-${{matrix.platform}}-${{matrix.compiler}}-${{matrix.config}} # The install directory used in the packaging step diff --git a/.github/workflows/compile-regression-test.yml b/.github/workflows/compile-regression-test.yml index f1809ea719..f73ec2c506 100644 --- a/.github/workflows/compile-regression-test.yml +++ b/.github/workflows/compile-regression-test.yml @@ -2,19 +2,21 @@ name: Compile Regression-Test on: push: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" pull_request: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -40,28 +42,28 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - fetch-depth: '0' - - name: Setup - uses: ./.github/actions/common-setup - with: - os: ${{matrix.os}} - compiler: ${{matrix.compiler}} - platform: ${{matrix.platform}} - config: ${{matrix.config}} - build-llvm: true - - name: Build Slang - run: | - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ - -DSLANG_ENABLE_CUDA=1 - cmake --workflow --preset "${{matrix.config}}" - - name: Run compile and validation test - run: | - cp -r /c/slang_compile_test_suite_a . - cd slang_compile_test_suite_a - export SLANGC_PATH="$bin_dir/slangc.exe" - bash ./compile_all_slang.sh + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: "0" + - name: Setup + uses: ./.github/actions/common-setup + with: + os: ${{matrix.os}} + compiler: ${{matrix.compiler}} + platform: ${{matrix.platform}} + config: ${{matrix.config}} + build-llvm: true + - name: Build Slang + run: | + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ + -DSLANG_ENABLE_CUDA=1 + cmake --workflow --preset "${{matrix.config}}" + - name: Run compile and validation test + run: | + cp -r /c/slang_compile_test_suite_a . + cd slang_compile_test_suite_a + export SLANGC_PATH="$bin_dir/slangc.exe" + bash ./compile_all_slang.sh diff --git a/.github/workflows/ensure-pr-label.yml b/.github/workflows/ensure-pr-label.yml index 8db5b6057d..8184efd721 100644 --- a/.github/workflows/ensure-pr-label.yml +++ b/.github/workflows/ensure-pr-label.yml @@ -3,10 +3,11 @@ on: pull_request: types: [opened, labeled, unlabeled, synchronize] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" jobs: label: runs-on: ubuntu-latest @@ -20,4 +21,4 @@ jobs: count: 1 labels: | pr: non-breaking - pr: breaking change \ No newline at end of file + pr: breaking change diff --git a/.github/workflows/falcor-compiler-perf-test.yml b/.github/workflows/falcor-compiler-perf-test.yml index d329642d9a..c7e3954167 100644 --- a/.github/workflows/falcor-compiler-perf-test.yml +++ b/.github/workflows/falcor-compiler-perf-test.yml @@ -4,19 +4,21 @@ name: Falcor Compiler Perf-Test on: push: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" pull_request: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -42,61 +44,61 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - fetch-depth: '0' + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: "0" - - name: Setup - uses: ./.github/actions/common-setup - with: - os: ${{matrix.os}} - compiler: ${{matrix.compiler}} - platform: ${{matrix.platform}} - config: ${{matrix.config}} - build-llvm: true + - name: Setup + uses: ./.github/actions/common-setup + with: + os: ${{matrix.os}} + compiler: ${{matrix.compiler}} + platform: ${{matrix.platform}} + config: ${{matrix.config}} + build-llvm: true - - name: Build Slang - run: | - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ - -DSLANG_ENABLE_CUDA=1 - cmake --workflow --preset "${{matrix.config}}" + - name: Build Slang + run: | + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ + -DSLANG_ENABLE_CUDA=1 + cmake --workflow --preset "${{matrix.config}}" - - uses: robinraju/release-downloader@v1.9 - id: download - with: - # The source repository path. - # Expected format {owner}/{repo} - # Default: ${{ github.repository }} - repository: "shader-slang/falcor-compile-perf-test" + - uses: robinraju/release-downloader@v1.11 + id: download + with: + # The source repository path. + # Expected format {owner}/{repo} + # Default: ${{ github.repository }} + repository: "shader-slang/falcor-compile-perf-test" - # A flag to set the download target as latest release - # The default value is 'false' - latest: true + # A flag to set the download target as latest release + # The default value is 'false' + latest: true - # The name of the file to download. - # Use this field only to specify filenames other than tarball or zipball, if any. - # Supports wildcard pattern (eg: '*', '*.deb', '*.zip' etc..) - fileName: "falcor_perf_test-*-win-64.zip" + # The name of the file to download. + # Use this field only to specify filenames other than tarball or zipball, if any. + # Supports wildcard pattern (eg: '*', '*.deb', '*.zip' etc..) + fileName: "falcor_perf_test-*-win-64.zip" - # Download the attached zipball (*.zip) - zipBall: true + # Download the attached zipball (*.zip) + zipBall: true - # Relative path under $GITHUB_WORKSPACE to place the downloaded file(s) - # It will create the target directory automatically if not present - # eg: out-file-path: "my-downloads" => It will create directory $GITHUB_WORKSPACE/my-downloads - out-file-path: "./falcor-perf-test" + # Relative path under $GITHUB_WORKSPACE to place the downloaded file(s) + # It will create the target directory automatically if not present + # eg: out-file-path: "my-downloads" => It will create directory $GITHUB_WORKSPACE/my-downloads + out-file-path: "./falcor-perf-test" - # Somehow there is a bug in this flag, the executable extracted is not runnable. We have to - # extract ourselves. - extract: false + # Somehow there is a bug in this flag, the executable extracted is not runnable. We have to + # extract ourselves. + extract: false - - name: run falcor-compiler-perf-test - shell: pwsh - run: | - $filename = '${{ fromJson(steps.download.outputs.downloaded_files)[0] }}' - Expand-Archive $filename -DestinationPath .\falcor-perf-test - $env:PATH += ";.\build\${{matrix.config}}\bin"; - .\falcor-perf-test\bin\Release\falcor_perftest.exe + - name: run falcor-compiler-perf-test + shell: pwsh + run: | + $filename = '${{ fromJson(steps.download.outputs.downloaded_files)[0] }}' + Expand-Archive $filename -DestinationPath .\falcor-perf-test + $env:PATH += ";.\build\${{matrix.config}}\bin"; + .\falcor-perf-test\bin\Release\falcor_perftest.exe diff --git a/.github/workflows/falcor-test.yml b/.github/workflows/falcor-test.yml index bb5faeddc6..ff9f2fb703 100644 --- a/.github/workflows/falcor-test.yml +++ b/.github/workflows/falcor-test.yml @@ -2,19 +2,21 @@ name: Falcor Tests on: push: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" pull_request: - branches: [ master ] + branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -40,54 +42,54 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v3 - with: - submodules: 'recursive' - fetch-depth: '0' - - name: Setup - uses: ./.github/actions/common-setup - with: - os: ${{matrix.os}} - compiler: ${{matrix.compiler}} - platform: ${{matrix.platform}} - config: ${{matrix.config}} - build-llvm: true - - name: setup-falcor - shell: pwsh - run: | - mkdir FalcorBin - cd FalcorBin - Copy-Item -Path 'C:\Falcor\build\windows-vs2022\bin' -Destination '.\build\windows-vs2022\bin' -Recurse -Exclude ("*.pdb") - Copy-Item -Path 'C:\Falcor\tests' -Destination '.\' -Recurse - Copy-Item -Path 'C:\Falcor\tools' -Destination '.\' -Recurse - Copy-Item -Path 'C:\Falcor\media' -Destination '.\' -Recurse - Copy-Item -Path 'C:\Falcor\media_internal' -Destination '.\' -Recurse - Copy-Item -Path 'C:\Falcor\scripts' -Destination '.\' -Recurse - cd ..\ - - name: Build Slang - run: | - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ - -DSLANG_ENABLE_CUDA=1 \ - -DSLANG_ENABLE_EXAMPLES=0 \ - -DSLANG_ENABLE_GFX=0 \ - -DSLANG_ENABLE_TESTS=0 - cmake --workflow --preset "${{matrix.config}}" - - name: Copy Slang to Falcor - run: | - cp --verbose --recursive --target-directory ./FalcorBin/build/windows-vs2022/bin/Release build/Release/bin/* - - name: falcor-unit-test - shell: pwsh - run: | - $ErrorActionPreference = "SilentlyContinue" - cd .\FalcorBin\tests - python ./testing/run_unit_tests.py --config windows-vs2022-Release -t "-slow" - cd ../../ - - name: falcor-image-test - shell: pwsh - run: | - $ErrorActionPreference = "SilentlyContinue" - cd .\FalcorBin\tests - python ./testing/run_image_tests.py --config windows-vs2022-Release --run-only - cd ../../ + - uses: actions/checkout@v4 + with: + submodules: "recursive" + fetch-depth: "0" + - name: Setup + uses: ./.github/actions/common-setup + with: + os: ${{matrix.os}} + compiler: ${{matrix.compiler}} + platform: ${{matrix.platform}} + config: ${{matrix.config}} + build-llvm: true + - name: setup-falcor + shell: pwsh + run: | + mkdir FalcorBin + cd FalcorBin + Copy-Item -Path 'C:\Falcor\build\windows-vs2022\bin' -Destination '.\build\windows-vs2022\bin' -Recurse -Exclude ("*.pdb") + Copy-Item -Path 'C:\Falcor\tests' -Destination '.\' -Recurse + Copy-Item -Path 'C:\Falcor\tools' -Destination '.\' -Recurse + Copy-Item -Path 'C:\Falcor\media' -Destination '.\' -Recurse + Copy-Item -Path 'C:\Falcor\media_internal' -Destination '.\' -Recurse + Copy-Item -Path 'C:\Falcor\scripts' -Destination '.\' -Recurse + cd ..\ + - name: Build Slang + run: | + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ + -DSLANG_ENABLE_CUDA=1 \ + -DSLANG_ENABLE_EXAMPLES=0 \ + -DSLANG_ENABLE_GFX=0 \ + -DSLANG_ENABLE_TESTS=0 + cmake --workflow --preset "${{matrix.config}}" + - name: Copy Slang to Falcor + run: | + cp --verbose --recursive --target-directory ./FalcorBin/build/windows-vs2022/bin/Release build/Release/bin/* + - name: falcor-unit-test + shell: pwsh + run: | + $ErrorActionPreference = "SilentlyContinue" + cd .\FalcorBin\tests + python ./testing/run_unit_tests.py --config windows-vs2022-Release -t "-slow" + cd ../../ + - name: falcor-image-test + shell: pwsh + run: | + $ErrorActionPreference = "SilentlyContinue" + cd .\FalcorBin\tests + python ./testing/run_image_tests.py --config windows-vs2022-Release --run-only + cd ../../ diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml new file mode 100644 index 0000000000..82fd624616 --- /dev/null +++ b/.github/workflows/format.yml @@ -0,0 +1,85 @@ +name: Format +on: + repository_dispatch: + types: [format-command] +jobs: + format: + runs-on: ubuntu-latest + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.head.ref }} + path: pr-branch + + - name: Checkout target branch + uses: actions/checkout@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.pull_request.base.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.base.ref }} + path: target-branch + + - name: Setup + uses: ./target-branch/.github/actions/format-setup + + - name: Run formatting + id: format + run: | + ./target-branch/extras/formatting.sh --source ./pr-branch + + - name: Configure Git commit signing + id: git-info + run: | + echo "${{ secrets.SLANGBOT_SIGNING_KEY }}" > "${{runner.temp}}"/signing_key + chmod 600 "${{runner.temp}}"/signing_key + git -C pr-branch config commit.gpgsign true + git -C pr-branch config gpg.format ssh + git -C pr-branch config user.signingkey "${{runner.temp}}"/signing_key + bot_info=$(curl -s -H "Authorization: Bearer ${{ secrets.SLANGBOT_PAT }}" \ + "https://api.github.com/user") + echo "bot_identity=$(echo $bot_info | jq --raw-output '.login + " <" + (.id|tostring) + "+" + .login + "@users.noreply.github.com>"')" >> $GITHUB_OUTPUT + echo "bot_name=$(echo $bot_info | jq --raw-output '.login')" >> $GITHUB_OUTPUT + + - name: Create Pull Request + id: create-pr + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.SLANGBOT_PAT }} + path: pr-branch + commit-message: "format code" + title: "Format code for PR #${{ github.event.client_payload.pull_request.number }}" + body: "Automated code formatting for ${{ github.event.client_payload.pull_request.html_url }}" + committer: ${{ steps.git-info.outputs.bot_identity }} + author: ${{ steps.git-info.outputs.bot_identity }} + branch: format-${{ github.event.client_payload.pull_request.number }}-${{ github.event.client_payload.pull_request.head.ref }} + base: ${{ github.event.client_payload.pull_request.head.ref }} + push-to-fork: ${{ steps.git-info.outputs.bot_name }}/slang + delete-branch: true + + - name: Comment on PR + uses: peter-evans/create-or-update-comment@v4 + if: always() + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.github.payload.repository.full_name }} + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + ${{ + steps.format.conclusion == 'failure' + && format('❌ Formatting failed. Please check the [workflow run](https://github.com/{0}/actions/runs/{1})', github.repository, github.run_id) + || (steps.create-pr.conclusion == 'failure' + && format('❌ Failed to create formatting pull request. Please check the [workflow run](https://github.com/{0}/actions/runs/{1})', github.repository, github.run_id) + || format('🌈 Formatted, please merge the changes from [this PR]({0})', steps.create-pr.outputs.pull-request-url)) + }} + + - name: Add reaction + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.github.payload.repository.full_name }} + comment-id: ${{ github.event.client_payload.github.payload.comment.id }} + reactions-edit-mode: replace + reactions: hooray diff --git a/.github/workflows/push-benchmark-results.yml b/.github/workflows/push-benchmark-results.yml index 6eab768167..acef247bb5 100644 --- a/.github/workflows/push-benchmark-results.yml +++ b/.github/workflows/push-benchmark-results.yml @@ -4,10 +4,11 @@ on: push: branches: [master] paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -16,10 +17,10 @@ jobs: build: runs-on: [Windows, benchmark, self-hosted] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - submodules: 'true' - fetch-depth: '0' + submodules: "true" + fetch-depth: "0" - name: Common setup uses: ./.github/actions/common-setup with: @@ -32,20 +33,20 @@ jobs: run: | cmake --preset default --fresh -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM -DCMAKE_COMPILE_WARNING_AS_ERROR=false cmake --workflow --preset release - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - repository: 'shader-slang/MDL-SDK' - path: 'external/MDL-SDK' + repository: "shader-slang/MDL-SDK" + path: "external/MDL-SDK" - name: Run benchmark run: | cd tools/benchmark cp ../../external/MDL-SDK/examples/mdl_sdk/dxr/content/slangified/*.slang . pip install prettytable argparse python compile.py --samples 16 --target dxil - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - repository: 'shader-slang/slang-material-modules-benchmark' - path: 'external/slang-material-modules-benchmark' + repository: "shader-slang/slang-material-modules-benchmark" + path: "external/slang-material-modules-benchmark" token: ${{ secrets.SLANG_MDL_BENCHMARK_RESULTS_PAT }} - name: Push results run: | diff --git a/.github/workflows/regenerate-toc.yml b/.github/workflows/regenerate-toc.yml new file mode 100644 index 0000000000..973bbcf950 --- /dev/null +++ b/.github/workflows/regenerate-toc.yml @@ -0,0 +1,82 @@ +name: Regenerate TOC +on: + repository_dispatch: + types: [regenerate-toc-command] +jobs: + regenerate-toc: + runs-on: ubuntu-latest + steps: + - name: Checkout PR branch + uses: actions/checkout@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.head.ref }} + path: pr-branch + + - name: Checkout target branch + uses: actions/checkout@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.pull_request.base.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.base.ref }} + path: target-branch + + - name: Regenerate Table of Contents + id: regen + run: | + ./target-branch/docs/build_toc.sh --source ./pr-branch + + - name: Configure Git commit signing + id: git-info + run: | + echo "${{ secrets.SLANGBOT_SIGNING_KEY }}" > "${{runner.temp}}"/signing_key + chmod 600 "${{runner.temp}}"/signing_key + git -C pr-branch config commit.gpgsign true + git -C pr-branch config gpg.format ssh + git -C pr-branch config user.signingkey "${{runner.temp}}"/signing_key + bot_info=$(curl -s -H "Authorization: Bearer ${{ secrets.SLANGBOT_PAT }}" \ + "https://api.github.com/user") + echo "bot_identity=$(echo $bot_info | jq --raw-output '.login + " <" + (.id|tostring) + "+" + .login + "@users.noreply.github.com>"')" >> $GITHUB_OUTPUT + echo "bot_name=$(echo $bot_info | jq --raw-output '.login')" >> $GITHUB_OUTPUT + + - name: Create Pull Request + id: create-pr + uses: peter-evans/create-pull-request@v7 + with: + token: ${{ secrets.SLANGBOT_PAT }} + path: pr-branch + commit-message: "regenerate documentation Table of Contents" + title: "Regenerate documentation ToC for PR #${{ github.event.client_payload.pull_request.number }}" + body: "Automated ToC generation for ${{ github.event.client_payload.pull_request.html_url }}" + committer: ${{ steps.git-info.outputs.bot_identity }} + author: ${{ steps.git-info.outputs.bot_identity }} + branch: regenerate-toc-${{ github.event.client_payload.pull_request.number }}-${{ github.event.client_payload.pull_request.head.ref }} + base: ${{ github.event.client_payload.pull_request.head.ref }} + push-to-fork: ${{ steps.git-info.outputs.bot_name }}/slang + delete-branch: true + + - name: Comment on PR + uses: peter-evans/create-or-update-comment@v4 + if: always() + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.github.payload.repository.full_name }} + issue-number: ${{ github.event.client_payload.pull_request.number }} + body: | + ${{ + steps.regen.conclusion == 'failure' + && format('❌ Table of Contents generation failed. Please check the [workflow run](https://github.com/{0}/actions/runs/{1})', github.repository, github.run_id) + || (steps.create-pr.conclusion == 'failure' + && format('❌ Failed to create regenerate ToC pull request. Please check the [workflow run](https://github.com/{0}/actions/runs/{1})', github.repository, github.run_id) + || format('🌈 Regenerated Table of Contents, please merge the changes from [this PR]({0})', steps.create-pr.outputs.pull-request-url)) + }} + + - name: Add reaction + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + repository: ${{ github.event.client_payload.github.payload.repository.full_name }} + comment-id: ${{ github.event.client_payload.github.payload.comment.id }} + reactions-edit-mode: replace + reactions: hooray diff --git a/.github/workflows/release-linux-glibc-2-17.yml b/.github/workflows/release-linux-glibc-2-17.yml index d147f38e1a..4c9485d1e4 100644 --- a/.github/workflows/release-linux-glibc-2-17.yml +++ b/.github/workflows/release-linux-glibc-2-17.yml @@ -1,17 +1,17 @@ on: push: tags: - - 'v*' + - "v*" name: centos7-gcc9 Release jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - submodules: 'recursive' - fetch-depth: '0' + submodules: "recursive" + fetch-depth: "0" # build the binary in docker image - name: Run the build process with Docker @@ -26,7 +26,7 @@ jobs: cd /home/app git config --global --add safe.directory /home/app - cmake --preset default --fresh -DSLANG_SLANG_LLVM_FLAVOR=DISABLE -DSLANG_EMBED_STDLIB=1 + cmake --preset default --fresh -DSLANG_SLANG_LLVM_FLAVOR=DISABLE cmake --build --preset release cpack --preset release -G ZIP cpack --preset release -G TGZ @@ -52,8 +52,8 @@ jobs: uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/v') with: - draft: contains(github.ref, 'draft') - prerelease: contains(github.ref, 'draft') + draft: ${{contains(github.ref, 'draft')}} + prerelease: ${{contains(github.ref, 'draft')}} files: | ${{ steps.package.outputs.SLANG_BINARY_ARCHIVE_ZIP }} ${{ steps.package.outputs.SLANG_BINARY_ARCHIVE_TAR }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7cbb04f836..36e30bec03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,12 +7,13 @@ on: branches: - master paths-ignore: - - 'docs/**' - - 'LICENCE' - - 'CONTRIBUTION.md' - - 'README.md' + - "docs/**" + - "LICENSES/**" + - "LICENSE" + - "CONTRIBUTING.md" + - "README.md" tags: - - 'v*' + - "v*" jobs: release: @@ -23,14 +24,14 @@ jobs: platform: [x86_64, aarch64] test-category: [smoke] include: - - {os: linux, runs-on: ubuntu-20.04, compiler: gcc} - - {os: windows, runs-on: windows-latest, compiler: cl} - - {os: macos, runs-on: macos-latest, compiler: clang} - - - {build-slang-llvm: false} - - {os: linux, platform: x86_64, build-slang-llvm: true} - - {os: windows, platform: x86_64, build-slang-llvm: true} - - {os: macos, platform: aarch64, build-slang-llvm: true} + - { os: linux, runs-on: ubuntu-20.04, compiler: gcc } + - { os: windows, runs-on: windows-latest, compiler: cl } + - { os: macos, runs-on: macos-latest, compiler: clang } + + - { build-slang-llvm: false } + - { os: linux, platform: x86_64, build-slang-llvm: true } + - { os: windows, platform: x86_64, build-slang-llvm: true } + - { os: macos, platform: aarch64, build-slang-llvm: true } fail-fast: false runs-on: ${{ matrix.runs-on }} container: ${{ matrix.image || '' }} @@ -40,10 +41,10 @@ jobs: shell: bash steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: - submodules: 'recursive' - fetch-depth: '0' + submodules: "recursive" + fetch-depth: "0" - name: Setup uses: ./.github/actions/common-setup with: @@ -80,15 +81,14 @@ jobs: - name: Build Slang run: | - if [[ "${{ matrix.os }}" == "windows" && "${{ matrix.config }}" != "release" ]]; then - echo "Please see ci.yml for the steps to make debug builds work on Windows" >&2 + if [[ "${{ matrix.os }}" == "windows" && "${{ matrix.config }}" != "release" && "${{ matrix.config }}" != "releaseWithDebugInfo" ]]; then + echo "Please see ci.yml for the steps to make non-release builds work on Windows" >&2 exit 1 fi cmake --preset default --fresh \ -DSLANG_GENERATORS_PATH=build-platform-generators/bin \ -DSLANG_ENABLE_EXAMPLES=OFF \ - -DSLANG_EMBED_STDLIB=ON \ "-DSLANG_SLANG_LLVM_FLAVOR=$( [[ "${{matrix.build-slang-llvm}}" = "true" ]] && echo "USE_SYSTEM_LLVM" || echo "DISABLE")" @@ -109,23 +109,18 @@ jobs: brew install Bearer/tap/gon security find-identity -v brew install coreutils - # create variables CERTIFICATE_PATH=$RUNNER_TEMP/build_certificate.p12 KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db - # import certificate and provisioning profile from secrets echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode --output "$CERTIFICATE_PATH" - # create temporary keychain security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH" security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" - # import certificate to keychain security import "$CERTIFICATE_PATH" -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH" security list-keychain -d user -s "$KEYCHAIN_PATH" - security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${KEYCHAIN_PASSWORD}" "$KEYCHAIN_PATH" binaries=( @@ -137,6 +132,8 @@ jobs: "${bin_dir}/slangd" "${bin_dir}/slangc" ) + + # Sign main binaries for b in "${binaries[@]}"; do if [[ -f "$b" ]]; then echo "Signing binary '$b'..." @@ -152,16 +149,28 @@ jobs: - name: Package Slang id: package run: | - # For the release, also generate a tar.gz file + # Package main binaries cpack --preset "$config" -G ZIP cpack --preset "$config" -G TGZ + # Package debug info + cpack --preset "$config-debug-info" -G ZIP + cpack --preset "$config-debug-info" -G TGZ + triggering_ref=${{ github.ref_name }} base=slang-${triggering_ref#v}-${{matrix.os}}-${{matrix.platform}} + + # Move main packages mv "$(pwd)/build/dist-${config}/slang.zip" "${base}.zip" echo "SLANG_BINARY_ARCHIVE_ZIP=${base}.zip" >> "$GITHUB_OUTPUT" mv "$(pwd)/build/dist-${config}/slang.tar.gz" "${base}.tar.gz" echo "SLANG_BINARY_ARCHIVE_TAR=${base}.tar.gz" >> "$GITHUB_OUTPUT" + # Move debug info packages + mv "$(pwd)/build/dist-${config}-debug-info/slang-debug-info.zip" "${base}-debug-info.zip" + echo "SLANG_DEBUG_INFO_ARCHIVE_ZIP=${base}-debug-info.zip" >> "$GITHUB_OUTPUT" + mv "$(pwd)/build/dist-${config}-debug-info/slang-debug-info.tar.gz" "${base}-debug-info.tar.gz" + echo "SLANG_DEBUG_INFO_ARCHIVE_TAR=${base}-debug-info.tar.gz" >> "$GITHUB_OUTPUT" + # For some reason, the binaries packed by cpack for macos is modified # by cpack and considered damanged by macos. For now we workaround this # by repacking all the binaries into the release package. @@ -169,8 +178,14 @@ jobs: mkdir ./ttmp unzip "${base}.zip" -d ./ttmp - /bin/cp -rf build/Release/bin/* ./ttmp/bin/ - /bin/cp -rf build/Release/lib/* ./ttmp/lib/ + # Copy only existing files from build directory + find ./ttmp/{bin,lib} -type f | while read -r file; do + src_file="build/$cmake_config/${file#./ttmp/}" + if [ -f "$src_file" ]; then + cp "$src_file" "$file" + fi + done + rm ${base}.zip rm ${base}.tar.gz cd ./ttmp @@ -178,6 +193,7 @@ jobs: tar -czvf ../${base}.tar.gz . cd ../ fi + - name: File check run: | find "build/dist-$config" -print0 ! -iname '*.md' ! -iname '*.h' -type f | xargs -0 file @@ -186,11 +202,30 @@ jobs: uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/v') with: - draft: contains(github.ref, 'draft') - prerelease: contains(github.ref, 'draft') + draft: ${{contains(github.ref, 'draft')}} + prerelease: ${{contains(github.ref, 'draft')}} files: | ${{ steps.package.outputs.SLANG_BINARY_ARCHIVE_ZIP }} ${{ steps.package.outputs.SLANG_BINARY_ARCHIVE_TAR }} + ${{ steps.package.outputs.SLANG_DEBUG_INFO_ARCHIVE_ZIP }} + ${{ steps.package.outputs.SLANG_DEBUG_INFO_ARCHIVE_TAR }} ${{ steps.notarize.outputs.SLANG_NOTARIZED_DIST }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Checkout stdlib reference + if: matrix.os == 'windows' && matrix.platform == 'x86_64' + uses: actions/checkout@v4 + with: + repository: shader-slang/stdlib-reference + path: docs/stdlib-reference/ + token: ${{ secrets.UPDATE_STDLIB_REFERENCE_PAT }} + - name: Update stdlib reference + if: matrix.os == 'windows' && matrix.platform == 'x86_64' + shell: powershell + run: | + cd docs/ + ls + & ".\build_reference.ps1" + env: + GITHUB_TOKEN: ${{ secrets.UPDATE_STDLIB_REFERENCE_PAT }} diff --git a/.github/workflows/slash-command-dispatch.yml b/.github/workflows/slash-command-dispatch.yml new file mode 100644 index 0000000000..0295e72401 --- /dev/null +++ b/.github/workflows/slash-command-dispatch.yml @@ -0,0 +1,37 @@ +name: Slash Command Dispatch +on: + issue_comment: + types: [created] +jobs: + slashCommandDispatch: + runs-on: ubuntu-latest + steps: + - name: Slash Command Dispatch + id: scd + uses: peter-evans/slash-command-dispatch@v4 + with: + token: ${{ secrets.GITHUB_TOKEN }} + reaction-token: ${{ secrets.SLANGBOT_PAT }} + issue-type: pull-request + config: > + [ + { + "command": "format", + "permission": "none", + "issue_type": "pull-request" + }, + { + "command": "regenerate-toc", + "permission": "none", + "issue_type": "pull-request" + } + ] + + - name: Edit comment with error message + if: steps.scd.outputs.error-message + uses: peter-evans/create-or-update-comment@v4 + with: + token: ${{ secrets.SLANGBOT_PAT }} + comment-id: ${{ github.event.comment.id }} + body: | + > ${{ steps.scd.outputs.error-message }} diff --git a/.github/workflows/vk-gl-cts-nightly.yml b/.github/workflows/vk-gl-cts-nightly.yml index a835d20fcc..0d2d29bde9 100644 --- a/.github/workflows/vk-gl-cts-nightly.yml +++ b/.github/workflows/vk-gl-cts-nightly.yml @@ -2,12 +2,14 @@ name: VK-GL-CTS Nightly on: schedule: - - cron: '00 07 * * *' + - cron: "00 07 * * *" concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: DISABLE_CTS_SLANG: 0 + ACTIONS_RUNNER_DEBUG: true + ACTIONS_STEP_DEBUG: true jobs: build: strategy: @@ -28,77 +30,83 @@ jobs: run: shell: bash steps: - - uses: actions/checkout@v4 - with: - submodules: 'true' - fetch-depth: '0' - - name: Setup - uses: ./.github/actions/common-setup - with: - os: ${{matrix.os}} - compiler: ${{matrix.compiler}} - platform: ${{matrix.platform}} - config: ${{matrix.config}} - build-llvm: true - - name: Build Slang - run: | - cmake --preset default --fresh \ - -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ - -DSLANG_ENABLE_CUDA=1 \ - -DSLANG_ENABLE_EXAMPLES=0 \ - -DSLANG_ENABLE_GFX=1 \ - -DSLANG_ENABLE_TESTS=1 - cmake --workflow --preset "${{matrix.config}}" - - uses: robinraju/release-downloader@v1.7 - with: - latest: true - repository: "shader-slang/VK-GL-CTS" - fileName: "VK-GL-CTS_WithSlang-0.0.3-win64.zip" - - uses: actions/checkout@v4 - with: - repository: "shader-slang/VK-GL-CTS" - sparse-checkout: | - test-lists/slang-passing-tests.txt - test-lists/slang-waiver-tests.xml - path: test-lists - sparse-checkout-cone-mode: false - - name: vkcts setup - shell: pwsh - run: | - Expand-Archive VK-GL-CTS_WithSlang-0.0.3-win64.zip - - copy ${{ github.workspace }}\build\Release\bin\slang.dll ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang.dll - copy ${{ github.workspace }}\build\Release\bin\slang-glslang.dll ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-glslang.dll - copy ${{ github.workspace }}\build\Release\bin\test-server.exe ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\test-server.exe + - uses: actions/checkout@v4 + with: + submodules: "true" + fetch-depth: "0" + - name: Setup + uses: ./.github/actions/common-setup + with: + os: ${{matrix.os}} + compiler: ${{matrix.compiler}} + platform: ${{matrix.platform}} + config: ${{matrix.config}} + build-llvm: true + - name: Build Slang + run: | + cmake --preset default --fresh \ + -DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM \ + -DCMAKE_COMPILE_WARNING_AS_ERROR=${{matrix.warnings-as-errors}} \ + -DSLANG_ENABLE_CUDA=1 \ + -DSLANG_ENABLE_EXAMPLES=0 \ + -DSLANG_ENABLE_GFX=1 \ + -DSLANG_ENABLE_TESTS=1 + cmake --workflow --preset "${{matrix.config}}" + - uses: robinraju/release-downloader@v1.11 + with: + latest: true + repository: "shader-slang/VK-GL-CTS" + fileName: "VK-GL-CTS_WithSlang-0.0.3-win64.zip" + - uses: actions/checkout@v4 + with: + repository: "shader-slang/VK-GL-CTS" + sparse-checkout: | + test-lists/slang-passing-tests.txt + test-lists/slang-waiver-tests.xml + path: test-lists + sparse-checkout-cone-mode: false + - name: vkcts setup + shell: pwsh + run: | + Expand-Archive VK-GL-CTS_WithSlang-0.0.3-win64.zip - copy ${{ github.workspace }}\test-lists\test-lists\slang-passing-tests.txt ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-passing-tests.txt - copy ${{ github.workspace }}\test-lists\test-lists\slang-waiver-tests.xml ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-waiver-tests.xml + copy ${{ github.workspace }}\build\Release\bin\slang.dll ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang.dll + copy ${{ github.workspace }}\build\Release\bin\slang-glslang.dll ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-glslang.dll + copy ${{ github.workspace }}\build\Release\bin\test-server.exe ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\test-server.exe - - name: vkcts run - shell: pwsh - working-directory: ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64 - run: | - .\deqp-vk.exe --deqp-archive-dir=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64 --deqp-caselist-file=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-passing-tests.txt --deqp-waiver-file=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-waiver-tests.xml - - name: success notification - id: slack-notify-success - if: ${{ success() }} - uses: slackapi/slack-github-action@v1.26.0 - with: - payload: | - { - "CTS-Nightly": ":green-check-mark: CTS nightly status: ${{ job.status }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - - name: failure notification - id: slack-notify-failure - if : ${{ !success() }} - uses: slackapi/slack-github-action@v1.26.0 - with: - payload: | - { - "CTS-Nightly": ":alert: :alert: :alert: :alert: :alert: :alert:\nCTS nightly status: ${{ job.status }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - } - env: - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + copy ${{ github.workspace }}\test-lists\test-lists\slang-passing-tests.txt ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-passing-tests.txt + copy ${{ github.workspace }}\test-lists\test-lists\slang-waiver-tests.xml ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-waiver-tests.xml + + - name: vkcts run + shell: pwsh + working-directory: ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64 + run: | + .\deqp-vk.exe --deqp-archive-dir=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64 --deqp-caselist-file=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-passing-tests.txt --deqp-waiver-file=${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64\slang-waiver-tests.xml + + - name: Dump TestResults.qpa if failed + shell: pwsh + if: ${{ !success() }} + working-directory: ${{ github.workspace }}\VK-GL-CTS_WithSlang-0.0.3-win64\VK-GL-CTS_WithSlang-0.0.3-win64 + run: Get-Content TestResults.qpa -Tail 1000 + - name: success notification + id: slack-notify-success + if: ${{ success() }} + uses: slackapi/slack-github-action@v1.26.0 + with: + payload: | + { + "CTS-Nightly": ":green-check-mark: CTS nightly status: ${{ job.status }}" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + - name: failure notification + id: slack-notify-failure + if: ${{ !success() }} + uses: slackapi/slack-github-action@v1.26.0 + with: + payload: | + { + "CTS-Nightly": ":alert: :alert: :alert: :alert: :alert: :alert:\nCTS nightly status: ${{ job.status }}: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" + } + env: + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} diff --git a/.gitignore b/.gitignore index 941b0b745c..c6fa154579 100644 --- a/.gitignore +++ b/.gitignore @@ -12,10 +12,10 @@ *.zip *.ini *.DS_store -.clang-format .gdb_history .vimspector .vimspector.json +compile_commands.json bin/ intermediate/ @@ -66,7 +66,8 @@ prelude/*.h.cpp /docs/_site /docs/Gemfile.lock /docs/Gemfile -/source/slang/slang-stdlib-generated.h +/docs/stdlib-reference +/source/slang/slang-core-module-generated.h /examples/heterogeneous-hello-world/shader.cpp /multiple-definitions.hlsl @@ -91,3 +92,5 @@ vkd3d-proton.cache.write *~ .*.swp .*.swo +/generators +/tests/library/linked.spirv diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000000..8abce847ee --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,43 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: Slang +Upstream-Contact: The Khronos Group, Inc. +Source: https://github.com/shader-slang/slang + +Files: * +Copyright: 2016, Carnegie Mellon University and NVIDIA Corporation + 2024 The Khronos Group, Inc. +License: Apache-2.0 WITH LLVM-exception + +Files: docs/_includes/anchor_headings.html +Copyright: 2018 Vladimir "allejo" Jimenez +License: Apache-2.0 WITH LLVM-exception + +Files: external/spirv/spirv.h + external/glext.h + external/wglext.h + external/spirv-tools-generated/OpenCLDebugInfo100.h + external/spirv-tools-generated/DebugInfo.h + external/spirv-tools-generated/NonSemanticShaderDebugInfo100.h + external/glslang-generated/glslang/build_info.h +Copyright: The Khronos Group, Inc. +License: Apache-2.0 + +Files: tests/fcpw/* +Copyright: 2020 Rohan Sawhney +License: MIT + +Files: external/renderdoc_app.h +Copyright: 2019-2021 Baldur Karlsson +License: MIT + +Files: external/dxc/dxcapi.h +Copyright: Microsoft Corporation. All rights reserved. +License: UOI-NCSA + +Files: source/core/slang-crypto.cpp +Copyright: 2001 Alexander Peslyak +License: Apache-2.0 + +Files: *.md +Copyright: 2024 The Khronos Group, Inc. +License: CC-BY-4.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index e1225022e3..b6f68b4271 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,14 @@ -cmake_minimum_required(VERSION 3.25) +cmake_minimum_required(VERSION 3.22) # Our module dir, include that now so that we can get the version automatically # from git describe list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") include(GitVersion) -get_git_version(SLANG_VERSION_NUMERIC SLANG_VERSION_FULL "${CMAKE_CURRENT_LIST_DIR}") +get_git_version( + SLANG_VERSION_NUMERIC + SLANG_VERSION_FULL + "${CMAKE_CURRENT_LIST_DIR}" +) # # Our project @@ -15,7 +19,9 @@ set(PROJECT_VERSION "${SLANG_VERSION_FULL}") # # Global CMake options # -cmake_policy(SET CMP0135 OLD) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.24") + cmake_policy(SET CMP0135 OLD) +endif() cmake_policy(SET CMP0077 NEW) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25") @@ -37,7 +43,6 @@ enable_language(C CXX) include(FindPackageHandleStandardArgs) include(CMakeDependentOption) -include(FetchContent) include(GNUInstallDirs) include(CCacheDebugInfoWorkaround) @@ -47,6 +52,7 @@ include(LLVM) include(SlangTarget) include(AutoOption) include(GitHubRelease) +include(FetchedSharedLibrary) # # Options @@ -81,11 +87,23 @@ auto_option( Aftermath "Enable Aftermath in GFX, and add aftermath crash example to project" ) -option(SLANG_ENABLE_DX_ON_VK "Use dxvk and vkd3d-proton for DirectX support") -mark_as_advanced(SLANG_ENABLE_DX_ON_VK) +advanced_option( + SLANG_ENABLE_DX_ON_VK + "Use dxvk and vkd3d-proton for DirectX support" + OFF +) +advanced_option(SLANG_ENABLE_SLANG_RHI "Use slang-rhi as dependency" ON) -option(SLANG_EMBED_STDLIB_SOURCE "Embed stdlib source in the binary" ON) -option(SLANG_EMBED_STDLIB "Build slang with an embedded version of the stdlib") +option( + SLANG_EMBED_CORE_MODULE_SOURCE + "Embed core module source in the binary" + ON +) +option( + SLANG_EMBED_CORE_MODULE + "Build slang with an embedded version of the core module" + ON +) option(SLANG_ENABLE_FULL_IR_VALIDATION "Enable full IR validation (SLOW!)") option(SLANG_ENABLE_IR_BREAK_ALLOC, "Enable _debugUID on IR allocation") @@ -96,11 +114,65 @@ option(SLANG_ENABLE_GFX "Enable gfx targets" ON) option(SLANG_ENABLE_SLANGD "Enable language server target" ON) option(SLANG_ENABLE_SLANGC "Enable standalone compiler target" ON) option(SLANG_ENABLE_SLANGRT "Enable runtime target" ON) -option(SLANG_ENABLE_SLANG_GLSLANG "Enable glslang dependency and slang-glslang wrapper target" ON) -option(SLANG_ENABLE_TESTS "Enable test targets, some tests may require SLANG_ENABLE_GFX, SLANG_ENABLE_SLANGD or SLANG_ENABLE_SLANGRT" ON) -option(SLANG_ENABLE_EXAMPLES "Enable example targets, requires SLANG_ENABLE_GFX" ON) +option( + SLANG_ENABLE_SLANG_GLSLANG + "Enable glslang dependency and slang-glslang wrapper target" + ON +) +option( + SLANG_ENABLE_TESTS + "Enable test targets, some tests may require SLANG_ENABLE_GFX, SLANG_ENABLE_SLANGD or SLANG_ENABLE_SLANGRT" + ON +) +option( + SLANG_ENABLE_EXAMPLES + "Enable example targets, requires SLANG_ENABLE_GFX" + ON +) option(SLANG_ENABLE_REPLAYER "Enable slang-replay tool" ON) +option( + SLANG_GITHUB_TOKEN + "Use a given token value for accessing Github REST API" + "" +) + +advanced_option(SLANG_USE_SYSTEM_MINIZ "Build using system Miniz library" OFF) +advanced_option(SLANG_USE_SYSTEM_LZ4 "Build using system LZ4 library" OFF) +advanced_option( + SLANG_USE_SYSTEM_VULKAN_HEADERS + "Build using system Vulkan headers" + OFF +) +advanced_option( + SLANG_USE_SYSTEM_SPIRV_HEADERS + "Build using system SPIR-V headers" + OFF +) +advanced_option( + SLANG_USE_SYSTEM_UNORDERED_DENSE + "Build using system unordered dense" + OFF +) + +option( + SLANG_SPIRV_HEADERS_INCLUDE_DIR + "Provide a specific path for the SPIR-V headers and grammar files" +) +mark_as_advanced(SLANG_SPIRV_HEADERS_INCLUDE_DIR) + +if(${SLANG_USE_SYSTEM_LZ4}) + add_compile_definitions(SLANG_USE_SYSTEM_LZ4_HEADER) +endif() + +if(${SLANG_USE_SYSTEM_SPIRV_HEADERS}) + add_compile_definitions(SLANG_USE_SYSTEM_SPIRV_HEADER) +endif() + +if(${SLANG_USE_SYSTEM_UNORDERED_DENSE}) + add_compile_definitions(SLANG_USE_SYSTEM_UNORDERED_DENSE_HEADER) +endif() + enum_option( SLANG_LIB_TYPE # Default @@ -113,6 +185,18 @@ enum_option( "Build slang as a static library" ) +option( + SLANG_ENABLE_RELEASE_DEBUG_INFO + "Generate debug info for Release builds" + ON +) + +option( + SLANG_ENABLE_SPLIT_DEBUG_INFO + "Generate split debug info for debug builds" + ON +) + set(SLANG_GENERATORS_PATH "" CACHE PATH @@ -122,11 +206,13 @@ set(SLANG_GENERATORS_PATH enum_option( SLANG_SLANG_LLVM_FLAVOR # Default - FETCH_BINARY + FETCH_BINARY_IF_POSSIBLE "How to get or build slang-llvm:" # Options FETCH_BINARY - "Use a binary distribution of the slang-llvm library instead of building or using LLVM (default)" + "Use a binary distribution of the slang-llvm library instead of building or using LLVM" + FETCH_BINARY_IF_POSSIBLE + "Like FETCH_BINARY, except falls back to DISABLE if a prebuilt slang-llvm can't be downloaded" USE_SYSTEM_LLVM "Build slang-llvm using system-provided LLVM and Clang binaries" DISABLE @@ -136,9 +222,19 @@ enum_option( if(SLANG_SLANG_LLVM_FLAVOR MATCHES FETCH_BINARY) # If the user didn't specify a URL, find the best one now if(NOT SLANG_SLANG_LLVM_BINARY_URL) - get_best_slang_binary_release_url(url) + get_best_slang_binary_release_url("${SLANG_GITHUB_TOKEN}" url) if(NOT DEFINED url) - message(FATAL_ERROR "Unable to find binary release for slang-llvm, please set a different SLANG_SLANG_LLVM_FLAVOR or set SLANG_SLANG_LLVM_BINARY_URL manually") + if(SLANG_SLANG_LLVM_FLAVOR STREQUAL FETCH_BINARY_IF_POSSIBLE) + message( + WARNING + "Unable to find a prebuilt binary for slang-llvm, Slang will be built without LLVM support. Please consider setting SLANG_SLANG_LLVM_BINARY_URL manually" + ) + else() + message( + FATAL_ERROR + "Unable to find binary release for slang-llvm, please set a different SLANG_SLANG_LLVM_FLAVOR or set SLANG_SLANG_LLVM_BINARY_URL manually" + ) + endif() endif() endif() set(SLANG_SLANG_LLVM_BINARY_URL @@ -148,14 +244,34 @@ if(SLANG_SLANG_LLVM_FLAVOR MATCHES FETCH_BINARY) ) endif() +set(webgpu_dawn_release_tag "webgpu_dawn-0") +if( + CMAKE_SYSTEM_NAME MATCHES "Windows" + AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64" +) + set(SLANG_WEBGPU_DAWN_BINARY_URL + "https://github.com/shader-slang/dawn/releases/download/${webgpu_dawn_release_tag}/webgpu_dawn-windows-x64.zip" + ) +endif() + +set(slang_tint_release_tag "slang-tint-0") +if( + CMAKE_SYSTEM_NAME MATCHES "Windows" + AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64" +) + set(SLANG_SLANG_TINT_BINARY_URL + "https://github.com/shader-slang/dawn/releases/download/${slang_tint_release_tag}/slang-tint-windows-x64.zip" + ) +endif() + # # Option validation # -if(NOT SLANG_EMBED_STDLIB AND NOT SLANG_EMBED_STDLIB_SOURCE) +if(NOT SLANG_EMBED_CORE_MODULE AND NOT SLANG_EMBED_CORE_MODULE_SOURCE) message( SEND_ERROR - "One of SLANG_EMBED_STDLIB and SLANG_EMBED_STDLIB_SOURCE must be enabled" + "One of SLANG_EMBED_CORE_MODULE and SLANG_EMBED_CORE_MODULE_SOURCE must be enabled" ) endif() @@ -170,21 +286,9 @@ if(SLANG_ENABLE_NVAPI AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows") message(SEND_ERROR "SLANG_ENABLE_NVAPI is only supported on Windows") endif() -# -# Clean files from premake -# -# The premake builds places generated files in the source tree, make sure these -# aren't present -glob_append( - premake_generated_files - "source/slang/*.meta.slang.h" - "source/slang/*-generated-*.h" - "source/slang/slang-lookup-*.cpp" -) -if(premake_generated_files) - file(REMOVE ${premake_generated_files}) +if(SLANG_ENABLE_TESTS AND NOT SLANG_ENABLE_GFX) + message(SEND_ERROR "SLANG_ENABLE_TESTS requires SLANG_ENABLE_GFX") endif() -file(REMOVE external/miniz/miniz_export.h) # # Dependencies, most of these are however handled inside the "auto_option" @@ -193,614 +297,42 @@ file(REMOVE external/miniz/miniz_export.h) find_package(Threads REQUIRED) -if(SLANG_SLANG_LLVM_FLAVOR STREQUAL "USE_SYSTEM_LLVM") - find_package(LLVM 13.0 REQUIRED CONFIG) - find_package(Clang REQUIRED CONFIG) +if(${SLANG_USE_SYSTEM_UNORDERED_DENSE}) + find_package(unordered_dense CONFIG QUIET) endif() add_subdirectory(external) -# -# Our targets -# - -slang_add_target( - source/core - STATIC - EXCLUDE_FROM_ALL - USE_EXTRA_WARNINGS - LINK_WITH_PRIVATE miniz lz4_static Threads::Threads ${CMAKE_DL_LIBS} - INCLUDE_DIRECTORIES_PUBLIC source include -) - -if(SLANG_ENABLE_SLANGRT) - slang_add_target( - source/slang-rt - SHARED - # This compiles 'core' again with the SLANG_RT_DYNAMIC_EXPORT macro defined - EXTRA_SOURCE_DIRS source/core - USE_EXTRA_WARNINGS - LINK_WITH_PRIVATE miniz lz4_static Threads::Threads ${CMAKE_DL_LIBS} - EXPORT_MACRO_PREFIX SLANG_RT - INCLUDE_DIRECTORIES_PUBLIC include - INSTALL - ) +# webgpu_dawn is only available as a fetched shared library, since Dawn's nested source +# trees are too large and onerous for us to depend on. +if(SLANG_WEBGPU_DAWN_BINARY_URL) + copy_fetched_shared_library("webgpu_dawn" "${SLANG_WEBGPU_DAWN_BINARY_URL}") endif() -slang_add_target( - source/compiler-core - STATIC - EXCLUDE_FROM_ALL - USE_EXTRA_WARNINGS - LINK_WITH_PRIVATE core -) -if(NOT MSVC) - # This is necessary to compile the DXC headers - set_source_files_properties( - source/compiler-core/slang-dxc-compiler.cpp - PROPERTIES COMPILE_OPTIONS "-fms-extensions" - DIRECTORY ${slang_SOURCE_DIR} - ) +# slang-tint is only available as a fetched shared library, since it's hosted in the Dawn +# repository, and Dawn's nested source trees are too large and onerous for us to depend +# on. +if(SLANG_SLANG_TINT_BINARY_URL) + copy_fetched_shared_library("slang-tint" "${SLANG_SLANG_TINT_BINARY_URL}") endif() -# -# Tools used to generate source during the build: -# - -add_custom_target( - all-generators - COMMENT "meta target which depends on all generators" -) -set_target_properties(all-generators PROPERTIES FOLDER generators) -function(generator dir) - if(SLANG_GENERATORS_PATH) - cmake_parse_arguments(ARG "" "TARGET_NAME" "" ${ARGN}) - if(ARG_TARGET_NAME) - set(target ${ARG_TARGET_NAME}) - else() - get_filename_component(target ${dir} NAME) - endif() - add_executable(${target} IMPORTED) - set_property( - TARGET ${target} - PROPERTY - IMPORTED_LOCATION - "${SLANG_GENERATORS_PATH}/${target}${CMAKE_EXECUTABLE_SUFFIX}" - ) - else() - slang_add_target( - ${dir} - EXECUTABLE - EXCLUDE_FROM_ALL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE core - OUTPUT_DIR generators - REQUIRED_BY all-generators - FOLDER generators - INSTALL_COMPONENT generators - ${ARGN} - ) - endif() -endfunction() -generator(tools/slang-cpp-extractor USE_FEWER_WARNINGS LINK_WITH_PRIVATE compiler-core) -generator(tools/slang-embed) -generator(tools/slang-generate USE_FEWER_WARNINGS) -generator(tools/slang-lookup-generator LINK_WITH_PRIVATE compiler-core) -generator(tools/slang-capability-generator LINK_WITH_PRIVATE compiler-core) -generator(tools/slang-spirv-embed-generator LINK_WITH_PRIVATE compiler-core) -generator( - source/slangc - TARGET_NAME slang-bootstrap - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE prelude slang-no-embedded-stdlib slang-capability-lookup slang-lookup-tables Threads::Threads -) +fetch_or_build_slang_llvm() # -# The compiler itself +# Our targets # -# keep these non-trivial targets in their own directories so as not to clutter -# this file +add_subdirectory(source/core) +add_subdirectory(source/slang-rt) +add_subdirectory(source/compiler-core) +add_subdirectory(source/slang-wasm) +add_subdirectory(source/slang-glslang) +add_subdirectory(tools) add_subdirectory(prelude) +add_subdirectory(source/slang-core-module) add_subdirectory(source/slang) - -if(SLANG_ENABLE_SLANGD) - slang_add_target( - tools/slangd - EXECUTABLE - LINK_WITH_PRIVATE - core - slang - slang-reflect-headers - slang-capability-defs - Threads::Threads - INSTALL - ) -endif() -if(SLANG_ENABLE_SLANGC) - slang_add_target( - source/slangc - EXECUTABLE - USE_FEWER_WARNINGS - DEBUG_DIR ${slang_SOURCE_DIR} - LINK_WITH_PRIVATE core slang Threads::Threads - INSTALL - ) -endif() - -# -# Our wrappers for glslang and llvm -# -if(SLANG_ENABLE_SLANG_GLSLANG) - slang_add_target( - source/slang-glslang - MODULE - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE glslang SPIRV SPIRV-Tools-opt - INCLUDE_DIRECTORIES_PRIVATE include - INSTALL - ) - # Our only interface is through what we define in source/slang-glslang, in the - # interests of hygiene, hide anything else we link in. - add_supported_cxx_linker_flags(slang-glslang PRIVATE "-Wl,--exclude-libs,ALL") -endif() - - -if(SLANG_SLANG_LLVM_FLAVOR STREQUAL "FETCH_BINARY") - # - # Do some stupid little dance to put everything in the right shape with - # correct dependencies - # - - set(slang_llvm_filename - "${CMAKE_SHARED_LIBRARY_PREFIX}slang-llvm${CMAKE_SHARED_LIBRARY_SUFFIX}" - ) - macro(from_glob dir) - # A little helper function - file( - GLOB_RECURSE slang_llvm_source_object - "${dir}/${slang_llvm_filename}" - ) - list(LENGTH slang_llvm_source_object nmatches) - if(nmatches EQUAL 0) - message( - SEND_ERROR - "Unable to find ${slang_llvm_filename} in ${SLANG_SLANG_LLVM_BINARY_URL}" - ) - elseif(nmatches GREATER 1) - message( - SEND_ERROR - "Found multiple files named ${slang_llvm_filename} in ${SLANG_SLANG_LLVM_BINARY_URL}" - ) - endif() - endmacro() - - if(IS_DIRECTORY "${SLANG_SLANG_LLVM_BINARY_URL}") - # Just glob directly from a local directory - from_glob("${SLANG_SLANG_LLVM_BINARY_URL}") - elseif( - SLANG_SLANG_LLVM_BINARY_URL - MATCHES - "${CMAKE_SHARED_LIBRARY_PREFIX}.+${CMAKE_SHARED_LIBRARY_SUFFIX}$" - AND EXISTS "${SLANG_SLANG_LLVM_BINARY_URL}" - ) - # Otherwise, if it's a direct path to a shared object, use that - set(slang_llvm_source_object "${SLANG_SLANG_LLVM_BINARY_URL}") - else() - # Otherwise, download and extract from whatever URL we have - fetchcontent_declare(slang-llvm URL "${SLANG_SLANG_LLVM_BINARY_URL}") - fetchcontent_populate(slang-llvm) - from_glob("${slang-llvm_SOURCE_DIR}") - endif() - - set(slang_llvm_dest_object - ${CMAKE_BINARY_DIR}/$/${module_subdir}/${slang_llvm_filename} - ) - add_custom_command( - OUTPUT ${slang_llvm_dest_object} - COMMAND - ${CMAKE_COMMAND} -E copy_if_different ${slang_llvm_source_object} - ${slang_llvm_dest_object} - DEPENDS ${slang_llvm_source_object} - VERBATIM - ) - # Give this copying action a name - add_custom_target(copy-slang-llvm DEPENDS ${slang_llvm_dest_object}) - set_target_properties(copy-slang-llvm PROPERTIES FOLDER generated) - - # Put this into a library target - add_library(slang-llvm MODULE IMPORTED GLOBAL) - add_dependencies(slang-llvm copy-slang-llvm) - set_property( - TARGET slang-llvm - PROPERTY IMPORTED_LOCATION ${slang_llvm_dest_object} - ) - install(PROGRAMS ${slang_llvm_dest_object} DESTINATION ${module_subdir}) -elseif(SLANG_SLANG_LLVM_FLAVOR STREQUAL "USE_SYSTEM_LLVM") - llvm_target_from_components(llvm-dep filecheck native orcjit) - clang_target_from_libs( - clang-dep - clangBasic - clangCodeGen - clangDriver - clangLex - clangFrontend - clangFrontendTool - ) - slang_add_target( - source/slang-llvm - MODULE - LINK_WITH_PRIVATE core compiler-core llvm-dep clang-dep - # We include slang.h, but don't need to link with it - INCLUDE_FROM_PRIVATE slang - # This uses the SLANG_DLL_EXPORT macro from slang.h, so make sure to set - # SLANG_DYNAMIC and SLANG_DYNAMIC_EXPORT - EXPORT_MACRO_PREFIX SLANG - INSTALL - INSTALL_COMPONENT slang-llvm - ) - # If we don't include this, then the symbols in the LLVM linked here may - # conflict with those of other LLVMs linked at runtime, for instance in mesa. - add_supported_cxx_linker_flags(slang-llvm PRIVATE "-Wl,--exclude-libs,ALL") - - # The LLVM headers need a warning disabling, which somehow slips through \external - if(MSVC) - target_compile_options(slang-llvm PRIVATE -wd4244) - endif() - - # TODO: Put a check here that libslang-llvm.so doesn't have a 'NEEDED' - # directive for libLLVM-13.so, it's almost certainly going to break at - # runtime in surprising ways when linked alongside Mesa (or anything else - # pulling in libLLVM.so) -endif() - -if(SLANG_ENABLE_PREBUILT_BINARIES) - if(CMAKE_SYSTEM_NAME MATCHES "Windows") - file(GLOB prebuilt_binaries "${CMAKE_SOURCE_DIR}/external/slang-binaries/bin/windows-x64/*") - add_custom_target( - copy-prebuilt-binaries ALL - COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/$/${runtime_subdir} - COMMAND ${CMAKE_COMMAND} -E copy_if_different - ${prebuilt_binaries} - ${CMAKE_BINARY_DIR}/$/${runtime_subdir} - VERBATIM - ) - endif() -endif() - -if(SLANG_ENABLE_GFX) - # - # `platform` contains all the platform abstractions for a GUI application. - # - slang_add_target( - tools/platform - SHARED - EXCLUDE_FROM_ALL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE - core - imgui - $<$:X11::X11> - "$<$:-framework Cocoa>" - "$<$:-framework QuartzCore>" - ${CMAKE_DL_LIBS} - LINK_WITH_FRAMEWORK - Foundation - Cocoa - QuartzCore - EXTRA_COMPILE_DEFINITIONS_PRIVATE - $<$:SLANG_ENABLE_XLIB=1> - INCLUDE_FROM_PRIVATE gfx - INCLUDE_DIRECTORIES_PUBLIC tools/platform - EXPORT_MACRO_PREFIX SLANG_PLATFORM - ) - - # - # GFX - # - slang_add_target( - tools/gfx - SHARED - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE - core - slang - Vulkan-Headers - metal-cpp - $<$:X11::X11> - $<$:CUDA::cuda_driver> - LINK_WITH_FRAMEWORK - Foundation - Cocoa - QuartzCore - Metal - EXTRA_COMPILE_DEFINITIONS_PRIVATE - $<$:GFX_ENABLE_CUDA> - $<$:GFX_OPTIX> - $<$:GFX_NVAPI> - $<$:SLANG_ENABLE_XLIB> - # This is a shared library, so we need to set a preprocessor macro to mark - # exported symbols - EXPORT_MACRO_PREFIX SLANG_GFX - # slang-gfx is in this directory, anything which depends on gfx should include - # this - INCLUDE_DIRECTORIES_PUBLIC . include - REQUIRES copy-gfx-slang-modules - INSTALL - FOLDER gfx - ) - set(modules_dest_dir $) - add_custom_target( - copy-gfx-slang-modules - COMMAND ${CMAKE_COMMAND} -E make_directory ${modules_dest_dir} - COMMAND - ${CMAKE_COMMAND} -E copy tools/gfx/gfx.slang - ${modules_dest_dir}/gfx.slang - COMMAND - ${CMAKE_COMMAND} -E copy tools/gfx/slang.slang - ${modules_dest_dir}/slang.slang - WORKING_DIRECTORY ${slang_SOURCE_DIR} - VERBATIM - ) - set_target_properties(copy-gfx-slang-modules PROPERTIES FOLDER generators) - install( - FILES ${modules_dest_dir}/gfx.slang ${modules_dest_dir}/slang.slang - DESTINATION ${runtime_subdir} - ) - - slang_add_target( - tools/gfx-util - STATIC - LINK_WITH_PRIVATE core - INCLUDE_FROM_PRIVATE gfx - # The headers are included with 'include "gfx-util/blah.h"' which is found - # in the tools directory - INCLUDE_DIRECTORIES_PUBLIC tools - FOLDER gfx - ) -endif() - -# -# The test executables and runtime-loaded modules -# -if(SLANG_ENABLE_TESTS) - slang_add_target( - tools/test-server - EXECUTABLE - EXCLUDE_FROM_ALL - LINK_WITH_PRIVATE core compiler-core slang - FOLDER test - ) - slang_add_target( - tools/test-process - EXECUTABLE - EXCLUDE_FROM_ALL - LINK_WITH_PRIVATE core compiler-core - FOLDER test - ) - - slang_add_target( - tools/slang-test - EXECUTABLE - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE core compiler-core slang ${CMAKE_DL_LIBS} Threads::Threads - REQUIRES - # Shared libraries dlopened by slang-test - slang-reflection-test - slang-unit-test - # Used by some tests when they run - slangd - test-server - test-process - OPTIONAL_REQUIRES - gfx - slang-rt - slang-glslang - slang-llvm - FOLDER test - DEBUG_DIR ${slang_SOURCE_DIR} - ) - set_property( - DIRECTORY ${slang_SOURCE_DIR} - PROPERTY VS_STARTUP_PROJECT slang-test - ) - - slang_add_target( - tools/unit-test - OBJECT - EXCLUDE_FROM_ALL - INCLUDE_FROM_PRIVATE slang - INCLUDE_DIRECTORIES_PRIVATE include - FOLDER test - ) - - # These are libraries loaded at runtime from the test executable: - if(SLANG_ENABLE_GFX) - slang_add_target( - tools/gfx-unit-test - MODULE - EXCLUDE_FROM_ALL - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_SHARED_LIBRARY_TOOL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE core slang unit-test gfx gfx-util platform - OUTPUT_NAME gfx-unit-test-tool - REQUIRED_BY slang-test - FOLDER test/tools - ) - slang_add_target( - tools/render-test - MODULE - EXCLUDE_FROM_ALL - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_SHARED_LIBRARY_TOOL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE - core - compiler-core - slang - slang-rhi - platform - $<$:CUDA::cuda_driver> - EXTRA_COMPILE_DEFINITIONS_PRIVATE - $<$:RENDER_TEST_CUDA> - $<$:RENDER_TEST_OPTIX> - OUTPUT_NAME render-test-tool - REQUIRED_BY slang-test - FOLDER test/tools - ) - endif() - slang_add_target( - tools/slang-unit-test - MODULE - EXCLUDE_FROM_ALL - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_SHARED_LIBRARY_TOOL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE core compiler-core unit-test slang Threads::Threads - OUTPUT_NAME slang-unit-test-tool - FOLDER test/tools - ) - slang_add_target( - tools/slang-reflection-test - MODULE - EXCLUDE_FROM_ALL - EXTRA_COMPILE_DEFINITIONS_PRIVATE SLANG_SHARED_LIBRARY_TOOL - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE core slang Threads::Threads - OUTPUT_NAME slang-reflection-test-tool - FOLDER test/tools - ) - - slang_add_target( - tools/slang-profile - EXECUTABLE - EXCLUDE_FROM_ALL - LINK_WITH_PRIVATE core slang - FOLDER test - ) -endif() - -if (SLANG_ENABLE_EXAMPLES AND SLANG_ENABLE_GFX) - # - # Examples - # - slang_add_target( - examples/example-base - STATIC - LINK_WITH_PRIVATE - core - slang - gfx - platform - $<$:CUDA::cuda_driver> - FOLDER examples - ) - - add_custom_target( - all-examples - COMMENT "meta target which depends on all examples" - ) - set_target_properties(all-examples PROPERTIES FOLDER examples) - function(example dir) - set(debug_dir ${CMAKE_BINARY_DIR}/${dir}) - - slang_add_target( - ${dir} - EXECUTABLE - USE_FEWER_WARNINGS - LINK_WITH_PRIVATE - core - example-base - slang - gfx - gfx-util - platform - $<$:CUDA::cuda_driver> - EXTRA_COMPILE_DEFINITIONS_PRIVATE - $<$:SLANG_ENABLE_XLIB> - REQUIRED_BY all-examples - FOLDER examples - DEBUG_DIR ${debug_dir} - ${ARGN} - ) - - get_filename_component(example_target ${dir} NAME) - file(GLOB asset_files - "${CMAKE_SOURCE_DIR}/${dir}/*.slang" - "${CMAKE_SOURCE_DIR}/${dir}/*.jpg" - "${CMAKE_SOURCE_DIR}/${dir}/*.obj" - "${CMAKE_SOURCE_DIR}/${dir}/*.mtl" - "${CMAKE_SOURCE_DIR}/${dir}/*.h" - ) - - list(LENGTH asset_files asset_files_length) - if (asset_files_length GREATER 0) - set(copy_assets_target "${example_target}-copy-assets") - - add_custom_target( - ${copy_assets_target} - COMMAND ${CMAKE_COMMAND} -E make_directory ${debug_dir} - COMMAND ${CMAKE_COMMAND} -E copy_if_different ${asset_files} ${debug_dir} - COMMENT "Copy example assets to ${debug_dir}" - ) - - set_target_properties(${copy_assets_target} PROPERTIES FOLDER "examples/copy_assets") - - add_dependencies(${example_target} ${copy_assets_target}) - - # Copy DirectX shader binaries so signing doesn't fail when running from Visual Studio - if (MSVC) - if (SLANG_ENABLE_PREBUILT_BINARIES) - add_dependencies(${example_target} copy-prebuilt-binaries) - endif() - endif() - endif() - endfunction() - - example(examples/autodiff-texture WIN32_EXECUTABLE) - example(examples/cpu-com-example ) - example(examples/cpu-hello-world ) - example(examples/gpu-printing ) - example(examples/hello-world LINK_WITH_PRIVATE Vulkan-Headers) - example(examples/model-viewer WIN32_EXECUTABLE) - example(examples/platform-test WIN32_EXECUTABLE) - example(examples/ray-tracing WIN32_EXECUTABLE) - example(examples/ray-tracing-pipeline WIN32_EXECUTABLE) - example(examples/shader-object ) - example(examples/shader-toy WIN32_EXECUTABLE) - example(examples/triangle WIN32_EXECUTABLE) - if(SLANG_ENABLE_AFTERMATH) - example(examples/nv-aftermath-example WIN32_EXECUTABLE) - endif() -endif() - -# -# slang-replay tool for replaying the record files -# -if (SLANG_ENABLE_REPLAYER) - slang_add_target( - tools/slang-replay - EXECUTABLE - EXTRA_SOURCE_DIRS source/slang-record-replay/replay source/slang-record-replay/util - LINK_WITH_PRIVATE core compiler-core slang - INCLUDE_DIRECTORIES_PUBLIC source/slang-record-replay - FOLDER test - ) -endif() - -# -# Testing -# -if(SLANG_ENABLE_TESTS) - include(CTest) - add_test( - NAME slang-test - COMMAND - slang-test -bindir ${slang_SOURCE_DIR}/build/$/${runtime_subdir} - -expected-failure-list ${slang_SOURCE_DIR}/tests/expected-failure.txt - -expected-failure-list - ${slang_SOURCE_DIR}/tests/expected-failure-github.txt - WORKING_DIRECTORY ${slang_SOURCE_DIR} - ) -endif() +add_subdirectory(source/slangc) +add_subdirectory(examples) # # Packaging @@ -808,20 +340,58 @@ endif() set(CPACK_ARCHIVE_COMPONENT_INSTALL ON) set(CPACK_COMPONENTS_ALL_IN_ONE_PACKAGE ON) set(CPACK_STRIP_FILES FALSE) -install(FILES - "${slang_SOURCE_DIR}/README.md" - "${slang_SOURCE_DIR}/LICENSE" - DESTINATION . - COMPONENT metadata - EXCLUDE_FROM_ALL +install( + FILES "${slang_SOURCE_DIR}/README.md" "${slang_SOURCE_DIR}/LICENSE" + DESTINATION . + COMPONENT metadata + EXCLUDE_FROM_ALL ) -install(DIRECTORY - "${slang_SOURCE_DIR}/docs/" - DESTINATION share/doc/slang +install( + DIRECTORY "${slang_SOURCE_DIR}/docs/" + DESTINATION share/doc/slang + PATTERN ".*" EXCLUDE ) -install(DIRECTORY - "${slang_SOURCE_DIR}/include" - DESTINATION . +install( + DIRECTORY "${slang_SOURCE_DIR}/include" + DESTINATION . + PATTERN ".*" EXCLUDE ) include(CPack) + +# Write basic package config version file using standard CMakePackageConfigHelpers utility +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${PROJECT_NAME}ConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion +) + +# Write SlangConfig.cmake which should allow find_pacakage(SLANG) to work correctly +# SlangConfig.cmake will define slang::slang target that can be linked with using +# target_link_libraries. It will also define SLANG_EXECUTABLE export variable that +# should point to slangc if SLANG_ENABLE_SLANGC is ON. +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/cmake/SlangConfig.cmake.in" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION cmake +) + +# Conditionally handle the case for Emscripten where slang does not create +# linkable targets. In this case do not export the targets. Otherwise, just +# export the slang targets. +if(NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + install( + EXPORT SlangTargets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION cmake + ) +endif() + +install( + FILES + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + "${PROJECT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" + DESTINATION cmake +) diff --git a/CMakePresets.json b/CMakePresets.json index e87b976bdc..b81309af4b 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -15,6 +15,18 @@ "CMAKE_MSVC_RUNTIME_LIBRARY": "MultiThreaded$<$:Debug>" } }, + { + "name": "emscripten", + "description": "Emscripten-based Wasm build", + "generator": "Ninja Multi-Config", + "binaryDir": "${sourceDir}/build.em", + "cacheVariables": { + "SLANG_SLANG_LLVM_FLAVOR": "DISABLE", + "CMAKE_C_FLAGS_INIT": "-fwasm-exceptions -Os", + "CMAKE_CXX_FLAGS_INIT": "-fwasm-exceptions -Os", + "CMAKE_EXE_LINKER_FLAGS": "-sASSERTIONS -sALLOW_MEMORY_GROWTH -fwasm-exceptions --export=__cpp_exception" + } + }, { "name": "msvc-base", "hidden": true, @@ -59,7 +71,8 @@ "inherits": "default", "description": "Build the compile time generators used in building Slang", "cacheVariables": { - "SLANG_SLANG_LLVM_FLAVOR": "DISABLE" + "SLANG_SLANG_LLVM_FLAVOR": "DISABLE", + "SLANG_ENABLE_SLANG_RHI": false } } ], @@ -74,21 +87,28 @@ "configurePreset": "default", "configuration": "Release" }, + { + "name": "releaseWithDebugInfo", + "configurePreset": "default", + "configuration": "RelWithDebInfo" + }, + { + "name": "emscripten", + "configurePreset": "emscripten", + "configuration": "Release", + "targets": ["slang-wasm"] + }, { "name": "generators", "inherits": "release", "configurePreset": "generators", - "targets": [ - "all-generators" - ] + "targets": ["all-generators"] }, { "name": "slang-llvm", "inherits": "release", "configurePreset": "slang-llvm", - "targets": [ - "slang-llvm" - ] + "targets": ["slang-llvm"] } ], "packagePresets": [ @@ -96,30 +116,56 @@ "name": "base", "hidden": true, "configurePreset": "default", - "generators": [ - "ZIP" - ], + "generators": ["ZIP"], "variables": { "CPACK_PACKAGE_FILE_NAME": "slang", "CPACK_COMPONENTS_ALL": "Unspecified;metadata;slang-llvm" } }, + { + "name": "base-debug-info", + "inherits": "base", + "variables": { + "CPACK_PACKAGE_FILE_NAME": "slang-debug-info", + "CPACK_COMPONENTS_ALL": "debug-info" + } + }, { "name": "release", "inherits": "base", - "configurations": [ - "Release" - ], + "configurations": ["Release"], "packageDirectory": "dist-release" }, + { + "name": "releaseWithDebugInfo", + "inherits": "base", + "configurations": ["RelWithDebInfo"], + "packageDirectory": "dist-releaseWithDebugInfo" + }, { "name": "debug", "inherits": "base", - "configurations": [ - "Debug" - ], + "configurations": ["Debug"], "packageDirectory": "dist-debug" }, + { + "name": "release-debug-info", + "inherits": "base-debug-info", + "configurations": ["Release"], + "packageDirectory": "dist-release-debug-info" + }, + { + "name": "releaseWithDebugInfo-debug-info", + "inherits": "base-debug-info", + "configurations": ["RelWithDebInfo"], + "packageDirectory": "dist-releaseWithDebugInfo-debug-info" + }, + { + "name": "debug-debug-info", + "inherits": "base-debug-info", + "configurations": ["Debug"], + "packageDirectory": "dist-debug-debug-info" + }, { "name": "generators", "inherits": "release", @@ -174,6 +220,23 @@ } ] }, + { + "name": "releaseWithDebugInfo", + "steps": [ + { + "type": "configure", + "name": "default" + }, + { + "type": "build", + "name": "releaseWithDebugInfo" + }, + { + "type": "package", + "name": "releaseWithDebugInfo" + } + ] + }, { "name": "generators", "steps": [ diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index d961737488..c0c1fde423 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,46 +1 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at shaderslang@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/4/ +A reminder that this issue tracker is managed by the Khronos Group. Interactions here should follow the Khronos Code of Conduct ([https://www.khronos.org/developers/code-of-conduct](https://www.khronos.org/developers/code-of-conduct)), which prohibits aggressive or derogatory language. Please keep the discussion friendly and civil. diff --git a/CONTRIBUTION.md b/CONTRIBUTING.md similarity index 83% rename from CONTRIBUTION.md rename to CONTRIBUTING.md index b0fc723ee2..591044908c 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTING.md @@ -6,6 +6,8 @@ Thank you for considering contributing to the Shader-Slang project! We welcome y This document is to guide you to contribute to the project. This document is intended to be easy to follow without sending the readers to other pages and links. You can simply copy and paste command lines described on this document. +* Contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant the rights to use your contribution. +* When you submit a pull request, a CLA bot will determine whether you need to sign a CLA. Simply follow the instructions provided. * Please read and follow the contributor [Code of Conduct](CODE_OF_CONDUCT.md). * Bug reports and feature requests should go through the GitHub issue tracker * Changes should ideally come in as small pull requests on top of master, coming from your own personal fork of the project @@ -202,31 +204,38 @@ $ git push origin feature/your-feature-name ``` ### Request Pull -Request a pull from "shader-slang" repository. + +Open a pull request against `shader-slang/slang`. + +Code formatting can be automatically fixed on your branch by commenting `/format`, a bot will proceed to open a PR targeting *your* branch. For the Pull Request, you will need to write a PR message. This message is for a set of commits you are requesting to pull. Try to make it brief because the actual details should be in the commit messages of each commit. The PR requires an approval from people who have permissions. They will review the changes before approve the Pull. During this step, you will get feedbacks from other people and they may request you to make some changes. When you need to make adjustments, you can commit new changes to the branch in your forlked repository that already has the changes in PR process. When new commits are added to the branch, they will automatically appear in the PR. -## Update your Repository -After your pull request is submitted, you can update your repository for your next changes. +## Addressing Code Reviews and Keep Branch In-Sync +After your pull request is submitted, you will receive code reviews from the community within 24 hours. Follow-up changes that address review comments should be pushed to your pull request branch as additional commits. When your branch is out of sync with top-of-tree, submit a merge commit to keep them in-sync. Do not rebase and force push after the PR is created to keep the change history during the review process. -Update your forked repository in github -When your forked repository is behind the original repository, Github will allow you to sync via a "Sync fork" button. +Use these commands to sync your branch: -Update your local machine from your forked repository ``` -$ git checkout master -$ git pull -$ git submodule update --init --recursive +$ git fetch upstream master +$ git merge upstream/master # resolve any conflicts here +$ git submodule update --recursive ``` -When you update the submodule, "--init" is required if there are new submodules added to the project. -Update tags on your local machine and your forked repository -``` -$ git fetch --tags upstream -$ git push --tags origin -``` +The Slang repository uses the squash strategy for merging pull requests, which means all your commits will be squashed into one commit by GitHub upon merge. + +## Labeling Breaking Changes + +All pull requests must be labeled as either `pr: non-breaking` or `pr: breaking change` before it can be merged to the main branch. If you are already a committer, you are expected to label your PR when you create it. If you are not yet a committer, a reviewer will do this for you. + +A PR is considered to introduce a breaking change if an existing application that uses Slang may no longer compile or behave the same way with the change. Typical examples of breaking changes include: + +- Changes to `slang.h` that modifies the Slang API in a way that breaks binary compatibility. +- Changes to the language syntax or semantics that may cause existing Slang code to not compile or produce different run-time result. For example changing the overload resolution rules. +- Removing or renaming an existing intrinsic from the core module. + ## Code Style Follow our [Coding conventions](docs/design/coding-conventions.md) to maintain consistency throughout the project. @@ -236,7 +245,7 @@ Here are a few highlights 1. Don't use the STL containers, iostreams, or the built-in C++ RTTI system. 1. Don't use the C++ variants of C headers (e.g., use `` instead of ``). 1. Don't use exceptions for non-fatal errors (and even then support a build flag to opt out of exceptions). -1. Types should use UpperCamelCase, values should use lowerCamelCase, and macros should use SCREAMING_SNAKE_CASE with a prefix `SLANG_`. +1. Types should use UpperCamelCase, values should use lowerCamelCase, and macros should use `SCREAMING_SNAKE_CASE` with a prefix `SLANG_`. 1. Global variables should have a `g` prefix, non-const static class members can have an `s` prefix, constant data (in the sense of static const) should have a `k` prefix, and an `m_` prefix on member variables and a `_` prefix on member functions are allowed. 1. Prefixes based on types (e.g., p for pointers) should never be used. 1. In function parameter lists, an `in`, `out`, or `io` prefix can be added to a parameter name to indicate whether a pointer/reference/buffer is intended to be used for input, output, or both input and output. diff --git a/LICENSE b/LICENSE index 23054ae341..b6918fff80 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,29 @@ -MIT License +SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -Copyright (c) 2016, Carnegie Mellon University and NVIDIA Corporation + 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 -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: + http://www.apache.org/licenses/LICENSE-2.0 -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. + 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. -THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +LLVM Exceptions to the Apache 2.0 License + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. diff --git a/LICENSES/Apache-2.0.txt b/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000000..137069b823 --- /dev/null +++ b/LICENSES/Apache-2.0.txt @@ -0,0 +1,73 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +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. diff --git a/LICENSES/CC-BY-4.0.txt b/LICENSES/CC-BY-4.0.txt new file mode 100644 index 0000000000..13ca539f37 --- /dev/null +++ b/LICENSES/CC-BY-4.0.txt @@ -0,0 +1,156 @@ +Creative Commons Attribution 4.0 International + + Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. + +Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. + +Creative Commons Attribution 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + + a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + + c. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + + d. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + + e. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + + f. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + + g. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + + h. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + + i. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + + j. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + + k. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + +b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + 4. If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + + b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and + + c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + + a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + + b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + + c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + + a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + + d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + + e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + + a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + + c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + + d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/LICENSES/LLVM-exception.txt b/LICENSES/LLVM-exception.txt new file mode 100644 index 0000000000..fa4b725a0e --- /dev/null +++ b/LICENSES/LLVM-exception.txt @@ -0,0 +1,15 @@ +---- LLVM Exceptions to the Apache 2.0 License ---- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into an Object form of such source code, you + may redistribute such embedded portions in such Object form without complying + with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + + In addition, if you combine or link compiled forms of this Software with + software that is licensed under the GPLv2 ("Combined Software") and if a + court of competent jurisdiction determines that the patent provision (Section + 3), the indemnity provision (Section 9) or other Section of the License + conflicts with the conditions of the GPLv2, you may retroactively and + prospectively choose to deem waived or otherwise exclude such Section(s) of + the License, but only in their entirety and only with respect to the Combined + Software. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt new file mode 100644 index 0000000000..2071b23b0e --- /dev/null +++ b/LICENSES/MIT.txt @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 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 Software. + +THE SOFTWARE IS 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 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/LICENSES/UOI-NCSA.txt b/LICENSES/UOI-NCSA.txt new file mode 100644 index 0000000000..1fb5af32aa --- /dev/null +++ b/LICENSES/UOI-NCSA.txt @@ -0,0 +1,57 @@ +============================================================================== +LLVM Release License +============================================================================== +University of Illinois/NCSA +Open Source License + +Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign. +All rights reserved. + +Developed by: + + LLVM Team + + University of Illinois at Urbana-Champaign + + http://llvm.org + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal with +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimers. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimers in the + documentation and/or other materials provided with the distribution. + + * Neither the names of the LLVM Team, University of Illinois at + Urbana-Champaign, nor the names of its contributors may be used to + endorse or promote products derived from this Software without specific + prior written permission. + +THE SOFTWARE IS 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 +CONTRIBUTORS 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 SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE +SOFTWARE. + +============================================================================== +Copyrights and Licenses for Third Party Software Distributed with LLVM: +============================================================================== +The LLVM software contains code written by third parties. Such software will +have its own individual LICENSE.TXT file in the directory in which it appears. +This file will describe the copyrights, license, and restrictions which apply +to that code. + +The disclaimer of warranty in the University of Illinois Open Source License +applies to all code in the LLVM Distribution, and nothing in any of the +other licenses gives permission to use the names of the LLVM Team or the +University of Illinois to endorse or promote products derived from this +Software. diff --git a/README.md b/README.md index 8de53b854c..19f55c7159 100644 --- a/README.md +++ b/README.md @@ -6,40 +6,58 @@ Slang Slang is a shading language that makes it easier to build and maintain large shader codebases in a modular and extensible fashion, while also maintaining the highest possible performance on modern GPUs and graphics APIs. Slang is based on years of collaboration between researchers at NVIDIA, Carnegie Mellon University, Stanford, MIT, UCSD and the University of Washington. -Key Features ------------- -The Slang system is designed to provide developers of real-time graphics applications with the services they need when working with shader code. +Why Slang? +--------------- + +The Slang shading language is designed to enable real-time graphics developers to work with large-scale, high-performance shader code. + +### Write Shaders Once, Run Anywhere + +The Slang compiler can generate code for a wide variety of targets: D3D12, Vulkan, Metal, D3D11, OpenGL, CUDA, and even generate code to run on a CPU. For textual targets, such as Metal Shading Language (MSL) and CUDA, Slang produces readable code that preserves original identifier names, as well as the type and call structure, making it easier to debug. -* Slang is backwards-compatible with most existing HLSL code. It is possible to start taking advantage of Slang's benefits without rewriting or porting your shader codebase. +### Access the Latest GPU Features -* The Slang compiler can generate code for a wide variety of targets and APIs: D3D12, Vulkan, Metal, D3D11, OpenGL, CUDA, and CPU. Slang code can be broadly portable, but still take advantage of the unique features of each platform. For textual targets such as Metal Shading Language(MSL) and CUDA, Slang generates readable code that preserves the original identifier names and the type + call structure for ease of debugging. +Slang code is highly portable, but can still leverage unique platform capabilities, including the latest features in Direct3D and Vulkan. For example, developers can make full use of [pointers](https://shader-slang.com/slang/user-guide/convenience-features.html#pointers-limited) when generating SPIR-V. +Slang's [capability system](https://shader-slang.com/slang/user-guide/capabilities.html) helps applications manage feature set differences across target platforms by ensuring code only uses available features during the type-checking step, before generating final code. Additionally, Slang provides [flexible interop](https://shader-slang.com/slang/user-guide/a1-04-interop.html) features to enable directly embedding target code or SPIR-V into generated shaders. -* [Automatic differentiation](https://shader-slang.com/slang/user-guide/autodiff.html) as a first-class language feature. Slang can automatically generate both forward and backward derivative propagation code for complex functions that involve arbitrary control flow and dynamic dispatch. This allows users to easily make existing rendering codebases differentiable, or to use Slang as the kernel language in a PyTorch driven machine learning framework via [`slangtorch`](https://shader-slang.com/slang/user-guide/a1-02-slangpy.html). +### Leverage Neural Graphics with Automatic Differentiation -* Generics and interfaces allow shader specialization to be expressed cleanly without resort to preprocessor techniques or string-pasting. Unlike C++ templates, Slang's generics are checked ahead of time and don't produce cascading error messages that are difficult to diagnose. The same generic shader can be specialized for a variety of different types to produce specialized code ahead of time, or on the fly, completely under application control. +Slang can [automatically generate both forward and backward derivative propagation code](https://shader-slang.com/slang/user-guide/autodiff.html) for complex functions that involve arbitrary control flow and dynamic dispatch. This allows existing rendering codebases to easily become differentiable, or for Slang to serve as the kernel language in a PyTorch-driven machine learning framework via [`slangtorch`](https://shader-slang.com/slang/user-guide/a1-02-slangpy.html). -* Slang provides a module system that can be used to logically organize code and benefit from separate compilation. Slang modules can be compiled offline to a custom IR (with optional obfuscation) and then linked at runtime to generate DXIL, SPIR-V etc. +### Scalable Software Development with Modules -* Parameter blocks (exposed as `ParameterBlock`) provide a first-class language feature for grouping related shader parameters and specifying that they should be passed to the GPU as a coherent block. Parameter blocks make it easy for applications to use the most efficient parameter-binding model of each API, such as descriptor tables/sets in D3D12/Vulkan. +Slang provides a [module system](https://shader-slang.com/slang/user-guide/modules.html) that enables logical organization of code for separate compilation. Slang modules can be independently compiled offline to a custom IR (with optional obfuscation) and then linked at runtime to generate code in formats such as DXIL or SPIR-V. -* Rather than require tedious explicit `register` and `layout` specifications on each shader parameter, Slang supports completely automate and deterministic assignment of binding locations to parameter. You can write simple and clean code and still get the deterministic layout your application wants. +### Code Specialization that Works with Modules -* For applications that want it, Slang provides full reflection information about the parameters of your shader code, with a consistent API across all target platforms and graphics APIs. Unlike some other compilers, Slang does not reorder or drop shader parameters based on how they are used, so you can always see the full picture. +Slang supports [generics and interfaces](https://shader-slang.com/slang/user-guide/interfaces-generics.html) (a.k.a. type traits/protocols), allowing for clear expression of shader specialization without the need for preprocessor techniques or string-pasting. Unlike C++ templates, Slang's generics are pre-checked and don't produce cascading error messages that are difficult to diagnose. The same generic shader can be specialized for a variety of different types to produce specialized code ahead of time, or on the fly, entirely under application control. -* Full intellisense features in Visual Studio Code and Visual Studio through the Language Server Protocol. +### Easy On-ramp for HLSL and GLSL Codebases -* Full debugging experience with SPIRV and RenderDoc. +Slang's syntax is similar to HLSL, and most existing HLSL code can be compiled with the Slang compiler out-of-the-box, or with just minor modifications. This allows existing shader codebases to immediately benefit from Slang without requiring a complete rewrite or port. + +Slang provides a compatibility module that enables the use of most GLSL intrinsic functions and GLSL's parameter binding syntax. + +### Comprehensive Tooling Support + +Slang comes with full support of IntelliSense editing features in Visual Studio Code and Visual Studio through the Language Server Protocol. +Full debugging capabilities are also available through RenderDoc and SPIR-V based tools. Getting Started --------------- -If you want to try out the Slang language without installing anything, a fast and simple way is to use the [Shader Playground](docs/shader-playground.md). - The fastest way to get started using Slang in your own development is to use a pre-built binary package, available through GitHub [releases](https://github.com/shader-slang/slang/releases). +Slang binaries are also included in the [Vulkan SDK](https://vulkan.lunarg.com/sdk/home) since version 1.3.296.0. + There are packages built for 32- and 64-bit Windows, as well as 64-bit Ubuntu. Each binary release includes the command-line `slangc` compiler, a shared library for the compiler, and the `slang.h` header. +See the user-guide for info on using the `slangc` command-line tool: [Slang Command Line Usage]( +https://shader-slang.com/slang/user-guide/compiling.html#command-line-compilation-with-slangc). + +If you want to try out the Slang language without installing anything, a fast and simple way is to use the [Slang Playground](https://shader-slang.com/slang-playground). The playground allows you to compile Slang code to a variety of targets, and even run some simple shaders directly within the browser. The playground loads Slang compiler to your browser and runs all compilation locally. No data will be sent to any servers. + If you would like to build Slang from source, please consult the [build instructions](docs/building.md). Documentation @@ -47,6 +65,8 @@ Documentation The Slang project provides a variety of different [documentation](docs/), but most users would be well served starting with the [User's Guide](https://shader-slang.github.io/slang/user-guide/). +For developers writing Slang code, the [Slang Core Module Reference](https://shader-slang.com/stdlib-reference/) provides detailed documentation on Slang's built-in types and functions. + We also provide a few [examples](examples/) of how to integrate Slang into a rendering application. These examples use a graphics layer that we include with Slang called "GFX" which is an abstraction library of various graphics APIs (D3D11, D2D12, OpenGL, Vulkan, CUDA, and the CPU) to support cross-platform applications using GPU graphics and compute capabilities. @@ -65,31 +85,56 @@ The following guidelines should be observed by contributors: * Changes should ideally come in as small pull requests on top of `master`, coming from your own personal fork of the project * Large features that will involve multiple contributors or a long development time should be discussed in issues, and broken down into smaller pieces that can be implemented and checked in in stages -[Contribution guide](CONTRIBUTION.md) describes the workflow for contributors at more detail. +[Contribution guide](CONTRIBUTING.md) describes the workflow for contributors at more detail. Limitations and Support ----------------------- ### Platform support -| Windows | Linux | MacOS | -|:---------------:|:--------------:|:------------:| -| supported | supported | supported | + +The Slang compiler and libraries can be built on the following platforms: + +| Windows | Linux | MacOS | WebAssembly | +|:---------:|:---------:|:---------:|:------------:| +| supported | supported | supported | experimental | + +Both `x86_64` and `aarch64` architectures are supported on Windows, Linux and MacOS platforms. ### Target support -| Direct3D 11 | Direct3D 12 | Vulkan | Metal | CUDA | OptiX | CPU Compute | -|:---------------:|:--------------:|:---------------:|:-------------------------------------------------------:|:-------------------:|:-----------:|:---------------------:| -| HLSL | HLSL | GLSL & SPIR-V | Metal Shading Language (Vertex/Fragment/Mesh/Compute stages) | C++ (compute-only) | C++ (WIP) | C++ (compute-only) | -*for greater detail, see the [Supported Compilation Targets](https://shader-slang.com/slang/user-guide/targets.html) section of the [User Guide](https://shader-slang.github.io/slang/user-guide/) +Slang can compile shader code to the following targets: + +| Target | Status | Output Formats | +|:-----------:|:-------------------------------------------------------------------------------------:|:----------------------------------------------------------------:| +| Direct3D 11 | [supported](https://shader-slang.com/slang/user-guide/targets.html#direct3d-11) | HLSL | +| Direct3D 12 | [supported](https://shader-slang.com/slang/user-guide/targets.html#direct3d-12) | HLSL | +| Vulkan | [supported](https://shader-slang.com/slang/user-guide/targets.html#vulkan) | SPIRV, GLSL | +| Metal | [experimental*](https://shader-slang.com/slang/user-guide/targets.html#metal) | Metal Shading Language | +| WebGPU | experimental** | WGSL | +| CUDA | [supported](https://shader-slang.com/slang/user-guide/targets.html#cuda-and-optix) | C++ (compute only) | +| Optix | [experimental](https://shader-slang.com/slang/user-guide/targets.html#cuda-and-optix) | C++ (WIP) | +| CPU | [experimental](https://shader-slang.com/slang/user-guide/targets.html#cpu-compute) | C++ (kernel), C++ (host), standalone executable, dynamic library | + +> *Slang currently supports generating vertex, fragment, compute, task and mesh +> shaders for Metal. + +> **WGSL support is still work in-progress. + +For greater detail, see the [Supported Compilation +Targets](https://shader-slang.com/slang/user-guide/targets.html) section of the +[User Guide](https://shader-slang.github.io/slang/user-guide/) -The Slang project has been used for production applications and large shader codebases, but it is still under active development. -Support is currently focused on the platforms (Windows, Linux) and target APIs (Direct3D 12, Vulkan) where Slang is used most heavily. -Users who are looking for support on other platforms or APIs should coordinate with the development team via the issue tracker to make sure that their use case(s) can be supported. +The Slang project has been used for production applications and large shader +codebases, but it is still under active development. Support is currently +focused on the platforms (Windows, Linux) and target APIs (Direct3D 12, Vulkan) +where Slang is used most heavily. Users who are looking for support on other +platforms or APIs should coordinate with the development team via the issue +tracker to make sure that their use cases can be supported. License ------- -The Slang code itself is under the MIT license (see [LICENSE](LICENSE)). +The Slang code itself is under the Apache 2.0 with LLVM Exception license (see [LICENSE](LICENSE)). Builds of the core Slang tools depend on the following projects, either automatically or optionally, which may have their own licenses: diff --git a/cmake/AutoOption.cmake b/cmake/AutoOption.cmake index 3f7cdee0ea..d25ea17b83 100644 --- a/cmake/AutoOption.cmake +++ b/cmake/AutoOption.cmake @@ -42,3 +42,8 @@ function(enum_option name init description) endforeach() message(FATAL_ERROR "${name} must be one of ${enums}") endfunction() + +function(advanced_option name description default) + option(${name} ${description} ${default}) + mark_as_advanced(${name}) +endfunction() diff --git a/cmake/CCacheDebugInfoWorkaround.cmake b/cmake/CCacheDebugInfoWorkaround.cmake index 82fb299e3b..743b9b8ea8 100644 --- a/cmake/CCacheDebugInfoWorkaround.cmake +++ b/cmake/CCacheDebugInfoWorkaround.cmake @@ -10,7 +10,7 @@ if( ) message( NOTICE - "Setting embedded debug info for MSVC to work around (s)ccache's inability to cache shared debug info files, Note that this requires CMake 3.25 or greater" + "Setting embedded debug info for MSVC to work around (s)ccache's inability to cache shared debug info files" ) cmake_minimum_required(VERSION 3.25) cmake_policy(GET CMP0141 cmp0141) diff --git a/cmake/CompilerFlags.cmake b/cmake/CompilerFlags.cmake index cd9021cd03..e3ddaa7e0f 100644 --- a/cmake/CompilerFlags.cmake +++ b/cmake/CompilerFlags.cmake @@ -152,8 +152,14 @@ function(set_default_compile_options target) add_supported_cxx_flags(${target} PRIVATE ${warning_flags}) - # Don't assume that symbols will be resolved at runtime - add_supported_cxx_linker_flags(${target} PRIVATE "-Wl,--no-undefined") + add_supported_cxx_linker_flags( + ${target} + PRIVATE + # Don't assume that symbols will be resolved at runtime + "-Wl,--no-undefined" + # No reason not to do this? Useful when using split debug info + "-Wl,--build-id" + ) set_target_properties( ${target} diff --git a/cmake/FetchedSharedLibrary.cmake b/cmake/FetchedSharedLibrary.cmake new file mode 100644 index 0000000000..bd7eb10f9f --- /dev/null +++ b/cmake/FetchedSharedLibrary.cmake @@ -0,0 +1,147 @@ +# Helper function to download and extract an archive +function(download_and_extract archive_name url) + cmake_path(GET url FILENAME filename_with_ext) + cmake_path(GET url STEM LAST_ONLY file_stem) + set(archive_path "${CMAKE_CURRENT_BINARY_DIR}/${filename_with_ext}") + set(extract_dir "${CMAKE_CURRENT_BINARY_DIR}/${file_stem}") + + # Check if already extracted + file(GLOB EXTRACT_DIR_CONTENTS "${extract_dir}/*") + if(EXTRACT_DIR_CONTENTS) + message(STATUS "Using existing extracted files in ${extract_dir}") + else() + # Check if archive already exists + if(EXISTS ${url}) + message(STATUS "Using local file for ${archive_name}: ${url}") + set(archive_path ${url}) + elseif(EXISTS ${archive_path}) + message( + STATUS + "Using existing archive for ${archive_name}: ${archive_path}" + ) + else() + message(STATUS "Fetching ${archive_name} from ${url}") + file(DOWNLOAD ${url} ${archive_path} STATUS status) + + list(GET status 0 status_code) + list(GET status 1 status_string) + if(NOT status_code EQUAL 0) + message( + WARNING + "Failed to download ${archive_name} from ${url}: ${status_string}" + ) + return() + endif() + endif() + + file(ARCHIVE_EXTRACT INPUT ${archive_path} DESTINATION ${extract_dir}) + message(STATUS "${archive_name} extracted to ${extract_dir}") + endif() + + set(${archive_name}_SOURCE_DIR ${extract_dir} PARENT_SCOPE) +endfunction() + +# Add rules to copy & install shared library of name 'library_name' in the 'module_subdir' directory. +# If 'url' is a directory, the shared library (with platform-specific shared library prefixes and suffixes) will be +# taken from the directory, and whatever is found there will be used to produce the install rule. +# If the 'url' is a path to a file with the platform-specific shared library prefix and suffix, then that file +# will be used to produce the install rule. +# Otherwise, the 'url' is interpreted as an URL, and the content of the URL will be fetched, extracted and searched +# for the shared library to produce the install rule. +function(copy_fetched_shared_library library_name url) + cmake_parse_arguments(ARG "IGNORE_FAILURE" "" "" ${ARGN}) + if(ARG_IGNORE_FAILURE) + set(error_type STATUS) + else() + set(error_type SEND_ERROR) + endif() + + set(shared_library_filename + "${CMAKE_SHARED_LIBRARY_PREFIX}${library_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" + ) + macro(from_glob dir) + # A little helper function + file(GLOB_RECURSE source_object "${dir}/${shared_library_filename}") + list(LENGTH source_object nmatches) + if(nmatches EQUAL 0) + message( + ${error_type} + "Unable to find ${shared_library_filename} in ${url}" + ) + elseif(nmatches GREATER 1) + message( + ${error_type} + "Found multiple files named ${shared_library_filename} in ${url}" + ) + endif() + endmacro() + + if(IS_DIRECTORY "${url}") + # Just glob directly from a local directory + from_glob("${url}") + elseif( + url + MATCHES + "${CMAKE_SHARED_LIBRARY_PREFIX}.+${CMAKE_SHARED_LIBRARY_SUFFIX}$" + AND EXISTS "${url}" + ) + # Otherwise, if it's a direct path to a shared object, use that + set(source_object "${url}") + else() + # Otherwise, download and extract from whatever URL we have + download_and_extract("${library_name}" "${url}") + if(DEFINED ${library_name}_SOURCE_DIR) + from_glob(${${library_name}_SOURCE_DIR}) + elseif(ARG_IGNORE_FAILURE) + return() + else() + message( + SEND_ERROR + "Unable to download and extract ${library_name} from ${url}" + ) + return() + endif() + endif() + + # We didn't find it, just return and don't create a target and operation + # which will fail + if(NOT EXISTS ${source_object} AND ARG_IGNORE_FAILURE) + return() + endif() + + set(dest_object + ${CMAKE_BINARY_DIR}/$/${module_subdir}/${shared_library_filename} + ) + add_custom_command( + OUTPUT ${dest_object} + COMMAND + ${CMAKE_COMMAND} -E copy_if_different ${source_object} + ${dest_object} + DEPENDS ${source_object} + VERBATIM + ) + # Give this copying action a name + add_custom_target(copy-${library_name} DEPENDS ${dest_object}) + set_target_properties(copy-${library_name} PROPERTIES FOLDER generated) + + # Put this into a library target + add_library(${library_name} MODULE IMPORTED GLOBAL) + add_dependencies(${library_name} copy-${library_name}) + set_property( + TARGET ${library_name} + PROPERTY IMPORTED_LOCATION ${dest_object} + ) +endfunction() + +function(install_fetched_shared_library library_name url) + copy_fetched_shared_library(${library_name} ${url} ${ARGN}) + set(shared_library_filename + "${CMAKE_SHARED_LIBRARY_PREFIX}${library_name}${CMAKE_SHARED_LIBRARY_SUFFIX}" + ) + set(dest_object + ${CMAKE_BINARY_DIR}/$/${module_subdir}/${shared_library_filename} + ) + if(TARGET ${library_name}) + install(PROGRAMS ${dest_object} DESTINATION ${module_subdir}) + endif() +endfunction() diff --git a/cmake/GitHubRelease.cmake b/cmake/GitHubRelease.cmake index e63fb7885b..adcb9a5634 100644 --- a/cmake/GitHubRelease.cmake +++ b/cmake/GitHubRelease.cmake @@ -1,48 +1,58 @@ -function(check_release_and_get_latest owner repo version os arch out_var) - # Construct the URL for the specified version's release API endpoint - set(version_url "https://api.github.com/repos/${owner}/${repo}/releases/tags/v${version}") - - set(json_output_file "${CMAKE_CURRENT_BINARY_DIR}/${owner}_${repo}_release_info.json") - - function(check_assets_for_file json_content filename found_var) - string(JSON asset_count LENGTH "${json_content}" "assets") - set(found "FALSE") - foreach(i RANGE 0 ${asset_count}) - string(JSON asset_name GET "${json_content}" "assets" ${i} "name") - if("${asset_name}" STREQUAL "${filename}") - set(found "TRUE") - break() - endif() - endforeach() - set(${found_var} "${found}" PARENT_SCOPE) - endfunction() - - # Download the specified release info from GitHub - file(DOWNLOAD "${version_url}" "${json_output_file}" STATUS download_statuses) - list(GET download_statuses 0 status_code) - if(status_code EQUAL 0) - file(READ "${json_output_file}" json_content) - - # Check if the specified version contains the expected ZIP file - set(desired_zip "${repo}-${version}-${os}-${arch}.zip") - check_assets_for_file("${json_content}" "${desired_zip}" file_found) +function(check_assets_for_file json_content filename found_var) + string(JSON asset_count LENGTH "${json_content}" "assets") + set(found "FALSE") - if(file_found) - set(${out_var} "${version}" PARENT_SCOPE) - return() + # Never change, CMake... + math(EXPR max_asset_index "${asset_count} - 1") + foreach(i RANGE 0 ${max_asset_index}) + string(JSON asset_name GET "${json_content}" "assets" ${i} "name") + if("${asset_name}" STREQUAL "${filename}") + set(found "TRUE") + break() endif() - message(WARNING "Failed to find ${desired_zip} in release assets for ${version} from ${version_url}\nFalling back to latest version if it differs") - else() - message(WARNING "Failed to download release info for version ${version} from ${version_url}\nFalling back to latest version if it differs") - endif() + endforeach() + set(${found_var} "${found}" PARENT_SCOPE) +endfunction() +function( + get_latest + owner + repo + os + arch + github_token + out_var +) + set(json_output_file + "${CMAKE_CURRENT_BINARY_DIR}/${owner}_${repo}_release_info.json" + ) + set(latest_release_url + "https://api.github.com/repos/${owner}/${repo}/releases/latest" + ) - # If not found, get the latest release tag - set(latest_release_url "https://api.github.com/repos/${owner}/${repo}/releases/latest") - file(DOWNLOAD "${latest_release_url}" "${json_output_file}" STATUS download_status) - list(GET download_status 0 status_code) + set(download_args + "${latest_release_url}" + "${json_output_file}" + STATUS + download_statuses + ) + + if(github_token) + list( + APPEND + download_args + HTTPHEADER + "Authorization: token ${github_token}" + ) + endif() + + file(DOWNLOAD ${download_args}) + list(GET download_statuses 0 status_code) if(NOT status_code EQUAL 0) - message(WARNING "Failed to download latest release info from ${latest_release_url}") + message( + WARNING + "Failed to download latest release info from ${latest_release_url}" + ) return() endif() @@ -51,31 +61,121 @@ function(check_release_and_get_latest owner repo version os arch out_var) string(JSON latest_release_tag GET "${latest_json_content}" "tag_name") string(REGEX REPLACE "^v" "" latest_version "${latest_release_tag}") - if(latest_version EQUAL version) - # The versions are the same - message(WARNING "No release binary for ${os}-${arch} exists for ${version}") - return() - endif() - # Check if the expected ZIP file is in the latest release set(desired_zip "${repo}-${latest_version}-${os}-${arch}.zip") - check_assets_for_file("${latest_json_content}" "${desired_zip}" file_found_latest) + message( + VERBOSE + "searching for the prebuilt slang-llvm library in ${latest_release_url}" + ) + check_assets_for_file( + "${latest_json_content}" + "${desired_zip}" + file_found_latest + ) if(file_found_latest) # If we got it, we found a good version set(${out_var} "${latest_version}" PARENT_SCOPE) else() - message(WARNING "No release binary for ${os}-${arch} exists for ${version} or the latest version ${latest_version}") + message( + WARNING + "No release binary for ${os}-${arch} exists for the latest version: ${latest_version}" + ) + endif() +endfunction() + +function( + check_release_and_get_latest + owner + repo + version + os + arch + github_token + out_var +) + # Construct the URL for the specified version's release API endpoint + set(version_url + "https://api.github.com/repos/${owner}/${repo}/releases/tags/v${version}" + ) + + set(json_output_file + "${CMAKE_CURRENT_BINARY_DIR}/${owner}_${repo}_release_info.json" + ) + + # Prepare download arguments + set(download_args + "${version_url}" + "${json_output_file}" + STATUS + download_statuses + ) + + if(github_token) + # Add authorization header if token is provided + list( + APPEND + download_args + HTTPHEADER + "Authorization: token ${github_token}" + ) + endif() + + # Perform the download + file(DOWNLOAD ${download_args}) + + # Check if the downloading was successful + list(GET download_statuses 0 status_code) + if(status_code EQUAL 0) + file(READ "${json_output_file}" json_content) + + # Check if the specified version contains the expected ZIP file + set(desired_zip "${repo}-${version}-${os}-${arch}.zip") + message( + VERBOSE + "searching for the prebuilt slang-llvm library in ${version_url}" + ) + check_assets_for_file("${json_content}" "${desired_zip}" file_found) + + if(file_found) + set(${out_var} "${version}" PARENT_SCOPE) + return() + endif() + message( + WARNING + "Failed to find ${desired_zip} in release assets for ${version} from ${version_url}\nFalling back to latest version if it differs" + ) + else() + set(w + "Failed to download release info for version ${version} from ${version_url}\nFalling back to latest version if it differs" + ) + if(status_code EQUAL 22) + set(w + "${w}\nIf you think this is failing because of GitHub API rate limiting, Github allows a higher limit if you use a token. Try the cmake option -DSLANG_GITHUB_TOKEN=your_token_here" + ) + endif() + + message(WARNING ${w}) endif() + + # If not found, get the latest release tag + get_latest(${owner} ${repo} ${os} ${arch} "${github_token}" latest_version) + if(NOT DEFINED latest_version) + return() + endif() + set(${out_var} "${latest_version}" PARENT_SCOPE) endfunction() -function(get_best_slang_binary_release_url out_var) +function(get_best_slang_binary_release_url github_token out_var) if(CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64|amd64|AMD64") set(arch "x86_64") elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64") set(arch "aarch64") else() - message(WARNING "Unsupported architecture for slang binary releases: ${CMAKE_SYSTEM_PROCESSOR}") + message( + WARNING + "Unsupported architecture for slang binary releases: ${CMAKE_SYSTEM_PROCESSOR}" + ) return() endif() @@ -86,15 +186,58 @@ function(get_best_slang_binary_release_url out_var) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(os "linux") else() - message(WARNING "Unsupported operating system for slang binary releases: ${CMAKE_SYSTEM_NAME}") + message( + WARNING + "Unsupported operating system for slang binary releases: ${CMAKE_SYSTEM_NAME}" + ) return() endif() set(owner "shader-slang") set(repo "slang") - check_release_and_get_latest(${owner} ${repo} ${SLANG_VERSION_NUMERIC} ${os} ${arch} release_version) + # This is the first version which distributed libslang-llvm.so, if it's + # older than that then someone didn't fetch tags, emit a message and + # fallback to the latest release + if(${SLANG_VERSION_NUMERIC} VERSION_LESS "2024.1.27") + if(${SLANG_VERSION_NUMERIC} VERSION_EQUAL "0.0.0") + message( + VERBOSE + "The detected version of slang is ${SLANG_VERSION_NUMERIC}, fetching libslang-llvm from the latest release" + ) + else() + message( + WARNING + "The detected version of slang ${SLANG_VERSION_NUMERIC} is very old (probably you haven't fetched tags recently?), libslang-llvm will be fetched from the latest release rather than the one matching ${SLANG_VERSION_NUMERIC}" + ) + endif() + get_latest( + ${owner} + ${repo} + ${os} + ${arch} + "${github_token}" + release_version + ) + else() + check_release_and_get_latest( + ${owner} + ${repo} + ${SLANG_VERSION_NUMERIC} + ${os} + ${arch} + "${github_token}" + release_version + ) + endif() if(DEFINED release_version) - set(${out_var} "https://github.com/${owner}/${repo}/releases/download/v${release_version}/slang-${release_version}-${os}-${arch}.zip" PARENT_SCOPE) + message( + VERBOSE + "Found a version of libslang-llvm.so in ${release_version}" + ) + set(${out_var} + "https://github.com/${owner}/${repo}/releases/download/v${release_version}/slang-${release_version}-${os}-${arch}.zip" + PARENT_SCOPE + ) endif() endfunction() diff --git a/cmake/GitVersion.cmake b/cmake/GitVersion.cmake index 386ca309c6..c8eb329478 100644 --- a/cmake/GitVersion.cmake +++ b/cmake/GitVersion.cmake @@ -24,7 +24,7 @@ function(get_git_version var_numeric var dir) if(NOT result EQUAL 0) message( WARNING - "Getting ${var} failed: ${command} returned ${result}" + "Getting ${var} failed: ${command} returned ${result}\nIs this a Git repo with tags?\nConsider settings -D${var} to specify a version manually" ) elseif("${version_out}" MATCHES "^v(([0-9]+(\\.[0-9]+)*).*)") set(version "${CMAKE_MATCH_1}") @@ -32,13 +32,13 @@ function(get_git_version var_numeric var dir) else() message( WARNING - "Couldn't parse version (like v1.2.3 or v1.2.3-foo) from ${version_out}" + "Couldn't parse version (like v1.2.3 or v1.2.3-foo) from ${version_out}, using ${version} for now" ) endif() else() message( WARNING - "Couldn't find git executable to get ${var}, please use -D${var}" + "Couldn't find git executable to get ${var}, please use -D${var}, using ${version} for now" ) endif() endif() diff --git a/cmake/Glob.cmake b/cmake/Glob.cmake index 831a074961..7adf355f12 100644 --- a/cmake/Glob.cmake +++ b/cmake/Glob.cmake @@ -22,9 +22,9 @@ function(slang_glob_sources var dir) "*.natstepfilter" "*.natjmc" ) - if (CMAKE_SYSTEM_NAME MATCHES "Darwin") + if(CMAKE_SYSTEM_NAME MATCHES "Darwin") list(APPEND patterns "*.mm") - endif() + endif() list(TRANSFORM patterns PREPEND "${dir}/") file(GLOB_RECURSE files CONFIGURE_DEPENDS ${patterns}) diff --git a/cmake/LLVM.cmake b/cmake/LLVM.cmake index 10a31e2d16..a72cae0f58 100644 --- a/cmake/LLVM.cmake +++ b/cmake/LLVM.cmake @@ -38,3 +38,112 @@ function(clang_target_from_libs target_name) add_supported_cxx_flags(${target_name} INTERFACE -fno-rtti /GR-) endif() endfunction() + +function(fetch_or_build_slang_llvm) + if(SLANG_SLANG_LLVM_FLAVOR STREQUAL "FETCH_BINARY") + install_fetched_shared_library( + "slang-llvm" + "${SLANG_SLANG_LLVM_BINARY_URL}" + ) + elseif(SLANG_SLANG_LLVM_FLAVOR STREQUAL "FETCH_BINARY_IF_POSSIBLE") + if(SLANG_SLANG_LLVM_BINARY_URL) + install_fetched_shared_library( + "slang-llvm" + "${SLANG_SLANG_LLVM_BINARY_URL}" + IGNORE_FAILURE + ) + if(NOT TARGET slang-llvm) + message( + WARNING + "Unable to fetch slang-llvm prebuilt binary, configuring without LLVM support" + ) + endif() + endif() + elseif(SLANG_SLANG_LLVM_FLAVOR STREQUAL "USE_SYSTEM_LLVM") + find_package(LLVM 13.0 REQUIRED CONFIG) + find_package(Clang REQUIRED CONFIG) + + llvm_target_from_components(llvm-dep filecheck native orcjit) + clang_target_from_libs( + clang-dep + clangBasic + clangCodeGen + clangDriver + clangLex + clangFrontend + clangFrontendTool + ) + slang_add_target( + source/slang-llvm + MODULE + LINK_WITH_PRIVATE core compiler-core llvm-dep clang-dep + # We include slang.h, but don't need to link with it + INCLUDE_FROM_PRIVATE slang + # We include tools/slang-test/filecheck.h, but don't need to link + # with it and it might not be a target if SLANG_ENABLE_TESTS is + # false, so just include the directory manually here + INCLUDE_DIRECTORIES_PRIVATE ${slang_SOURCE_DIR}/tools + # This uses the SLANG_DLL_EXPORT macro from slang.h, so make sure to set + # SLANG_DYNAMIC and SLANG_DYNAMIC_EXPORT + EXPORT_MACRO_PREFIX SLANG + INSTALL + INSTALL_COMPONENT slang-llvm + EXPORT_SET_NAME SlangTargets + ) + # If we don't include this, then the symbols in the LLVM linked here may + # conflict with those of other LLVMs linked at runtime, for instance in mesa. + add_supported_cxx_linker_flags( + slang-llvm + PRIVATE + "-Wl,--exclude-libs,ALL" + ) + + # The LLVM headers need a warning disabling, which somehow slips through \external + if(MSVC) + target_compile_options(slang-llvm PRIVATE -wd4244) + endif() + + # TODO: Put a check here that libslang-llvm.so doesn't have a 'NEEDED' + # directive for libLLVM-13.so, it's almost certainly going to break at + # runtime in surprising ways when linked alongside Mesa (or anything else + # pulling in libLLVM.so) + endif() + + if(SLANG_ENABLE_PREBUILT_BINARIES) + if(CMAKE_SYSTEM_NAME MATCHES "Windows") + # DX Agility SDK requires the D3D12*.DLL files to be placed under a sub-directory, "D3D12". + # https://devblogs.microsoft.com/directx/gettingstarted-dx12agility/#d3d12sdkpath-should-not-be-the-same-directory-as-the-application-exe + file( + GLOB prebuilt_binaries + "${slang_SOURCE_DIR}/external/slang-binaries/bin/windows-x64/*" + ) + file( + GLOB prebuilt_d3d12_binaries + "${slang_SOURCE_DIR}/external/slang-binaries/bin/windows-x64/[dD]3[dD]12*" + ) + list(REMOVE_ITEM prebuilt_binaries ${prebuilt_d3d12_binaries}) + add_custom_target( + copy-prebuilt-binaries + ALL + COMMAND + ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/$/${runtime_subdir} + COMMAND + ${CMAKE_COMMAND} -E copy_if_different ${prebuilt_binaries} + ${CMAKE_BINARY_DIR}/$/${runtime_subdir} + COMMAND + ${CMAKE_COMMAND} -E make_directory + ${CMAKE_BINARY_DIR}/$/${runtime_subdir}/D3D12 + COMMAND + ${CMAKE_COMMAND} -E copy_if_different + ${prebuilt_d3d12_binaries} + ${CMAKE_BINARY_DIR}/$/${runtime_subdir}/D3D12 + VERBATIM + ) + set_target_properties( + copy-prebuilt-binaries + PROPERTIES FOLDER external + ) + endif() + endif() +endfunction() diff --git a/cmake/SlangConfig.cmake.in b/cmake/SlangConfig.cmake.in new file mode 100644 index 0000000000..2539586902 --- /dev/null +++ b/cmake/SlangConfig.cmake.in @@ -0,0 +1,20 @@ + +@PACKAGE_INIT@ + +if (NOT CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + include("${CMAKE_CURRENT_LIST_DIR}/slangTargets.cmake") + check_required_components("slang") +endif() + +if(@SLANG_ENABLE_SLANGC@) + + find_program(SLANGC_EXECUTABLE "slangc" HINTS ENV PATH "${PACKAGE_PREFIX_DIR}/bin") + + if (NOT SLANGC_EXECUTABLE) + message(STATUS "slangc executable not found; ensure it is available in your PATH.") + endif() + + set(SLANG_EXECUTABLE ${SLANGC_EXECUTABLE} CACHE STRING "Path to the slangc executable") + +endif() + diff --git a/cmake/SlangTarget.cmake b/cmake/SlangTarget.cmake index e370a4987d..45e7cf1e1d 100644 --- a/cmake/SlangTarget.cmake +++ b/cmake/SlangTarget.cmake @@ -1,5 +1,5 @@ # -# A function to make target creation a little more declarative +# A function to make target specification a little more declarative # # See the comments on the options below for usage # @@ -18,6 +18,11 @@ function(slang_add_target dir type) WIN32_EXECUTABLE # Install this target for a non-component install INSTALL + # Don't include any source in this target, this is a complement to + # EXPLICIT_SOURCE, and doesn't interact with EXTRA_SOURCE_DIRS + NO_SOURCE + # Don't generate split debug info for this target + NO_SPLIT_DEBUG_INFO ) set(single_value_args # Set the target name, useful for multiple targets from the same @@ -35,6 +40,10 @@ function(slang_add_target dir type) # ${EXPORT_MACRO_PREFIX}_DYNAMIC_EXPORT macros are set for using and # building respectively EXPORT_MACRO_PREFIX + # Ignore target type and use a particular style of export macro + # _DYNAMIC or _STATIC, this is useful when the target type is OBJECT + # pass in STATIC or SHARED + EXPORT_TYPE_AS # The folder in which to place this target for IDE-based generators (VS # and XCode) FOLDER @@ -42,6 +51,12 @@ function(slang_add_target dir type) DEBUG_DIR # Install this target as part of a component INSTALL_COMPONENT + # Override the debug info component name for installation + # explicit name instead, used for externally built things such as + # slang-glslang and slang-llvm which have large pdb files + DEBUG_INFO_INSTALL_COMPONENT + # The name of the Export set to associate with this installed target + EXPORT_SET_NAME ) set(multi_value_args # Use exactly these sources, instead of globbing from the directory @@ -55,10 +70,16 @@ function(slang_add_target dir type) EXTRA_COMPILE_OPTIONS_PRIVATE # Targets with which to link privately LINK_WITH_PRIVATE + # Targets with which to link publicly, for example if their headers + # appear in our headers + LINK_WITH_PUBLIC # Frameworks with which to link privately LINK_WITH_FRAMEWORK # Targets whose headers we use, but don't link with INCLUDE_FROM_PRIVATE + # Targets whose headers we use in our headers, so need to make sure + # dependencies of this target also include them + INCLUDE_FROM_PUBLIC # Any include directories other targets need to use this target INCLUDE_DIRECTORIES_PUBLIC # Any include directories this target only needs @@ -109,7 +130,8 @@ function(slang_add_target dir type) # # Find the source for this target # - if(ARG_EXPLICIT_SOURCE) + if(ARG_NO_SOURCE) + elseif(ARG_EXPLICIT_SOURCE) list(APPEND source ${ARG_EXPLICIT_SOURCE}) else() slang_glob_sources(source ${dir}) @@ -142,6 +164,15 @@ function(slang_add_target dir type) return() endif() + # Enable link-time optimization for release builds + # See: https://cmake.org/cmake/help/latest/prop_tgt/INTERPROCEDURAL_OPTIMIZATION.html + set_target_properties( + ${target} + PROPERTIES + INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE + INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE + ) + # # Set the output directory # @@ -171,6 +202,29 @@ function(slang_add_target dir type) PDB_OUTPUT_DIRECTORY "${output_dir}/${runtime_subdir}" ) + set(debug_configs "Debug,RelWithDebInfo") + if(SLANG_ENABLE_RELEASE_DEBUG_INFO) + set(debug_configs "Debug,RelWithDebInfo,Release") + endif() + + set_target_properties( + ${target} + PROPERTIES + MSVC_DEBUG_INFORMATION_FORMAT + "$<$:Embedded>" + ) + if(MSVC) + target_link_options( + ${target} + PRIVATE "$<$:/DEBUG>" + ) + else() + target_compile_options( + ${target} + PRIVATE "$<$:-g>" + ) + endif() + # # Set common compile options and properties # @@ -182,6 +236,61 @@ function(slang_add_target dir type) set_default_compile_options(${target}) endif() + # Set debug info options if not disabled + # Determine if this target produces a binary that can have debug info + if( + NOT ARG_NO_SPLIT_DEBUG_INFO + AND type MATCHES "^(EXECUTABLE|SHARED|MODULE)$" + AND SLANG_ENABLE_SPLIT_DEBUG_INFO + ) + set(generate_split_debug_info TRUE) + else() + set(generate_split_debug_info FALSE) + endif() + + if(generate_split_debug_info) + if(MSVC) + set_target_properties( + ${target} + PROPERTIES + COMPILE_PDB_NAME "${target}" + COMPILE_PDB_OUTPUT_DIRECTORY "${output_dir}" + ) + else() + if(CMAKE_SYSTEM_NAME MATCHES "Darwin") + # macOS - use dsymutil with --flat to create separate debug file + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND + dsymutil --flat $ -o + $.dwarf + COMMAND chmod 644 $.dwarf + COMMAND ${CMAKE_STRIP} -S $ + WORKING_DIRECTORY ${output_dir} + VERBATIM + ) + else() + add_custom_command( + TARGET ${target} + POST_BUILD + COMMAND + ${CMAKE_OBJCOPY} --only-keep-debug + $ $.dwarf + COMMAND chmod 644 $.dwarf + COMMAND + ${CMAKE_STRIP} --strip-debug $ + COMMAND + ${CMAKE_OBJCOPY} + --add-gnu-debuglink=$.dwarf + $ + WORKING_DIRECTORY ${output_dir} + VERBATIM + ) + endif() + endif() + endif() + set_target_properties( ${target} PROPERTIES EXCLUDE_FROM_ALL ${ARG_EXCLUDE_FROM_ALL} @@ -214,10 +323,14 @@ function(slang_add_target dir type) # Link and include from dependencies # target_link_libraries(${target} PRIVATE ${ARG_LINK_WITH_PRIVATE}) + target_link_libraries(${target} PUBLIC ${ARG_LINK_WITH_PUBLIC}) if(CMAKE_SYSTEM_NAME MATCHES "Darwin") foreach(link_framework ${ARG_LINK_WITH_FRAMEWORK}) - target_link_libraries(${target} PRIVATE "-framework ${link_framework}") + target_link_libraries( + ${target} + PRIVATE "-framework ${link_framework}" + ) endforeach() endif() @@ -228,6 +341,13 @@ function(slang_add_target dir type) $ ) endforeach() + foreach(include_from ${ARG_INCLUDE_FROM_PUBLIC}) + target_include_directories( + ${target} + PUBLIC + $ + ) + endforeach() # # Set our exported include directories @@ -255,6 +375,8 @@ function(slang_add_target dir type) if( target_type STREQUAL SHARED_LIBRARY OR target_type STREQUAL MODULE_LIBRARY + OR ARG_EXPORT_TYPE_AS STREQUAL SHARED + OR ARG_EXPORT_TYPE_AS STREQUAL MODULE ) target_compile_definitions( ${target} @@ -263,11 +385,17 @@ function(slang_add_target dir type) ) elseif( target_type STREQUAL STATIC_LIBRARY + OR ARG_EXPORT_TYPE_AS STREQUAL STATIC ) target_compile_definitions( ${target} PUBLIC "${ARG_EXPORT_MACRO_PREFIX}_STATIC" ) + else() + message( + WARNING + "unhandled case in slang_add_target while setting export macro" + ) endif() endif() @@ -363,34 +491,59 @@ function(slang_add_target dir type) # # Mark for installation # - if(ARG_INSTALL OR ARG_INSTALL_COMPONENT) - set(component_args) - if(ARG_INSTALL_COMPONENT) - set(component_args COMPONENT ${ARG_INSTALL_COMPONENT}) + macro(i) + if(ARG_EXPORT_SET_NAME) + set(export_args EXPORT ${ARG_EXPORT_SET_NAME}) + else() + if(type MATCHES "^(EXECUTABLE|SHARED|MODULE)$") + message( + WARNING + "Target ${target} is set to be INSTALLED but EXPORT_SET_NAME wasn't specified" + ) + endif() + set(export_args) endif() - set(exclude_arg) - if(NOT ARG_INSTALL) - set(exclude_arg EXCLUDE_FROM_ALL) + install( + TARGETS ${target} ${export_args} + ARCHIVE DESTINATION ${archive_subdir} ${ARGN} + LIBRARY DESTINATION ${library_subdir} ${ARGN} + RUNTIME DESTINATION ${runtime_subdir} ${ARGN} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ${ARGN} + ) + endmacro() + + if(ARG_INSTALL_COMPONENT) + i(EXCLUDE_FROM_ALL COMPONENT ${ARG_INSTALL_COMPONENT}) + set(debug_component "${ARG_INSTALL_COMPONENT}-debug-info") + elseif(ARG_INSTALL) + i() + set(debug_component "debug-info") + endif() + + if(DEFINED ARG_DEBUG_INFO_INSTALL_COMPONENT) + set(debug_component "${ARG_DEBUG_INFO_INSTALL_COMPONENT}") + endif() + + # Install debug info only if target is being installed + if((ARG_INSTALL OR ARG_INSTALL_COMPONENT) AND generate_split_debug_info) + if(type STREQUAL "EXECUTABLE" OR WIN32) + set(debug_dest ${runtime_subdir}) + else() + set(debug_dest ${library_subdir}) + endif() + + if(MSVC) + set(debug_file $) + else() + set(debug_file "$.dwarf") endif() + install( - TARGETS ${target} - EXPORT SlangTargets - ARCHIVE - DESTINATION ${archive_subdir} - ${component_args} - ${exclude_arg} - LIBRARY - DESTINATION ${library_subdir} - ${component_args} - ${exclude_arg} - RUNTIME - DESTINATION ${runtime_subdir} - ${component_args} - ${exclude_arg} - PUBLIC_HEADER - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - ${component_args} - ${exclude_arg} + FILES ${debug_file} + DESTINATION ${debug_dest} + COMPONENT ${debug_component} + EXCLUDE_FROM_ALL + OPTIONAL ) endif() endfunction() diff --git a/docs/64bit-type-support.md b/docs/64bit-type-support.md index 506e054935..15faccd864 100644 --- a/docs/64bit-type-support.md +++ b/docs/64bit-type-support.md @@ -5,9 +5,10 @@ Slang 64-bit Type Support * Not all targets support 64 bit types, or all 64 bit types * 64 bit integers generally require later APIs/shader models -* When specifying 64 bit literals *always* use the type suffixes (ie `L`, `ULL`, `LL`) +* When specifying 64 bit floating-point literals *always* use the type suffixes (ie `L`) +* An integer literal will be interpreted as 64 bits if it cannot fit in a 32 bit value. * GPU target/s generally do not support all double intrinsics - * Typically missing are trascendentals (sin, cos etc), logarithm and exponental functions + * Typically missing are trascendentals (sin, cos etc), logarithm and exponential functions * CUDA is the exception supporting nearly all double intrinsics * D3D * D3D targets *appear* to support double intrinsics (like sin, cos, log etc), but behind the scenes they are actually being converted to float @@ -20,15 +21,15 @@ Overview The Slang language supports 64 bit built in types. Such as -* double -* uint64_t -* int64_t +* `double` +* `uint64_t` +* `int64_t` This also applies to vector and matrix versions of these types. -Unfortunately if a specific target supports the type or the typical HLSL instrinsic functions (such as sin/cos/max/min etc) depends very much on the target. +Unfortunately if a specific target supports the type or the typical HLSL intrinsic functions (such as sin/cos/max/min etc) depends very much on the target. -Special attention has to be made with respect to literal 64 bit types. By default float and integer literals if they do not have an explicit suffix are assumed to be 32 bit. There is a variety of reasons for this design choice - the main one being around by default behavior of getting good performance. The suffixes required for 64 bit types are as follows +Special attention has to be made with respect to literal 64 bit types. By default float literals if they do not have an explicit suffix are assumed to be 32 bit. There is a variety of reasons for this design choice - the main one being around by default behavior of getting good performance. The suffixes required for 64 bit types are as follows ``` // double - 'l' or 'L' @@ -40,20 +41,12 @@ double b = 1.34e-200; // int64_t - 'll' or 'LL' (or combination of upper/lower) int64_t c = -5436365345345234ll; -// WRONG!: This is the same as d = int64_t(int32_t(-5436365345345234)) which means d ! = -5436365345345234LL. -// Will produce a warning. -int64_t d = -5436365345345234; int64_t e = ~0LL; // Same as 0xffffffffffffffff -// Does produce the same result as 'e' because equivalent int64_t(~int32_t(0)) -int64_t f = ~0; // uint64_t - 'ull' or 'ULL' (or combination of upper/lower) uint64_t g = 0x8000000000000000ull; -// WRONG!: This is the same as h = uint64_t(uint32_t(0x8000000000000000)) which means h = 0 -// Will produce a warning. -uint64_t h = 0x8000000000000000u; uint64_t i = ~0ull; // Same as 0xffffffffffffffff uint64_t j = ~0; // Equivalent to 'i' because uint64_t(int64_t(~int32_t(0))); @@ -61,6 +54,34 @@ uint64_t j = ~0; // Equivalent to 'i' because uint64_t(int64_t(~int32_t These issues are discussed more on issue [#1185](https://github.com/shader-slang/slang/issues/1185) +The type of a decimal non-suffixed integer literal is the first integer type from the list [`int`, `int64_t`] +which can represent the specified literal value. If the value cannot fit, the literal is represented as an `uint64_t` +and a warning is given. +The type of a hexadecimal non-suffixed integer literal is the first type from the list [`int`, `uint`, `int64_t`, `uint64_t`] +that can represent the specified literal value. A non-suffixed integer literal will be 64 bit if it cannot fit in 32 bits. +``` +// Same as int64_t a = int(1), the value can fit into a 32 bit integer. +int64_t a = 1; + +// Same as int64_t b = int64_t(2147483648), the value cannot fit into a 32 bit integer. +int64_t b = 2147483648; + +// Same as int64_t c = uint64_t(18446744073709551615), the value is larger than the maximum value of a signed 64 bit +// integer, and is interpreted as an unsigned 64 bit integer. Warning is given. +uint64_t c = 18446744073709551615; + +// Same as uint64_t = int(0x7FFFFFFF), the value can fit into a 32 bit integer. +uint64_t d = 0x7FFFFFFF; + +// Same as uint64_t = int64_t(0x7FFFFFFFFFFFFFFF), the value cannot fit into an unsigned 32 bit integer but +// can fit into a signed 64 bit integer. +uint64_t e = 0x7FFFFFFFFFFFFFFF; + +// Same as uint64_t = uint64_t(0xFFFFFFFFFFFFFFFF), the value cannot fit into a signed 64 bit integer, and +// is interpreted as an unsigned 64 bit integer. +uint64_t f = 0xFFFFFFFFFFFFFFFF; +``` + Double support ============== @@ -107,7 +128,7 @@ On dxc the following intrinsics are available with double:: These are tested in the test `tests/hlsl-intrinsic/scalar-double-d3d-intrinsic.slang`. -There is no suport for transcendentals (`sin`, `cos` etc) or `log`/`exp`. More surprising is that`sqrt`, `rsqrt`, `frac`, `ceil`, `floor`, `trunc`, `step`, `lerp`, `smoothstep` are also not supported. +There is no support for transcendentals (`sin`, `cos` etc) or `log`/`exp`. More surprising is that `sqrt`, `rsqrt`, `frac`, `ceil`, `floor`, `trunc`, `step`, `lerp`, `smoothstep` are also not supported. uint64_t and int64_t Support ============================ @@ -125,8 +146,8 @@ D3D12 | FXC/DXBC | No | No | 2 2) uint64_t support requires https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/hlsl-shader-model-6-0-features-for-direct3d-12, so DXBC is not a target. -The intrinsics available on uint64_t type are `abs`, `min`, `max`, `clamp` and `countbits`. -The intrinsics available on uint64_t type are `abs`, `min`, `max` and `clamp`. +The intrinsics available on `uint64_t` type are `abs`, `min`, `max`, `clamp` and `countbits`. +The intrinsics available on `uint64_t` type are `abs`, `min`, `max` and `clamp`. GLSL ==== diff --git a/docs/README.md b/docs/README.md index b53060a267..ca6a3ddfe6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -9,7 +9,7 @@ Getting Started The Slang [User's Guide](https://shader-slang.github.io/slang/user-guide/) provides an introduction to the Slang language and its major features, as well as the compilation and reflection API. -There is also documentation specific to using the [`slangc`](command-line-slangc.md) command-line tool. +There is also documentation specific to using the [slangc](https://shader-slang.github.io/slang/user-guide/compiling.html#command-line-compilation-with-slangc) command-line tool. Advanced Users -------------- @@ -19,7 +19,7 @@ The [target compatibility guide](target-compatibility.md) gives an overview of f The [CPU target guide](cpu-target.md) gives information on compiling Slang or C++ source into shared libraries/executables or functions that can be directly executed. It also covers how to generate C++ code from Slang source. -The [CUDA target guide](cuda-target.md) provides information on compiling Slang/HLSL or CUDA source. Slang can compile to equivalent CUDA source, as well as to PTX via the nvrtc CUDA complier. +The [CUDA target guide](cuda-target.md) provides information on compiling Slang/HLSL or CUDA source. Slang can compile to equivalent CUDA source, as well as to PTX via the nvrtc CUDA compiler. Contributors ------------ diff --git a/docs/_layouts/user-guide.html b/docs/_layouts/user-guide.html index b9a3876864..347eb283ed 100644 --- a/docs/_layouts/user-guide.html +++ b/docs/_layouts/user-guide.html @@ -7,6 +7,13 @@ + + @@ -388,8 +395,6 @@ window.addEventListener("scroll", windowScroll); updateCurrentSubsection(findCurrentSubsection()); - - - - {% if site.google_analytics %} - - {% endif %} \ No newline at end of file diff --git a/docs/build_reference.ps1 b/docs/build_reference.ps1 new file mode 100644 index 0000000000..a296768195 --- /dev/null +++ b/docs/build_reference.ps1 @@ -0,0 +1,62 @@ +# This script uses `slangc` to generate the core module reference documentation and push the updated +# documents to shader-slang/stdlib-reference repository. +# The stdlib-reference repository has github-pages setup so that the markdown files we generate +# in this step will be rendered as html pages by Jekyll upon a commit to the repository. +# So we we need to do here is to pull the stdlib-reference repository, regenerate the markdown files +# and push the changes back to the repository. + +# The generated markdown files will be located in three folders: +# - ./global-decls +# - ./interfaces +# - ./types +# In addition, slangc will generate a table of content file `toc.html` which will be copied to +# ./_includes/stdlib-reference-toc.html for Jekyll for consume it correctly. + +# If stdlib-reference folder does not exist, clone from github repo +if (-not (Test-Path ".\stdlib-reference")) { + git clone https://github.com/shader-slang/stdlib-reference/ +} +else { +# If it already exist, just pull the latest changes. + cd stdlib-reference + git pull + cd ../ +} +# Remove the old generated files. +Remove-Item -Path ".\stdlib-reference\global-decls" -Recurse -Force +Remove-Item -Path ".\stdlib-reference\interfaces" -Recurse -Force +Remove-Item -Path ".\stdlib-reference\types" -Recurse -Force +Remove-Item -Path ".\stdlib-reference\attributes" -Recurse -Force + +# Use git describe to produce a version string and write it to _includes/version.inc. +# This file will be included by the stdlib-reference Jekyll template. +git describe --tags | Out-File -FilePath ".\stdlib-reference\_includes\version.inc" -Encoding ASCII + +cd stdlib-reference +$slangPaths = @( + "../../build/RelWithDebInfo/bin/slangc.exe", + "../../build/Release/bin/slangc.exe", + "../../build/Debug/bin/slangc.exe" +) +$slangExe = $slangPaths | Where-Object { Test-Path $_ } | Select-Object -First 1 +if ($slangExe) { + & $slangExe -compile-core-module -doc + Move-Item -Path ".\toc.html" -Destination ".\_includes\stdlib-reference-toc.html" -Force + git config user.email "bot@shader-slang.com" + git config user.name "Stdlib Reference Bot" + git add . + git commit -m "Update the core module reference" + git push +} else { + Write-Error "Could not find slangc executable in RelWithDebInfo or Release directories" +} +cd ../ + +# For local debugging only. +# Remove-Item -Path "D:\git_repo\stdlib-reference\global-decls" -Recurse -Force +# Remove-Item -Path "D:\git_repo\stdlib-reference\interfaces" -Recurse -Force +# Remove-Item -Path "D:\git_repo\stdlib-reference\types" -Recurse -Force +# Copy-Item -Path .\stdlib-reference\global-decls -Destination D:\git_repo\stdlib-reference\global-decls -Recurse -Force +# Copy-Item -Path .\stdlib-reference\interfaces -Destination D:\git_repo\stdlib-reference\interfaces -Recurse -Force +# Copy-Item -Path .\stdlib-reference\types -Destination D:\git_repo\stdlib-reference\types -Recurse -Force +# Copy-Item -Path .\stdlib-reference\_includes\stdlib-reference-toc.html -Destination D:\git_repo\stdlib-reference\_includes\stdlib-reference-toc.html -Force diff --git a/docs/build_toc.sh b/docs/build_toc.sh new file mode 100755 index 0000000000..9c197cad65 --- /dev/null +++ b/docs/build_toc.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +set -e + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +project_root="$(dirname "$script_dir")" +check_only=0 + +show_help() { + me=$(basename "$0") + cat <] [--check-only] + +Options: + --help Show this help message + --source Path to project root directory (defaults to parent of the script directory) + --check-only Check if TOC needs updating, exit 1 if changes needed +EOF +} + +while [[ "$#" -gt 0 ]]; do + case $1 in + -h | --help) + show_help + exit 0 + ;; + --source) + project_root="$2" + shift + ;; + --check-only) + check_only=1 + ;; + *) + echo "unrecognized argument: $1" >&2 + show_help >&2 + exit 1 + ;; + esac + shift +done + +missing_bin=0 + +require_bin() { + local name="$1" + if ! command -v "$name" &>/dev/null; then + echo "This script needs $name, but it isn't in \$PATH" >&2 + missing_bin=1 + return + fi +} + +require_bin "mcs" +require_bin "mono" + +if [ "$missing_bin" -eq 1 ]; then + exit 1 +fi + +temp_dir=$(mktemp -d) +trap 'rm -rf "$temp_dir"' EXIT + +docs_dir="$project_root/docs" + +cat >"$temp_dir/temp_program.cs" <&2 + exit 1 +fi + +for dir in "user-guide" "gfx-user-guide"; do + if [ -d "$docs_dir/$dir" ]; then + if [ "$check_only" -eq 1 ]; then + # Ensure working directory is clean + if ! git -C "$project_root" diff --quiet "docs/$dir/toc.html" 2>/dev/null; then + echo "Working directory not clean, cannot check TOC" >&2 + exit 1 + fi + fi + + if ! mono "$temp_dir/toc-builder.exe" "$docs_dir/$dir"; then + echo "TOC generation failed for $dir" >&2 + exit 1 + fi + + if [ "$check_only" -eq 1 ]; then + if ! git -C "$project_root" diff --quiet "docs/$dir/toc.html" 2>/dev/null; then + git -C "$project_root" diff --color "docs/$dir/toc.html" + git -C "$project_root" checkout -- "docs/$dir/toc.html" 2>/dev/null + exit 1 + fi + fi + else + echo "Directory $dir not found" >&2 + fi +done diff --git a/docs/building.md b/docs/building.md index d86b80205f..f3b7e9d292 100644 --- a/docs/building.md +++ b/docs/building.md @@ -9,11 +9,12 @@ version of Slang. Please install: -- CMake +- CMake (3.25 preferred, but 3.22 works[^1]) - A C++ compiler with support for C++17. GCC, Clang and MSVC are supported - A CMake compatible backend, for example Visual Studio or Ninja +- Python3 (a dependency for building spirv-tools) -Optional dependencies include +Optional dependencies for tests include - CUDA - OptiX @@ -21,6 +22,9 @@ Optional dependencies include - Aftermath - X11 +Other dependencies are sourced from submodules in the [./external](./external) +directory. + ## Get the Source Code Clone [this](https://github.com/shader-slang/slang) repository. Make sure to @@ -32,20 +36,104 @@ git clone https://github.com/shader-slang/slang --recursive ## Configure and build +> This section assumes cmake 3.25 or greater, if you're on a lower version +> please see [building with an older cmake](#building-with-an-older-cmake) + For a Ninja based build system (all platforms) run: ```bash cmake --preset default -cmake --build --preset release # or --preset debug +cmake --build --preset releaseWithDebugInfo # or --preset debug, or --preset release ``` For Visual Studio run: ```bash cmake --preset vs2022 # or 'vs2019' or `vs2022-dev` start devenv ./build/slang.sln # to optionally open the project in Visual Studio -cmake --build --preset release # to build from the CLI +cmake --build --preset releaseWithDebugInfo # to build from the CLI, could also use --preset release or --preset debug +``` + +There also exists a `vs2022-dev` preset which turns on features to aid +debugging. + +### WebAssembly build + +In order to build WebAssembly build of Slang, Slang needs to be compiled with +[Emscripten SDK](https://github.com/emscripten-core/emsdk). You can find more +information about [Emscripten](https://emscripten.org/). + +You need to clone the EMSDK repo. And you need to install and activate the latest. + + +```bash +git clone https://github.com/emscripten-core/emsdk.git +cd emsdk +``` + +For non-Windows platforms +```bash +./emsdk install latest +./emsdk activate latest +``` + +For Windows +```cmd +emsdk.bat install latest +emsdk.bat activate latest ``` -The `vs2022-dev` preset turns on features that makes debugging easy. +After EMSDK is activated, Slang needs to be built in a cross compiling setup: + +- build the `generators` target for the build platform +- configure the build with `emcmake` for the host platform +- build for the host platform. + +> Note: For more details on cross compiling please refer to the +> [cross-compiling](docs/building.md#cross-compiling) section. + +```bash +# Build generators. +cmake --workflow --preset generators --fresh +mkdir generators +cmake --install build --prefix generators --component generators + +# Configure the build with emcmake. +# emcmake is available only when emsdk_env setup the environment correctly. +pushd ../emsdk +source ./emsdk_env # For Windows, emsdk_env.bat +popd +emcmake cmake -DSLANG_GENERATORS_PATH=generators/bin --preset emscripten -G "Ninja" + +# Build slang-wasm.js and slang-wasm.wasm in build.em/Release/bin +cmake --build --preset emscripten --target slang-wasm +``` + +> Note: If the last build step fails, try running the command that `emcmake` +> outputs, directly. + +## Installing + +Build targets may be installed using cmake: + +```bash +cmake --build . --target install +``` + +This should install `SlangConfig.cmake` that should allow `find_package` to work. +SlangConfig.cmake defines `SLANG_EXECUTABLE` variable that will point to `slangc` +executable and also define `slang::slang` target to be linked to. + +For now, `slang::slang` is the only exported target defined in the config which can +be linked to. + +Example usage + +```cmake +find_package(slang REQUIRED PATHS ${your_cmake_install_prefix_path} NO_DEFAULT_PATH) +# slang_FOUND should be automatically set +target_link_libraries(yourLib PUBLIC + slang::slang +) +``` ## Testing @@ -59,45 +147,60 @@ See the [documentation on testing](../tools/slang-test/README.md) for more infor ### CMake options -| Option | Default | Description | -|-----------------------------------|------------------|--------------------------------------------------------------------| -| `SLANG_VERSION` | Latest `v*` tag | The project version, detected using git if available | -| `SLANG_EMBED_STDLIB` | `FALSE` | Build slang with an embedded version of the stdlib | -| `SLANG_EMBED_STDLIB_SOURCE` | `TRUE` | Embed stdlib source in the binary | -| `SLANG_ENABLE_ASAN` | `FALSE` | Enable ASAN (address sanitizer) | -| `SLANG_ENABLE_FULL_IR_VALIDATION` | `FALSE` | Enable full IR validation (SLOW!) | -| `SLANG_ENABLE_IR_BREAK_ALLOC` | `FALSE` | Enable IR BreakAlloc functionality for debugging. | -| `SLANG_ENABLE_GFX` | `TRUE` | Enable gfx targets | -| `SLANG_ENABLE_SLANGD` | `TRUE` | Enable language server target | -| `SLANG_ENABLE_SLANGC` | `TRUE` | Enable standalone compiler target | -| `SLANG_ENABLE_SLANGRT` | `TRUE` | Enable runtime target | -| `SLANG_ENABLE_SLANG_GLSLANG` | `TRUE` | Enable glslang dependency and slang-glslang wrapper target | -| `SLANG_ENABLE_TESTS` | `TRUE` | Enable test targets, requires SLANG_ENABLE_GFX, SLANG_ENABLE_SLANGD and SLANG_ENABLE_SLANGRT | -| `SLANG_ENABLE_EXAMPLES` | `TRUE` | Enable example targets, requires SLANG_ENABLE_GFX | -| `SLANG_LIB_TYPE` | `SHARED` | How to build the slang library | -| `SLANG_SLANG_LLVM_FLAVOR` | `FETCH_BINARY` | How to set up llvm support | -| `SLANG_SLANG_LLVM_BINARY_URL` | System dependent | URL specifying the location of the slang-llvm prebuilt library | -| `SLANG_GENERATORS_PATH` | `` | Path to an installed `all-generators` target for cross compilation | +| Option | Default | Description | +|-----------------------------------|----------------------------|----------------------------------------------------------------------------------------------| +| `SLANG_VERSION` | Latest `v*` tag | The project version, detected using git if available | +| `SLANG_EMBED_CORE_MODULE` | `TRUE` | Build slang with an embedded version of the core module | +| `SLANG_EMBED_CORE_MODULE_SOURCE` | `TRUE` | Embed the core module source in the binary | +| `SLANG_ENABLE_ASAN` | `FALSE` | Enable ASAN (address sanitizer) | +| `SLANG_ENABLE_FULL_IR_VALIDATION` | `FALSE` | Enable full IR validation (SLOW!) | +| `SLANG_ENABLE_IR_BREAK_ALLOC` | `FALSE` | Enable IR BreakAlloc functionality for debugging. | +| `SLANG_ENABLE_GFX` | `TRUE` | Enable gfx targets | +| `SLANG_ENABLE_SLANGD` | `TRUE` | Enable language server target | +| `SLANG_ENABLE_SLANGC` | `TRUE` | Enable standalone compiler target | +| `SLANG_ENABLE_SLANGRT` | `TRUE` | Enable runtime target | +| `SLANG_ENABLE_SLANG_GLSLANG` | `TRUE` | Enable glslang dependency and slang-glslang wrapper target | +| `SLANG_ENABLE_TESTS` | `TRUE` | Enable test targets, requires SLANG_ENABLE_GFX, SLANG_ENABLE_SLANGD and SLANG_ENABLE_SLANGRT | +| `SLANG_ENABLE_EXAMPLES` | `TRUE` | Enable example targets, requires SLANG_ENABLE_GFX | +| `SLANG_LIB_TYPE` | `SHARED` | How to build the slang library | +| `SLANG_ENABLE_RELEASE_DEBUG_INFO` | `TRUE` | Enable generating debug info for Release configs | +| `SLANG_ENABLE_SPLIT_DEBUG_INFO` | `TRUE` | Enable generating split debug info for Debug and RelWithDebInfo configs | +| `SLANG_SLANG_LLVM_FLAVOR` | `FETCH_BINARY_IF_POSSIBLE` | How to set up llvm support | +| `SLANG_SLANG_LLVM_BINARY_URL` | System dependent | URL specifying the location of the slang-llvm prebuilt library | +| `SLANG_GENERATORS_PATH` | `` | Path to an installed `all-generators` target for cross compilation | The following options relate to optional dependencies for additional backends and running additional tests. Left unchanged they are auto detected, however they can be set to `OFF` to prevent their usage, or set to `ON` to make it an error if they can't be found. -| Option | CMake hints | Notes | -|--------------------------|--------------------------------|---------------------------------------------------------------------| -| `SLANG_ENABLE_CUDA` | `CUDAToolkit_ROOT` `CUDA_PATH` | | -| `SLANG_ENABLE_OPTIX` | `Optix_ROOT_DIR` | Requires CUDA | -| `SLANG_ENABLE_NVAPI` | `NVAPI_ROOT_DIR` | Only available for builds targeting Windows | -| `SLANG_ENABLE_AFTERMATH` | `Aftermath_ROOT_DIR` | Enable Aftermath in GFX, and add aftermath crash example to project | -| `SLANG_ENABLE_XLIB` | | | +| Option | CMake hints | Notes | +|--------------------------|--------------------------------|----------------------------------------------------------------------------------------------| +| `SLANG_ENABLE_CUDA` | `CUDAToolkit_ROOT` `CUDA_PATH` | Enable running tests with the CUDA backend, doesn't affect the targets Slang itself supports | +| `SLANG_ENABLE_OPTIX` | `Optix_ROOT_DIR` | Requires CUDA | +| `SLANG_ENABLE_NVAPI` | `NVAPI_ROOT_DIR` | Only available for builds targeting Windows | +| `SLANG_ENABLE_AFTERMATH` | `Aftermath_ROOT_DIR` | Enable Aftermath in GFX, and add aftermath crash example to project | +| `SLANG_ENABLE_XLIB` | | | + +### Advanced options + +| Option | Default | Description | +|------------------------------------|---------|--------------------------------------------------------------------------------------------------------------------------------| +| `SLANG_ENABLE_DX_ON_VK` | `FALSE` | Enable running the DX11 and DX12 tests on non-warning Windows platforms via vkd3d-proton, requires system-provided d3d headers | +| `SLANG_ENABLE_SLANG_RHI` | `TRUE` | Enable building and using [slang-rhi](https://github.com/shader-slang/slang-rhi) for tests | +| `SLANG_USE_SYSTEM_MINIZ` | `FALSE` | Build using system Miniz library instead of the bundled version in [./external](./external) | +| `SLANG_USE_SYSTEM_LZ4` | `FALSE` | Build using system LZ4 library instead of the bundled version in [./external](./external) | +| `SLANG_USE_SYSTEM_VULKAN_HEADERS` | `FALSE` | Build using system Vulkan headers instead of the bundled version in [./external](./external) | +| `SLANG_USE_SYSTEM_SPIRV_HEADERS` | `FALSE` | Build using system SPIR-V headers instead of the bundled version in [./external](./external) | +| `SLANG_USE_SYSTEM_UNORDERED_DENSE` | `FALSE` | Build using system unordered dense instead of the bundled version in [./external](./external) | +| `SLANG_SPIRV_HEADERS_INCLUDE_DIR` | `` | Use this specific path to SPIR-V headers instead of the bundled version in [./external](./external) | ### LLVM Support There are several options for getting llvm-support: -- Use a prebuilt binary slang-llvm library: `-DSLANG_SLANG_LLVM_FLAVOR=FETCH_BINARY`, - this is the default +- Use a prebuilt binary slang-llvm library: + `-DSLANG_SLANG_LLVM_FLAVOR=FETCH_BINARY` or `-DSLANG_SLANG_LLVM_FLAVOR=FETCH_BINARY_IF_POSSIBLE` (this is the default) - You can set `SLANG_SLANG_LLVM_BINARY_URL` to point to a local `libslang-llvm.so/slang-llvm.dll` or set it to a URL of an zip/archive containing such a file @@ -105,6 +208,9 @@ There are several options for getting llvm-support: release on github matching the current tag. If such a tag doesn't exist or doesn't have the correct os*arch combination then the latest release will be tried. + - If `SLANG_SLANG_LLVM_BINARY_URL` is `FETCH_BINARY_IF_POSSIBLE` then in + the case that a prebuilt binary can't be found then the build will proceed + as though `DISABLE` was chosen - Use a system supplied LLVM: `-DSLANG_SLANG_LLVM_FLAVOR=USE_SYSTEM_LLVM`, you must have llvm-13.0 and a matching libclang installed. It's important that either: @@ -115,12 +221,6 @@ There are several options for getting llvm-support: compiling LLVM without the dynamic library. - Anything else which may be linked in (for example Mesa, also dynamically loads the same llvm object) -- Have the Slang build system build LLVM: - `-DSLANG_SLANG_LLVM_FLAVOR=BUILD_LLVM`, this will build LLVM binaries at - configure time and use that. This is only intended to be used as part of the - process of generating the portable binary slang-llvm library. This always - builds a `Release` LLVM, so is unsuitable to use when building a `Debug` - `slang-llvm` on Windows as the runtime libraries will be incompatible. - Do not enable LLVM support: `-DSLANG_SLANG_LLVM_FLAVOR=DISABLE` To build only a standalone slang-llvm, you can run: @@ -141,17 +241,42 @@ generators for the build platform. Build them with the `generators` preset, and pass the install path to the cross building CMake invocation using `SLANG_GENERATORS_PATH` +Non-Windows platforms: + +```bash +# build the generators +cmake --workflow --preset generators --fresh +mkdir build-platform-generators +cmake --install build --config Release --prefix build-platform-generators --component generators +# reconfigure, pointing to these generators +# Here is also where you should set up any cross compiling environment +cmake \ + --preset default \ + --fresh \ + -DSLANG_GENERATORS_PATH=build-platform-generators/bin \ + -Dwhatever-other-necessary-options-for-your-cross-build \ + # for example \ + -DCMAKE_C_COMPILER=my-arch-gcc \ + -DCMAKE_CXX_COMPILER=my-arch-g++ +# perform the final build +cmake --workflow --preset release +``` + +Windows + ```bash # build the generators cmake --workflow --preset generators --fresh -mkdir my-build-platform-generators -cmake --install build --config Release --prefix my-build-platform-generators --component generators +mkdir build-platform-generators +cmake --install build --config Release --prefix build-platform-generators --component generators # reconfigure, pointing to these generators # Here is also where you should set up any cross compiling environment +# For example +./vcvarsamd64_arm64.bat cmake \ --preset default \ --fresh \ - -DSLANG_GENERATORS_PATH=my-build-platform-generators/bin \ + -DSLANG_GENERATORS_PATH=build-platform-generators/bin \ -Dwhatever-other-necessary-options-for-your-cross-build # perform the final build cmake --workflow --preset release @@ -183,3 +308,20 @@ rm -rf build # The Visual Studio generator will complain if this is left over fr cmake --preset vs2022 --fresh -A arm64 -DSLANG_GENERATORS_PATH=generators/bin cmake --build --preset release ``` + +## Building with an older CMake + +Because older CMake versions don't support all the features we want to use in +CMakePresets, you'll have to do without the presets. Something like the following + +```bash +cmake -B build -G Ninja +cmake --build build -j +``` + +## Notes + +[^1] below 3.25, CMake lacks the ability to mark directories as being +system directories (https://cmake.org/cmake/help/latest/prop_tgt/SYSTEM.html#prop_tgt:SYSTEM), +this leads to an inability to suppress warnings originating in the +dependencies in `./external`, so be prepared for some additional warnings. diff --git a/docs/ci.md b/docs/ci.md index bfb101dff3..fb4c7e68ba 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -1,18 +1,36 @@ # Our CI -There are github actions for testing building and testing slang. +There are github actions for building and testing slang. ## Tests -Most configurations run a restricted set of tests, however on some self hosted runners we run the full test suite, as well as running Falcor's test suite with the new slang build. +Most configurations run a restricted set of tests, however on some self hosted +runners we run the full test suite, as well as running Falcor's test suite with +the new slang build. ## Building LLVM -We require a static build of LLVM for building slang-llvm, we build and cache this in all workflow runs. Since this changes infrequently, the cache is almost always hit. A cold build takes about an hour on the slowest platform. The cached output is a few hundred MB, so conceivably if we add many more platforms we might be caching more than the 10GB github allowance, which would necessitate being a bit more complicated in building and tracking outputs here. +We require a static build of LLVM for building slang-llvm, we build and cache +this in all workflow runs. Since this changes infrequently, the cache is almost +always hit. A cold build takes about an hour on the slowest platform. The +cached output is a few hundred MB, so conceivably if we add many more platforms +we might be caching more than the 10GB github allowance, which would +necessitate being a bit more complicated in building and tracking outputs here. -For slang-llvm, this is handled the same as any other dependency, except on Windows Debug builds, where we are required by the differences in Debug/Release standard libraries to always make a release build, this is noted in the ci action yaml file. +For slang-llvm, this is handled the same as any other dependency, except on +Windows Debug builds, where we are required by the differences in Debug/Release +standard libraries to always make a release build, this is noted in the ci +action yaml file. + +Note that we don't use sccache while building LLVM, as it changes very +infrequently. The caching of LLVM is done by caching the final build product +only. ## sccache -The CI actions use sccache, keyed on compiler and platform, this runs on all configurations and significantly speeds up small source change builds. This cache can be safely missed without a large impact on build times. +> Due to reliability issues, we are not currently using sccache, this is +> historical/aspirational. +The CI actions use sccache, keyed on compiler and platform, this runs on all +configurations and significantly speeds up small source change builds. This +cache can be safely missed without a large impact on build times. diff --git a/docs/command-line-slangc-reference.md b/docs/command-line-slangc-reference.md index a6df65ab27..36493b2f96 100644 Binary files a/docs/command-line-slangc-reference.md and b/docs/command-line-slangc-reference.md differ diff --git a/docs/command-line-slangc.md b/docs/command-line-slangc.md deleted file mode 100644 index d953650837..0000000000 --- a/docs/command-line-slangc.md +++ /dev/null @@ -1,209 +0,0 @@ -Using the `slangc` Command-Line Compiler -======================================== - -The `slangc` command-line tool is used to compile or cross-compile shader source code. - -``` -slangc [] [...] -``` - -## Options - -The available options are in [the command line option reference](command-line-slangc-reference.md). - -This information is also available from `slangc` via - -``` -slangc -h -``` - -The sections below describe usage in more detail. - -Simple Examples ---------------- - -### HLSL - -When compiling an HLSL shader, you must specify the path to your shader code file as well as the target shader model (profile) and shader stage to use. -For example, to see D3D bytecode assembly for a fragment shader entry point: - - slangc my-shader.hlsl -profile sm_5_0 -stage fragment - -To direct that output to a bytecode file: - - slangc my-shader.hlsl -profile sm_5_0 -stage fragment -o my-shader.dxbc - -If the entry-point function has a name other than the default `main`, then this is specified with `-entry`: - - slangc my-shader.hlsl -profile sm_5_0 -entry psMain -stage fragment - -If you are using the `[shader("...")]` syntax to mark your entry points, then you may leave off the `-stage` option: - - slangc my-shader.hlsl -profile sm_5_0 -entry psMain - -### Slang - -Compiling an entry point from a Slang file is similar to HLSL, except that you must also specify a desired code generation target, because there is no assumed default (like DXBC for Direct3D Shader Model 5.x). - -To get DXBC assembly written to the console: - - slangc my-shader.slang -profile sm_5_0 -stage fragment -entry main -target dxbc - -To get SPIR-V assembly: - - slangc my-shader.slang -profile sm_5_0 -stage fragment -entry main -target spriv - -The code generation target is implicit when writing to a file with an appropriate extension. -To write DXBC, SPIR-V, or GLSL to files, use: - - slangc my-shader.slang -profile sm_5_0 -entry main -stage fragment -o my-shader.dxbc - slangc my-shader.slang -profile sm_6_0 -entry main -stage fragment -o my-shader.dxil - slangc my-shader.slang -profile glsl_450 -entry main -stage fragment -o my-shader.spv - -Usage ------ - -## Multiple Entry Points - -`slangc` can compile multiple entry points, which may span multiple files in a single invocation. -This is useful when you are taking advantage of Slang's ability to automatically assign binding locations to shader parameters, because the compiler can take all of your entry points into account when assigning location (avoiding overlap between entry points that will be used together). - -When specifying multiple entry points, you use multiple `-entry` options on the command line. -The main thing to be aware of is that any `-stage` options apply to the most recent `-entry` point, and the same goes for any `-o` options to specify per-entry-point output files. -For example, here is a command line to compile both vertex and fragment shader entry points from a single file and output them to distinct DXBC files: - - slangc -profile sm_5_0 my-shader.hlsl - -entry vsMain -stage vertex -o my-shader.vs.dxbc - -entry fsMain -stage fragment -o my-shader.fs.dxbc - -If your shader entry points are spread across multiple HLSL files, then each `-entry` option indicates an entry point in the preceding file. -For example, if the preceding example put its vertex and fragment entry points in distinct files, the command line would be: - - slangc -profile sm_5_0 my-shader.vs.hlsl -entry vsMain -stage vertex -o my-shader.vs.dxbc - my-shader.fs.hlsl -entry fsMain -stage fragment -o my-shader.fs.dxbc - -Note that when compiling multiple `.slang` files in one invocation, they will all be compiled together as a single module (with a single global namespace) so that the relative order of `-entry` options and source files does not matter. - -These long command lines obviously aren't pleasant. -We encourage applications that require complex shader compilation workflows to use the Slang API directly so that they can implement compilation that follows application conventions/policy. -The ability to specify compilation actions like this on the command line is primarily intended a testing and debugging tool. - - -## Downstream Arguments - -During a Slang compilation work may be performed by multiple other stages including downstream compilers and linkers. It isn't possible in general or perhaps even desirable to provide Slang command line equivalents of every option available at every stage of compilation. It is useful to be able to set options specific to a particular compilation stage - to alter code generation, linkage and other options. - -The mechanism used here is based on the `-X` mechanism used in GCC, to specify arguments to the linker. - -``` --Xlinker option -``` - -When used, `option` is not interpreted by GCC, but is passed to the linker once compilation is complete. Slang extends this idea in several ways. First there are many more 'downstream' stages available to Slang than just `linker`. These different stages are known as `SlangPassThrough` types in the API and have the following names - -* `fxc` - FXC HLSL compiler -* `dxc` - DXC HLSL compiler -* `glslang` - GLSLANG GLSL compiler -* `visualstudio` - Visual Studio C/C++ compiler -* `clang` - Clang C/C++ compiler -* `gcc` - GCC C/C++ compiler -* `genericcpp` - A generic C++ compiler (can be any one of visual studio, clang or gcc depending on system and availability) -* `nvrtc` - NVRTC CUDA compiler - -The Slang command line allows you to specify an argument to these downstream compilers, by using their name after the `-X`. So for example to send an option `-Gfa` through to DXC you can use - -``` --Xdxc -Gfa -``` - -Note that if an option is available via normal Slang command line options then these should be used. This will generally work across multiple targets, but also avoids options clashing which is undefined behavior currently. The `-X` mechanism is best used for options that are unavailable through normal Slang mechanisms. - -If you want to pass multiple options using this mechanism the `-Xdxc` needs to be in front of every options. For example - -``` --Xdxc -Gfa -Xdxc -Vd -``` - -Would reach `dxc` as - -``` --Gfa -Vd -``` - -This can get a little repetitive especially if there are many parameters, so Slang adds a mechanism to have multiple options passed by using an ellipsis `...`. The syntax is as follows - -``` --Xdxc... -Gfa -Vd -X. -``` - -The `...` at the end indicates all the following parameters should be sent to `dxc` until it reaches the matching terminating `-X.` or the end of the command line. - -It is also worth noting that `-X...` options can be nested. This would allow a GCC downstream compilation to control linking, for example with - -``` --Xgcc -Xlinker --split -X. -``` - -In this example gcc would see - -``` --Xlinker --split -``` - -And the linker would see (as passed through by gcc) - -``` ---split -``` - -Setting options for tools that aren't used in a Slang compilation has no effect. This allows for setting `-X` options specific for all downstream tools on a command line, and they are only used as part of a compilation that needs them. - -NOTE! Not all tools that Slang uses downstream make command line argument parsing available. `FXC` and `GLSLANG` currently do not have any command line argument passing as part of their integration, although this could change in the future. - -The `-X` mechanism is also supported by render-test tool. In this usage `slang` becomes a downstream tool. Thus you can use the `dxc` option `-Gfa` in a render-test via - -``` --Xslang... -Xdxc -Gfa -X. -``` - -Means that the dxc compilation in the render test (assuming dxc is invoked) will receive - -``` --Gfa -``` - -Some options are made available via the same mechanism for all downstream compilers. - -* Use `-I` to specify include path for downstream compilers - -For example to specify an include path "somePath" to DXC you can use... - -``` --Xdxc -IsomePath -``` - -## Specifying where dlls/shared libraries are loaded from - -On windows if you want a dll loaded from a specific path, the path must be specified absolutely. See the [LoadLibrary documentation](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya) for more details. A relative path will cause Windows to check all locations along it's search procedure. - -On linux it's similar, but any path (relative or not) will override the regular search mechanism. See [dlopen](https://man7.org/linux/man-pages/man3/dlopen.3.html) for more details. - -See [the reference for a complete list](#command-line-slangc-reference.md#none-path) - -* `-dxc-path`: Sets the path where dxc dll/shared libraries are loaded from (dxcompiler & dxil). -* `-fxc-path`: Sets the path where fxc dll is loaded from (d3dcompiler_47.dll). -* `-glslang-path`: Sets where the Slang specific 'slang-glslang' is loaded from - -Paths can specify a directory that holds the appropriate binaries. It can also be used to name a specific downstream binary - be it a shared library or an executable. Note that if it is a shared library, it is not necessary to provide the full filesystem name - just the path and/or name that will be used to load it. For example on windows `fxc` can be loaded from `D:/mydlls` with - -* `D:/mydlls` - will look for `d3dcompiler_47.dll` in this directory -* `D:/mydlls/d3dcompiler_47` - it's not necessary to specify .dll to load a dll on windows -* `D:/mydlls/d3dcompiler_47.dll` - it is also possible name the shared library explicitly for example - -The name of the shared library/executable can be used to specify a specific version, for example by using `D:/mydlls/dxcompiler-some-version` for a specific version of `dxc`. - -Limitations ------------ - -A major limitation of the `slangc` command today is that there is no provision for getting reflection data out along with the compiled shader code. -For now, the command-line tool is best seen as a debugging/testing tool, and all serious applications should drive Slang through the API. diff --git a/docs/cpu-target.md b/docs/cpu-target.md index 76226a2b8e..89a43e09ff 100644 --- a/docs/cpu-target.md +++ b/docs/cpu-target.md @@ -52,9 +52,9 @@ SLANG_HOST_CPP_SOURCE, ///< C++ code for `host` style Using the `-target` command line option -* C_SOURCE: c -* CPP_SOURCE: cpp,c++,cxx -* HOST_CPP_SOURCE: host-cpp,host-c++,host-cxx +* `C_SOURCE`: c +* `CPP_SOURCE`: cpp,c++,cxx +* `HOST_CPP_SOURCE`: host-cpp,host-c++,host-cxx Note! Output of C source is not currently supported. @@ -70,11 +70,11 @@ SLANG_OBJECT_CODE, ///< Object code that can be used for later link Using the `-target` command line option -* EXECUTABLE: exe, executable -* SHADER_SHARED_LIBRARY: sharedlib, sharedlibrary, dll -* SHADER_HOST_CALLABLE: callable, host-callable -* OBJECT_CODE: object-conde -* HOST_HOST_CALLABLE: host-host-callable +* `EXECUTABLE`: exe, executable +* `SHADER_SHARED_LIBRARY`: sharedlib, sharedlibrary, dll +* `SHADER_HOST_CALLABLE`: callable, host-callable +* `OBJECT_CODE`: object-conde +* `HOST_HOST_CALLABLE`: host-host-callable Using `host-callable` types from the the command line, other than to test such code compile and can be loaded for host execution. @@ -90,7 +90,7 @@ The `shader` style implies * The code *can* be executed in a GPU-kernel like execution model, launched across multiple threads (as described in the [ABI](#abi)) * Currently no reference counting -* Only functionality from the Slang stdlib, built in HLSL or anything supplied by a [COM interfaces](#com-interface) is available +* Only functionality from the Slang core module, built in HLSL or anything supplied by a [COM interfaces](#com-interface) is available * Currently [slang-llvm](#slang-llvm) only supports the `shader` style The `host` style implies @@ -293,7 +293,7 @@ The global can now be set from host code via } ``` -In terms of reflection `__global` variables are not visibile. +In terms of reflection `__global` variables are not visible. ## NativeString @@ -309,7 +309,7 @@ TODO(JS): What happens with String with shader compile style on CPU? Shouldn't i It is currently not possible to step into LLVM-JIT code when using [slang-llvm](#slang-llvm). Fortunately it is possible to step into code compiled via a [regular C/C++ compiler](#regular-cpp). -Below is a code snippet showing how to swich to a [regular C/C++ compiler](#regular-cpp) at runtime. +Below is a code snippet showing how to switch to a [regular C/C++ compiler](#regular-cpp) at runtime. ```C++ SlangPassThrough findRegularCppCompiler(slang::IGlobalSession* slangSession) @@ -401,7 +401,7 @@ struct ComputeVaryingInput `ComputeVaryingInput` allows specifying a range of groupIDs to execute - all the ids in a grid from startGroup to endGroup, but not including the endGroupIDs. Most compute APIs allow specifying an x,y,z extent on 'dispatch'. This would be equivalent as having startGroupID = { 0, 0, 0} and endGroupID = { x, y, z }. The exported function allows setting a range of groupIDs such that client code could dispatch different parts of the work to different cores. This group range mechanism was chosen as the 'default' mechanism as it is most likely to achieve the best performance. -There are two other functions that consist of the entry point name postfixed with `_Thread` and `_Group`. For the entry point 'computeMain' these functions would be accessable from the shared library interface as `computeMain_Group` and `computeMain_Thread`. `_Group` has the same signature as the listed for computeMain, but it doesn't execute a range, only the single group specified by startGroupID (endGroupID is ignored). That is all of the threads within the group (as specified by `[numthreads]`) will be executed in a single call. +There are two other functions that consist of the entry point name postfixed with `_Thread` and `_Group`. For the entry point 'computeMain' these functions would be accessible from the shared library interface as `computeMain_Group` and `computeMain_Thread`. `_Group` has the same signature as the listed for computeMain, but it doesn't execute a range, only the single group specified by startGroupID (endGroupID is ignored). That is all of the threads within the group (as specified by `[numthreads]`) will be executed in a single call. It may be desirable to have even finer control of how execution takes place down to the level of individual 'thread's and this can be achieved with the `_Thread` style. The signature looks as follows @@ -566,7 +566,7 @@ It may be useful to be able to include `slang-cpp-types.h` in C++ code to access Would wrap all the Slang prelude types in the namespace `CPPPrelude`, such that say a `StructuredBuffer` could be specified in C++ source code as `CPPPrelude::StructuredBuffer`. -The code that sets up the prelude for the test infrastucture and command line usage can be found in ```TestToolUtil::setSessionDefaultPrelude```. Essentially this determines what the absolute path is to `slang-cpp-prelude.h` is and then just makes the prelude `#include "the absolute path"`. +The code that sets up the prelude for the test infrastructure and command line usage can be found in ```TestToolUtil::setSessionDefaultPrelude```. Essentially this determines what the absolute path is to `slang-cpp-prelude.h` is and then just makes the prelude `#include "the absolute path"`. The *default* prelude is set to the contents of the files for C++ held in the prelude directory and is held within the Slang shared library. It is therefore typically not necessary to distribute Slang with prelude files. @@ -616,7 +616,7 @@ Vector defValue = {}; // Zero initialize such that read access values.at(3).x = 10; ``` -Note that '[] 'would be turned into the `at` function, which takes the default value as a paramter provided by the caller. If this is then written to then only the defValue is corrupted. Even this mechanism not be quite right, because if we write and then read again from the out of bounds reference in HLSL we may expect that 0 is returned, whereas here we get the value that was last written. +Note that '[] 'would be turned into the `at` function, which takes the default value as a parameter provided by the caller. If this is then written to then only the defValue is corrupted. Even this mechanism not be quite right, because if we write and then read again from the out of bounds reference in HLSL we may expect that 0 is returned, whereas here we get the value that was last written. ## Zero index bound checking diff --git a/docs/cuda-target.md b/docs/cuda-target.md index 17d1c6a0dd..a80dc59f9c 100644 --- a/docs/cuda-target.md +++ b/docs/cuda-target.md @@ -30,7 +30,7 @@ The following are a work in progress or not implemented but are planned to be so For producing PTX binaries Slang uses [NVRTC](https://docs.nvidia.com/cuda/nvrtc/index.html). NVRTC dll/shared library has to be available to Slang (for example in the appropriate PATH for example) for it to be able to produce PTX. -The NVRTC compiler can be accessed directly via the pass through mechanism and is identifed by the enum value `SLANG_PASS_THROUGH_NVRTC`. +The NVRTC compiler can be accessed directly via the pass through mechanism and is identified by the enum value `SLANG_PASS_THROUGH_NVRTC`. Much like other targets that use downstream compilers Slang can be used to compile CUDA source directly to PTX via the pass through mechansism. The Slang command line options will broadly be mapped down to the appropriate options for the NVRTC compilation. In the API the `SlangCompileTarget` for CUDA is `SLANG_CUDA_SOURCE` and for PTX is `SLANG_PTX`. These can also be specified on the Slang command line as `-target cuda` and `-target ptx`. @@ -126,11 +126,11 @@ The UniformState and UniformEntryPointParams struct typically vary by shader. Un Read only textures will be bound as the opaque CUDA type CUtexObject. This type is the combination of both a texture AND a sampler. This is somewhat different from HLSL, where there can be separate `SamplerState` variables. This allows access of a single texture binding with different types of sampling. -If code relys on this behavior it will be necessary to bind multiple CtexObjects with different sampler settings, accessing the same texture data. +If code relies on this behavior it will be necessary to bind multiple CtexObjects with different sampler settings, accessing the same texture data. Slang has some preliminary support for TextureSampler type - a combined Texture and SamplerState. To write Slang code that can target CUDA and other platforms using this mechanism will expose the semantics appropriately within the source. -Load is only supported for Texture1D, and the mip map selection argument is ignored. This is because there is tex1Dfetch and no higher dimensional equivalents. CUDA also only allows such access if the backing array is linear memory - meaning the bound texture cannot have mip maps - thus making the mip map parameter superflous anyway. RWTexture does allow Load on other texture types. +Load is only supported for Texture1D, and the mip map selection argument is ignored. This is because there is tex1Dfetch and no higher dimensional equivalents. CUDA also only allows such access if the backing array is linear memory - meaning the bound texture cannot have mip maps - thus making the mip map parameter superfluous anyway. RWTexture does allow Load on other texture types. ## RWTexture @@ -145,7 +145,7 @@ RWTexture2D rwt2D_2; The format names used are the same as for [GLSL layout format types](https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)). If no format is specified Slang will *assume* that the format is the same as the type specified. -Note that the format attribution is on variables/paramters/fields and not part of the type system. This means that if you have a scenario like... +Note that the format attribution is on variables/parameters/fields and not part of the type system. This means that if you have a scenario like... ``` [format(rg16f)] @@ -239,7 +239,7 @@ That for pass-through usage, prelude is not pre-pended, preludes are for code ge void setDownstreamCompilerPrelude(SlangPassThrough passThrough, const char* preludeText); ``` -The code that sets up the prelude for the test infrastucture and command line usage can be found in ```TestToolUtil::setSessionDefaultPrelude```. Essentially this determines what the absolute path is to `slang-cpp-prelude.h` is and then just makes the prelude `#include "the absolute path"`. +The code that sets up the prelude for the test infrastructure and command line usage can be found in ```TestToolUtil::setSessionDefaultPrelude```. Essentially this determines what the absolute path is to `slang-cpp-prelude.h` is and then just makes the prelude `#include "the absolute path"`. Half Support ============ @@ -256,7 +256,7 @@ If this fails - the prelude include of `cuda_fp16.h` will most likely fail on NV CUDA has the `__half` and `__half2` types defined in `cuda_fp16.h`. The `__half2` can produce results just as quickly as doing the same operation on `__half` - in essence for some operations `__half2` is [SIMD](https://en.wikipedia.org/wiki/SIMD) like. The half implementation in Slang tries to take advantage of this optimization. -Since Slang supports up to 4 wide vectors Slang has to build on CUDAs half support. The types _`_half3` and `__half4` are implemented in `slang-cuda-prelude.h` for this reason. It is worth noting that `__half3` is made up of a `__half2` and a `__half`. As `__half2` is 4 byte aligned, this means `__half3` is actually 8 bytes, rather than 6 bytes that might be expected. +Since Slang supports up to 4 wide vectors Slang has to build on CUDAs half support. The types `__half3` and `__half4` are implemented in `slang-cuda-prelude.h` for this reason. It is worth noting that `__half3` is made up of a `__half2` and a `__half`. As `__half2` is 4 byte aligned, this means `__half3` is actually 8 bytes, rather than 6 bytes that might be expected. One area where this optimization isn't fully used is in comparisons - as in effect Slang treats all the vector/matrix half comparisons as if they are scalar. This could be perhaps be improved on in the future. Doing so would require using features that are not directly available in the CUDA headers. @@ -265,9 +265,9 @@ Wave Intrinsics There is broad support for [HLSL Wave intrinsics](https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/hlsl-shader-model-6-0-features-for-direct3d-12), including support for [SM 6.5 intrinsics](https://microsoft.github.io/DirectX-Specs/d3d/HLSL_ShaderModel6_5.html). -Most Wave intrinsics will work with vector, matrix or scalar types of typical built in types - uint, int, float, double, uint64_t, int64_t. +Most Wave intrinsics will work with vector, matrix or scalar types of typical built in types - `uint`, `int`, `float`, `double`, `uint64_t`, `int64_t`. -The support is provided via both the Slang stdlib as well as the Slang CUDA prelude found in 'prelude/slang-cuda-prelude.h'. Many Wave intrinsics are not directly applicable within CUDA which supplies a more low level mechanisms. The implementation of most Wave functions work most optimally if a 'Wave' where all lanes are used. If all lanes from index 0 to pow2(n) -1 are used (which is also true if all lanes are used) a binary reduction is typically applied. If this is not the case the implementation fallsback on a slow path which is linear in the number of active lanes, and so is typically significantly less performant. +The support is provided via both the Slang core module as well as the Slang CUDA prelude found in 'prelude/slang-cuda-prelude.h'. Many Wave intrinsics are not directly applicable within CUDA which supplies a more low level mechanisms. The implementation of most Wave functions work most optimally if a 'Wave' where all lanes are used. If all lanes from index 0 to pow2(n) -1 are used (which is also true if all lanes are used) a binary reduction is typically applied. If this is not the case the implementation fallsback on a slow path which is linear in the number of active lanes, and so is typically significantly less performant. For more a more concrete example take @@ -292,7 +292,7 @@ Will require 3 times as many steps as the earlier scalar example just using a si ## WaveGetLaneIndex -'WaveGetLaneIndex' defaults to `(threadIdx.x & SLANG_CUDA_WARP_MASK)`. Depending on how the kernel is launched this could be incorrect. There other ways to get lane index, for example using inline assembly. This mechanism though is apparently slower than the simple method used here. There is support for using the asm mechnism in the CUDA prelude using the `SLANG_USE_ASM_LANE_ID` preprocessor define to enable the feature. +'WaveGetLaneIndex' defaults to `(threadIdx.x & SLANG_CUDA_WARP_MASK)`. Depending on how the kernel is launched this could be incorrect. There are other ways to get lane index, for example using inline assembly. This mechanism though is apparently slower than the simple method used here. There is support for using the asm mechanism in the CUDA prelude using the `SLANG_USE_ASM_LANE_ID` preprocessor define to enable the feature. There is potential to calculate the lane id using the [numthreads] markup in Slang/HLSL, but that also requires some assumptions of how that maps to a lane index. diff --git a/docs/design/README.md b/docs/design/README.md index c98e6951fc..58e1e39a78 100644 --- a/docs/design/README.md +++ b/docs/design/README.md @@ -2,7 +2,7 @@ Slang Design and Implementation Notes ===================================== This directory contains documents that are primarily intended for developers working on the Slang implementation. -They are not indended to be helpful to Slang users. +They are not intended to be helpful to Slang users. These documents can only be trusted to reflect the state of the codebase or the plans of their authors at the time they were written. Changes to the implementation are not expected to always come with matching changes to these documents, so some amount of drift is to be expected. @@ -20,4 +20,6 @@ The [Existential Types](existential-types.md) document goes into some detail abo The [Capabilities](capabilities.md) document explains the proposed model for how Slang will support general notions of profile- or capability-based overloading/dispatch. -The [Casting](casting.md) document explains how casting works in the slang C++ compiler code base. \ No newline at end of file +The [Casting](casting.md) document explains how casting works in the slang C++ compiler code base. + +The [Experimental API Interfaces](experimental.md) document explains how experimental Slang API changes are to be deployed. \ No newline at end of file diff --git a/docs/design/autodiff.md b/docs/design/autodiff.md index 29d7c82c7a..8bf26baa90 100644 --- a/docs/design/autodiff.md +++ b/docs/design/autodiff.md @@ -201,7 +201,7 @@ DP f_SSA_Proped(DP dpa, DP dpb) } // Note here that we have to 'store' all the intermediaries - // _t1, _t2, _q4, _t3, _q5, _t3_d, _t4 and _q1. This is fundementally + // _t1, _t2, _q4, _t3, _q5, _t3_d, _t4 and _q1. This is fundamentally // the tradeoff between fwd_mode and rev_mode if (_b1) @@ -288,7 +288,7 @@ void f_SSA_Rev(inout DP dpa, inout DP dpb, float dout) } // Note here that we have to 'store' all the intermediaries - // _t1, _t2, _q4, _t3, _q5, _t3_d, _t4 and _q1. This is fundementally + // _t1, _t2, _q4, _t3, _q5, _t3_d, _t4 and _q1. This is fundamentally // the tradeoff between fwd_mode and rev_mode if (_b1) @@ -330,4 +330,4 @@ void f_SSA_Rev(inout DP dpa, inout DP dpb, float dout) } } -``` \ No newline at end of file +``` diff --git a/docs/design/autodiff/basics.md b/docs/design/autodiff/basics.md index 189260aff0..43ed164ad4 100644 --- a/docs/design/autodiff/basics.md +++ b/docs/design/autodiff/basics.md @@ -4,7 +4,7 @@ This documentation is intended for Slang contributors and is written from a comp ## What is Automatic Differentiation? -Before diving into the design of the automatic differentiation (for brevity, we will call it 'auto-diff') passes, it is important to understand the end goal of what auto-diff tries to acheive. +Before diving into the design of the automatic differentiation (for brevity, we will call it 'auto-diff') passes, it is important to understand the end goal of what auto-diff tries to achieve. The over-arching goal of Slang's auto-diff is to enable the user to compute derivatives of a given shader program or function's output w.r.t its input parameters. This critical compiler feature enables users to quickly use their shaders with gradient-based parameter optimization algorithms, which forms the backbone of modern machine learning systems. It enables users to train and deploy graphics systems that contain ML primitives (like multi-layer perceptron's or MLPs) or use their shader programs as differentiable primitives within larger ML pipelines. @@ -60,7 +60,7 @@ DifferentialPair fwd_f(DifferentialPair dpx) } ``` -Note that `(2 * x)` is the multiplier corresponding to $Df(x)$. We refer to $x$ and $f(x)$ as "*primal*" values and the pertubations $dx$ and $Df(x)\cdot dx$ as "*differential*" values. The reason for this separation is that the "*differential*" output values are always linear w.r.t their "*differential*" inputs. +Note that `(2 * x)` is the multiplier corresponding to $Df(x)$. We refer to $x$ and $f(x)$ as "*primal*" values and the perturbations $dx$ and $Df(x)\cdot dx$ as "*differential*" values. The reason for this separation is that the "*differential*" output values are always linear w.r.t their "*differential*" inputs. As the name implies, `DifferentialPair` is a special pair type used by Slang to hold values and their corresponding differentials. @@ -256,7 +256,7 @@ void rev_f(inout DifferentialPair dpx, inout DifferentialPair dpy, Note that `rev_f` accepts derivatives w.r.t the output value as the input, and returns derivatives w.r.t inputs as its output (through `inout` parameters). `rev_f` still needs the primal values `x` and `y` to compute the derivatives, so those are still passed in as an input through the primal part of the differential pair. -Also note that the reverse-mode derivative function does not have to compute the primal result value (its return is void). The reason for this is a matter of convenience: reverse-mode derivatives are often invoked after all the primal fuctions, and there is typically no need for these values. We go into more detail on this topic in the checkpointing chapter. +Also note that the reverse-mode derivative function does not have to compute the primal result value (its return is void). The reason for this is a matter of convenience: reverse-mode derivatives are often invoked after all the primal functions, and there is typically no need for these values. We go into more detail on this topic in the checkpointing chapter. The reverse mode function can be used to compute both `dOutput/dx` and `dOutput/dy` with a single invocation (unlike the forward-mode case where we had to invoke `fwd_f` once for each input) diff --git a/docs/design/autodiff/decorators.md b/docs/design/autodiff/decorators.md index b08da29122..27bf0e3d00 100644 --- a/docs/design/autodiff/decorators.md +++ b/docs/design/autodiff/decorators.md @@ -45,16 +45,16 @@ interface IFoo_after_checking_and_lowering ### `[TreatAsDifferentiable]` In large codebases where some interfaces may have several possible implementations, it may not be reasonable to have to mark all possible implementations with `[Differentiable]`, especially if certain implementations use hacks or workarounds that need additional consideration before they can be marked `[Differentiable]` -In such cases, we provide the `[TreatAsDifferentiable]` decoration (AST node: `TreatAsDifferentiableAttribute`, IR: `OpTreatAsDifferentiableDecoration`), which instructs the auto-diff passes to construct an 'empty' function that returns a 0 (or 0-equivalent) for the derivative values. This allows the signature of a `[TreatAsDifferentiable]` function to match a `[Differentiable]` requirment without actually having to produce a derivative. +In such cases, we provide the `[TreatAsDifferentiable]` decoration (AST node: `TreatAsDifferentiableAttribute`, IR: `OpTreatAsDifferentiableDecoration`), which instructs the auto-diff passes to construct an 'empty' function that returns a 0 (or 0-equivalent) for the derivative values. This allows the signature of a `[TreatAsDifferentiable]` function to match a `[Differentiable]` requirement without actually having to produce a derivative. ## Custom derivative decorators In many cases, it is desirable to manually specify the derivative code for a method rather than let the auto-diff pass synthesize it from the method body. This is usually desirable if: 1. The body of the method is too complex, and there is a simpler, mathematically equivalent way to compute the same value (often the case for intrinsics like `sin(x)`, `arccos(x)`, etc..) -2. The method involves global/shared memory accesses, and synthesized derivative code may cause race conditions or be very slow due to overuse of synchronization. For this reason Slang assumes global memory accesses are non-differentiable by default, and requires that the user (or stdlib) define separate accessors with different derivative semantics. +2. The method involves global/shared memory accesses, and synthesized derivative code may cause race conditions or be very slow due to overuse of synchronization. For this reason Slang assumes global memory accesses are non-differentiable by default, and requires that the user (or the core module) define separate accessors with different derivative semantics. The Slang front-end provides two sets of decorators to facilitate this: 1. To reference a custom derivative function from a primal function: `[ForwardDerivative(fn)]` and `[BackwardDerivative(fn)]` (AST Nodes: `ForwardDerivativeAttribute`/`BackwardDerivativeAttribute`, IR: `OpForwardDervativeDecoration`/`OpBackwardDerivativeDecoration`), and -2. To reference a primal function from its custom derivative function: `[ForwardDerivativeOf(fn)]` and `[BackwardDerivativeOf(fn)]` (AST Nodes: `ForwardDerivativeAttributeOf`/`BackwardDerivativeAttributeOf`). These attributes are useful to provide custom derivatives for existing methods in a different file without having to edit/change that module. For instance, we use `diff.meta.slang` to provide derivatives for stdlib functions in `hlsl.meta.slang`. When lowering to IR, these references are placed on the target (primal function). That way both sets of decorations are lowered on the primal function. +2. To reference a primal function from its custom derivative function: `[ForwardDerivativeOf(fn)]` and `[BackwardDerivativeOf(fn)]` (AST Nodes: `ForwardDerivativeAttributeOf`/`BackwardDerivativeAttributeOf`). These attributes are useful to provide custom derivatives for existing methods in a different file without having to edit/change that module. For instance, we use `diff.meta.slang` to provide derivatives for the core module functions in `hlsl.meta.slang`. When lowering to IR, these references are placed on the target (primal function). That way both sets of decorations are lowered on the primal function. These decorators also work on generically defined methods, as well as struct methods. Similar to how function calls work, these decorators also work on overloaded methods (and reuse the `ResolveInoke` infrastructure to perform resolution) @@ -68,7 +68,7 @@ In some cases, we face the opposite problem that inspired custom derivatives. Th This frequently occurs with hardware intrinsic operations that are lowered into special op-codes that map to hardware units, such as texture sampling & interpolation operations. However, these operations do have reference 'software' implementations which can be used to produce the derivative. -To allow user code to use the fast hardward intrinsics for the primal pass, but use synthesized derivatives for the derivative pass, we provide decorators `[PrimalSubstitute(ref-fn)]` and `[PrimalSubstituteOf(orig-fn)]` (AST Node: `PrimalSubstituteAttribute`/`PrimalSubstituteOfAttribute`, IR: `OpPrimalSubstituteDecoration`), that can be used to provide a reference implementation for the auto-diff pass. +To allow user code to use the fast hardware intrinsics for the primal pass, but use synthesized derivatives for the derivative pass, we provide decorators `[PrimalSubstitute(ref-fn)]` and `[PrimalSubstituteOf(orig-fn)]` (AST Node: `PrimalSubstituteAttribute`/`PrimalSubstituteOfAttribute`, IR: `OpPrimalSubstituteDecoration`), that can be used to provide a reference implementation for the auto-diff pass. Example: ```C @@ -89,4 +89,4 @@ void sampleTexture_bwd(TexHandle2D tex, inout DifferentialPair dp_uv, fl } ``` -The implementation of `[PrimalSubstitute(fn)]` is relatively straightforward. When the transcribers are asked to synthesize a derivative of a function, they check for a `OpPrimalSubstituteDecoration`, and swap the current function out for the substitute function before proceeding with derivative synthesis. \ No newline at end of file +The implementation of `[PrimalSubstitute(fn)]` is relatively straightforward. When the transcribers are asked to synthesize a derivative of a function, they check for a `OpPrimalSubstituteDecoration`, and swap the current function out for the substitute function before proceeding with derivative synthesis. diff --git a/docs/design/autodiff/ir-overview.md b/docs/design/autodiff/ir-overview.md index a6b3ec2070..83391e27f2 100644 --- a/docs/design/autodiff/ir-overview.md +++ b/docs/design/autodiff/ir-overview.md @@ -17,7 +17,7 @@ At this step, there are 2 other variants that can appear `IRBackwardDifferentiat 4. This process from (1.) is run in a loop. This is because we can have nested differentiation requests such as `IRForwardDifferentiate(IRBackwardDifferentiate(a : IRFuncType))`. The inner request is processed in the first pass, and the outer request gets processed in the next pass. ## Auto-Diff Passes for `IRForwardDifferentiate` -For forward-mode derivatives, we only require a single pass implemented wholly in `ForwardDiffTranscriber`. This implementes the linearization algorithm, which roughly follows this logic: +For forward-mode derivatives, we only require a single pass implemented wholly in `ForwardDiffTranscriber`. This implements the linearization algorithm, which roughly follows this logic: 1. Create a clone of the original function 2. Perform pre-autodiff transformations, the most @@ -357,7 +357,7 @@ The unzipping pass uses the decorations from the linearization step to figure ou The separation process uses the following high-level logic: 1. Create two clones of all the blocks in the provided function (one for primal insts, one for differential insts), and hold a mapping between each original (mixed) block to each primal and differential block. The return statement of the current final block is **removed**. 2. Process each instruction of each block: instructions marked as **primal** are moved to the corresponding **primal block**, instructions marked **differential** are moved to the corresponding **differential block**. -3. Instructions marked **mixed** need op-specific handling, and so are dispatched to the appropriate splitting function. For instance, block parameters that are holding differential-pair values are split into parameters for holding primal and differential values (the exception is function parameters, which are not affected). Simlarly, `IRVar`s, `IRTerminatorInst`s (control-flow) and `IRCall`s are all split into multiple insts. +3. Instructions marked **mixed** need op-specific handling, and so are dispatched to the appropriate splitting function. For instance, block parameters that are holding differential-pair values are split into parameters for holding primal and differential values (the exception is function parameters, which are not affected). Similarly, `IRVar`s, `IRTerminatorInst`s (control-flow) and `IRCall`s are all split into multiple insts. 4. Except for `IRReturn`, all other control-flow insts are effectively duplicated so that the control-flow between the primal blocks and differential blocks both follow the original blocks' control-flow. The main difference is that PHI arguments are split (primal blocks carry primal values in their PHI arguments, and differential blocks carry diff values) between the two. Note that condition values (i.e. booleans) are used by both the primal and differential control-flow insts. However, since booleans are always primal values, they are always defined in the primal blocks. @@ -522,7 +522,7 @@ We synthesize a CFG that satisfies this property through the following steps: %da_rev = OpAdd %da_rev_1 %da_rev_2 : %float ``` - Derivative accumulation is acheived through two ways: + Derivative accumulation is achieved through two ways: **Within** a block, we keep a list all the reverse derivative insts for each inst and only **materialize** the total derivative when it is required as an operand. This is the most efficient way to do this, because we can apply certain optimizations for composite types (derivative of an array element, vector element, struct field, etc..). @@ -756,12 +756,12 @@ After AD passes, this results in the following code: { /*...*/ } ``` -4. Construct the reverse control-flow (`reveseCFGRegion()`) by going through the reference forward-mode blocks, and cloning the control-flow onto the reverse-mode blocks, but in reverse. This is acheived by running `reverseCFGRegion()` recursively on each sub-region, where a *region* is defined as a set of blocks with a single entry block and a single exit block. This definition of a region only works because we normalized the CFG into this form. +4. Construct the reverse control-flow (`reveseCFGRegion()`) by going through the reference forward-mode blocks, and cloning the control-flow onto the reverse-mode blocks, but in reverse. This is achieved by running `reverseCFGRegion()` recursively on each sub-region, where a *region* is defined as a set of blocks with a single entry block and a single exit block. This definition of a region only works because we normalized the CFG into this form. The reversal logic follows these general rules: 1. **Unconditional Branch**: For an unconditional branch from `A->B` we simply have to map the reverse version of B with that of A. i.e. `rev[B] -> rev[A]` 2. **If-Else**: For an if-else of the form `A->[true = T->...->T_last->M, false = F->...->F_last->M]`, we construct `rev[M]->[true = rev[T_last]->...->rev[T_last]->rev[A], false = rev[F_last]->...->rev[F]->rev[A]]`. That is, we reverse each sub-region, and start from the merge block and end at the split block. - Note that we need to identify `T_last` and `F_last` i.e. the last two blocks in the true and false regions. We make the last block in the region an additional return value of `reverseCFGRegion()`, so that when reversing the true and false sub-regions, we also get the relevent last block as an additional output. Also note that additional empty blocks may be inserted to carry derivatives of the phi arguments, but this does not alter the control-flow. + Note that we need to identify `T_last` and `F_last` i.e. the last two blocks in the true and false regions. We make the last block in the region an additional return value of `reverseCFGRegion()`, so that when reversing the true and false sub-regions, we also get the relevant last block as an additional output. Also note that additional empty blocks may be inserted to carry derivatives of the phi arguments, but this does not alter the control-flow. 3. **Switch-case**: Proceeds in exactly the same way as `if-else` reversal, but with multiple cases instead of just 2. 4. **Loop**: After normalization, all (non-trivial) loops are of the form: `A->C->[true = T->...->T_last->C, false=B->...->M]`. We reverse this loop into `rev[M]->...rev[B]->rev[C]->[true=rev[T_last]->...->rev[T]->rev[C], false=rev[A]]`. The actual reversal logic also handles some corner cases by inserting additional blank blocks to avoid situations where regions may share the same merge block. @@ -975,12 +975,12 @@ When storing values this way, we must consider that instructions within loops ca **Indexed Region Processing:** In order to be able to allocate the right array and use the right indices, we need information about which blocks are part of which loop (and loops can be nested, so blocks can be part of multiple loops). To do this, we run a pre-processing step that maps all blocks to all relevant loop regions, the corresponding index variables and the inferred iteration limits (maximum times a loop can run). Note that if an instruction appears in a nested block, we create a multi-dimensional array and use multiple indices. - **Loop State Variables:** Certain variables cannot be classified as recompute. Major examples are loop state variables which are defined as variables that are read from and written to within the loop. In practice, they appear as phi-variables on the first loop block after SSA simplification. Their uses _must_ be classifed as 'store', because recomputing them requires duplicating the primal loop within the differential loop. This is because the differential loop runs backwards so the state of a primal variable at loop index $N$ cannot be recomputed when the loop is running backwards ($N+1 \to N \to N-1$), and involves running the primal loop up to $N$ times within the current iteration of the differential loop. In terms of complexity, this turns an $O(N)$ loop into an $O(N^2)$ loop, and so we disallow this. + **Loop State Variables:** Certain variables cannot be classified as recompute. Major examples are loop state variables which are defined as variables that are read from and written to within the loop. In practice, they appear as phi-variables on the first loop block after SSA simplification. Their uses _must_ be classified as 'store', because recomputing them requires duplicating the primal loop within the differential loop. This is because the differential loop runs backwards so the state of a primal variable at loop index $N$ cannot be recomputed when the loop is running backwards ($N+1 \to N \to N-1$), and involves running the primal loop up to $N$ times within the current iteration of the differential loop. In terms of complexity, this turns an $O(N)$ loop into an $O(N^2)$ loop, and so we disallow this. It is possible that the resulting $O(N^2)$ loop may end up being faster in practice due to reduced memory requirements, but we currently lack the infrastructure to robustly allow such loop duplication while keeping the user informed of the potentially drastic complexity issues. 3. **Process 'Recompute' insts:** Insert a copy of the primal instruction into a corresponding 'recomputation' block that is inserted into the differential control-flow so that it dominates the use-site. - **Insertion of Recompute Blocks:** In order to accomodate recomputation, we first preprocess the function, by going through each **breakable (i.e. loop) region** in the differential blocks, looking up the corresponding **primal region** and cloning all the primal blocks into the beginning of the differential region. Note that this cloning process does not actually clone the instructions within each block, only the control-flow (i.e. terminator) insts. This way, there is a 1:1 mapping between the primal blocks and the newly created **recompute blocks**, This way, if we decide to 'recompute' an instruction, we can simply clone it into the corresponding recompute block, and we have a guarantee that the definition and use-site are within the same loop scope, and that the definition comes before the use. + **Insertion of Recompute Blocks:** In order to accommodate recomputation, we first preprocess the function, by going through each **breakable (i.e. loop) region** in the differential blocks, looking up the corresponding **primal region** and cloning all the primal blocks into the beginning of the differential region. Note that this cloning process does not actually clone the instructions within each block, only the control-flow (i.e. terminator) insts. This way, there is a 1:1 mapping between the primal blocks and the newly created **recompute blocks**, This way, if we decide to 'recompute' an instruction, we can simply clone it into the corresponding recompute block, and we have a guarantee that the definition and use-site are within the same loop scope, and that the definition comes before the use. **Legalizing Accesses from Branches:** Our per-loop-region recompute blocks ensure that the recomputed inst is always within the same region as its uses, but it can still be out-of-scope if it is defined within a branch (i.e. if-else). We therefore still run a light-weight hoisting pass that detects these uses, inserts an `IRVar` at the immediate dominator of the def and use, and inserts loads and stores accordingly. Since they occur within the same loop region, there is no need to worry about arrays/indices (unlike the 'store' case). @@ -1363,7 +1363,7 @@ struct f_Intermediates }; -// After extraction: primal context funtion +// After extraction: primal context function float s_primal_ctx_f(float x, out f_Intermediates ctx) { // @@ -1459,4 +1459,4 @@ void outer_rev(DifferentialPair dpx, float d_output) dpx = _dpx; } -``` \ No newline at end of file +``` diff --git a/docs/design/autodiff/types.md b/docs/design/autodiff/types.md index 12b468a6e4..3860f0dfb4 100644 --- a/docs/design/autodiff/types.md +++ b/docs/design/autodiff/types.md @@ -8,7 +8,7 @@ Here we detail the main components of the type system: the `IDifferentiable` int We also detail how auto-diff operators are type-checked (the higher-order function checking system), how the `no_diff` decoration can be used to avoid differentiation through attributed types, and the derivative data flow analysis that warns the the user of unintentionally stopping derivatives. ## `interface IDifferentiable` -Defined in core.meta.slang, `IDifferentiable` forms the basis for denoting differentiable types, both within the stdlib, and otherwise. +Defined in core.meta.slang, `IDifferentiable` forms the basis for denoting differentiable types, both within the core module, and otherwise. The definition of `IDifferentiable` is designed to encapsulate the following 4 items: 1. `Differential`: The type of the differential value of the conforming type. This allows custom data-structures to be defined to carry the differential values, which may be optimized for space instead of relying solely on compiler synthesis/ @@ -74,9 +74,9 @@ T.Differential dmul(S s, T.Differential a) 5. During auto-diff, the compiler can sometimes synthesize new aggregate types. The most common case is the intermediate context type (`kIROp_BackwardDerivativeIntermediateContextType`), which is lowered into a standard struct once the auto-diff pass is complete. It is important to synthesize the `IDifferentiable` conformance for such types since they may be further differentiated (through higher-order differentiation). This implementation is contained in `fillDifferentialTypeImplementationForStruct(...)` and is roughly analogous to the AST-side synthesis. ### Differentiable Type Dictionaries -During auto-diff, the IR passes frequently need to perform lookups to check if an `IRType` is differentiable, and retreive references to the corresponding `IDifferentiable` methods. These lookups also need to work on generic parameters (that are defined inside generic containers), and existential types that are interface-typed parameters. +During auto-diff, the IR passes frequently need to perform lookups to check if an `IRType` is differentiable, and retrieve references to the corresponding `IDifferentiable` methods. These lookups also need to work on generic parameters (that are defined inside generic containers), and existential types that are interface-typed parameters. -To accomodate this range of different type systems, Slang uses a type dictionary system that associates a dictionary of relevant types with each function. This works in the following way: +To accommodate this range of different type systems, Slang uses a type dictionary system that associates a dictionary of relevant types with each function. This works in the following way: 1. When `CheckTerm()` is called on an expression within a function that is marked differentiable (`[Differentiable]`), we check if the resolved type conforms to `IDifferentiable`. If so, we add this type to the dictionary along with the witness to its differentiability. The dictionary is currently located on `DifferentiableAttribute` that corresponds to the `[Differentiable]` modifier. 2. When lowering to IR, we create a `DifferentiableTypeDictionaryDecoration` which holds the IR versions of all the types in the dictionary as well as a reference to their `IDifferentiable` witness tables. @@ -110,7 +110,7 @@ void bwd_myFunc( Existential types are interface-typed values, where there are multiple possible implementations at run-time. The existential type carries information about the concrete type at run-time and is effectively a 'tagged union' of all possible types. #### Differential type of an Existential -The differential type of an existential type is tricky to define since our type system's only restriction on the `.Differential` type is that it also conforms to `IDifferentiable`. The differential type of any interface `IInterface : IDifferentiable` is therefore the interface type `IDifferentiable`. This is problematic since Slang generally requires a static `anyValueSize` that must be a strict upper bound on the sizes of all conforming types (since this size is used to allocate space for the union). Since `IDifferentiable` is defined in the stdlib `core.meta.slang` and can be used by the user, it is impossible to define a reliable bound. +The differential type of an existential type is tricky to define since our type system's only restriction on the `.Differential` type is that it also conforms to `IDifferentiable`. The differential type of any interface `IInterface : IDifferentiable` is therefore the interface type `IDifferentiable`. This is problematic since Slang generally requires a static `anyValueSize` that must be a strict upper bound on the sizes of all conforming types (since this size is used to allocate space for the union). Since `IDifferentiable` is defined in the core module `core.meta.slang` and can be used by the user, it is impossible to define a reliable bound. We instead provide a new **any-value-size inference** pass (`slang-ir-any-value-inference.h`/`slang-ir-any-value-inference.cpp`) that assembles a list of types that conform to each interface in the final linked IR and determines a relevant upper bound. This allows us to ignore types that conform to `IDifferentiable` but aren't used in the final IR, and generate a tighter upper bound. **Future work:** diff --git a/docs/design/capabilities.md b/docs/design/capabilities.md index 74c08fca98..b4bd4c099a 100644 --- a/docs/design/capabilities.md +++ b/docs/design/capabilities.md @@ -9,7 +9,7 @@ Slang aims to be a portable language for shader programming, which introduces tw Item (2) is traditionally handled with preprocessor techniques (e.g., `#ifdef`ing the body of a function based on target platform), but that of course requires that the user invoke the Slang front end once for each target platform, and target-specific coding in a library will then "infect" code that uses that library, forcing them to invoke the front-end once per target as well. -We are especially sensitive to this problem in the compiler itself, because we have to author and maintain the Slang standard library, which needs to (1) expose the capabilities of many platforms and (2) work across all those platforms. It would be very unfortunate if we had to build different copies of our standard library per-target. +We are especially sensitive to this problem in the compiler itself, because we have to author and maintain the Slang standard modules, which needs to (1) expose the capabilities of many platforms and (2) work across all those platforms. It would be very unfortunate if we had to build different copies of our standard modules per-target. The intention in Slang is to solve both of these problems with a system of *capabilities*. @@ -19,7 +19,7 @@ What is a capability? For our purposes a capability is a discrete feature that a compilation target either does or does not support. We could imagine defining a capability for the presence of texture sampling operations with implicit gradients; this capability would be supported when generating fragment shader kernel code, but not when generating code for other stages. -Let's imagine a language syntax that the standard library could use to define some *atomic* capabilities: +Let's imagine a language syntax that the standard modules could use to define some *atomic* capabilities: ``` capability implicit_gradient_texture_fetches; @@ -31,7 +31,7 @@ struct Texture2D { ... - // Implicit-graident sampling operation. + // Implicit-gradient sampling operation. [availableFor(implicit_gradient_texture_fetches)] float4 Sample(SamplerState s, float2 uv); } @@ -54,7 +54,7 @@ capability fragment : implicit_gradient_texture_fetches; Here we've said that whenever the `fragment` capability is available, we can safely assume that the `implicit_gradient_texture_fetches` capability is available (but not vice versa). -Given even a rudientary tool like that, we can start to build up capabilities that relate closely to the "profiles" in things like D3D: +Given even a rudimentary tool like that, we can start to build up capabilities that relate closely to the "profiles" in things like D3D: ``` capability d3d; @@ -77,12 +77,12 @@ capability opengl : khronos; Here we are saying that `sm_5_1` supports everything `sm_5_0` supports, and potentially more. We are saying that `d3d12` supports `sm_6_0` but maybe not, e.g., `sm_6_3`. We are expressing that fact that having a `glsl_*` capability means you are on some Khronos API target, but that it doesn't specify which one. -(The extact details of these declarations obviously aren't the point; getting a good hierarchy of capabilites will take time.) +(The exact details of these declarations obviously aren't the point; getting a good hierarchy of capabilities will take time.) Capability Composition ---------------------- -Sometimes we'll want to give a distinct name to a specific combination of capabilties, but not say that it supports anything new: +Sometimes we'll want to give a distinct name to a specific combination of capabilities, but not say that it supports anything new: ``` capability ps_5_1 = sm_5_1 & fragment; @@ -129,7 +129,7 @@ For a given function definition `F`, the front end will scan its body and see wh If `F` doesn't have an `[availableFor(...)]` attribute, then we can derive its *effective* `[availableFor(...)]` capability as `R` (this probably needs to be expressed as an iterative dataflow problem over the call graph, to handle cycles). -If `F` *does* have one or more `[availabelFor(...)]` clauses that amount to a declared capability `C` (again in disjunctive normal form), then we can check that `C` implies `R` and error out if it is not the case. +If `F` *does* have one or more `[availableFor(...)]` clauses that amount to a declared capability `C` (again in disjunctive normal form), then we can check that `C` implies `R` and error out if it is not the case. A reasonable implementation would track which calls introduced which requirements, and be able to explain *why* `C` does not capture the stated requirements. For a shader entry point, we should check it as if it had an `[availableFor(...)]` that is the OR of all the specified target profiles (e.g., `sm_5_0 | glsl_450 | ...`) ANDed with the specified stage (e.g., `fragment`). @@ -152,7 +152,7 @@ It should be possible to define multiple versions of a function, having differen ``` For front-end checking, these should be treated as if they were a single definition of `myFunc` with an ORed capability (e.g., `vulkan | d3d12`). -Overload resoultion will pick the "best" candidate at a call site based *only* on the signatures of the function (note that this differs greatly from how profile-specific function overloading works in Cg). +Overload resolution will pick the "best" candidate at a call site based *only* on the signatures of the function (note that this differs greatly from how profile-specific function overloading works in Cg). The front-end will then generate initial IR code for each definition of `myFunc`. Each of the IR functions will have the *same* mangled name, but different bodies, and each will have appropriate IR decorations to indicate the capabilities it requires. @@ -213,7 +213,7 @@ Certain compositions of capabilities make no sense. If a user declared a functio Knowing that certain capabilities are disjoint can also help improve the overall user experience. If a function requires `(vulkan & extensionA) | (d3d12 & featureb)` and we know we are compiling for `vulkan` we should be able to give the user a pointed error message saying they need to ask for `extensionA`, because adding `featureB` isn't going to do any good. -As a first-pass model we could have a notion of `abstract` capabilities that are used to model the root of hierarcies of disjoint capabilities: +As a first-pass model we could have a notion of `abstract` capabilities that are used to model the root of hierarchies of disjoint capabilities: ``` abstract capability api; @@ -268,4 +268,4 @@ Conclusion ---------- Overall, the hope is that in many cases developers will be able to use capability-based partitioning and overloading of APIs to build code that only has to pass through the Slang front-end once, but that can then go through back-end code generation for each target. -In cases where this can't be achieved, the way that capability-based overloading is built into the Slang IR design means that we should be able to merge multiple target-specific definitions into one IR module, so that a library can employ target-specific specializations while still presenting a single API to consumers. +In cases where this can't be achieved, the way that capability-based overloading is built into the Slang IR design means that we should be able to merge multiple target-specific definitions into one IR module, so that a module can employ target-specific specializations while still presenting a single API to consumers. diff --git a/docs/design/casting.md b/docs/design/casting.md index 80c1f149fc..6eafea1acc 100644 --- a/docs/design/casting.md +++ b/docs/design/casting.md @@ -146,9 +146,5 @@ The following code shows the change in behavior of 'as' is based on the source * SLANG_ASSERT(as(exprType) == nullptr); // dynamicCast is always the same object returned, so must match - SLANG_ASSERT(dynamcCast(exprType) == exprType); ``` - - - - \ No newline at end of file diff --git a/docs/design/coding-conventions.md b/docs/design/coding-conventions.md index 2dffaff49d..bc540783aa 100644 --- a/docs/design/coding-conventions.md +++ b/docs/design/coding-conventions.md @@ -11,7 +11,7 @@ The first goal is to make the code look relatively consistent so that it is easy Having varying styles across different modules, files, functions, or lines of code makes the overall design and intention of the codebase harder to follow. The second goal is to minimize the scope complexity of diffs when multiple maintainers work together on the codebase. -In the absence of an enforced style, developers tend to "clean up" code they encoutner to match their personal preferences, and in so doing create additional diffs that increase the chances of merge conflicts and pain down the line. +In the absence of an enforced style, developers tend to "clean up" code they encounter to match their personal preferences, and in so doing create additional diffs that increase the chances of merge conflicts and pain down the line. Because the Slang codebase has passed through many hands and evolved without a pre-existing convention, these two goals can come into conflict. We encourage developers to err on the side of leaving well enough alone (favoring the second goal). @@ -72,7 +72,7 @@ As a general rule, default to making the implementation of a type `public`, and ### Slang -The Slang project codebase also includes `.slang` files implementing the Slang standard library, as well as various test cases and examples. +The Slang project codebase also includes `.slang` files implementing the Slang core module, as well as various test cases and examples. The conventions described here are thus the "official" recommendations for how users should format Slang code. To the extent possible, we will try to apply the same basic conventions to both C++ and Slang. @@ -132,169 +132,24 @@ Namespaces Favor fewer namespaces when possible. Small programs may not need any. -All library code that a Slang user might link against should go in the `Slang` namespace for now, to avoid any possibility of clashes in a static linking scenario. +All standard module code that a Slang user might link against should go in the `Slang` namespace for now, to avoid any possibility of clashes in a static linking scenario. The public C API is obviously an exception to this. -Indenting, Spacing, and Braces +Code Formatting ------------------------------ -Indent by four spaces. Don't use tabs except in files that require them (e.g., `Makefile`s). +- For C++ files, please format using `clang-format`; `.clang-format` files in + the source tree define the style. +- For CMake files, please format using `gersemi` +- For shell scripts, please format using `shfmt` +- For YAML files, please use `prettier` -Matching opening/closing curly braces should be indented to the same column, with an exception for empty braces (`{}`). -An opening curly brace should always be on a new line. +The formatting for the codebase is overall specified by the +[`extras/formatting.sh`](./extras/formatting.sh) script. -```c++ -void someFunc(int a) -{ - doThings(a); -} - -void emptyFunc() -{} - -struct Helper -{ - void help() - { - emptyFunc(); - } -} -``` - -Extremely short "accessor" style functions can violate these rules if the whole definition fits on a line. - -```c++ -struct Vec1 -{ - float x; - - float getX() { return x; } -} -``` - -There is no hard limit on line length, but if you are going past 80-100 columns quite often, maybe think about breaking lines. - -When you decide to break lines for a paramter or argument list, always break after the opening `(`, and put each argument/parameter on its own line: - -```c++ -float bigFunc( - int a, - float b, - void* c) -{ - ... -} - -float gVar = bigFunc( - 0, - 1.0f, - data); -``` - -You can vertically align succesive lines of code to emphasize common structure, but this is not required: - -```c++ -case A_AND_B: doA(); doB(); break; -case JUST_A: doA(); break; -case JUST_B: doB(); break; -``` - -Put space between a control-flow keyword and a following `(`. -This is a default setting of Visual Studio 2019 and 2022. -Examples of how to format the major C++ control-flow constructs follow: - -```c++ -void example() -{ - for (int ii = 0; ii < N; ++ii) - { - if (ii == 0) - { - } - else - { - } - } - - int x = 0; - while (x < 100) - { - x++; - } - - int mode = 0; - do - { - switch (mode) - { - case 0: - x /= 2; - /* fallthrough */ - case 1: - x--; - mode = 3; - - case 2: - default: - x++; - mode--; - break; - } - } while (x > 0); -} -``` - -Don't put space between a unary operator and its operand. -Always put space between an assignment (including compound assignment) operator and its operands. -For other binary operators, use your best judgement. - -If you have to line break a binary expression, put the line break after the operator for an assignment, and before the operator before all others. - -Intializer lists for constructors get some special-case formatting rules. -If everything fits on one line, then great: - -```c++ -SomeClass::SomeClass() - : a(0), b(1), c(2) -{} -``` - -Otherwise, put the line break *before* the comma: - -```c++ -SomeClass::SomeClass() - : a(0) - , b(1) - , c(2) -{} -``` - -When working with `static const` arrays, put the outer `{}` for the array on their own line, and then put each element on its own line and aim for vertical alignment. - -```c++ -struct Mapping -{ - char const* key; - char const* val; -} kMapping[] = -{ - { "a", "aardvark" }, - { "b", "bat" }, -}; -``` - -A trailing comma should always be used for array initializer lists like this, as well as for `enum` tags. - -When writing multi-line macros, the backslash escapes should align vertically. -For consistentcy, a trailing `\` can be used, followed by a comment to mark the end of the definition: - -```c++ -#define FOREACH_ANIMAL(X) \ - X(Aardvark) \ - X(Bat) \ - /* end */ -``` +If you open a pull request and the formatting is incorrect, you can comment +`/format` and a bot will format your code for you. Naming ------ @@ -382,7 +237,7 @@ enum Note that the type name reflects the plural case, while the cases that represent individual bits are named with a singular prefix. -In public APIs, all `enum`s should use the style of separating the type defintion from the `enum`, and all cases should use `SCREAMING_SNAKE_CASE`: +In public APIs, all `enum`s should use the style of separating the type definition from the `enum`, and all cases should use `SCREAMING_SNAKE_CASE`: ```c++ typedef unsigned int SlangAxes; @@ -400,14 +255,14 @@ enum ### General -Names should default to the English language and US spellings, to match the dominant conventiosn of contemporary open-source projects. +Names should default to the English language and US spellings, to match the dominant conventions of contemporary open-source projects. Function names should either be named with action verbs (`get`, `set`, `create`, `emit`, `parse`, etc.) or read as questions (`isEnabled`, `shouldEmit`, etc.). Whenever possible, compiler concepts should be named using the most widely-understood term available: e.g., we use `Token` over `Lexeme`, and `Lexer` over `Scanner` simply because they appear to be the more common names. Avoid abbreviations and initialisms unless they are already widely established across the codebase; a longer name may be cumbersome to write in the moment, but the code will probably be read many more times than it is written, so clarity should be preferred. -An important exception to this is common compiler concepts or techqniues which may have laboriously long names: e.g., Static Single Assignment (SSA), Sparse Conditional Copy Propagation (SCCP), etc. +An important exception to this is common compiler concepts or techniques which may have laboriously long names: e.g., Static Single Assignment (SSA), Sparse Conditional Copy Propagation (SCCP), etc. One gotcha particular to compiler front-ends is that almost every synonym for "type" has some kind of established technical meaning; most notably the term "kind" has a precise meaning that is relevant in our domain. It is common practice in C and C++ to define tagged union types with a selector field called a "type" or "kind," which does not usually match this technical definition. diff --git a/docs/design/decl-refs.md b/docs/design/decl-refs.md index 34b74a6f40..5c1958694e 100644 --- a/docs/design/decl-refs.md +++ b/docs/design/decl-refs.md @@ -25,7 +25,7 @@ Why do we need `DeclRef`s? -------------------------- In a compiler for a simple language, we might represent a reference to a declaration as simply a pointer to the AST node for the declaration, or some kind of handle/ID that references that AST node. -A reprsentation like that will work in simple cases, for example: +A representation like that will work in simple cases, for example: ```hlsl struct Cell { int value }; diff --git a/docs/design/existential-types.md b/docs/design/existential-types.md index 06e2613e3b..0f34690518 100644 --- a/docs/design/existential-types.md +++ b/docs/design/existential-types.md @@ -194,7 +194,7 @@ When dealing with a value type, though, we have to deal with things like making ``` interface IWritable { [mutating] void write(int val); } -stuct Cell : IWritable { int data; void write(int val) { data = val; } } +struct Cell : IWritable { int data; void write(int val) { data = val; } } T copyAndClobber(T obj) { diff --git a/docs/design/experimental.md b/docs/design/experimental.md new file mode 100644 index 0000000000..38707ab1c7 --- /dev/null +++ b/docs/design/experimental.md @@ -0,0 +1,74 @@ +Deploying Experimental API Additions +==================================== + +This page intends to provide guidance to Slang developers when extending the Slang API, particularly when working on experimental features. +It applies to the "COM-lite" Slang API, rather than the deprecated C Slang API (sp* functions). + +* Note: This guidance relates to Slang API changes, not to language changes. That is, what Slang does with shader source code across releases is not discussed here. + +The goal is to maintain binary compatibility as much as possible between Slang releases, and to aid applications in dealing with changes to Slang. + +Slang is distributed as a dynamic library, and there is an expectation from Slang API users that upgrading by installing an updated slang.dll or slang.so will not break their application unnecessarily. + +ABI compatibility within the Slang API can be preserved between releases if some rules are followed by developers. + +Slang API uses a "COM-lite" structure wherein functionality is exposed through interfaces on objects. If the interfaces never change, ABI compatibility is preserved, but changes happen. When adding or changing interfaces, please observe the following: + +1. It is preferred to create *new* COM interfaces when adding new functionality. +* This maintains ABI compatibility. +* Applications must acquire access to the new functionality using QueryInterface(), which will gracefully fail if the slang.dll/slang.so does not implement the functionality. + +2. Changes to existing virtual methods in COM interfaces should be avoided, as that is an ABI breakage. +* If a change is required though, change the interface's UUID. + +3. New virtual methods _may_ be added (only) to the end of existing COM interface structs. +* This does not disturb the ABI compatibility of the associated vtable. Old apps can remain unaware of the new function pointers appended to the end of the vtable. +* A UUID change is not necessary. +* Note that in the event that a Slang application which uses the added feature is run with an old slang.dll/slang.so, the experience for the user is not as clean as if the added method belongs to a new interface. + +Adding Experimental Interfaces +============================== + +When the above recommendations cannot be followed, as with features that are expected to be iterated on or are regarded as temporary, there are additional recommendations. + +Interfaces that are expected to change must be marked `_Experimental` in their class name and in their UUID name. + +For example, + + +```csharp +/* Experimental interface for doing something cool. This interface is susceptible to ABI breakage. */ +struct ICoolNewFeature_Experimental : public ISlangUnknown +{ + SLANG_COM_INTERFACE(0x8e12e8e3, 0x5fcd, 0x433e, { 0xaf, 0xcb, 0x13, 0xa0, 0x88, 0xbc, 0x5e, 0xe5 }) + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL coolMethod() = 0; +}; + +#define SLANG_UUID_ICoolNewFeature_Experimental ICoolNewFeature_Experimental::getTypeGuid() +``` + +Note: Use uuidgen to generate IIDs new interfaces. + +Removing Experimental Interfaces +================================ + +By the nature of being marked "Experimental", users have been warned that the interfaces are not officially supported and may be removed. You may simply delete the class and UUID, e.g. "ICoolNewFeature_Experimental" struct may be deleted from slang.h along with the definition of SLANG_UUID_ICoolNewFeature_Experimental. + +This will show up in applications as QueryInterface failures. + +It is nice, but not required, to retain the interface declarations for some time after removing internal support before deleting them from slang.h, so that applications have time to remove their dependence on the unsupported feature while still being able to compile in the interim. + +Changing Experimental Interfaces +================================ + +Backwards incompatible changes to Slang COM interfaces should be accompanied with a UUID change. + +In the event that an old application runs with a new slang library, applications are more capable of gracefully handling an unavailable interface than a changed one. The former may be still be functional, or include a helpful error message, whereas the latter is most likely a crash of some sort. + +Promoting Experimental Interfaces +================================= + +The class name and the UUID name should be changed in slang.h and in the slang source code, e.g. Rename "ICoolNewFeature_Experimental" to just "ICoolFeature". + +The SLANG_UUID for the interface should be renamed to omit "EXPERIMENTAL" but its value should remain the same. This is because, if there are no backwards incompatible changes that accompany the promotion from experimental to permanent, applications written against the experimental version can continue working against Slang libraries where the interface was promoted to permanent. diff --git a/docs/design/interfaces.md b/docs/design/interfaces.md index ce6e0be285..b0c4843274 100644 --- a/docs/design/interfaces.md +++ b/docs/design/interfaces.md @@ -13,7 +13,7 @@ Introduction The basic problem here is not unique to shader programming: you want to write code that accomplished one task, while abstracting over how to accomplish another task. As an example, we might want to write code to integrate incident radiance over a list of lights, while not concerning ourself with how to evaluate a reflectance function at each of those lights. -If we were doing this task on a CPU, and performance wasn't critical, we could probably handle this with higher-order functions or an equivalent mechansim like function pointers: +If we were doing this task on a CPU, and performance wasn't critical, we could probably handle this with higher-order functions or an equivalent mechanism like function pointers: float4 integrateLighting( Light[] lights, @@ -38,8 +38,8 @@ Depending on the scenario, we might be able to generate statically specialized c // ... } -Current shading langauges support neither higher-order functions nor templates/generics, so neither of these options is viable. -Instead practicioners typically use preprocessor techniques to either stich together the final code, or to substitute in different function/type definitions to make a definition like `integrateLighting` reusable. +Current shading languages support neither higher-order functions nor templates/generics, so neither of these options is viable. +Instead practitioners typically use preprocessor techniques to either stich together the final code, or to substitute in different function/type definitions to make a definition like `integrateLighting` reusable. These ad hoc approaches actually work well in practice; we aren't proposing to replace them *just* to make code abstractly "cleaner." Rather, we've found that the ad hoc approaches end up interacting poorly with the resource binding model in modern APIs, so that *something* less ad hoc is required to achieve our performance goals. @@ -48,7 +48,7 @@ At that point, we might as well ensure that the mechanism we introduce is also a Overview -------- -The baisc idea for our approach is as follows: +The basic idea for our approach is as follows: - Start with the general *semantics* of a generic-based ("template") approach @@ -63,7 +63,7 @@ Interfaces ---------- An **interface** in Slang is akin to a `protocol` in Swift or a `trait` in Rust. -The choice of the `interface` keyword is to hilight the overlap with the conceptually similar construct that appeared in Cg, and then later in HLSL. +The choice of the `interface` keyword is to highlight the overlap with the conceptually similar construct that appeared in Cg, and then later in HLSL. ### Declaring an interface @@ -163,7 +163,7 @@ That is intentional, because at the most basic level, interfaces are designed to ### Generic Declarations -The Slang compiler currently has some ad hoc support for generic declarations that it uses to implement the HLSL standard library (which has a few generic types). +The Slang compiler currently has some ad hoc support for generic declarations that it uses to implement the HLSL standard module (which has a few generic types). The syntax for those is currently very bad, and it makes sense to converge on the style for generic declarations used by C# and Swift: float myGenericFunc(T someValue); @@ -263,7 +263,7 @@ Then what should `BRDFParams` be? The two-parameter or six-parameter case? An **associated type** is a concept that solves exactly this problem. We don't care *what* the concrete type of `BRDFParams` is, so long as *every* implementation of `Material` has one. -The exact `BRDFParams` type can be different for each implementation of `Material`; the type is *assocaited* with a particular implementation. +The exact `BRDFParams` type can be different for each implementation of `Material`; the type is *associated* with a particular implementation. We will crib our syntax for this entirely from Swift, where it is verbose but explicit: @@ -276,7 +276,7 @@ We will crib our syntax for this entirely from Swift, where it is verbose but ex float3 evaluateBRDF(BRDFParams param, float3 wi, float3 wo); } -In this example we've added an assocaited type requirement so that every implementation of `Material` must supply a type named `BRDFParams` as a member. +In this example we've added an associated type requirement so that every implementation of `Material` must supply a type named `BRDFParams` as a member. We've also added a requirement that is a function to evaluate the BRDF given its parameters and incoming/outgoing directions. Using this declaration one can now define a generic function that works on any material: @@ -300,7 +300,7 @@ Some quick notes: - The use of `associatedtype` (for associated types) and `typealias` (for `typedef`-like definitions) as distinct keywords in Swift was well motivated by their experience (they used to use `typealias` for both). I would avoid having the two cases be syntactically identical. -- Swift has a pretty involved inference system where a type doesn't actually need to explicitly provide a type member with the chosen name. Instead, if you have a required method that takes or returns the assocaited type, then the compiler can infer what the type is by looking at the signature of the methods that meet other requirements. This is a complex and magical feature, and we shouldn't try to duplicate it. +- Swift has a pretty involved inference system where a type doesn't actually need to explicitly provide a type member with the chosen name. Instead, if you have a required method that takes or returns the associated type, then the compiler can infer what the type is by looking at the signature of the methods that meet other requirements. This is a complex and magical feature, and we shouldn't try to duplicate it. - Both Rust and Swift call this an "associated type." They are related to "virtual types" in things like Scala (which are in turn related to virtual classes in beta/gbeta). There are similar ideas that arise in Haskell-like languages with type classes (IIRC, the term "functional dependencies" is relevant). @@ -308,7 +308,7 @@ Some quick notes: I want to point out a few alternatives to the `Material` design above, just to show that associated types seem to be an elegant solution compared to the alternatives. -First, note that we could break `Material` into two interfaces, so long as we are allowed to place type constraints on assocaited types: +First, note that we could break `Material` into two interfaces, so long as we are allowed to place type constraints on associated types: interface BRDF { @@ -412,7 +412,7 @@ can in principle be desugared into: } with particular loss in what can be expressed. -The same desugaring appraoch should apply to global-scope functions that want to return an existential type (just with a global `typealias` instead of an `associatedtype`). +The same desugaring approach should apply to global-scope functions that want to return an existential type (just with a global `typealias` instead of an `associatedtype`). It might be inconvenient for the user to have to explicitly write the type-level expression that yields the result type (consider cases where C++ template metaprogrammers would use `auto` as a result type), but there is really no added power. @@ -434,12 +434,12 @@ The intent seems to be clear if we instead write: We could consider the latter to be sugar for the former, and allow users to write in familiar syntax akin to what ws already supported in Cg. -We'd have to be careful with such sugar, though, because there is a real and menaingful difference between saying: +We'd have to be careful with such sugar, though, because there is a real and meaningful difference between saying: - "`material` has type `Material` which is an interface type" - "`material` has type `M` where `M` implements `Material`" -In particular, if we start to work with assocaited types: +In particular, if we start to work with associated types: let b = material.evaluatePattern(...); diff --git a/docs/design/ir.md b/docs/design/ir.md index c7f4ffeb22..ba156c2f6c 100644 --- a/docs/design/ir.md +++ b/docs/design/ir.md @@ -15,7 +15,7 @@ We will start by enumerating these goals (and related non-goals) explicitly so t * As a particular case of analysis and optimization, it should be possible to validate flow-dependent properties of an input function/program (e.g., whether an `[unroll]` loop is actually unrollable) using the IR, and emit meaningful error messages that reference the AST-level names/locations of constructs involved in an error. -* It should be posible to compile modules to the IR separately and then "link" them in a way that depends only on IR-level (not AST-level) constructs. We want to allow changing implementation details of a module without forcing a re-compile of IR code using that module (what counts as "implementation details") is negotiable. +* It should be possible to compile modules to the IR separately and then "link" them in a way that depends only on IR-level (not AST-level) constructs. We want to allow changing implementation details of a module without forcing a re-compile of IR code using that module (what counts as "implementation details") is negotiable. * There should be a way to serialize IR modules in a round-trip fashion preserving all of the structure. As a long-term goal, the serialized format should provide stability across compiler versions (working more as an IL than an IR) @@ -81,7 +81,7 @@ The only exception to this rule is instructions that represent literal constants The in-memory encoding places a few more restrictions on top of this so that, e.g., currently an instruction can either have operands of children, but not both. -Because everything that could be used as an operand is also an instruction, the operands of an instruction are stored in a highly uniform way as a contiguous array of `IRUse` values (even the type is continguous with this array, so that it can be treated as an additional operand when required). +Because everything that could be used as an operand is also an instruction, the operands of an instruction are stored in a highly uniform way as a contiguous array of `IRUse` values (even the type is contiguous with this array, so that it can be treated as an additional operand when required). The `IRUse` type maintains explicit links for use-def information, currently in a slightly bloated fashion (there are well-known techniques for reducing the size of this information). ### A Class Hierarchy Mirrored in Opcodes @@ -112,7 +112,7 @@ The idea doesn't really start in Swift, but rather in the existing observation t Like Swift, we do not use an explicit CPS representation, but instead find a middle ground of a traditional SSA IR where instead of phi instructions basic blocks have parameters. The first N instructions in a Slang basic block are its parameters, each of which is an `IRParam` instruction. -A block that would have had N phi instrutions now has N parameters, but the parameters do not have operands. +A block that would have had N phi instructions now has N parameters, but the parameters do not have operands. Instead, a branch instruction that targets that block will have N *arguments* to match the parameters, representing the values to be assigned to the parameters when this control-flow edge is taken. This encoding is equivalent in what it represents to traditional phi instructions, but nicely solves the problems outlined above: @@ -123,7 +123,7 @@ This encoding is equivalent in what it represents to traditional phi instruction - There is no special work required to track which phi operands come from which predecessor block, since the operands are attached to the terminator instruction of the predecessor block itself. There is no need to update phi instructions after a CFG change that might affect the predecessor list of a block. The trade-off is that any change in the *number* of parameters of a block now requires changes to the terminator of each predecessor, but that is a less common change (isolated to passes that can introduce or eliminate block parameters/phis). -- It it much more clear how to give an operational semantics to a "branch with arguments" instead of phi instructions: compute the target block, copy the argumenst to temporary storage (because of the simultaneity requirement), and then copy the temporaries over the parameters of the target block. +- It it much more clear how to give an operational semantics to a "branch with arguments" instead of phi instructions: compute the target block, copy the arguments to temporary storage (because of the simultaneity requirement), and then copy the temporaries over the parameters of the target block. The main caveat of this representation is that it requires branch instructions to have room for arguments to the target block. For an ordinary unconditional branch this is pretty easy: we just put a variable number of arguments after the operand for the target block. For branch instructions like a two-way conditional, we might need to encode two argument lists - one for each target block - and an N-way `switch` branch only gets more complicated. @@ -138,7 +138,7 @@ This constraint could be lifted at some point, but it is important to note that A traditional SSA IR represents a function as a bunch of basic blocks of instructions, where each block ends in a *terminator* instruction. Terminators are instructions that can branch to another block, and are only allowed at the end of a block. The potential targets of a terminator determine the *successors* of the block where it appears, and contribute to the *predecessors* of any target block. -The succesor-to-predecessor edges form a graph over the basic blocks called the control-flow graph (CFG). +The successor-to-predecessor edges form a graph over the basic blocks called the control-flow graph (CFG). A simple representation of a function would store the CFG explicitly as a graph data structure, but in that case the data structure would need to be updated whenever a change is made to the terminator instruction of a branch in a way that might change the successor/predecessor relationship. diff --git a/docs/design/overview.md b/docs/design/overview.md index 7c2b16cf3c..24c3160386 100644 --- a/docs/design/overview.md +++ b/docs/design/overview.md @@ -11,7 +11,7 @@ Compilation is always performed in the context of a *compile request*, which bun Inside the code, there is a type `CompileRequest` to represent this. The user specifies some number of *translation units* (represented in the code as a `TranslationUnitRequest`) which comprise some number of *sources* (files or strings). -HLSL follows the traditional C model where a "translaiton unit" is more or less synonymous with a source file, so when compiling HLSL code the command-line `slangc` will treat each source file as its own translation unit. +HLSL follows the traditional C model where a "translation unit" is more or less synonymous with a source file, so when compiling HLSL code the command-line `slangc` will treat each source file as its own translation unit. For Slang code, the command-line tool will by default put all source files into a single translation unit (so that they represent a shared namespace0). The user can also specify some number of *entry points* in each translation unit (`EntryPointRequest`), which combines the name of a function to compile with the pipeline stage to compile for. @@ -23,7 +23,7 @@ It might not be immediately clear why we have such fine-grained concepts as this The "Front End" --------------- -The job of the Slang front-end is to turn textual source code into a combination of code in our custom intermediate represnetation (IR) plus layout and binding information for shader parameters. +The job of the Slang front-end is to turn textual source code into a combination of code in our custom intermediate representation (IR) plus layout and binding information for shader parameters. ### Lexing @@ -60,7 +60,7 @@ The parser (`Parser` in `parser.{h,cpp}`) is mostly a straightforward recursive- Because the input is already tokenized before we start, we can use arbitrary lookahead, although we seldom look ahead more than one token. Traditionally, parsing of C-like languages requires context-sensitive parsing techniques to distinguish types from values, and deal with stuff like the C++ "most vexing parse." -Slang instead uses heuristic approaches: for example, when we encouter an `<` after an identifier, we first try parsing a generic argument list with a closing `>` and then look at the next token to determine if this looks like a generic application (in which case we continue from there) or not (in which case we backtrack). +Slang instead uses heuristic approaches: for example, when we encounter an `<` after an identifier, we first try parsing a generic argument list with a closing `>` and then look at the next token to determine if this looks like a generic application (in which case we continue from there) or not (in which case we backtrack). There are still some cases where we use lookup in the current environment to see if something is a type or a value, but officially we strive to support out-of-order declarations like most modern languages. In order to achieve that goal we will eventually move to a model where we parse the bodies of declarations and functions in a later pass, after we have resolved names in the global scope. @@ -71,7 +71,7 @@ This means that most of the language "keywords" in Slang aren't keywords at all, Syntax declarations are associated with a callback that is invoked to parse the construct they name. The design of treating syntax as ordinary declarations has a long-term motivation (we'd like to support a flexible macro system) but it also has short-term practical benefits. -It is easy for us to add new modifier keywords to the language without touching the lexer or parser (just adding them to the standard library), and we also don't have to worry about any of Slang's extended construct (e.g., `import`) breaking existing HLSL code that just happens to use one of those new keywords as a local variable name. +It is easy for us to add new modifier keywords to the language without touching the lexer or parser (just adding them to the core module), and we also don't have to worry about any of Slang's extended construct (e.g., `import`) breaking existing HLSL code that just happens to use one of those new keywords as a local variable name. What the parser produces is an abstract syntax tree (AST). The AST currently uses a strongly-typed C++ class hierarchy with a "visitor" API generated via some ugly macro magic. @@ -97,7 +97,7 @@ An expression that ends up referring to a type will have a `TypeType` as its typ The most complicated thing about semantic checking is that we strive to support out-of-order declarations, which means we may need to check a function declaration later in the file before checking a function body early in the file. In turn, that function declaration might depend on a reference to a nested type declared somewhere else, etc. -We currently solve this issue by doing some amount of on-demand checking; when we have a reference to a function declaration and we need to know its type, we will first check if the function has been through semantic checking yet, and if not we will go ahead and recurisvely type check that function before we proceed. +We currently solve this issue by doing some amount of on-demand checking; when we have a reference to a function declaration and we need to know its type, we will first check if the function has been through semantic checking yet, and if not we will go ahead and recursively type check that function before we proceed. This kind of unfounded recursion can lead to real problems (especially when the user might write code with circular dependencies), so we have made some attempts to more strictly "phase" the semantic checking, but those efforts have not yet been done systematically. @@ -105,7 +105,7 @@ When code involved generics and/or interfaces, the semantic checking phase is re ### Lowering and Mandatory Optimizations -The lowering step (`lower-to-ir.{h,cpp}`) is responsible for converting semantically valid ASTs into an intermediate representation that is more suitable for specialization, optimization, and code generaton. +The lowering step (`lower-to-ir.{h,cpp}`) is responsible for converting semantically valid ASTs into an intermediate representation that is more suitable for specialization, optimization, and code generation. The main thing that happens at this step is that a lot of the "sugar" in a high-level language gets baked out. For example: - A "member function" in a type will turn into an ordinary function that takes an initial `this` parameter @@ -116,29 +116,29 @@ The main thing that happens at this step is that a lot of the "sugar" in a high- The lowering step is done once for each translation unit, and like semantic checking it does *not* depend on any particular compilation target. During this step we attach "mangled" names to any imported or exported symbols, so that each function overload, etc. has a unique name. -After IR code has been generated for a translation unit (now called a "module") we next perform a set of "mandatory" optimizations, including SSA promotion and simple copy propagation and elmination of dead control-flow paths. +After IR code has been generated for a translation unit (now called a "module") we next perform a set of "mandatory" optimizations, including SSA promotion and simple copy propagation and elimination of dead control-flow paths. These optimizations are not primarily motivated by a desire to speed up code, but rather to ensure that certain "obvious" simplifications have been performed before the next step of validation. After the IR has been "optimized" we perform certain validation/checking tasks that would have been difficult or impossible to perform on the AST. For example, we can validate that control flow never reached the end of a non-`void` function, and issue an error otherwise. There are other validation tasks that can/should be performed at this step, although not all of them are currently implemented: -- We should check that any `[unroll]` loops can actually be unrolled, by ensuring tha their termination conditions can be resolved to a compile-time constant (even if we don't know the constant yet) +- We should check that any `[unroll]` loops can actually be unrolled, by ensuring that their termination conditions can be resolved to a compile-time constant (even if we don't know the constant yet) - We should check that any resource types are being used in ways that can be statically resolved (e.g., that the code never conditionally computes a resource to reference), since this is a requirement for all our current targets -- We should check that the operands to any operation that requires a compile-time constant (e.g., the texel offset argument to certain `Sample()` calls) are passed values that end up being compile-time cosntants +- We should check that the operands to any operation that requires a compile-time constant (e.g., the texel offset argument to certain `Sample()` calls) are passed values that end up being compile-time constants The goal is to eliminate any possible sources of failure in low-level code generation, without needing to have a global view of all the code in a program. Any error conditions we have to push off until later starts to limit the value of our separate compilation support. ### Parameter Binding and Type Layout -The next phase of parameter binding (`parameter-binding.{h,cpp}`) is independednt of IR generation, and proceeds based on the AST that came out of semantic checking. +The next phase of parameter binding (`parameter-binding.{h,cpp}`) is independent of IR generation, and proceeds based on the AST that came out of semantic checking. Parameter binding is the task of figuring out what locations/bindings/offsets should be given to all shader parameters referenced by the user's code. Parameter binding is done once for each target (because, e.g., Vulkan may bind parameters differently than D3D12), and it is done for the whole compile request (all translation units) rather than one at a time. -This is because when users compile something like HLSL vertex and fragment shaders in distinct translation units, they will often share the "same" parameter via a header, and we need to ensure that it gets just one locaton. +This is because when users compile something like HLSL vertex and fragment shaders in distinct translation units, they will often share the "same" parameter via a header, and we need to ensure that it gets just one location. At a high level, parameter binding starts by computing the *type layout* of each shader parameter. A type layout describes the amount of registers/bindings/bytes/etc. that a type consumes, and also encodes the information needed to compute offsets/registers for individual `struct` fields or array elements. @@ -186,11 +186,11 @@ We make a copy of things so that any optimization/transformation passes we do fo While copying IR code into the fresh module, we have cases where there might be multiple definitions of the same function or other entity. In those cases, we apply "target specialization" to pick the definition that is the best for the chosen target. -This step is where we can select between, say, a built-in definition of the `saturate` function for D3D targets, vs. a hand-written one in the Slang standard library to use for GLSL-based targets. +This step is where we can select between, say, a built-in definition of the `saturate` function for D3D targets, vs. a hand-written one in a Slang standard module to use for GLSL-based targets. ### API Legalization -If we are targetting a GLSL-based platform, we need to translate "varying" shader entry point parameters into global variables used for cross-stage data passing. +If we are targeting a GLSL-based platform, we need to translate "varying" shader entry point parameters into global variables used for cross-stage data passing. We also need to translate any "system value" semantics into uses of the special built-in `gl_*` variables. We currently handle this kind of API-specific legalization quite early in the process, performing it right after linking. @@ -208,7 +208,7 @@ At the end of specialization, we should have code that makes no use of user-defi ### Type Legalization While HLSL and Slang allow a single `struct` type to contain both "ordinary" data like a `float3` and "resources" like a `Texture2D`, the rules for GLSL and SPIR-V are more restrictive. -Ther are some additional wrinkles that arise for such "mixed" types, so we prefer to always "legalize" the types in the users code by replacing an aggregate type like: +There are some additional wrinkles that arise for such "mixed" types, so we prefer to always "legalize" the types in the users code by replacing an aggregate type like: ```hlsl struct Material { float4 baseColor; Texture2D detailMap; }; @@ -230,7 +230,7 @@ Changing the "shape" of a type like this (so that a single variable becomes more We dont' currently apply many other optimizations on the IR code in the back-end, under the assumption that the lower-level compilers below Slang will do some of the "heavy lifting." -That said, there are certain optimizations that Slang must do eventually, for semantic completeness. One of the most important examples of these is implementing the sematncis of the `[unroll]` attribute, since we can't always rely on downstream compilers to have a capable unrolling implementation. +That said, there are certain optimizations that Slang must do eventually, for semantic completeness. One of the most important examples of these is implementing the semantics of the `[unroll]` attribute, since we can't always rely on downstream compilers to have a capable unrolling implementation. We expect that over time it will be valuable for Slang to support a wider array of optimization passes, as long as they are ones that are considered "safe" to do above the driver interface, because they won't interfere with downstream optimization opportunities. diff --git a/docs/design/semantic-checking.md b/docs/design/semantic-checking.md index 0617aa0ab2..10ddd51426 100644 --- a/docs/design/semantic-checking.md +++ b/docs/design/semantic-checking.md @@ -22,7 +22,7 @@ Checking Terms ### Some Terminology for Terms -We use the word "term" to refer genericaly to something that can be evaluated to produce a result, but where we do not yet know if the result will be a type or a value. For example, `Texture2D` might be a term that results in a type, while `main` might be a term that results in a value (of function type), but both start out as a `NameExpr` in the AST. Thus the AST uses the class hierarchy under `Expr` to represent terms, whether they evaluate to values or types. +We use the word "term" to refer generically to something that can be evaluated to produce a result, but where we do not yet know if the result will be a type or a value. For example, `Texture2D` might be a term that results in a type, while `main` might be a term that results in a value (of function type), but both start out as a `NameExpr` in the AST. Thus the AST uses the class hierarchy under `Expr` to represent terms, whether they evaluate to values or types. There is also the `Type` hierarchy, but it is important to understand that `Type` represents types as their logical immutable selves, while `Expr`s that evaluate to types are *type expressions* which can be concretely pointed to in the user's code. Type expressions have source locations, because they represent something the user wrote in their code, while `Type`s don't have singular locations by default. @@ -67,7 +67,7 @@ If we can't reasonably form an expression to return *at all* then we will return These classes are designed to make sure that subsequent code won't crash on them (since we have non-null objects), but to help avoid cascading errors. Some semantic checking logic will detect `ErrorType`s on sub-expressions and skip its own checking logic (e.g., this happens for function overload resolution), producing an `ErrorType` further up. In other cases, expressions with `ErrorType` can be silently consumed. -For example, an errorneous expression is implicitly convertible to *any* type, which means that assignment of an error expression to a local variable will always succeed, regardless of variable's type. +For example, an erroneous expression is implicitly convertible to *any* type, which means that assignment of an error expression to a local variable will always succeed, regardless of variable's type. ### Overload Resolution @@ -139,14 +139,14 @@ Checking of declarations is the most complicated and involved part of semantic c Simple approaches to semantic checking of declarations fall into two camps: -1. One can define a total ordering on declarations (usually textual order in the source file) and only allow dependecies to follow that order, so that checking can follow the same order. This is the style of C/C++, which is inherited from the legacy of traditional single-pass compilers. +1. One can define a total ordering on declarations (usually textual order in the source file) and only allow dependencies to follow that order, so that checking can follow the same order. This is the style of C/C++, which is inherited from the legacy of traditional single-pass compilers. 2. One can define a total ordering on *phases* of semantic checking, so that every declaration in the file is checked at phase N before any is checked at phase N+1. E.g., the types of all variables and functions must be determined before any expressions that use those variables/functions can be checked. This is the style of, e.g., Java and C#, which put a premium on defining context-free languages that don't dictate order of declaration. Slang tries to bridge these two worlds: it has inherited features from HLSL that were inspired by C/C++, while it also strives to support out-of-order declarations like Java/C#. -Unsurprisngly, this leads to unique challenges. +Unsurprisingly, this leads to unique challenges. -Supporting out-of-order declarations meeans that there is no simple total order on declarations (we can have mutually recursive function or type declarations), and supporting generics with value parameters means there is no simple total order on phases. +Supporting out-of-order declarations means that there is no simple total order on declarations (we can have mutually recursive function or type declarations), and supporting generics with value parameters means there is no simple total order on phases. For that last part observe that: * Resolving an overloaded function call requires knowing the types of the parameters for candidate functions. @@ -191,13 +191,13 @@ As a programmer contributing to the semantic checking infrastructure, the declar Name Lookup ----------- -Lookup is the processing of resolving the contextual meaning of names either in a lexical scope (e.g., the user wrote `foo` in a function body - what does it refer to?) or in the scope of scome type (e.g., the user wrote `obj.foo` for some value `obj` of type `T` - what does it refer to?). +Lookup is the processing of resolving the contextual meaning of names either in a lexical scope (e.g., the user wrote `foo` in a function body - what does it refer to?) or in the scope of some type (e.g., the user wrote `obj.foo` for some value `obj` of type `T` - what does it refer to?). Lookup can be tied to semantic analysis quite deeply. In order to know what a member reference like `obj.foo` refers to, we not only need to know the type of `obj`, but we may also need to know what interfaces that type conforms to (e.g., it might be a type parameter `T` with a constraint `T : IFoo`). In order to support lookup in the presence of our declaration-checking strategy described above, the lookup logic may be passed a `SemanticsVisitor` that it can use to `ensureDecl()` declarations before it relies on their properties. -However, lookup also currently gets used during parsing, and in those cases it may need ot be applied without access to the semantics-checking infrastructure (since we currently separate parsing and semantic analysis). +However, lookup also currently gets used during parsing, and in those cases it may need to be applied without access to the semantics-checking infrastructure (since we currently separate parsing and semantic analysis). In those cases a null `SemanticsVisitor` is passed in, and the lookup process will avoid using lookup approaches that rely on derived semantic information. This is fine in practice because the main thing that gets looked up during parsing are names of `SyntaxDecl`s (which are all global) and also global type/function/variable names. @@ -210,7 +210,7 @@ Just like a C/C++ parser, the Slang parser sometimes needs to disambiguate wheth Ideally the way forward is some combination of the following two strategies: -* We should strive to make parsing at the "global scope" fully context-insensitive (e.g., by using similar lookahead heuristics to C#). We are already close to this goal today, but will need to be careful that we do not introduce regressions compared to the old parser (perhaps a "compatiblity" mode for legacy HLSL code is needed?) +* We should strive to make parsing at the "global scope" fully context-insensitive (e.g., by using similar lookahead heuristics to C#). We are already close to this goal today, but will need to be careful that we do not introduce regressions compared to the old parser (perhaps a "compatibility" mode for legacy HLSL code is needed?) * We should delay the parsing of nested scopes (both function and type bodies bracketed with `{}`) until later steps of the compiler. Ideally, parsing of function bodies can be done in a context-sensitive manner that interleaves with semantic checking, closer to the traditional C/C++ model (since we don't care about out-of-order declarations in function bodies). diff --git a/docs/design/serialization.md b/docs/design/serialization.md index 1f69eb61d7..008fd6da6c 100644 --- a/docs/design/serialization.md +++ b/docs/design/serialization.md @@ -24,7 +24,7 @@ We could imagine a mechanism that saved off each instance, by writing off the ad * If we try to read back on a different machine, with a different pointer size, the object layout will be incompatible * If we try to read back on the same machine where the source is compiled by a different compiler, the object layout might be incompatible (say bool or enum are different size) -* Endianess might be different +* Endianness might be different * Knowing where all the pointers are and what they point to and therefore what to serialize is far from simple. * The alignment of types might be different across different processors and different compilers @@ -268,7 +268,7 @@ AST Serialization AST serialization uses the generalized serialization mechanism. -When serializing out an AST module it is typical to want to just serialize out the definitions within that module. Without this, the generalized serializer will crawl over the whole of the AST structure serializing every thing that can be reached - including the whole of the standard library. +When serializing out an AST module it is typical to want to just serialize out the definitions within that module. Without this, the generalized serializer will crawl over the whole of the AST structure serializing every thing that can be reached - including the whole of the core module. The filter `ModuleSerialFilter` can be used when writing the AST module, it will replace any references to elements outside of the current module with a `ImportExternalDecl`. This contains a mangled name to the item being referenced in another module. @@ -304,7 +304,7 @@ Riff Container [Riff](https://en.wikipedia.org/wiki/Resource_Interchange_File_Format) is used as a mechanism to store binary sections. The format allows for a hierarchy of `chunks` that hold binary data. How the data is interpreted depends on the [FOURCC](https://en.wikipedia.org/wiki/FourCC) associated with each chunk. -As previously touched on there are multiple different mechanisms used for serialization. IR serialization, generalized serialization, SourceLoc serialization - there are also other uses, such as serializing of entry point information. Riff is used to combine all of these incompatible binary parts togther such that they can be stored together. +As previously touched on there are multiple different mechanisms used for serialization. IR serialization, generalized serialization, SourceLoc serialization - there are also other uses, such as serializing of entry point information. Riff is used to combine all of these incompatible binary parts together such that they can be stored together. The handling of these riff containers is held within the `SerialContainerUtil` class. @@ -328,4 +328,4 @@ Issues * All types (and typedefs) that are serialized must be defined in the same scope - child types don't work correctly * When using value serialization serialization all the members that are serializable must be public -* The types output in slang fields do not correctly take into account scope (this is a similar issue to the issue above) \ No newline at end of file +* The types output in slang fields do not correctly take into account scope (this is a similar issue to the issue above) diff --git a/docs/design/stdlib-intrinsics.md b/docs/design/stdlib-intrinsics.md index 8d78de504a..a9369138db 100644 --- a/docs/design/stdlib-intrinsics.md +++ b/docs/design/stdlib-intrinsics.md @@ -1,17 +1,17 @@ -Stdlib Intrinsics -================= +Core Module Intrinsics +====================== -The following document aims to cover a variety of systems used to add target specific features. They are most extensively used in the slang standard library (stdlib). +The following document aims to cover a variety of systems used to add target specific features. They are most extensively used in the slang core module. **NOTE!** These features should *not* be considered stable! They can be used in regular slang code to add features, but they risk breaking with any Slang version change. Additionally the features implementation can be very particular to what is required for a specific feature set, so might not work as expected in all scenarios. As these features are in flux, it is quite possible this document is behind the current features available within the Slang code base. -If you want to add support for a feature for a target to Slang, implementing it as part of the Slang standard library is typically a good way to progress. Depending on the extension/feature it may not be possible to add support exclusively via changes to the standard library alone. That said most support for target specific extensions and features involve at least some changes to the slang standard library, and typically using the mechanisms described here. +If you want to add support for a feature for a target to Slang, implementing it as a part of the Slang standard modules is typically a good way to progress. Depending on the extension/feature it may not be possible to add support exclusively via changes to the standard module alone. That said most support for target specific extensions and features involve at least some changes to the slang standard modules including the core module, and typically using the mechanisms described here. -## Standard Library +## Core Module -The main place these features are used are within the slang standard library (aka stdlib). This is implemented with a set of slang files within the slang project +The main place these features are used are within the slang core module. This is implemented with a set of slang files within the slang project * core.meta.slang * hlsl.meta.slang @@ -21,7 +21,7 @@ Looking at these files will demonstrate the features in use. Most of the intrinsics and attributes have names that indicate that they are not for normal use. This is typically via a `__` prefix. -The `.meta.slang` files look largely like Slang source files, but their contents can also be generated programatically with C++ code. A section of code can drop into `C++` code if it is proceeded by `${{{{`. The C++ section is closed with a closing `}}}}`. This mechanism is typically used to generate different versions of a similar code sequence. Values from the C++ code can be accessed via the `$()`, where the contents of the brackets specifies something that can be calculated from within the C++ code. +The `.meta.slang` files look largely like Slang source files, but their contents can also be generated programmatically with C++ code. A section of code can drop into `C++` code if it is proceeded by `${{{{`. The C++ section is closed with a closing `}}}}`. This mechanism is typically used to generate different versions of a similar code sequence. Values from the C++ code can be accessed via the `$()`, where the contents of the brackets specifies something that can be calculated from within the C++ code. As an example, to produce an an array with values 0 to 9 we could write... @@ -146,7 +146,7 @@ Used before a type declaration. The clsName is the name of the class that is use Used to specify the IR opcode associated with a type. The IR opcode is listed as something like `$(kIROp_HLSLByteAddressBufferType)`, which will expand to the integer value of the opcode (because the opcode value is an enum value that is visible from C++). It is possible to just write the opcode number, but that is generally inadvisable as the ids for ops are not stable. If a code change in Slang C++ adds or removes an opcode the number is likely to be incorrect. -As an example from stdlib +As an example from the core module ```slang __magic_type(HLSLByteAddressBufferType) diff --git a/docs/doc-system.md b/docs/doc-system.md index 56635e4ed9..d552bf1e4c 100644 --- a/docs/doc-system.md +++ b/docs/doc-system.md @@ -85,10 +85,10 @@ Currently the Slang doc system does not support any of the 'advanced' doxygen do Currently the only documentation style supported is a single file 'markdown' output. Future versions will support splitting into multiple files and linking between them. Also future versions may also support other documentation formats/standards. -It is possible to generate documentation for Slangs internal `stdlib`. This can be achieved with `slangc` via +It is possible to generate documentation for the slang core module. This can be achieved with `slangc` via ``` -slangc -doc -compile-stdlib +slangc -doc -compile-core-module ``` The documentation will be written to a file `stdlib-doc.md`. diff --git a/docs/faq.md b/docs/faq.md index 5f021d7d09..824d99679c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -34,7 +34,7 @@ The implementation of Slang has so far focused heavily on the needs of Falcor. ### Won't we all just be using C/C++ for shaders soon? -The great thing about both Vulkan and D3D12 moving to publicly-documented binary intermediate langugaes (SPIR-V and DXIL, respectively) is that there is plenty of room for language innovation on top of these interfaces. +The great thing about both Vulkan and D3D12 moving to publicly-documented binary intermediate languages (SPIR-V and DXIL, respectively) is that there is plenty of room for language innovation on top of these interfaces. Having support for writing GPU shaders in a reasonably-complete C/C++ language would be great. We are supportive of efforts in the "C++ for shaders" direction. diff --git a/docs/gfx-user-guide/01-getting-started.md b/docs/gfx-user-guide/01-getting-started.md index 41b9738f68..ae270450ac 100644 --- a/docs/gfx-user-guide/01-getting-started.md +++ b/docs/gfx-user-guide/01-getting-started.md @@ -136,7 +136,7 @@ SLANG_RETURN_ON_FAIL(device->createBufferResource( Creating a Pipeline State --------------------------- -A pipeline state object encapsulates the shader program to execute on the GPU device, as well as other fix function states for graphics rendering. In this example, we will be compiling and runing a simple compute shader written in Slang. To do that we need to create a compute pipeline state from a Slang `IComponentType`. We refer the reader to the (Slang getting started tutorial)[../user-guide/01-getting-started.html] on how to create a Slang `IComponentType` from a shader file. The following source creates a Graphics layer `IPipelineState` object from a shader module represented by a `slang::IComponentType` object: +A pipeline state object encapsulates the shader program to execute on the GPU device, as well as other fix function states for graphics rendering. In this example, we will be compiling and running a simple compute shader written in Slang. To do that we need to create a compute pipeline state from a Slang `IComponentType`. We refer the reader to the (Slang getting started tutorial)[../user-guide/01-getting-started.html] on how to create a Slang `IComponentType` from a shader file. The following source creates a Graphics layer `IPipelineState` object from a shader module represented by a `slang::IComponentType` object: ```cpp void createComputePipelineFromShader( @@ -261,4 +261,4 @@ buffer0View->release(); gDevice->release(); ``` -The order of calls to `release` does not matter, as long as all objects are released from the user. \ No newline at end of file +The order of calls to `release` does not matter, as long as all objects are released from the user. diff --git a/docs/gfx-user-guide/unsupported-formats.md b/docs/gfx-user-guide/unsupported-formats.md index 54fd1a0f16..f93567a950 100644 --- a/docs/gfx-user-guide/unsupported-formats.md +++ b/docs/gfx-user-guide/unsupported-formats.md @@ -1,263 +1,266 @@ Unsupported Formats ====================== -GFX currently does not support the following listed D3D and Vulkan formats. With the exception of D24_UNORM_S8_UINT, these formats have been omitted as their counterpart API does not have a corresponding format. D24_UNORM_S8_UINT has been omitted as it is only supported by Nvidia. -DXGI_FORMAT_R32G8X24_TYPELESS \ -DXGI_FORMAT_D32_FLOAT_S8X24_UINT \ -DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS \ -DXGI_FORMAT_X32_TYPELESS_G8X24_UINT \ -DXGI_FORMAT_R24G8_TYPELESS \ -DXGI_FORMAT_D24_UNORM_S8_UINT \ -DXGI_FORMAT_R24_UNORM_X8_TYPELESS \ -DXGI_FORMAT_X24_TYPELESS_G8_UINT \ -DXGI_FORMAT_A8_UNORM \ -DXGI_FORMAT_R1_UNORM \ -DXGI_FORMAT_R8G8_B8G8_UNORM \ -DXGI_FORMAT_G8R8_G8B8_UNORM \ -DXGI_FORMAT_BC1_TYPELESS \ -DXGI_FORMAT_BC2_TYPELESS \ -DXGI_FORMAT_BC3_TYPELESS \ -DXGI_FORMAT_BC4_TYPELESS \ -DXGI_FORMAT_BC5_TYPELESS \ -DXGI_FORMAT_B8G8R8X8_UNORM \ -DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM \ -DXGI_FORMAT_B8G8R8X8_TYPELESS \ -DXGI_FORMAT_B8G8R8X8_UNORM_SRGB \ -DXGI_FORMAT_BC6H_TYPELESS \ -DXGI_FORMAT_BC7_TYPELESS \ -DXGI_FORMAT_AYUV \ -DXGI_FORMAT_Y410 \ -DXGI_FORMAT_Y416 \ -DXGI_FORMAT_NV12 \ -DXGI_FORMAT_P010 \ -DXGI_FORMAT_P016 \ -DXGI_FORMAT_420_OPAQUE \ -DXGI_FORMAT_YUY2 \ -DXGI_FORMAT_Y210 \ -DXGI_FORMAT_Y216 \ -DXGI_FORMAT_NV11 \ -DXGI_FORMAT_AI44 \ -DXGI_FORMAT_IA44 \ -DXGI_FORMAT_P8 \ -DXGI_FORMAT_A8P8 \ -DXGI_FORMAT_P208 \ -DXGI_FORMAT_V208 \ -DXGI_FORMAT_V408 \ -DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE \ -DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE \ +GFX currently does not support the following listed D3D and Vulkan formats. +With the exception of `D24_UNORM_S8_UINT`, these formats have been omitted as +their counterpart API does not have a corresponding format. `D24_UNORM_S8_UINT` +has been omitted as it is only supported by Nvidia. -VK_FORMAT_R4G4_UNORM_PACK8 \ -VK_FORMAT_R4G4B4A4_UNORM_PACK16 \ -VK_FORMAT_B4G4R4A4_UNORM_PACK16 \ -VK_FORMAT_B5G6R5_UNORM_PACK16 \ -VK_FORMAT_R5G5B5A1_UNORM_PACK16 \ -VK_FORMAT_B5G5R5A1_UNORM_PACK16 \ -VK_FORMAT_R8_USCALED \ -VK_FORMAT_R8_SSCALED \ -VK_FORMAT_R8_SRGB \ -VK_FORMAT_R8G8_USCALED \ -VK_FORMAT_R8G8_SSCALED \ -VK_FORMAT_R8G8_SRGB \ -VK_FORMAT_R8G8B8_UNORM \ -VK_FORMAT_R8G8B8_SNORM \ -VK_FORMAT_R8G8B8_USCALED \ -VK_FORMAT_R8G8B8_SSCALED \ -VK_FORMAT_R8G8B8_UINT \ -VK_FORMAT_R8G8B8_SINT \ -VK_FORMAT_R8G8B8_SRGB \ -VK_FORMAT_B8G8R8_UNORM \ -VK_FORMAT_B8G8R8_SNORM \ -VK_FORMAT_B8G8R8_USCALED \ -VK_FORMAT_B8G8R8_SSCALED \ -VK_FORMAT_B8G8R8_UINT \ -VK_FORMAT_B8G8R8_SINT \ -VK_FORMAT_B8G8R8_SRGB \ -VK_FORMAT_R8G8B8A8_USCALED \ -VK_FORMAT_R8G8B8A8_SSCALED \ -VK_FORMAT_B8G8R8A8_SNORM \ -VK_FORMAT_B8G8R8A8_USCALED \ -VK_FORMAT_B8G8R8A8_SSCALED \ -VK_FORMAT_B8G8R8A8_UINT \ -VK_FORMAT_B8G8R8A8_SINT \ -VK_FORMAT_A8B8G8R8_UNORM_PACK32 \ -VK_FORMAT_A8B8G8R8_SNORM_PACK32 \ -VK_FORMAT_A8B8G8R8_USCALED_PACK32 \ -VK_FORMAT_A8B8G8R8_SSCALED_PACK32 \ -VK_FORMAT_A8B8G8R8_UINT_PACK32 \ -VK_FORMAT_A8B8G8R8_SINT_PACK32 \ -VK_FORMAT_A8B8G8R8_SRGB_PACK32 \ -VK_FORMAT_A2R10G10B10_UNORM_PACK32 \ -VK_FORMAT_A2R10G10B10_SNORM_PACK32 \ -VK_FORMAT_A2R10G10B10_USCALED_PACK32 \ -VK_FORMAT_A2R10G10B10_SSCALED_PACK32 \ -VK_FORMAT_A2R10G10B10_UINT_PACK32 \ -VK_FORMAT_A2R10G10B10_SINT_PACK32 \ -VK_FORMAT_A2B10G10R10_SNORM_PACK32 \ -VK_FORMAT_A2B10G10R10_USCALED_PACK32 \ -VK_FORMAT_A2B10G10R10_SSCALED_PACK32 \ -VK_FORMAT_A2B10G10R10_SINT_PACK32 \ -VK_FORMAT_R16_USCALED \ -VK_FORMAT_R16_SSCALED \ -VK_FORMAT_R16G16_USCALED \ -VK_FORMAT_R16G16_SSCALED \ -VK_FORMAT_R16G16B16_UNORM \ -VK_FORMAT_R16G16B16_SNORM \ -VK_FORMAT_R16G16B16_USCALED \ -VK_FORMAT_R16G16B16_SSCALED \ -VK_FORMAT_R16G16B16_UINT \ -VK_FORMAT_R16G16B16_SINT \ -VK_FORMAT_R16G16B16_SFLOAT \ -VK_FORMAT_R16G16B16A16_USCALED \ -VK_FORMAT_R16G16B16A16_SSCALED \ -VK_FORMAT_R64_UINT \ -VK_FORMAT_R64_SINT \ -VK_FORMAT_R64_SFLOAT \ -VK_FORMAT_R64G64_UINT \ -VK_FORMAT_R64G64_SINT \ -VK_FORMAT_R64G64_SFLOAT \ -VK_FORMAT_R64G64B64_UINT \ -VK_FORMAT_R64G64B64_SINT \ -VK_FORMAT_R64G64B64_SFLOAT \ -VK_FORMAT_R64G64B64A64_UINT \ -VK_FORMAT_R64G64B64A64_SINT \ -VK_FORMAT_R64G64B64A64_SFLOAT \ -VK_FORMAT_X8_D24_UNORM_PACK32 \ -VK_FORMAT_S8_UINT \ -VK_FORMAT_D16_UNORM_S8_UINT \ -VK_FORMAT_D24_UNORM_S8_UINT \ -VK_FORMAT_D32_SFLOAT_S8_UINT \ -VK_FORMAT_BC1_RGB_UNORM_BLOCK \ -VK_FORMAT_BC1_RGB_SRGB_BLOCK \ -VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK \ -VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK \ -VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK \ -VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK \ -VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK \ -VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK \ -VK_FORMAT_EAC_R11_UNORM_BLOCK \ -VK_FORMAT_EAC_R11_SNORM_BLOCK \ -VK_FORMAT_EAC_R11G11_UNORM_BLOCK \ -VK_FORMAT_EAC_R11G11_SNORM_BLOCK \ -VK_FORMAT_ASTC_4x4_UNORM_BLOCK \ -VK_FORMAT_ASTC_4x4_SRGB_BLOCK \ -VK_FORMAT_ASTC_5x4_UNORM_BLOCK \ -VK_FORMAT_ASTC_5x4_SRGB_BLOCK \ -VK_FORMAT_ASTC_5x5_UNORM_BLOCK \ -VK_FORMAT_ASTC_5x5_SRGB_BLOCK \ -VK_FORMAT_ASTC_6x5_UNORM_BLOCK \ -VK_FORMAT_ASTC_6x5_SRGB_BLOCK \ -VK_FORMAT_ASTC_6x6_UNORM_BLOCK \ -VK_FORMAT_ASTC_6x6_SRGB_BLOCK \ -VK_FORMAT_ASTC_8x5_UNORM_BLOCK \ -VK_FORMAT_ASTC_8x5_SRGB_BLOCK \ -VK_FORMAT_ASTC_8x6_UNORM_BLOCK \ -VK_FORMAT_ASTC_8x6_SRGB_BLOCK \ -VK_FORMAT_ASTC_8x8_UNORM_BLOCK \ -VK_FORMAT_ASTC_8x8_SRGB_BLOCK \ -VK_FORMAT_ASTC_10x5_UNORM_BLOCK \ -VK_FORMAT_ASTC_10x5_SRGB_BLOCK \ -VK_FORMAT_ASTC_10x6_UNORM_BLOCK \ -VK_FORMAT_ASTC_10x6_SRGB_BLOCK \ -VK_FORMAT_ASTC_10x8_UNORM_BLOCK \ -VK_FORMAT_ASTC_10x8_SRGB_BLOCK \ -VK_FORMAT_ASTC_10x10_UNORM_BLOCK \ -VK_FORMAT_ASTC_10x10_SRGB_BLOCK \ -VK_FORMAT_ASTC_12x10_UNORM_BLOCK \ -VK_FORMAT_ASTC_12x10_SRGB_BLOCK \ -VK_FORMAT_ASTC_12x12_UNORM_BLOCK \ -VK_FORMAT_ASTC_12x12_SRGB_BLOCK \ -VK_FORMAT_G8B8G8R8_422_UNORM \ -VK_FORMAT_B8G8R8G8_422_UNORM \ -VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM \ -VK_FORMAT_G8_B8R8_2PLANE_420_UNORM \ -VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM \ -VK_FORMAT_G8_B8R8_2PLANE_422_UNORM \ -VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM \ -VK_FORMAT_R10X6_UNORM_PACK16 \ -VK_FORMAT_R10X6G10X6_UNORM_2PACK16 \ -VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16 \ -VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16 \ -VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16 \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16 \ -VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16 \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16 \ -VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16 \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16 \ -VK_FORMAT_R12X4_UNORM_PACK16 \ -VK_FORMAT_R12X4G12X4_UNORM_2PACK16 \ -VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16 \ -VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16 \ -VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16 \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16 \ -VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16 \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16 \ -VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16 \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16 \ -VK_FORMAT_G16B16G16R16_422_UNORM \ -VK_FORMAT_B16G16R16G16_422_UNORM \ -VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM \ -VK_FORMAT_G16_B16R16_2PLANE_420_UNORM \ -VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM \ -VK_FORMAT_G16_B16R16_2PLANE_422_UNORM \ -VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM \ -VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG \ -VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG \ -VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG \ -VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG \ -VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG \ -VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG \ -VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG \ -VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG \ -VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT \ -VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT \ -VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT \ -VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT \ -VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT \ -VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT \ -VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT \ -VK_FORMAT_G8B8G8R8_422_UNORM_KHR \ -VK_FORMAT_B8G8R8G8_422_UNORM_KHR \ -VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR \ -VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR \ -VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR \ -VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR \ -VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR \ -VK_FORMAT_R10X6_UNORM_PACK16_KHR \ -VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR \ -VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR \ -VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR \ -VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR \ -VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR \ -VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR \ -VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR \ -VK_FORMAT_R12X4_UNORM_PACK16_KHR \ -VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR \ -VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR \ -VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR \ -VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR \ -VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR \ -VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR \ -VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR \ -VK_FORMAT_G16B16G16R16_422_UNORM_KHR \ -VK_FORMAT_B16G16R16G16_422_UNORM_KHR \ -VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR \ -VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR \ -VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR \ -VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR \ -VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_KHR \ No newline at end of file +- `DXGI_FORMAT_R32G8X24_TYPELESS` +- `DXGI_FORMAT_D32_FLOAT_S8X24_UINT` +- `DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS` +- `DXGI_FORMAT_X32_TYPELESS_G8X24_UINT` +- `DXGI_FORMAT_R24G8_TYPELESS` +- `DXGI_FORMAT_D24_UNORM_S8_UINT` +- `DXGI_FORMAT_R24_UNORM_X8_TYPELESS` +- `DXGI_FORMAT_X24_TYPELESS_G8_UINT` +- `DXGI_FORMAT_A8_UNORM` +- `DXGI_FORMAT_R1_UNORM` +- `DXGI_FORMAT_R8G8_B8G8_UNORM` +- `DXGI_FORMAT_G8R8_G8B8_UNORM` +- `DXGI_FORMAT_BC1_TYPELESS` +- `DXGI_FORMAT_BC2_TYPELESS` +- `DXGI_FORMAT_BC3_TYPELESS` +- `DXGI_FORMAT_BC4_TYPELESS` +- `DXGI_FORMAT_BC5_TYPELESS` +- `DXGI_FORMAT_B8G8R8X8_UNORM` +- `DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM` +- `DXGI_FORMAT_B8G8R8X8_TYPELESS` +- `DXGI_FORMAT_B8G8R8X8_UNORM_SRGB` +- `DXGI_FORMAT_BC6H_TYPELESS` +- `DXGI_FORMAT_BC7_TYPELESS` +- `DXGI_FORMAT_AYUV` +- `DXGI_FORMAT_Y410` +- `DXGI_FORMAT_Y416` +- `DXGI_FORMAT_NV12` +- `DXGI_FORMAT_P010` +- `DXGI_FORMAT_P016` +- `DXGI_FORMAT_420_OPAQUE` +- `DXGI_FORMAT_YUY2` +- `DXGI_FORMAT_Y210` +- `DXGI_FORMAT_Y216` +- `DXGI_FORMAT_NV11` +- `DXGI_FORMAT_AI44` +- `DXGI_FORMAT_IA44` +- `DXGI_FORMAT_P8` +- `DXGI_FORMAT_A8P8` +- `DXGI_FORMAT_P208` +- `DXGI_FORMAT_V208` +- `DXGI_FORMAT_V408` +- `DXGI_FORMAT_SAMPLER_FEEDBACK_MIN_MIP_OPAQUE` +- `DXGI_FORMAT_SAMPLER_FEEDBACK_MIP_REGION_USED_OPAQUE` +- `VK_FORMAT_R4G4_UNORM_PACK8` +- `VK_FORMAT_R4G4B4A4_UNORM_PACK16` +- `VK_FORMAT_B4G4R4A4_UNORM_PACK16` +- `VK_FORMAT_B5G6R5_UNORM_PACK16` +- `VK_FORMAT_R5G5B5A1_UNORM_PACK16` +- `VK_FORMAT_B5G5R5A1_UNORM_PACK16` +- `VK_FORMAT_R8_USCALED` +- `VK_FORMAT_R8_SSCALED` +- `VK_FORMAT_R8_SRGB` +- `VK_FORMAT_R8G8_USCALED` +- `VK_FORMAT_R8G8_SSCALED` +- `VK_FORMAT_R8G8_SRGB` +- `VK_FORMAT_R8G8B8_UNORM` +- `VK_FORMAT_R8G8B8_SNORM` +- `VK_FORMAT_R8G8B8_USCALED` +- `VK_FORMAT_R8G8B8_SSCALED` +- `VK_FORMAT_R8G8B8_UINT` +- `VK_FORMAT_R8G8B8_SINT` +- `VK_FORMAT_R8G8B8_SRGB` +- `VK_FORMAT_B8G8R8_UNORM` +- `VK_FORMAT_B8G8R8_SNORM` +- `VK_FORMAT_B8G8R8_USCALED` +- `VK_FORMAT_B8G8R8_SSCALED` +- `VK_FORMAT_B8G8R8_UINT` +- `VK_FORMAT_B8G8R8_SINT` +- `VK_FORMAT_B8G8R8_SRGB` +- `VK_FORMAT_R8G8B8A8_USCALED` +- `VK_FORMAT_R8G8B8A8_SSCALED` +- `VK_FORMAT_B8G8R8A8_SNORM` +- `VK_FORMAT_B8G8R8A8_USCALED` +- `VK_FORMAT_B8G8R8A8_SSCALED` +- `VK_FORMAT_B8G8R8A8_UINT` +- `VK_FORMAT_B8G8R8A8_SINT` +- `VK_FORMAT_A8B8G8R8_UNORM_PACK32` +- `VK_FORMAT_A8B8G8R8_SNORM_PACK32` +- `VK_FORMAT_A8B8G8R8_USCALED_PACK32` +- `VK_FORMAT_A8B8G8R8_SSCALED_PACK32` +- `VK_FORMAT_A8B8G8R8_UINT_PACK32` +- `VK_FORMAT_A8B8G8R8_SINT_PACK32` +- `VK_FORMAT_A8B8G8R8_SRGB_PACK32` +- `VK_FORMAT_A2R10G10B10_UNORM_PACK32` +- `VK_FORMAT_A2R10G10B10_SNORM_PACK32` +- `VK_FORMAT_A2R10G10B10_USCALED_PACK32` +- `VK_FORMAT_A2R10G10B10_SSCALED_PACK32` +- `VK_FORMAT_A2R10G10B10_UINT_PACK32` +- `VK_FORMAT_A2R10G10B10_SINT_PACK32` +- `VK_FORMAT_A2B10G10R10_SNORM_PACK32` +- `VK_FORMAT_A2B10G10R10_USCALED_PACK32` +- `VK_FORMAT_A2B10G10R10_SSCALED_PACK32` +- `VK_FORMAT_A2B10G10R10_SINT_PACK32` +- `VK_FORMAT_R16_USCALED` +- `VK_FORMAT_R16_SSCALED` +- `VK_FORMAT_R16G16_USCALED` +- `VK_FORMAT_R16G16_SSCALED` +- `VK_FORMAT_R16G16B16_UNORM` +- `VK_FORMAT_R16G16B16_SNORM` +- `VK_FORMAT_R16G16B16_USCALED` +- `VK_FORMAT_R16G16B16_SSCALED` +- `VK_FORMAT_R16G16B16_UINT` +- `VK_FORMAT_R16G16B16_SINT` +- `VK_FORMAT_R16G16B16_SFLOAT` +- `VK_FORMAT_R16G16B16A16_USCALED` +- `VK_FORMAT_R16G16B16A16_SSCALED` +- `VK_FORMAT_R64_UINT` +- `VK_FORMAT_R64_SINT` +- `VK_FORMAT_R64_SFLOAT` +- `VK_FORMAT_R64G64_UINT` +- `VK_FORMAT_R64G64_SINT` +- `VK_FORMAT_R64G64_SFLOAT` +- `VK_FORMAT_R64G64B64_UINT` +- `VK_FORMAT_R64G64B64_SINT` +- `VK_FORMAT_R64G64B64_SFLOAT` +- `VK_FORMAT_R64G64B64A64_UINT` +- `VK_FORMAT_R64G64B64A64_SINT` +- `VK_FORMAT_R64G64B64A64_SFLOAT` +- `VK_FORMAT_X8_D24_UNORM_PACK32` +- `VK_FORMAT_S8_UINT` +- `VK_FORMAT_D16_UNORM_S8_UINT` +- `VK_FORMAT_D24_UNORM_S8_UINT` +- `VK_FORMAT_D32_SFLOAT_S8_UINT` +- `VK_FORMAT_BC1_RGB_UNORM_BLOCK` +- `VK_FORMAT_BC1_RGB_SRGB_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK` +- `VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK` +- `VK_FORMAT_EAC_R11_UNORM_BLOCK` +- `VK_FORMAT_EAC_R11_SNORM_BLOCK` +- `VK_FORMAT_EAC_R11G11_UNORM_BLOCK` +- `VK_FORMAT_EAC_R11G11_SNORM_BLOCK` +- `VK_FORMAT_ASTC_4x4_UNORM_BLOCK` +- `VK_FORMAT_ASTC_4x4_SRGB_BLOCK` +- `VK_FORMAT_ASTC_5x4_UNORM_BLOCK` +- `VK_FORMAT_ASTC_5x4_SRGB_BLOCK` +- `VK_FORMAT_ASTC_5x5_UNORM_BLOCK` +- `VK_FORMAT_ASTC_5x5_SRGB_BLOCK` +- `VK_FORMAT_ASTC_6x5_UNORM_BLOCK` +- `VK_FORMAT_ASTC_6x5_SRGB_BLOCK` +- `VK_FORMAT_ASTC_6x6_UNORM_BLOCK` +- `VK_FORMAT_ASTC_6x6_SRGB_BLOCK` +- `VK_FORMAT_ASTC_8x5_UNORM_BLOCK` +- `VK_FORMAT_ASTC_8x5_SRGB_BLOCK` +- `VK_FORMAT_ASTC_8x6_UNORM_BLOCK` +- `VK_FORMAT_ASTC_8x6_SRGB_BLOCK` +- `VK_FORMAT_ASTC_8x8_UNORM_BLOCK` +- `VK_FORMAT_ASTC_8x8_SRGB_BLOCK` +- `VK_FORMAT_ASTC_10x5_UNORM_BLOCK` +- `VK_FORMAT_ASTC_10x5_SRGB_BLOCK` +- `VK_FORMAT_ASTC_10x6_UNORM_BLOCK` +- `VK_FORMAT_ASTC_10x6_SRGB_BLOCK` +- `VK_FORMAT_ASTC_10x8_UNORM_BLOCK` +- `VK_FORMAT_ASTC_10x8_SRGB_BLOCK` +- `VK_FORMAT_ASTC_10x10_UNORM_BLOCK` +- `VK_FORMAT_ASTC_10x10_SRGB_BLOCK` +- `VK_FORMAT_ASTC_12x10_UNORM_BLOCK` +- `VK_FORMAT_ASTC_12x10_SRGB_BLOCK` +- `VK_FORMAT_ASTC_12x12_UNORM_BLOCK` +- `VK_FORMAT_ASTC_12x12_SRGB_BLOCK` +- `VK_FORMAT_G8B8G8R8_422_UNORM` +- `VK_FORMAT_B8G8R8G8_422_UNORM` +- `VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM` +- `VK_FORMAT_G8_B8R8_2PLANE_420_UNORM` +- `VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM` +- `VK_FORMAT_G8_B8R8_2PLANE_422_UNORM` +- `VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM` +- `VK_FORMAT_R10X6_UNORM_PACK16` +- `VK_FORMAT_R10X6G10X6_UNORM_2PACK16` +- `VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16` +- `VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16` +- `VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16` +- `VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16` +- `VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16` +- `VK_FORMAT_R12X4_UNORM_PACK16` +- `VK_FORMAT_R12X4G12X4_UNORM_2PACK16` +- `VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16` +- `VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16` +- `VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16` +- `VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16` +- `VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16` +- `VK_FORMAT_G16B16G16R16_422_UNORM` +- `VK_FORMAT_B16G16R16G16_422_UNORM` +- `VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM` +- `VK_FORMAT_G16_B16R16_2PLANE_420_UNORM` +- `VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM` +- `VK_FORMAT_G16_B16R16_2PLANE_422_UNORM` +- `VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM` +- `VK_FORMAT_PVRTC1_2BPP_UNORM_BLOCK_IMG` +- `VK_FORMAT_PVRTC1_4BPP_UNORM_BLOCK_IMG` +- `VK_FORMAT_PVRTC2_2BPP_UNORM_BLOCK_IMG` +- `VK_FORMAT_PVRTC2_4BPP_UNORM_BLOCK_IMG` +- `VK_FORMAT_PVRTC1_2BPP_SRGB_BLOCK_IMG` +- `VK_FORMAT_PVRTC1_4BPP_SRGB_BLOCK_IMG` +- `VK_FORMAT_PVRTC2_2BPP_SRGB_BLOCK_IMG` +- `VK_FORMAT_PVRTC2_4BPP_SRGB_BLOCK_IMG` +- `VK_FORMAT_ASTC_4x4_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_5x4_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_5x5_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_6x5_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_6x6_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_8x5_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_8x6_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_8x8_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_10x5_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_10x6_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_10x8_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_10x10_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_12x10_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_ASTC_12x12_SFLOAT_BLOCK_EXT` +- `VK_FORMAT_G8_B8R8_2PLANE_444_UNORM_EXT` +- `VK_FORMAT_G10X6_B10X6R10X6_2PLANE_444_UNORM_3PACK16_EXT` +- `VK_FORMAT_G12X4_B12X4R12X4_2PLANE_444_UNORM_3PACK16_EXT` +- `VK_FORMAT_G16_B16R16_2PLANE_444_UNORM_EXT` +- `VK_FORMAT_A4B4G4R4_UNORM_PACK16_EXT` +- `VK_FORMAT_G8B8G8R8_422_UNORM_KHR` +- `VK_FORMAT_B8G8R8G8_422_UNORM_KHR` +- `VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM_KHR` +- `VK_FORMAT_G8_B8R8_2PLANE_420_UNORM_KHR` +- `VK_FORMAT_G8_B8_R8_3PLANE_422_UNORM_KHR` +- `VK_FORMAT_G8_B8R8_2PLANE_422_UNORM_KHR` +- `VK_FORMAT_G8_B8_R8_3PLANE_444_UNORM_KHR` +- `VK_FORMAT_R10X6_UNORM_PACK16_KHR` +- `VK_FORMAT_R10X6G10X6_UNORM_2PACK16_KHR` +- `VK_FORMAT_R10X6G10X6B10X6A10X6_UNORM_4PACK16_KHR` +- `VK_FORMAT_G10X6B10X6G10X6R10X6_422_UNORM_4PACK16_KHR` +- `VK_FORMAT_B10X6G10X6R10X6G10X6_422_UNORM_4PACK16_KHR` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_420_UNORM_3PACK16_KHR` +- `VK_FORMAT_G10X6_B10X6R10X6_2PLANE_420_UNORM_3PACK16_KHR` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_422_UNORM_3PACK16_KHR` +- `VK_FORMAT_G10X6_B10X6R10X6_2PLANE_422_UNORM_3PACK16_KHR` +- `VK_FORMAT_G10X6_B10X6_R10X6_3PLANE_444_UNORM_3PACK16_KHR` +- `VK_FORMAT_R12X4_UNORM_PACK16_KHR` +- `VK_FORMAT_R12X4G12X4_UNORM_2PACK16_KHR` +- `VK_FORMAT_R12X4G12X4B12X4A12X4_UNORM_4PACK16_KHR` +- `VK_FORMAT_G12X4B12X4G12X4R12X4_422_UNORM_4PACK16_KHR` +- `VK_FORMAT_B12X4G12X4R12X4G12X4_422_UNORM_4PACK16_KHR` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_420_UNORM_3PACK16_KHR` +- `VK_FORMAT_G12X4_B12X4R12X4_2PLANE_420_UNORM_3PACK16_KHR` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_422_UNORM_3PACK16_KHR` +- `VK_FORMAT_G12X4_B12X4R12X4_2PLANE_422_UNORM_3PACK16_KHR` +- `VK_FORMAT_G12X4_B12X4_R12X4_3PLANE_444_UNORM_3PACK16_KHR` +- `VK_FORMAT_G16B16G16R16_422_UNORM_KHR` +- `VK_FORMAT_B16G16R16G16_422_UNORM_KHR` +- `VK_FORMAT_G16_B16_R16_3PLANE_420_UNORM_KHR` +- `VK_FORMAT_G16_B16R16_2PLANE_420_UNORM_KHR` +- `VK_FORMAT_G16_B16_R16_3PLANE_422_UNORM_KHR` +- `VK_FORMAT_G16_B16R16_2PLANE_422_UNORM_KHR` +- `VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM_K` diff --git a/docs/gpu-feature/derivatives-in-compute/derivatives-in-compute.md b/docs/gpu-feature/derivatives-in-compute/derivatives-in-compute.md index 8319202f4d..038ea148e3 100644 --- a/docs/gpu-feature/derivatives-in-compute/derivatives-in-compute.md +++ b/docs/gpu-feature/derivatives-in-compute/derivatives-in-compute.md @@ -1,9 +1,9 @@ ### Derivatives In Compute -An entry point may be decorated with `[DerivativeGroupQuad]` or `[DerivativeGroupLinear]` to specifiy how to use derivatives in compute shaders. +An entry point may be decorated with `[DerivativeGroupQuad]` or `[DerivativeGroupLinear]` to specify how to use derivatives in compute shaders. -GLSL syntax may also be used, but is not reccomended (`derivative_group_quadsNV`/`derivative_group_linearNV`). +GLSL syntax may also be used, but is not recommended (`derivative_group_quadsNV`/`derivative_group_linearNV`). Targets: * **_SPIRV:_** Enables `DerivativeGroupQuadsNV` or `DerivativeGroupLinearNV`. * **_GLSL:_** Enables `derivative_group_quadsNV` or `derivative_group_LinearNV`. -* **_HLSL:_** Does nothing. sm_6_6 is required to use derivatives in compute shaders. HLSL uses an equivlent of `DerivativeGroupQuad`. \ No newline at end of file +* **_HLSL:_** Does nothing. `sm_6_6` is required to use derivatives in compute shaders. HLSL uses an equivalent of `DerivativeGroupQuad`. diff --git a/docs/gpu-feature/texture/footprint-queries.md b/docs/gpu-feature/texture/footprint-queries.md index b47a952623..6e76414c8a 100644 --- a/docs/gpu-feature/texture/footprint-queries.md +++ b/docs/gpu-feature/texture/footprint-queries.md @@ -28,7 +28,7 @@ Texture footprint queries are intended to solve this problem by providing applic # Slang Shader API -Rather than exactly mirror the Vulkan GLSL extension or the NVAPI functions, Slang's standard library provides a single common interface that can map to either of those implementations. +Rather than exactly mirror the Vulkan GLSL extension or the NVAPI functions, the Slang core module provides a single common interface that can map to either of those implementations. ## Basics @@ -154,7 +154,7 @@ TextureFootprint3D Texture3D.queryFootprintFineBiasClamp( ## Footprint Types -Footprint queries on 2D and 3D textures return values of type `TextureFootprint2D` and `TextureFootprint3D`, respectively, which are built-in `struct`s defined in the Slang standard library: +Footprint queries on 2D and 3D textures return values of type `TextureFootprint2D` and `TextureFootprint3D`, respectively, which are built-in `struct`s defined in the Slang core module: ``` struct TextureFootprint2D diff --git a/docs/language-guide.md b/docs/language-guide.md index 4790794c80..d445051d68 100644 --- a/docs/language-guide.md +++ b/docs/language-guide.md @@ -26,7 +26,7 @@ New Features ### Import Declarations -In order to support better software modularity, and also to deal with the issue of how to integrate shader libraries written in Slang into other langauges, Slang introduces an `import` declaration construct. +In order to support better software modularity, and also to deal with the issue of how to integrate shader libraries written in Slang into other languages, Slang introduces an `import` declaration construct. The basic idea is that if you write a file `foo.slang` like this: @@ -53,7 +53,7 @@ When it comes time to generate output code, Slang will output any declarations f A few other details worth knowing about `import` declarations: -* The name you use on the `import` line gets translated into a file name with some very simple rules. An underscore (`_`) in the name turns into a dash (`-`) in the file name, and dot separators (`.`) turn into directory seprators (`/`). After these substitutions, `.slang` is added to the end of the name. +* The name you use on the `import` line gets translated into a file name with some very simple rules. An underscore (`_`) in the name turns into a dash (`-`) in the file name, and dot separators (`.`) turn into directory separators (`/`). After these substitutions, `.slang` is added to the end of the name. * If there are multiple `import` declarations naming the same file, it will only be imported once. This is also true for nested imports. @@ -61,12 +61,12 @@ A few other details worth knowing about `import` declarations: * If file `A.slang` imports `B.slang`, and then some other file does `import A;`, then only the names from `A.slang` are brought into scope, not those from `B.slang`. This behavior can be controlled by having `A.slang` use `__exported import B;` to also re-export the declarations it imports from `B`. -* An import is *not* like a `#include`, and so the file that does the `import` can't see preprocessor macros defined in the imported file (and vice versa). Think of `import foo;` as closer to `using namspace foo;` in C++ (perhaps without the same baggage). +* An import is *not* like a `#include`, and so the file that does the `import` can't see preprocessor macros defined in the imported file (and vice versa). Think of `import foo;` as closer to `using namespace foo;` in C++ (perhaps without the same baggage). ### Explicit Parameter Blocks -One of the most important new features of modern APIs like Direct3D 12 and Vulkan is an interface for providing shader parameters using efficient *parameter blocks* that can be stored in GPU memory (these are implemented as descritpor tables/sets in D3D12/Vulkan, and "attribute buffers" in Metal). -However, HLSL and GLSL don't support explicit syntax for parmaeter blocks, and so shader programmers are left to manually pack parameters into blocks either using `register`/`layout` modifiers, or with API-based remapping (in the D3D12 case). +One of the most important new features of modern APIs like Direct3D 12 and Vulkan is an interface for providing shader parameters using efficient *parameter blocks* that can be stored in GPU memory (these are implemented as descriptor tables/sets in D3D12/Vulkan, and "attribute buffers" in Metal). +However, HLSL and GLSL don't support explicit syntax for parameter blocks, and so shader programmers are left to manually pack parameters into blocks either using `register`/`layout` modifiers, or with API-based remapping (in the D3D12 case). Slang supports a simple and explicit syntax for exploiting parameter blocks: @@ -190,7 +190,7 @@ interface IMaterial What is the type `???` that `evalPattern` should return? We know that it needs to be a type that supports `IBRDF`, but *which* type? One material might want to use `DisneyBRDF` while another wants to use `KajiyaKay`. -The solution in Slang, as in modern languages like Swift and Rust, is to use *associated types* to express the depdence of the BRDF type on the material type: +The solution in Slang, as in modern languages like Swift and Rust, is to use *associated types* to express the dependence of the BRDF type on the material type: ```hlsl interface IMaterial diff --git a/docs/language-reference/04-types.md b/docs/language-reference/04-types.md index bef9f2d31c..3ccc7bdcba 100644 --- a/docs/language-reference/04-types.md +++ b/docs/language-reference/04-types.md @@ -92,7 +92,7 @@ The alignment of a vector type may vary by target platforms. The alignment of `vector` will be at least the alignment of `T` and may be at most `N` times the alignment of `T`. As a convenience, Slang defines built-in type aliases for vectors of the built-in scalar types. -E.g., declarations equivalent to the following are provided by the Slang standard library: +E.g., declarations equivalent to the following are provided by the Slang core module: ```hlsl typealias float4 = vector; @@ -139,7 +139,7 @@ Under column-major layout, a matrix is laid out in memory equivalent to the row- This means it will be laid out equivalently to a `C`-element array of `vector` elements. As a convenience, Slang defines built-in type aliases for matrices of the built-in scalar types. -E.g., declarations equivalent to the following are provided by the Slang standard library: +E.g., declarations equivalent to the following are provided by the Slang core module: ```hlsl typealias float3x4 = matrix; @@ -311,7 +311,7 @@ Opaque Types _Opaque_ types are built-in types that (depending on the target platform) may not have a well-defined size or representation in memory. Similar languages may refer to these as "resource types" or "object types." -The full list of opaque types supported by Slang can be found in the standard library reference, but important examples are: +The full list of opaque types supported by Slang can be found in the core module reference, but important examples are: * Texture types such as `Texture2D`, `TextureCubeArray`, and `RWTexture2DMS` * Sampler state types: `SamplerState` and `SamplerComparisonState` diff --git a/docs/language-reference/05-expressions.md b/docs/language-reference/05-expressions.md index da0921ff28..64bee737af 100644 --- a/docs/language-reference/05-expressions.md +++ b/docs/language-reference/05-expressions.md @@ -105,7 +105,7 @@ If the member name of a swizzle consists of a single character, then the express If the member name of a swizzle consists of `M` characters, then the result is a `vector` built from the elements of the base vector with the corresponding indices. -A vector swizzle expression is an l-value if the base expression was an l-value and the list of indices corresponding to the characeters of the member name contains no duplicates. +A vector swizzle expression is an l-value if the base expression was an l-value and the list of indices corresponding to the characters of the member name contains no duplicates. ### Matrix Swizzles @@ -224,7 +224,7 @@ A cast expression can perform both built-in type conversions and invoke any sing ### Compatibility Feature -As a compatiblity feature for older code, Slang supports using a cast where the base expression is an integer literal zero and the target type is a user-defined structure type: +As a compatibility feature for older code, Slang supports using a cast where the base expression is an integer literal zero and the target type is a user-defined structure type: ```hlsl MyStruct s = (MyStruct) 0; @@ -338,7 +338,7 @@ With the exception of the assignment operator (`=`), an infix operator expressio ### Conditional Expression -The conditonal operator, `?:`, is used to select between two expressions based on the value of a condition: +The conditional operator, `?:`, is used to select between two expressions based on the value of a condition: ```hlsl useNegative ? -1.0f : 1.0f diff --git a/docs/language-reference/06-statements.md b/docs/language-reference/06-statements.md index 7a4770d994..5c3b77ad45 100644 --- a/docs/language-reference/06-statements.md +++ b/docs/language-reference/06-statements.md @@ -3,7 +3,7 @@ Statements ========== -Statements are used to define the bodies of functions and deterine order of evaluation and control flow for an entire program. +Statements are used to define the bodies of functions and determine order of evaluation and control flow for an entire program. Statements are distinct from expressions in that statements do not yield results and do not have types. This section lists the kinds of statements supported by Slang. @@ -101,7 +101,7 @@ default: break; ``` -A _case label_ consists of the keyword `case` followed by an expresison and a colon (`:`). +A _case label_ consists of the keyword `case` followed by an expressions and a colon (`:`). The expression must evaluate to a compile-time constant integer. A _default label_ consists of the keyword `default` followed by a colon (`:`). @@ -203,7 +203,7 @@ The value returned must be able to coerce to the result type of the lexically en ### Discard Statement -A `discard` statement can only be used in the context of a fragment shader, in which case it causes the current invocation to terminate and the graphics system to discard the corresponding fragment so that it does not get combined with the framebuffer pixel at its coordintes. +A `discard` statement can only be used in the context of a fragment shader, in which case it causes the current invocation to terminate and the graphics system to discard the corresponding fragment so that it does not get combined with the framebuffer pixel at its coordinates. Operations with side effects that were executed by the invocation before a `discard` will still be performed and their results will become visible according to the rules of the platform. diff --git a/docs/language-reference/07-declarations.md b/docs/language-reference/07-declarations.md index 2df87b8a60..2c6e6bdbe7 100644 --- a/docs/language-reference/07-declarations.md +++ b/docs/language-reference/07-declarations.md @@ -85,7 +85,7 @@ var y = 9.0; A `let` declaration introduces an immutable variable, which may not be assigned to or used as the argument for an `in out` or `out` parameter. A `var` declaration introduces a mutable variable. -An explicit type may be given for a variable by placing it afte the variable name and a colon (`:`): +An explicit type may be given for a variable by placing it after the variable name and a colon (`:`): ```hlsl let x : int = 7; @@ -160,7 +160,7 @@ A global shader parameter may include an initial-value epxression, but such an e ### Variables at Function Scope -Variables declared at _function scope_ (in the body of a function, initializer, subscript acessor, etc.) may be either a function-scope constant, function-scope static variable, or a local variable. +Variables declared at _function scope_ (in the body of a function, initializer, subscript accessor, etc.) may be either a function-scope constant, function-scope static variable, or a local variable. #### Function-Scope Constants @@ -216,7 +216,7 @@ The available directions are: * `in out` or `inout` indicates pass-by-value-result (copy-in and copy-out) semantics. The callee receives a copy of the argument passed by the caller, it may manipulate the copy, and then when the call returns the final value is copied back to the argument of the caller. An implementation may assume that at every call site the arguments for `out` or `in out` parameters never alias. -Under those assumptions, the `out` and `inout` cases may be optimized to use pass-by-refernece instead of copy-in and copy-out. +Under those assumptions, the `out` and `inout` cases may be optimized to use pass-by-reference instead of copy-in and copy-out. > Note: Applications that rely on the precise order in which write-back for `out` and `in out` parameters is performed are already on shaky semantic ground. @@ -332,7 +332,7 @@ struct Things { ... } When a structure declarations ends without a semicolon, the closing curly brace (`}`) must be the last non-comment, non-whitespace token on its line. -For compatiblity with C-style code, a structure type declaration may be used as the type specifier in a traditional-style variable declaration: +For compatibility with C-style code, a structure type declaration may be used as the type specifier in a traditional-style variable declaration: ```hlsl struct Association @@ -372,7 +372,7 @@ An optional trailing comma may terminate the lis of cases. A _case declaration_ consists of the name of the case, along with an optional initial-value expression that specifies the _tag value_ for that case. If the first case declaration in the body elides an initial-value expression, the value `0` is used for the tag value. -If any other case decalration elides an initial-value expresison, its tag value is one greater than the tag value of the immediately preceding case declaration. +If any other case declaration elides an initial-value expressions, its tag value is one greater than the tag value of the immediately preceding case declaration. An enumeration case is referred to as if it were a `static` member of the enumeration type (e.g., `Color.Red`). @@ -429,7 +429,7 @@ typedef int Height; Constant Buffers and Texture Buffers ------------------------------------ -As a compatiblity feature, the `cbuffer` and `tbuffer` keywords can be used to introduce variable declarations. +As a compatibility feature, the `cbuffer` and `tbuffer` keywords can be used to introduce variable declarations. A declaration of the form: @@ -528,7 +528,7 @@ It is an error to declare an associated type anywhere other than the body of an An associated type declaration may have an inheritance clause. The inheritance clause of an associated type may only list interfaces; these are the _required interfaces_ for the associated type. -A concrete type that is used to satisfy an associated type requirement must conform to all of the required interaces of the associated type. +A concrete type that is used to satisfy an associated type requirement must conform to all of the required interfaces of the associated type. Initializers ------------ @@ -599,7 +599,7 @@ MyVector v = ...; float f = v[0]; ``` -A subscript declaration lists one or more parameters inside parantheses, followed by a result type clause starting with `->`. +A subscript declaration lists one or more parameters inside parentheses, followed by a result type clause starting with `->`. The result type clause of a subscript declaration cannot be elided. The body of a subscript declaration consists of _accessor declarations_. @@ -642,7 +642,7 @@ float f = v.getLength(); int n = MyVector.getDimensionality(); ``` -An extension declaration need not be placed in the same module as the type being extended; it is possible to extend a type from third-party or standard-library code. +An extension declaration need not be placed in the same module as the type being extended; it is possible to extend a type from third-party or standard module code. The members of an extension are only visible inside of modules that `import` the module declaring the extension; extension members are *not* automatically visible wherever the type being extended is visible. diff --git a/docs/language-reference/08-attributes.md b/docs/language-reference/08-attributes.md index 7ffe0f0fec..f4d900d33f 100644 --- a/docs/language-reference/08-attributes.md +++ b/docs/language-reference/08-attributes.md @@ -11,7 +11,7 @@ Attributes This attribute is only available for Vulkan SPIR-V output. -The attibute allows access to SPIR-V intrinsics, by supplying a function declaration with the appropriate signature for the SPIR-V op and no body. The intrinsic takes a single parameter which is the integer value for the SPIR-V op. +The attribute allows access to SPIR-V intrinsics, by supplying a function declaration with the appropriate signature for the SPIR-V op and no body. The intrinsic takes a single parameter which is the integer value for the SPIR-V op. In the example below the add function, uses the mechanism to directly use the SPIR-V integer add 'op' which is 128 in this case. diff --git a/docs/layout.md b/docs/layout.md index 12144c155d..75e4b9863d 100644 --- a/docs/layout.md +++ b/docs/layout.md @@ -46,7 +46,7 @@ The order of parameters in the user's code is derived by "walking" through the c * Walk through each source file of a translation unit in the order they were added/listed -* Walk through global-scope shader paramter declarations (global variables, `cbuffer`s, etc.) in the order they are listed in the (preprocessed) file. +* Walk through global-scope shader parameter declarations (global variables, `cbuffer`s, etc.) in the order they are listed in the (preprocessed) file. * After all global parameters for a translation unit have been walked, walk through any entry points in the translation unit. @@ -64,7 +64,7 @@ Computing Resource Requirements Each shader parameter computes its resource requirements based on its type, and how it is declared. -* Global-scope parameters, entry point `uniform` parameters, and `cbuffer` decalrations all use the "default" layout rules +* Global-scope parameters, entry point `uniform` parameters, and `cbuffer` declarations all use the "default" layout rules * Entry point non-`uniform` parameters use "varying" layout rules, either input or output diff --git a/docs/nvapi-support.md b/docs/nvapi-support.md index ac3a2e943e..cb96f65fd7 100644 --- a/docs/nvapi-support.md +++ b/docs/nvapi-support.md @@ -46,7 +46,7 @@ Thus causing the prelude to include nvHLSLExtns.h, and specifying the slot and p The actual values for the slot and optionally the space, are found by Slang examining the values of those values at the end of preprocessing input Slang source files. -This means that if you compile Slang source that has implicit use NVAPI, the slot and optionally the space must be defined. This can be achieved with a command line -D, throught the API or through having suitable `#define`s in the Slang source code. +This means that if you compile Slang source that has implicit use NVAPI, the slot and optionally the space must be defined. This can be achieved with a command line -D, through the API or through having suitable `#define`s in the Slang source code. It is worth noting if you *replace* the default HLSL prelude, and use NVAPI then it will be necessary to have something like the default HLSL prelude part of your custom prelude. @@ -63,7 +63,7 @@ The astute reader may have noticed that the default Slang HLSL prelude *does* co #endif ``` -This means that the *downstream* compiler (such as DXC and FXC) must be able to handle this include. Include paths can be specified for downstream compilers via the [-X mechanism](command-line-slangc.md#downstream-arguments). So for example... +This means that the *downstream* compiler (such as DXC and FXC) must be able to handle this include. Include paths can be specified for downstream compilers via the [-X mechanism](user-guide/08-compiling.md#downstream-arguments). So for example... ``` -Xfxc -IpathTo/nvapi -Xdxc -IpathTo/nvapi diff --git a/docs/proposals/000-template.md b/docs/proposals/000-template.md index 3803d856b6..cb0377886d 100644 --- a/docs/proposals/000-template.md +++ b/docs/proposals/000-template.md @@ -13,7 +13,7 @@ Status Status: Design Review/Planned/Implementation In-Progress/Implemented/Partially Implemented. Note here whether the proposal is unimplemented, in-progress, has landed, etc. -Implemtation: [PR 000] [PR 001] ... (list links to PRs) +Implementation: [PR 000] [PR 001] ... (list links to PRs) Author: authors of the design doc and the implementation. diff --git a/docs/proposals/001-where-clauses.md b/docs/proposals/001-where-clauses.md index 0e49735e2f..02f60a08fd 100644 --- a/docs/proposals/001-where-clauses.md +++ b/docs/proposals/001-where-clauses.md @@ -81,7 +81,7 @@ C# is broadly similar, but uses multiple `where` clauses, one per constraint: While Haskell is a quite different language from the others mentioned here, Haskell typeclasses have undeniably influenced the concept of traits/protocols in Rust/Swift. -In Haskell a typeclass is not somethign a type "inherits" from, and instead uses type parameter for even the `This` type. +In Haskell a typeclass is not something a type "inherits" from, and instead uses type parameter for even the `This` type. Type parameters in Haskell are also introduced implicitly rather than explicitly. The `resolve` example above would become something like: @@ -89,7 +89,7 @@ The `resolve` example above would become something like: ResolutionContext u -> List t -> v We see here that the constraints are all grouped together in the `(...) =>` clause before the actual type signature of the function. -That clause serves a simlar semantic role to `where` clauses in these other languages. +That clause serves a similar semantic role to `where` clauses in these other languages. Proposed Approach ----------------- @@ -223,7 +223,7 @@ Technically it was already possible to have redundancy in a constraint by using void f( ... ) { ... } -One question that is raised by the possiblity of redundant constraints is whether the compiler should produce a diagnostic for them and, if so, whether it should be a warning or an error. +One question that is raised by the possibility of redundant constraints is whether the compiler should produce a diagnostic for them and, if so, whether it should be a warning or an error. While it may seem obvious that redundant constraints are to be avoided, it is possible that refactoring of `interface` hierarchies could change whether existing constraints are redundant or not, potentially forcing widespread edits to code that is semantically unambiguous (and just a little more verbose than necessary). We propose that redundant constraints should probably produce a warning, with a way to silence that warning easily. @@ -231,7 +231,7 @@ We propose that redundant constraints should probably produce a warning, with a The long and short of the above section is that there can be multiple ways to write semantically equivalent generic declarations, by changing the form, order, etc. of constraints. We want the signature of a function (and its mangled name, etc.) to be identical for semantically equivalent declaration syntax. -In order to ensure that a declaration's mangled name is indepenent of the form of its constraints, we must have a way to *canonicalize* those constraints. +In order to ensure that a declaration's mangled name is independent of the form of its constraints, we must have a way to *canonicalize* those constraints. The Swift compiler codebase includes a document that details the rules used for canonicalization of constraints for that compiler, and we can take inspiration from it. Our constraints are currently much more restricted, so canonicalization can follow a much simpler process, such as: @@ -288,7 +288,7 @@ In the context of `class`-based hierarchies, we can also consider having constra ### Allow `where` clauses on non-generic declarations -We could consider allowing `where` clauses to appear on any declaration nested under a generic, such that those declarations are only usable when certain additinal constraints are met. +We could consider allowing `where` clauses to appear on any declaration nested under a generic, such that those declarations are only usable when certain additional constraints are met. E.g.,: struct MyDictionary diff --git a/docs/proposals/002-type-equality-constraints.md b/docs/proposals/002-type-equality-constraints.md index 44562075ee..33612720cb 100644 --- a/docs/proposals/002-type-equality-constraints.md +++ b/docs/proposals/002-type-equality-constraints.md @@ -20,7 +20,7 @@ As of proposal [001](001-where-clauses.md), Slang allows for generic declaration Currently, the language only accepts *conformance* constraints of the form `T : IFoo`, where `T` is one of the parameters of the generic, and `IFoo` is either an `interface` or a conjunction of interfaces, which indicate that the type `T` must conform to `IFoo`. -This proposal is motivated by the observation that when an interface has associated types, there is currently no way for a programmer to introduce a generic that is only applicable when an associated type satisfies certain constriants. +This proposal is motivated by the observation that when an interface has associated types, there is currently no way for a programmer to introduce a generic that is only applicable when an associated type satisfies certain constraints. As an example, consider an interface for types that can be "packed" into a smaller representation for in-memory storage (instead of a default representation optimized for access from registers): @@ -146,7 +146,7 @@ The choice of how to represent equality constraints is more subtle. One option is to lower an equality constraint to *nothing* at the IR level, under the assumption that the casts that reference these constraints should lower to nothing. Doing so would introduce yet another case where the IR we generate doesn't "type-check." The other option is to lower a type equality constraint to an explicit generic parameter which is then applied via an explicit op to convert between the associated type and its known concrete equivalent. -The representation of the witnesses required to provide *arguments* for such parameters is something that hasn't been fully explored, so for now we prpose to take the first (easier) option. +The representation of the witnesses required to provide *arguments* for such parameters is something that hasn't been fully explored, so for now we propose to take the first (easier) option. ### Canonicalization @@ -156,7 +156,7 @@ Conformane constraints involving associated types should already be order-able a We propose the following approach: * Take all of the equality constraints that arise after any expansion steps -* Divide the types named on either side of any equality constraint into *equivalence classes*, where if `X == Y` is a constraint, then `X` and `Y` must in teh same equivalence class +* Divide the types named on either side of any equality constraint into *equivalence classes*, where if `X == Y` is a constraint, then `X` and `Y` must in the same equivalence class * Each type in an equivalence class will either be an associated type of the form `T.A.B...Z`, derived from a generic type parameter, or a *independent* type, which here means anything other than those associated types. * Because of the rules enforced during semantic checking, each equivalence class must have at least one associated type in it. * Each equivalence class may have zero or more independent types in it. diff --git a/docs/proposals/003-atomic-t.md b/docs/proposals/003-atomic-t.md new file mode 100644 index 0000000000..c846ad3c70 --- /dev/null +++ b/docs/proposals/003-atomic-t.md @@ -0,0 +1,153 @@ +SP #003 - `Atomic` type +============== + + +Status +------ + +Author: Yong He + +Status: Implemented. + +Implementation: [PR 5125](https://github.com/shader-slang/slang/pull/5125) + +Reviewed by: Theresa Foley, Jay Kwak + +Background +---------- + +HLSL defines atomic intrinsics to work on free references to ordinary values such as `int` and `float`. However, this doesn't translate well to Metal and WebGPU, +which defines `atomic` type and only allow atomic operations to be applied on values of `atomic` types. + +Slang's Metal backend follows the same technique in SPIRV-Cross and DXIL->Metal converter that relies on a C++ undefined behavior that casts an ordinary `int*` pointer to a `atomic*` pointer +and then call atomic intrinsic on the reinterpreted pointer. This is fragile and not guaranteed to work in the future. + +To make the situation worse, WebGPU bans all possible ways to cast a normal pointer into an `atomic` pointer. In order to provide a truly portable way to define +atomic operations and allow them to be translatable to all targets, we will also need an `atomic` type in Slang that maps to `atomic` in WGSL and Metal, and maps to +`T` for HLSL/SPIRV. + + +Proposed Approach +----------------- + +We define an `Atomic` type that functions as a wrapper of `T` and provides atomic operations: +```csharp +enum MemoryOrder +{ + Relaxed = 0, + Acquire = 1, + Release = 2, + AcquireRelease = 3, + SeqCst = 4, +} + +[sealed] interface IAtomicable {} +[sealed] interface IArithmeticAtomicable : IAtomicable, IArithmetic {} +[sealed] interface IBitAtomicable : IArithmeticAtomicable, IInteger {} + +[require(cuda_glsl_hlsl_metal_spirv_wgsl)] +struct Atomic +{ + T load(MemoryOrder order = MemoryOrder.Relaxed); + + [__ref] void store(T newValue, MemoryOrder order = MemoryOrder.Relaxed); + + [__ref] T exchange(T newValue, MemoryOrder order = MemoryOrder.Relaxed); // returns old value + + [__ref] T compareExchange( + T compareValue, + T newValue, + MemoryOrder successOrder = MemoryOrder.Relaxed, + MemoryOrder failOrder = MemoryOrder.Relaxed); +} + +extension Atomic +{ + [__ref] T add(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T sub(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T max(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T min(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value +} + +extension Atomic +{ + [__ref] T and(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T or(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T xor(T value, MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T increment(MemoryOrder order = MemoryOrder.Relaxed); // returns original value + [__ref] T decrement(MemoryOrder order = MemoryOrder.Relaxed); // returns original value +} + +extension int : IArithmeticAtomicable {} +extension uint : IArithmeticAtomicable {} +extension int64_t : IBitAtomicable {} +extension uint64_t : IBitAtomicable {} +extension double : IArithmeticAtomicable {} +extension float : IArithmeticAtomicable {} +extension half : IArithmeticAtomicable {} + +// Operator overloads: +// All operator overloads are using MemoryOrder.Relaxed semantics. +__prefix T operator++(__ref Atomic v); // returns new value. +__postfix T operator++(__ref Atomic v); // returns original value. +__prefix T operator--(__ref Atomic v); // returns new value. +__postfix T operator--(__ref Atomic v); // returns original value. +T operator+=(__ref Atomic v, T operand); // returns new value. +T operator-=(__ref Atomic v, T operand); // returns new value. +T operator|=(__ref Atomic v, T operand); // returns new value. +T operator&=(__ref Atomic v, T operand); // returns new value. +T operator^=(__ref Atomic v, T operand); // returns new value. +``` + +We allow `Atomic` to be defined in struct fields, as array elements, as elements of `RWStructuredBuffer` types, +or as groupshared variable types or `__ref` function parameter types. For example: + +```hlsl +struct MyType +{ + int ordinaryValue; + Atomic atomicValue; +} + +RWStructuredBuffer atomicBuffer; + +void main() +{ + atomicBuffer[0].atomicValue.atomicAdd(1); + printf("%d", atomicBuffer[0].atomicValue.load()); +} +``` + +In groupshared memory: + +```hlsl +void main() +{ + groupshared atomic c; + c.atomicAdd(1); +} +``` + +Note that in many targets, it is invalid to use `atomic` type to define a local variable or a function parameter, or in any way +to cause a `atomic` to reside in local/function/private address space. Slang should be able to lower the type +into its underlying type. The use of atomic type in these positions will simply have no meaning. However, we are going to leave +this legalization as future work and leave such situation as undefined behavior for now. + +This should be handled by a legalization pass similar to `lowerBufferElementTypeToStorageType` but operates +in the opposite direction: the "loaded" value from a buffer is converted into an atomic-free type, and storing a value leads to an +atomic store at the corresponding locations. + +For non-WGSL/Metal targets, we can simply lower the type out of existence into its underlying type. + +# Related Work + +`Atomic` type exists in almost all CPU programming languages and is the proven way to express atomic operations over different +architectures that have different memory models. WGSL and Metal follows this trend to require atomic operations being expressed +this way. This proposal is to make Slang follow this trend and make `Atomic` the recommended way to express atomic operation +going forward. + +# Future Work + +As discussed in previous sections, we should consider adding a legalization pass to allow `Atomic` type to be used anywhere in +any memory space, and legalize them out to just normal types if they are used in memory spaces where atomic semantic has no/trivial +meaning. diff --git a/docs/proposals/004-initialization.md b/docs/proposals/004-initialization.md new file mode 100644 index 0000000000..6a41cab231 --- /dev/null +++ b/docs/proposals/004-initialization.md @@ -0,0 +1,408 @@ +SP #004: Initialization +================= + +This proposal documents the desired behavior of initialization related language semantics, including default constructor, initialization list and variable initialization. + +Status +------ + +Status: Design Approved, implementation in-progress. + +Implementation: N/A + +Author: Yong He + +Reviewer: Theresa Foley, Kai Zhang + +Background +---------- + +Slang has introduced several different syntax around initialization to provide syntactic compatibility with HLSL/C++. As the language evolve, there are many corners where +the semantics around initialization are not well-defined, and causing confusion or leading to surprising behaviors. + +This proposal attempts to provide a design on where we want the language to be in terms of how initialization is handled in all different places. + +Related Work +------------ + +C++ has many different ways and syntax to initialize an object: through explicit constructor calls, initialization list, or implicitly in a member/variable declaration. +A variable in C++ can also be in an uninitialized state after its declaration. HLSL inherits most of these behvior from C++ by allowing variables to be uninitialized. + +On the other hand, languages like C# and Swift has a set of well defined rules to ensure every variable is initialized after its declaration. +C++ allows using the initialization list syntax to initialize an object. The semantics of initialization lists depends on whether or not explicit constructors +are defined on the type. + +Proposed Approach +----------------- + +In this section, we document all concepts and rules related to initialization, constructors and initialization lists. + +### Default Initializable type + +A type is considered "default-initializable" if it provides a constructor that can take 0 arguments, so that it can be constructed with `T()`. + +### Variable Initialization + +Generally, a variable is considered uninitialized at its declaration site without an explicit value expression. +For example, +```csharp +struct MyType { int x ; } + +void foo() +{ + MyType t; // t is uninitialized. + var t1 : MyType; // same in modern syntax, t1 is uninitialized. +} +``` + +However, the Slang language has been allowing implicit initialization of variables whose types are default initializable types. +For example, +```csharp +struct MyType1 { + int x; + __init() { x = 0; } +} +void foo() { + MyType t1; // `t1` is initialized with a call to `__init`. +} +``` + +We would like to move away from this legacy behavior towards a consistent semantics of never implicitly initializing a variable. +To maintain backward compatibility, we will keep the legacy behavior, but remove the implicit initialization when the variable is defined +in modern syntax: +```csharp +void foo() { + var t1: MyType; // `t1` will no longer be initialized. +} +``` +We will also remove the default initilaization semantics for traditional syntax in modern Slang modules that comes with an explicit `module` declaration. + +Trying to use a variable without initializing it first is an error. +For backward compatibility, we will introduce a compiler option to turn this error into a warning, but we may deprecate this option in the future. + +### Generic Type Parameter + +A generic type parameter is not considered default-initializable by-default. As a result, the following code should leave `t` in an uninitialized state: +```csharp +void foo() +{ + T t; // `t` is uninitialized at declaration. +} +``` + +### Synthesis of constructors for member initialization + +If a type already defines any explicit constructors, do not synthesize any constructors for initializer list call. An initializer list expression +for the type must exactly match one of the explicitly defined constructors. + +If the type doesn't provide any explicit constructors, the compiler need to synthesize the constructors for the calls that that the initializer +lists translate into, so that an initializer list expression can be used to initialize a variable of the type. + +For each type, we will synthesize one constructor at the same visibility of the type itself: + +The signature for the synthesized initializer for type `V struct T` is: +```csharp +V T.__init(member0: typeof(member0) = default(member0), member1 : typeof(member1) = default(member1), ...) +``` +where `V` is a visibility modifier, `(member0, member1, ... memberN)` is the set of members that has visibility `V`, and `default(member0)` +is the value defined by the initialization expression in `member0` if it exist, or the default value of `member0`'s type. +If `member0`'s type is not default initializable and the the member doesn't provide an initial value, then the parameter will not have a default value. + +The synthesized constructor will be marked as `[Synthesized]` by the compiler, so the call site can inject additional compatibility logic when calling a synthesized constructor. + +The body of the constructor will initialize each member with the value coming from the corresponding constructor argument if such argument exists, +otherwise the member will be initialized to its default value either defined by the init expr of the member, or the default value of the type if the +type is default-initializable. If the member type is not default-initializable and a default value isn't provided on the member, then such the constructor +synthesis will fail and the constructor will not be added to the type. Failure to synthesis a constructor is not an error, and an error will appear +if the user is trying to initialize a value of the type in question assuming such a constructor exist. + +Note that if every member of a struct contains a default expression, the synthesized `__init` method can be called with 0 arguments, however, this will not cause a variable declaration to be implicitly initialized. Implicit initialization is a backward compatibility feature that only work for user-defined `__init()` methods. + +### Single argument constructor call + +Call to a constructor with a single argument is always treated as a syntactic sugar of type cast: +```csharp +int x = int(1.0f); // is treated as (int) 1.0f; +MyType y = MyType(arg); // is treated as (MyType)arg; +MyType x = MyType(y); // equivalent to `x = y`. +``` + +The compiler will attempt to resolve all type casts using type coercion rules, if that failed, will fall back to resolve it as a constructor call. + +### Initialization List + +Slang allows initialization of a variable by assigning it with an initialization list. +Generally, Slang will always try to resolve initialization list coercion as if it is an explicit constructor invocation. +For example, given: +```csharp +S obj = {1,2}; +``` +Slang will try to convert the code into: +```csharp +S obj = S(1,2); +``` + +Following the same logic, an empty initializer list will translate into a default-initialization: +```csharp +S obj = {}; +// equivalent to: +S obj = S(); +``` + +Note that initializer list of a single argument does not translate into a type cast, unlike the constructor call syntax. Initializing with a single element in the initializer list always translates directly into a constructor call. For example: +```csharp +void test() +{ + MyType t = {1}; + // translates to direct constructor call: + // MyType t = MyType.__init(1); + // which is NOT the same as: + // MyType t = MyType(t) + // or: + // MyType t = (MyType)t; +} +``` + +If the above code passes type check, then it will be used as the way to initialize `obj`. + +If the above code does not pass type check, and if there is only one constructor for`MyType` that is synthesized as described in the previous section (and therefore marked as `[Synthesized]`, Slang continues to check if `S` meets the standard of a "legacy C-style struct` type. +A type is a "legacy C-Style struct" if all of the following conditions are met: +- It is a user-defined struct type or a basic scalar, vector or matrix type, e.g. `int`, `float4x4`. +- It does not contain any explicit constructors defined by the user. +- All its members have the same visibility as the type itself. +- All its members are legacy C-Style structs or arrays of legacy C-style structs. +Note that C-Style structs are allowed to have member default values. +In such case, we perform a legacy "read data" style consumption of the initializer list to synthesize the arguments to call the constructor, so that the following behavior is valid: + +```csharp +struct Inner { int x; int y; }; +struct Outer { Inner i; Inner j; } + +// Initializes `o` into `{ Inner{1,2}, Inner{3,0} }`, by synthesizing the +// arguments to call `Outer.__init(Inner(1,2), Inner(3, 0))`. +Outer o = {1, 2, 3}; +``` + +If the type is not a legacy C-Style struct, Slang should produce an error. + +### Legacy HLSL syntax to cast from 0 + +HLSL allows a legacy syntax to cast from literal `0` to a struct type, for example: +```hlsl +MyStruct s { int x; } +void test() +{ + MyStruct s = (MyStruct)0; +} +``` + +Slang treats this as equivalent to a empty-initialization: +```csharp +MyStruct s = (MyStruct)0; +// is equivalent to +MyStruct s = {}; +``` + +Examples +------------------- +```csharp + +// Assume everything below is public unless explicitly declared. + +struct Empty +{ + // compiler synthesizes: + // __init(); +} +void test() +{ + Empty s0 = {}; // Works, `s` is considered initialized via ctor call. + Empty s1; // `s1` is considered uninitialized. +} + +struct CLike +{ + int x; int y; + // compiler synthesizes: + // __init(int x, int y); +} +void test1() +{ + CLike c0; // `c0` is uninitialized. + + // case 1: initialized with synthesized ctor call using legacy logic to form arguments, + // and `c1` is now `{0,0}`. + // (we will refer to this scenario as "initialized with legacy logic" for + // the rest of the examples): + CLike c1 = {}; + + // case 2: initialized with legacy initializaer list logic, `c1` is now `{1,0}`: + CLike c2 = {1}; + + // case 3: initilaized with ctor call `CLike(1,2)`, `c3` is now `{1,2}`: + CLike c3 = {1, 2}; +} + +struct ExplicitCtor +{ + int x; + int y; + __init(int x) {...} + // compiler does not synthesize any ctors. +} +void test2() +{ + ExplicitCtor e0; // `e0` is uninitialized. + ExplicitCtor e1 = {1}; // calls `__init`. + ExplicitCtor e2 = {1, 2}; // error, no ctor matches initializer list. +} + +struct DefaultMember { + int x = 0; + int y = 1; + // compiler synthesizes: + // __init(int x = 0, int y = 1); +} +void test3() +{ + DefaultMember m; // `m` is uninitialized. + DefaultMember m1 = {}; // calls `__init()`, initialized to `{0,1}`. + DefaultMember m2 = {1}; // calls `__init(1)`, initialized to `{1,1}`. + DefaultMember m3 = {1,2}; // calls `__init(1,2)`, initialized to `{1,2}`. +} + +struct PartialInit { + // warning: not all members are initialized. + // members should either be all-uninitialized or all-initialized with + // default expr. + int x; + int y = 1; + // compiler synthesizes: + // __init(int x, int y = 1); +} +void test4() +{ + PartialInit i; // `i` is not initialized. + PartialInit i1 = {2}; // calls `__init`, result is `{2,1}`. + PartialInit i2 = {2, 3}; // calls `__init`, result is {2, 3} +} + +struct PartialInit2 { + int x = 1; + int y; // warning: not all members are initialized. + // compiler synthesizes: + // __init(int x, int y); +} +void test5() +{ + PartialInit2 j; // `j` is not initialized. + PartialInit2 j1 = {2}; // error, no ctor match. + PartialInit2 j2 = {2, 3}; // calls `__init`, result is {2, 3} +} + +public struct Visibility1 +{ + internal int x; + public int y = 0; + // the compiler does not synthesize any ctor. + // the compiler will try to synthesize: + // public __init(int y); + // but then it will find that `x` cannot be initialized. + // so this synthesis will fail and no ctor will be added + // to the type. +} +void test6() +{ + Visibility1 t = {0, 0}; // error, no matching ctor + Visibility1 t1 = {}; // error, no matching ctor + Visibility1 t2 = {1}; // error, no matching ctor +} + +public struct Visibility2 +{ + // Visibility2 type contains members of different visibility, + // which disqualifies it from being considered as C-style struct. + // Therefore we will not attempt the legacy fallback logic for + // initializer-list syntax. + internal int x = 1; + public int y = 0; + // compiler synthesizes: + // public __init(int y = 0); +} +void test7() +{ + Visibility2 t = {0, 0}; // error, no matching ctor. + Visibility2 t1 = {}; // OK, initialized to {1,0} via ctor call. + Visibility2 t2 = {1}; // OK, initialized to {1,1} via ctor call. +} + +internal struct Visibility3 +{ + // Visibility3 type is considered as C-style struct. + // Because all members have the same visibility as the type. + // Therefore we will attempt the legacy fallback logic for + // initializer-list syntax. + // Note that c-style structs can still have init exprs on members. + internal int x; + internal int y = 2; + // compiler synthesizes: + // internal __init(int x, int y = 2); +} +internal void test8() +{ + Visibility3 t = {0, 0}; // OK, initialized to {0,0} via ctor call. + Visibility3 t1 = {1}; // OK, initialized to {1,2} via ctor call. + Visibility3 t2 = {}; // OK, initialized to {0, 2} via legacy logic. +} + +internal struct Visibility4 +{ + // Visibility4 type is considered as C-style struct. + // And we still synthesize a ctor for member initialization. + // Because Visibility4 has no public members, the synthesized + // ctor will take 0 arguments. + internal int x = 1; + internal int y = 2; + // compiler synthesizes: + // internal __init(int x = 1, int y = 2); +} +internal void test9() +{ + Visibility4 t = {0, 0}; // OK, initialized to {0,0} via ctor call. + Visibility4 t1 = {3}; // OK, initialized to {3,2} via ctor call. + Visibility4 t2 = {}; // OK, initialized to {1,2} via ctor call. +} +``` + +### Zero Initialization + +The Slang compiler supported an option to force zero-initialization of all local variables. +This is currently implemented by adding `IDefaultInitializable` conformance to all user +defined types. With the direction we are heading, we should remove this option in the future. +For now we can continue to provide this functionality but through an IR rewrite pass instead +of changing the frontend semantics. + +When users specifies `-zero-initialize`, we should still use the same front-end logic for +all the checking. After lowering to IR, we should insert a `store` after all `IRVar : T` to +initialize them to `defaultConstruct(T)`. + + +Q&A +----------- + +### Should global static and groupshared variables be default initialized? + +Similar to local variables, all declarations are not default initialized at its declaration site. +In particular, it is difficult to efficiently initialized global variables safely and correctly in a general way on platforms such as Vulkan, +so implicit initialization for these variables can come with serious performance consequences. + +### Should `out` parameters be default initialized? + +Following the same philosophy of not initializing any declarations, `out` parameters are also not default-initialized. + +Alternatives Considered +----------------------- + +One important decision point is whether or not Slang should allow variables to be left in uninitialized state after its declaration as it is allowed in C++. In contrast, C# forces everything to be default initialized at its declaration site, which come at the cost of incurring the burden to developers to come up with a way to define the default value for each type. +Our opinion is we want to allow things as uninitialized, and to have the compiler validation checks to inform +the developer something is wrong if they try to use a variable in uninitialized state. We believe it is desirable to tell the developer what's wrong instead of using a heavyweight mechanism to ensure everything is initialized at declaration sites, which can have non-trivial performance consequences for GPU programs, especially when the variable is declared in groupshared memory. \ No newline at end of file diff --git a/docs/proposals/005-write-only-textures.md b/docs/proposals/005-write-only-textures.md new file mode 100644 index 0000000000..698ea6e866 --- /dev/null +++ b/docs/proposals/005-write-only-textures.md @@ -0,0 +1,61 @@ +SP #005: Write-Only Textures +================= + +Add Write-Only texture types to Slang's core module. + + +Status +------ + +Status: Design Review. + +Implementation: N/A + +Author: Yong He + +Reviewer: + +Background +---------- + +Slang inherits HLSL's RWTexture types to represent UAV/storage texture resources, this works well for HLSL, GLSL, CUDA and SPIRV targets. +However Metal has the notion of write only textures, and WebGPU has limited support of read-write textures. In WebGPU, a read-write texture can only have +uncompressed single-channel 32bit texel format, which means a `RWTexture2D` cannot be used to write to a `rgba8unorm` texture. + +To provide better mapping to write-only textures on Metal and WebGPU, we propose to add write-only textures to Slang to allow writing portable code +without relying on backend workarounds. + +Proposed Approach +----------------- + +Slang's core module already defines all texture types as a single generic `_Texture` type, where `access` is a value parameter +representing the allowed access of the texture. The valid values of access are: + +``` +kCoreModule_ResourceAccessReadOnly +kCoreModule_ResourceAccessReadWrite +kCoreModule_ResourceAccessRasterizerOrdered +kCoreModule_ResourceAccessFeedback +``` + +We propose to add another case: + +``` +kCoreModule_ResourceAccessWriteOnly +``` + +to represent write-only textures. + + +Also add the typealiases prefixed with "W" for all write only textures: +``` +WTexture1D, WTexture2D, ... +``` + +These types will be reported in the reflection API with `access=SLANG_RESOURCE_ACCESS_WRITE`. + +Write-only textures support `GetDimension` and `Store(coord, value)` methods. `Load` or `subscript` is not defined for write-only texture types, +so the user cannot write code that reads from a write-only texture. + +Write only textures are supported on all targets. For traditional HLSL, GLSL, SPIRV and CUDA targets, they are translated +exactly the same as `RW` textures. For Metal, they map to `access::write`, and for WGSL, they map to `texture_storage_X`. diff --git a/docs/proposals/007-variadic-generics.md b/docs/proposals/007-variadic-generics.md index 9249119f78..8034c03120 100644 --- a/docs/proposals/007-variadic-generics.md +++ b/docs/proposals/007-variadic-generics.md @@ -29,8 +29,8 @@ Background ---------- We have several cases that will benefit from variadic generics. One simplest example is the `printf` function is currently -defined to have different overloads for each number of arguments. The downside of duplicating overloads is the bloating standard -library size and a predefined upper limit of argument count. If users are to build their own functions that wraps the `printf` +defined to have different overloads for each number of arguments. The downside of duplicating overloads is the bloating the core +module size and a predefined upper limit of argument count. If users are to build their own functions that wraps the `printf` function, they will have to define a set of overloads for each number of arguments too, further bloating code size. Some of our users would like to implement the functor idiom in their shader code with interfaces. This is almost possible @@ -212,7 +212,7 @@ void k() {} // Error. void h() {} // OK. ``` -Addtionally, we establish these restrictions on how `expand` and `each` maybe used: +Additionally, we establish these restrictions on how `expand` and `each` maybe used: - The pattern type of an `expand` type expression must capture at least one generic type pack parameter in an `each` expression. - The type expression after `each` must refer to a generic type pack parameter, and the `each` expression can only appear inside an `expand` expression. @@ -222,7 +222,7 @@ Similarly, when using `expand` and `each` on values, we require that: - The pattern expression of an `expand` expression must capture at least one value whose type is a generic type pack parameter. - The expression after `each` must refer to a value whose type is a generic type pack parameter, and the `each` expression can only appear inside an `expand` expression. -Combined with type euqality constriants, variadic generic type pack can be used to define homogeneously typed parameter pack: +Combined with type euqality constraints, variadic generic type pack can be used to define homogeneously typed parameter pack: ``` void calcInts(expand each T values) where T == int { @@ -653,8 +653,8 @@ by packing up all the values computed at each "loop iteration" in an `IRMakeValu } ``` -With this, we can replace the original `IRExpand` inst with `%expand` and specailization is done. The specialized instructions like `IRGetTupleElement(%v, 0)` will be picked up -in the follow-up step during specalization and replaced with the actual value at the specified index since `%v` is a known value pack represented by `IRMakeValuePack`. So after +With this, we can replace the original `IRExpand` inst with `%expand` and specialization is done. The specialized instructions like `IRGetTupleElement(%v, 0)` will be picked up +in the follow-up step during specialization and replaced with the actual value at the specified index since `%v` is a known value pack represented by `IRMakeValuePack`. So after folding and other simplifications, we should result in ``` %expand = IRMakeValuePack(2,3,4) @@ -673,7 +673,7 @@ After the specialization pass, there should be no more `IRExpand` and `IRExpandT Alternatives Considered ----------------------- -We considered the C++ `...` oeprator syntax and Swift's `repeat each` syntax and ended up picking Swift's design because it is easier to parse and is less ambiguous. Swift is strict about requiring `each` to precede a generic type pack parameter so `void f(T v)` is not a valid syntax to prevent confusion on what `T` is in this context. In Slang we don't require this because `expand each T` is always simplified down to `T`, and refer to the type pack. +We considered the C++ `...` operator syntax and Swift's `repeat each` syntax and ended up picking Swift's design because it is easier to parse and is less ambiguous. Swift is strict about requiring `each` to precede a generic type pack parameter so `void f(T v)` is not a valid syntax to prevent confusion on what `T` is in this context. In Slang we don't require this because `expand each T` is always simplified down to `T`, and refer to the type pack. We also considered not adding variadic generics support to the language at all, and just implement `Tuple` and `IFunc` as special system builtin types, like how it is done in C#. However we believe that this approach is too limited when it comes to what the user can do with tuples and `IFunc`. Given Slang's position as a high performance GPU-first language, it is more important for Slang than other CPU languages to have a powerful type system that can provide zero-cost abstraction for meta-programming tasks. That lead us to believe that the language and the users can benefit from proper support of variadic generics. diff --git a/docs/proposals/008-tuples.md b/docs/proposals/008-tuples.md index efbcb7d282..a052585d62 100644 --- a/docs/proposals/008-tuples.md +++ b/docs/proposals/008-tuples.md @@ -28,7 +28,7 @@ to interop more directly with other parts of the user application written in oth Proposed Approach ----------------- -With variadic generics support, we can now easily define a Tuple type in stdlib as: +With variadic generics support, we can now easily define a Tuple type in the core module as: ``` __generic __magic_type(TupleType) @@ -43,7 +43,7 @@ This will allow users to instantiate tuple types from their code with `Tuple makeTuple(expand each T values); @@ -73,7 +73,7 @@ let v = t._1_0; ### Concatenation -We can define tuple concatenation operation in stdlib as: +We can define tuple concatenation operation in the core module as: ``` Tuple concat(Tuple first, Tuple second) { @@ -103,7 +103,7 @@ int foo() ### Operator Overloads We should have builtin operator overloads for all comparison operators if every element type of a tuple conforms to `IComparable`. -This can be supported by defining an overload for these operators in stdlib in the form of: +This can be supported by defining an overload for these operators in the core module in the form of: ``` bool assign(inout bool r, bool v) { r = v; return v; } @@ -137,4 +137,4 @@ Tuple concat(Tuple t, each U values); ``` However, this could lead to surprising behavior when the user writes `concat(t0, t1, t2)` where t1 and t2 are also tuples. Having this overload means the result would be `(t0_0, t0_1, ... t0_n, t1, t2)` where the user could be expecting `t1` and `t2` -to be flattened into the resulting tuple. To avoid this surprising behavior, we decide to not include this overload in stdlib. \ No newline at end of file +to be flattened into the resulting tuple. To avoid this surprising behavior, we decide to not include this overload in the core module. diff --git a/docs/proposals/010-new-diff-type-system.md b/docs/proposals/010-new-diff-type-system.md index dd5623a1d1..61157819e7 100644 --- a/docs/proposals/010-new-diff-type-system.md +++ b/docs/proposals/010-new-diff-type-system.md @@ -111,9 +111,9 @@ interface IDifferentiablePtrType : __IDifferentiableBase ``` -Some extras in stdlib allow us to constrain the diffpair type for things like `IArithmetic` +Some extras in the core module allow us to constrain the diffpair type for things like `IArithmetic` ```csharp -// --- STDLIB EXTRAS --- +// --- CORE MODULE EXTRAS --- interface ISelfDifferentiableValueType : IDifferentiableValueType { diff --git a/docs/proposals/012-language-version-directive.md b/docs/proposals/012-language-version-directive.md new file mode 100644 index 0000000000..3a75e50693 --- /dev/null +++ b/docs/proposals/012-language-version-directive.md @@ -0,0 +1,221 @@ +SP #012: Introduce a `#language` Directive +========================================= + +Status: Design Review + +Implementation: - + +Author: Theresa Foley + +Reviewer: - + +Introduction +------------ + +We propose to add a preprocessor directive, `#language` to allow a Slang source file to specify the version of the Slang language that is used in that file. +The basic form is something like: + + // MyModule.slang + + #language slang 2024.1 + + ... + +In the above example, the programmer has declared that their file is written using version 2024.1 of the Slang language and standard library. +Slang toolsets with versions below 2024.1 will refuse to compile this file, since it might use features that they do not support. +Slang toolsets with versions greater than 2024.1 *may* refuse to compile the file, if they have removed support for that language version. + +Putting a language version directly in source files allows the Slang language and standard library to evolve (including in ways that remove existing constructs) without breaking existing code. +A single release of the Slang toolchain may support a range of language versions, with different supported language/library constructs, and select the correct features to enable/disable based on the `#language` directive. + +When a release of the Slang toolchain doesn't support the language version requested by a programmer's code, the diagnostics produced can clearly state the problem and possible solutions, such as switching to a different toolchain version, or migrating code. + +Background +---------- + +Like many programming languages, Slang experiences a tension between the desire for rapid innovation/evolution and stability. +One of the benefits that users of Slang have so far enjoyed has been the rapid pace of innovation in the language and its standard library. +However, as developers start to have larger bodies of Slang code, they may become concerned that changes to the language could break existing code. +There is no magical way to keep innovating while also keeping the language static. + +This proposal is an attempt to find a middle road between the extremes of unconstrained evolution and ongoing stasis. + +Related Work +------------ + +### GLSL ### + +The most obvious precedent for the feature proposed here is the [`#version` directive](https://www.khronos.org/opengl/wiki/Core_Language_(GLSL)#Version) in GLSL, which can be used to specify a version of the GLSL language being used and, optionally, a profile name: + + #version 460 core + +There are some key lessons from the history of GLSL that are worth paying attention to: + +* When OpenGL ES was introduced, the OpenGL ES Shading Language also used an identical `#version` directive, but the meaning of a given version number was different between GLSL and GLSL ES (that is, different language features/capabilities were implied by the same `#version`, depending on whether one was compiling with a GLSL or GLSL ES compiler). The use of the optional profile name is highly encouraged when there might be differences in capability not encoded by just the version number. + +* Initially, the version numbers for OpenGL and GLSL were not aligned. For example, OpenGL 2.0 used GLSL 1.10 by default. This led to confusion for developers, who needed to keep track of what API version corresponded to what language version. The version numbers for OpenGL and GLSL became aligned starting with OpenGL 3.3 and GLSL 3.30. + +* A common, but minor, gotcha for developers is that the GLSL `#version` directive can only be preceded by trivia (whitespace and comments) and, importantly, cannot be preceded by any other preprocessor directives. This limitation has created problems when applications want to, e.g., prepend a sequence of `#define`s to an existing shader that starts with a `#version`. + +When a GLSL file does not include a `#version` directive, it implicitly indicates version 1.10. +This is a safe o + +### Racket ### + +While it is a very different sort of language than Slang, it is valuable to make note of the Racket programming language's [`#lang` notation](https://docs.racket-lang.org/guide/Module_Syntax.html#%28part._hash-lang%29). + +A `#lang` line like: + + #lang scribble/base + +indicates that the rest of the file should be read using the language implementation in the module named `scribble/base`. +Different modules can implement vastly different languages (e.g., `scribble/base` is a LaTeX-like document-preparation language). + +This construct in Racket is extremely flexible, allowing for entirely different languages (e.g., custom DSLs) to be processed by the Racket toolchain, but it could also trivially be used to support things like versioning: + + #lang slang 2024.1 + +While we do not necessarily need or want the same degree of flexibility for the Slang language itself, it is worth noting that the Slang project, and its toolchain, is in the situation of supporting multiple distinct languages/dialects (Slang, a GLSL-flavored dialect, and an HLSL-flavored dialect), and has extensive logic for inferring the right language to use on a per-file basis from things like file extensions. + +The Racket toolchain treats files without a `#lang` line as using the ordinary Racket language, and provide whatever language and library features were current at the time that toolchain was built. + +### Other Languages ### + +Most other language implementations do not embed versioning information in source files themselves, and instead make the language version be something that is passed in via compiler options: + +* gcc and clang use the `-std` option to select both a language and a version of that language: e.g., `c99` vs `c++14`. + +* dxc uses the `-HV` option to specify the version of the HLSL language to use, typically named by a year: e.g., `2016` or `2021`. + +* Rust developers typically use configuration files for the Cargo package manager, which allows specifying the Rust language and compiler version to use with syntax like `rust-version = "1.56"`. + +When language versions are not specified via these options, most toolchains select a default, but that default may change between releases of the toolchain (e.g., recent versions of clang will use C++17 by default, even if older releases of the toolchain defaulted to C++14 or lower). + + +Proposed Approach +----------------- + +### Language and Compiler Versions ### + +We will differentiate between two kinds of versions, which will have aligned numbering: + +* The *language version* determines what language features (keywords, attributes, etc.) and standard library declarations (types, functions, etc.) are available, and what their semantic guarantees are. + +* The *compiler version* or *toolset version* refers to the version of a release of the actual Slang tools such as `slangc`, `slang.dll`, etc. + +This proposal doesn't intend to dictate the format used for version numbers, since that is tied into the release process for the Slang toolset. +We expect that version numbers will start with a year, so that, e.g., `2025.0` would be the first release in the year 2025. + +A given version of the Slang toolset (e.g, `2024.10`) should always support the matching language version. + +If this proposal is accepted, we expect releases of the Slang toolset to support a *range* of language versions, ideally covering a full year or more of backwards compatibility. +This proposal does not seek to make any guarantees about the level of backwards compatibility, leaving that the Slang project team to determine in collaboration with users. + +### `#language` Directives ### + +Any file that is being processed as Slang code (as opposed to HLSL or GLSL) may have a `#language` directive and, if it does, that directive determines the language version required by that file. + +A `#language` directive specifying Slang version 2025.7 would look like: + + #language slang 2025.7 + +If the toolset being used supports the requested version, it will process that file with only the capabilities of that language version. +If the requested version is out of the range supported by the toolset (either too old or too new) compilation will fail with an appropriate diagnostic. + +If a file has *no* version directive, then the toolset will process that file as if it requested the version corresponding to the toolset release (e.g., a 2025.1 toolset release would compile such a file using language version 2025.1). + +Detailed Explanation +-------------------- + +* A `#language` directive must only be preceded by trivia (whitespace and comments). + +* The directive must always be of the form `#language slang `; it is not valid to only list a version number without the language name `slang`. + +* The version number follows the syntactic form of a floating-point literal, and might be lexed as one for simplicity, but internally each of the components of the version should be treated as an integer. For example, a version `2026.10` is *not* equivalent to `2026.1`, and is a higher version number than `2026.9`. + +* We are not proposing strict adherence to [Semantic Versioning](https://semver.org/) at this time. + +* The `#language` directive will not support specifying a version in the form `MAJOR.MINOR.PATCH` - only `MAJOR` and `MAJOR.MINOR` are allowed. The assumption is that patch releases should always be backwards-compatible, and a given toolset can always safely use the highest patch number that matches the requested version. + +* If the version number is given as just the form `MAJOR` instead of `MAJOR.MINOR`, then the toolset will use the highest language version it supports that has that major version. That is, `#language slang 2026` is not an alias for `2026.0`, but instead acts as a kind of wildcard, matching any `2026.*` version. + +* The directive is allowed to be given as just `#language slang`, in which case the toolset will use the highest supported language version, as it would when the directive is absent. + +* If an explicit compiler option was used to select a language other than Slang (e.g., via `-lang hlsl` to explicitly select HLSL), then the `#language` directive described in this proposal will result in an error being diagnosed. + +* When the toolset version and the language version are not the same (e.g., a `2026.1` compiler is applied to `2025.3` code), the request language version *only* affects what language and library constructs are supported, and their semantics. Things like performance optimizations, supported targets, etc. are still determined by the toolset. + +Alternatives Considered +----------------------- + +### Compiler Options ### + +The main alternative here is to allow the language version to be specified via compiler options. +The existing `-lang` option for `slangc` could be extended to include a language version: e.g., `slang2025.1`. + +This proposal is motivated by extensive experience with the pain points that arise when semantically-significant options, flags, and capabilities required by a project are encoded not in its source code, but only in its build scripts or other configuration files. +Anybody who has been handed a single `.hlsl` file and asked to simply compile it (e.g., to reproduce a bug or performance issue) likely knows the litany of questions that need to be answered before that file is usable: what is the entry point name? What stage? What shader model? + +The addition of the `[shader(...)]` attribute to HLSL represents a significant improvement to quality-of-life for developers, in part because it encodes the answers to two of the above question (the entry point name and stage) into the source code itself. +We believe this example should be followed, to enable as much information as possible that is relevant to compilation to be embedded in the source itself. + +### Leaving Out the Language Name ### + +It is tempting to support a directive with *just* the language version, e.g. something like: + + #version 2025.3 + +We strongly believe that including an explicit language name is valuable for future-proofing, especially given the lessons from GLSL and GLSL ES mentioned earlier. + +The requirement of an explicit language name has the following benefits: + +* It avoids any possible confusion with the GLSL `#version` directive, which serves a similar purpose but has its own incompatible version numbering. If we supported using just a bare version number, then there would be a strong push to use the name `#version` for our directive instead of `#language`. + +* It leaves the syntax open to future extensions, such that the Slang toolset could recognize other languages/dialects (e.g., supporting a `#language hlsl 2021` directive). Further down that particular rabbit-hole would be support for Racket-style DSLs. + +* It could potentially encourage other languages with overlapping communities (such as HLSL, WGSL, etc.) to adopt a matching/compatible directives, thus increasing the capability for tooling to automatically recognize and work with multiple languages. + +### Naming ### + +The name for this directive could easily lead to a lot of bikeshedding, with major alternatives being: + +* We could use `#version` to match GLSL, *especially* if we decide to change the approach and allow the language name `slang` to be elided. However, as discussed above, we think that this is likely to cause confusion between Slang's directive and the GLSL directive, especially when the Slang toolchain supports both languages. + +* We could hew closely to the precedent of Racket and use `#lang` instead of `#language`. There is no strong reason to pursue actual *compatibility* between the two (i.e., so that Slang code can be fed to the Racket toolchain, or vice versa), so the benefits of using the exact same spelling are minimal. This proposal favors being more humane and spelling things out fully over using contractions. + +### What is the right default? ### + +Given that existing Slang code doesn't use anything like `#language`, we cannot require that all files add the directive without breaking **all** existing code (which is unacceptable). +Thus we need to provide a default behavior for files that don't use `#language`, and there are seemingly only two reasonable options: + +* We can follow the precedent of GLSL and treat the absence of the directive as a request for the lowest possible version of the language. In our case, that would mean locking code without a `#language` to whatever was the last language version before `#language` was introduced. + +* We can follow the precedent of most other toolsets, and treat the absence of the directive as a request for the latest *stable* language version. That is, in the absence of a directive a program should have access to all *non-experimental* language features. + +While the first option was the right choice for GLSL (where existing applications might feed existing GLSL to new GPU drivers with new compiler implementations, and need it to Just Work), it ultimately leads to the directive being *de facto* required after a certain point (does anybody intentionally write GLSL 1.10 code any more?). + +Furthermore, interpreting a missing directive as asking for some old language version will not play nicely with our intention to allow newer toolset releases to (eventually) drop support for older language versions. It is probably reasonable for Slang releases in 2026 to no longer support the 2024 version of the language, but if that meant they would have to reject all source files that omit `#language` because of a version mismatch... again, we are back to the recognition that the directive has become required without us explicitly saying so. + +The second option means that omitting the `#language` directive will remain a meaningful choice for developers: it indicates an intention to track the language as it evolves, and to accept that some things might break along the way. +Any developer that does not accept those terms would need to specify the language version they are sticking with, which is exactly what the `#language` directive does. + + +Future Directions +----------------- + +Some of the more likely future directions include: + +* Allow the version part of `#language` to support a patch number, so that code that requires a particular bug fix to compile can be annotated with that fact and thus fail compilation cleanly when processed with a buggy toolset version. + +* Extend support for versioning to modules other than the standard library. The `#language` directive effectively introduces a versioning scheme for the Slang standard library and allows a user-defined module to specify the version(s) it is compatible with. This system could be extended to allow all modules (including user-defined modules) to define their own version numbers, and for `import` declarations to identify the version of a dependency that is required. + + * Taking such a direction should only be done with a careful survey of existing approaches to versioning used by package managers for popular languages, to ensure that we do not overlook important features that make management of dependency versions practical. + +Some less likely or less practical directions include: + +* Add other supported language names. Supporting something like `#language hlsl 2021` would allow for our HLSL-flavored dialect to recognize different versions of HLSL without resorting to command-line flags. + +* If we did the above, we would probably need to consider allowing a "safe" subset of preprocessor directives to appear before a `#language` line - most importantly, `#if` and `#ifdef`, so that one could conditionally compile a `#language` line depending on whether HLSL-flavored code is being processed with the Slang toolchain (which would support `#language`) or other compilers like dxc (which might not). + +* In the far-flung future, we could consider the Racket-like ability to have a `#language` directive support looking up a language implementation module matching the language name, and then parsing the rest of the file as that language, for DSL support, etc. + diff --git a/docs/proposals/013-aligned-load-store.md b/docs/proposals/013-aligned-load-store.md new file mode 100644 index 0000000000..ea6f495628 --- /dev/null +++ b/docs/proposals/013-aligned-load-store.md @@ -0,0 +1,58 @@ +SP #013: Aligned load store +========================================= + +Status: Experimental + +Implementation: [PR 5736](https://github.com/shader-slang/slang/pull/5736) + +Author: Yong He (yhe@nvidia.com) + +Reviewer: + +Introduction +---------- + +On many architectures, aligned vector loads (e.g. loading a float4 with 16 byte alignment) is often more efficient than ordinary unaligned loads. Slang's pointer type does not encode any additional alignment info, and all pointer read/writes are by default assuming the alignment of the underlying pointee type, which is 4 bytes for float4 vectors. This means that loading from a `float4*` will result in unaligned load instructions. + +This proposal attempts to provide a way for performance sensitive code to specify an aligned load/store through Slang pointers. + + +Proposed Approach +------------ + +We propose to add intrinsic functions to perform aligned load/store through a pointer: + +``` +T loadAligned(T* ptr); +void storeAligned(T* ptr, T value); +``` + +Example: + +``` +uniform float4* data; + +[numthreads(1,1,1)] +void computeMain() +{ + var v = loadAligned<8>(data); + storeAligned<16>(data+1, v); +} +``` + +Related Work +------------ + +### GLSL ### + +GLSL supports the `align` layout on a `buffer_reference` block to specify the alignment of the buffer pointer. + +### SPIRV ### + +In SPIRV, the alignment can either be encoded as a decoration on the pointer type, or as a memory operand on the OpLoad and OpStore operations. + +### Other Languages ### + +Most C-like languages allow users to put additional attributes on types to specify the alignment of the type. All loads/stores through pointers of the type will use the alignment. + +Instead of introducing type modifiers on data or pointer types, Slang should explicitly provide a `loadAligned` and `storeAligned` intrinsic functions to leads to `OpLoad` and `OpStore` with the `Aligned` memory operand when generating SPIRV. This way we don't have to deal with the complexity around rules of handling type coercion between modified/unmodified types and recalculate alignment for pointers representing an access chain. Developers writing performance sentisitive code can always be assured that the alignment specified on each critical load or store will be assumed, without having to work backwards through type modifications and thinking about the typing rules associated with such modifiers. \ No newline at end of file diff --git a/docs/proposals/13-extended-length-vectors.md b/docs/proposals/13-extended-length-vectors.md new file mode 100644 index 0000000000..3b0a2d190a --- /dev/null +++ b/docs/proposals/13-extended-length-vectors.md @@ -0,0 +1,193 @@ +# SP #13: Extended Length Vectors + +This proposal introduces support for vectors with 0 or more than 4 components in +Slang, extending the current vector type system while maintaining compatibility +with existing features. + +## Status + +Status: Design Review + +Implementation: N/A + +Author: Ellie Hermaszewska + +Reviewer: TBD + +## Background + +Currently, Slang supports vectors between 1 and 4 components (float1, float2, +float3, float4, (etc for other element types)), following HLSL conventions. +This limitation stems from historical GPU hardware constraints and HLSL's +graphics-focused heritage. However, modern compute applications may require +working with longer vectors for tasks like machine learning, scientific +computing, and select graphics tasks. + +Related Work + +- C++: std::array provides fixed-size array containers but lacks + vector-specific operations. SIMD types like std::simd (C++23) support + hardware-specific vector lengths. + +- CUDA: While CUDA doesn't provide native long vectors, libraries like Thrust + implement vector abstractions. Built-in vector types are limited to 1-4 + components (float1, float2, float3, float4). + +- OpenCL: Provides vector types up to 16 components (float2, float4, float8, + float16, etc.) with full arithmetic and logical operations. + +- Modern CPU SIMD: Hardware support for longer vectors continues to grow: + - Intel AVX-512: 512-bit vectors (16 float32s) + - ARM SVE/SVE2: Scalable vector lengths up to 2048 bits + - RISC-V Vector Extensions: Variable-length vector support + +These approaches demonstrate different strategies for handling longer vectors, +from fixed-size containers to hardware-specific implementations. + +## Motivation + +The primary motivation for extended length vectors is to support mathematical +operations and algorithms that naturally operate on higher-dimensional vectors. +While Slang already supports arrays for data storage, certain computations +specifically require vector semantics and operations that arrays don't provide. + +A key principle of this proposal is consistency: there is no fundamental +mathematical reason to limit vectors to 4 components. While the current limit +stems from graphics hardware history, modern compute applications shouldn't be +constrained by this arbitrary boundary. Supporting any natural length N +provides a clean, orthogonal design that follows mathematical principles rather +than historical limitations. + +Some example use cases: + +- Geometric Algebra and Clifford Algebras: + + - 6D vectors for Plücker coordinates (representing lines in 3D space) + - 6D vectors for screw theory in robotics (combining rotation and translation) + - 8D vectors for dual quaternions in their vector representation + - Higher-dimensional geometric products and outer products + +- Machine Learning: + + - Neural network feature vectors where vector operations (dot products, + normalization) are fundamental + - Distance metrics in high-dimensional embedding spaces + - Principal Component Analysis with multiple components + +- Scientific Computing: + - Spherical harmonics: Vector operations on coefficient spaces beyond 4D + - Quantum computing: State vectors in higher-dimensional Hilbert spaces + +This extension maintains Slang's mathematical vector semantics while enabling +computations that naturally operate in higher dimensions. The focus is not on +data storage (which arrays already handle) but on preserving vector-specific +operations and mathematical properties in higher dimensions and improving +consistency in the language. + +## Proposed Approach + +We propose extending Slang's vector type system to support vectors of arbitrary +length, supporting as many of the operations available to 4-vectors as +possible. Hardware limitations will prohibit a complete implementation, for +example certain atomic operations may not be possible on longer vectors. + +Key aspects: + +- Support vectors of any length that is a natural number, subject to the same + limits as fixed-length arrays +- Maintain existing syntax for vectors up to length 4 +- Maintain numeric swizzling operators. +- Support standard vector operations (add, multiply, etc.) + +## Detailed Explanation + +### Type System Integration + +There are no type system changes required, as the vector type constructor is +already parameterized over arbitrary vector length. + +### Operations + +#### Component Access: + +```slang +vector v; +float f0 = v.x; // First component +float f1 = v[1]; // Array-style access +float2 f3 = v_6_7; // last two member +vector = float2(1,2).xxxxxxxx; // extended swizzling example +``` + +#### Arithmetic Operations: + +Any operations currently supported and generic over restricted vector length +will be made unrestricted. + +Part of the scope of this work is to generate a precise list. + +For example all componentwise operations will be supported, as well as +reductions. + +Cross product will remain restricted to 3-vectors, and will not be overloaded +to 0-vectors or 7-vectors; this is due to worse type inference and error +messages should overloads be added. + +#### Atomic Operations: + +Not supported + +### Storage Operations: + +Most platforms restrict the type of data able to be stored in textures, this +proposal does not intend to work-around these restrictions. + +### Implementation Details + +Memory Layout: + +- Vectors are stored in contiguous memory +- Alignment follows platform requirements +- Padding may be required for certain lengths, for example padding to the + nearest multiple of 4 + +Performance Considerations: + +- No performance degredation for 1,2,3,4-vectors +- SIMD implementation work possible, not initially required + +## Alternatives Considered + +Fixed Maximum Length: + +- Could limit to common sizes (8, 16, 32) +- Simpler implementation but less flexible +- Rejected due to limiting future use cases + +Do nothing: + +- See motivation section + +## Additional notes + +### Zero-Length Vectors + +This proposal includes support for zero-length vectors. While seemingly +unusual, zero-length vectors are mathematically well-defined and provide +important completeness properties: + +- They are the natural result of certain slicing operations +- They serve as the identity element for vector concatenation + +### Extended Matrices + +While this proposal focuses on vectors, it naturally suggests a future +extension to matrices beyond the current 4x4 limit. Extended matrices would +follow similar principles. + +However, extended matrices introduce additional considerations: + +- Memory layout and padding strategies for large matrices +- Optimization of common operations (multiplication, transpose) + +These matrix-specific concerns are best addressed in a separate proposal that +can build upon the extended vector foundation established here. diff --git a/docs/proposals/implementation/ast-ir-serialization.md b/docs/proposals/implementation/ast-ir-serialization.md index 62f18dca96..cc65c07159 100644 --- a/docs/proposals/implementation/ast-ir-serialization.md +++ b/docs/proposals/implementation/ast-ir-serialization.md @@ -18,8 +18,8 @@ Currently, deserialization of the AST or IR for a module is an all-or-nothing op Either the entire `Decl` hierarchy of the AST is deserialized and turned into in-memory C++ objects, or none of it is. Similarly, we can either construct the `IRInst` hierarchy for an entire module, or none of it. -Releases of the Slang compiler typically included a serialized form of the standard library ("stdlib") module, and the runtime cost of deserializing this module has proven to be a problem for users of the compiler. -Becuse parts of the Slang compiler are not fully thread-safe/reentrant, the stdlib must be deserialized for each "global session," so that deserialization cost is incurred per-thread in scenarios with thread pools. +Releases of the Slang compiler typically included a serialized form of the core module, and the runtime cost of deserializing this module has proven to be a problem for users of the compiler. +Because parts of the Slang compiler are not fully thread-safe/reentrant, the core module must be deserialized for each "global session," so that deserialization cost is incurred per-thread in scenarios with thread pools. Even in single-threaded scenarios, the deserialization step adds significantly to the startup time for the compiler, making single-file compiles less efficient than compiling large batches of files in a single process. Overview of Proposed Solution @@ -49,7 +49,7 @@ The linker creates a *fresh* `IRModule` for the linked result, and clones/copies 1. Given an instruction in an input module to be copied over, use an `IRBuilder` on the output module to create a deep copy of that instruction and its children. -2. Whenever an instruction being copied over references another top-level instruction local to the same input module (that is, one without a linkage decoration), either construct a deep copy of the refereneced instruction in the output module, or find and re-use a copy that was made previously. +2. Whenever an instruction being copied over references another top-level instruction local to the same input module (that is, one without a linkage decoration), either construct a deep copy of the referenced instruction in the output module, or find and re-use a copy that was made previously. 3. Whenever an instruction being copied over references a top-level instruction that might be resolved to come from another module (that is, one with a linkage decoration), use the mangled name on the linkage decoration to search *all* of the input modules for candidate instructions that match. Use some fancy logic to pick one of them (the details aren't relevant at this exact moment) and then copy the chosen instruction over, more or less starting at (1) above. @@ -117,7 +117,7 @@ The two main ways that the child declarations are accessed are: Currently the `memberDictionary` field is private, and has access go through methods that check whether the dictionary needs to be rebuilt. The `members` field should also be made private, so that we can carefully intercept any code that wants to enumerate all members of a declaration. -We should probably also make the `memberDictionary` field map from a name to the *index* of a declaration in `members`, instead of direclty to a `Decl*`. +We should probably also make the `memberDictionary` field map from a name to the *index* of a declaration in `members`, instead of directly to a `Decl*`. > Note: We're ignoring the `ContainerDecl::transparentMembers` field here, but it does need to be taken into account in the actual implementation. @@ -137,7 +137,7 @@ The `members` array will either be empty, or will be correctly-sized for the num The entries in `members` may be null, however, if the corresponding child declaration has not been deserialized. We will need to attach a pointer to information related to lazy-loading to the `ContainerDecl`. -The simplest approach would be to add a field to `ContainerDecl`, but we could also consider using a custom `Modifier` if we are concerend about bloat. +The simplest approach would be to add a field to `ContainerDecl`, but we could also consider using a custom `Modifier` if we are concerned about bloat. #### Enumeration @@ -187,7 +187,7 @@ These complications lead to two big consequences for the encoding: * The array of *AST entries* will not just contain the entries for top-level `Decl`s. It needs to contain an entry for each `Decl` that might be referenced from elsewhere in the AST. For simplicity, it will probably contain *all* `Decl`s that are not explicitly stripped as part of producing the serialized AST. -* The array won't even consist of just `Decl`s. It will also need to have entries for things like `DeclRef`s and `Type`s that can also be referened as operands of AST nodes. +* The array won't even consist of just `Decl`s. It will also need to have entries for things like `DeclRef`s and `Type`s that can also be referenced as operands of AST nodes. As a stab at a simple representation, each AST entry should include: @@ -195,7 +195,7 @@ As a stab at a simple representation, each AST entry should include: * A range of bytes in the raw data that holds the serialized representation of that node (e.g., its operands) -An entry for a `ContainerDecl` should include (whether direclty or encoded in the raw data...) +An entry for a `ContainerDecl` should include (whether directly or encoded in the raw data...) * A contiguous range of AST entry indices that represent the direct children of the node, in declaration order (the order they'd appear in `ContainerDecl::members`) @@ -208,7 +208,7 @@ Given the above representation, there is no need to explicitly encode the parent Given an AST entry index for a `Decl`, we can find its parent by recursing through the hierarchy starting at the root, and doing a binary search at each hierarchy level to find the (unique) child declaration at that level which contains that index in its range of descendents. When there is a request to on-demand deserialize a `Decl` based on its AST entry index, we would need to first deserialize each of its ancestors, up the hierarchy. -That on-demand deserialization of the ancestors can follow the flow given above for recursively walking the hirarchy to find which declaration at each level contains the given index. +That on-demand deserialization of the ancestors can follow the flow given above for recursively walking the hierarchy to find which declaration at each level contains the given index. In order to support lookup of members of a declaration by name, we propose the following: @@ -283,4 +283,4 @@ Each entry in the abbreviation table would store: When deserializing a node, code would read its abbreviation index first, and then look up the corresponding abbreviation to both find important information about the node, and also to drive deserialization of the rest of its data (e.g., by determining how many operands to read before reading in children). -In cases where the low-level serialization uses things like variable-length encodings for integers, the abbreviations can be sorted so that the most-frequently used abbreviations have the lowest indices, and thus take the fewest bits/bytes to encode. \ No newline at end of file +In cases where the low-level serialization uses things like variable-length encodings for integers, the abbreviations can be sorted so that the most-frequently used abbreviations have the lowest indices, and thus take the fewest bits/bytes to encode. diff --git a/docs/proposals/legacy/001-basic-interfaces.md b/docs/proposals/legacy/001-basic-interfaces.md index 4d04cbe047..669537b423 100644 --- a/docs/proposals/legacy/001-basic-interfaces.md +++ b/docs/proposals/legacy/001-basic-interfaces.md @@ -1,7 +1,7 @@ Basic Interfaces ================ -The Slang standard library is in need of basic interfaces that allow generic code to be written that abstracts over built-in types. +The Slang core module is in need of basic interfaces that allow generic code to be written that abstracts over built-in types. This document sketches what the relevant interfaces and their operations might be. Status @@ -49,7 +49,7 @@ T horizontalSum( vector v ) } ``` -This alternative is much more palatable to users, but it results in them using a double-underscored interface (which we consider to mean "implementation details that are subject to change"). Users often get tripped up when they find out that certain operations that make sense to be available through `__BuiltinFloatingPointType` are not available (because those operations were not needed in the definition of the stdlib, which is what the `__` interfaces were created to support). +This alternative is much more palatable to users, but it results in them using a double-underscored interface (which we consider to mean "implementation details that are subject to change"). Users often get tripped up when they find out that certain operations that make sense to be available through `__BuiltinFloatingPointType` are not available (because those operations were not needed in the definition of the core module, which is what the `__` interfaces were created to support). Related Work ------------ @@ -228,11 +228,11 @@ The main reason for the current `__Builtin` interfaces is that it allows us to d ### What should the naming convention be for `interface`s in Slang? -These would be the first `interface`s officially exposed by the standard library. +These would be the first `interface`s officially exposed by the core module. While most of our existing code written in Slang uses an `I` prefix as the naming convention for `interface`s (e.g., `IThing`), we have never really discussed that choice in detail. Whatever we decide to expose for this stuff is likely to become the de facto convention for Slang code. -The `I` prefix is precedented in COM and C#/.net/CLR, which are likely to be familiar to many devleopers using Slang. +The `I` prefix is precedented in COM and C#/.net/CLR, which are likely to be familiar to many developers using Slang. Because of COM, it is also the convention used in the C++ API headers for Slang and GFX. The Rust/Swift languages do not distinguish between traits/protocols and other types. diff --git a/docs/proposals/legacy/002-api-headers.md b/docs/proposals/legacy/002-api-headers.md index 66b649228b..5efbc1d16b 100644 --- a/docs/proposals/legacy/002-api-headers.md +++ b/docs/proposals/legacy/002-api-headers.md @@ -29,7 +29,7 @@ We know that we cannot remove support for difficult cases, but it would be good Related Work ------------ -There are obviously far too many C/C++ APIs and approachs to design for C/C++ APIs for us to review them all. +There are obviously far too many C/C++ APIs and approaches to design for C/C++ APIs for us to review them all. We will simply note a few key examples that can be relevant for comparison. The gold standard for C/C++ APIs is ultimately plain C. Plain C is easy for most systems programmers to understand and benefits from having a well-defined ABI on almost every interesting platform. FFI systems for other languages tend to work with plain C APIs. Clarity around ABI makes it easy to know what changes/additions to a plain C API will and will not break binary compatibility. The Cg compiler API and the Vulkan GPU API are good examples of C-based APIs in the same domains as Slang and GFX, respectively. These APIs reveal some of the challenges of using plain C for large and complicated APIs: @@ -64,7 +64,7 @@ Across such APIs, we see a wide variety of strategies to dealing with extensibil * Vulkan uses "desc" structures (usually called "info" or "create info" structures), which contain a baseline set of state/fields, along with a linked list of dynamically-typed/-tagged extension structures. New functionality that only requires changes to "desc" structures can be added by defining a new tag and extension structure. New operations are added in a manner similar to OpenGL. -* D3D12 also uses COM interfaces and "desc" structures (although now officialy called "descriptions" to not overload the use of "descriptor" in descriptor tables), much like D3D11, and sometimes uses the same approach to extensibility (e.g., there are currently `ID3D12Device`, `ID3D12Device`, ... `ID2D12Device9`). In addition, D3D12 has also added two variations on Vulkan-like models for creating pipeline state (`ID3D12Device2::CreatePipelineState` and `ID3D12Device5::CreateStateObject`), using a notion of more fine-grained "subojects" that are dynamically-typed/-tagged and each have their own "desc". +* D3D12 also uses COM interfaces and "desc" structures (although now officially called "descriptions" to not overload the use of "descriptor" in descriptor tables), much like D3D11, and sometimes uses the same approach to extensibility (e.g., there are currently `ID3D12Device`, `ID3D12Device`, ... `ID2D12Device9`). In addition, D3D12 has also added two variations on Vulkan-like models for creating pipeline state (`ID3D12Device2::CreatePipelineState` and `ID3D12Device5::CreateStateObject`), using a notion of more fine-grained "subojects" that are dynamically-typed/-tagged and each have their own "desc". It is important to note that even with the nominal flexibility that COM provides around versioning, D3D12 has opted for a more fine-grained approach when dealing with something as complicated as GPU pipeline state. @@ -91,7 +91,7 @@ At the end of this document there is a lengthy code block that sketches a possib Questions --------- -### Will we generate all or some of the API header? If so, what will be the "ground truth" verison? +### Will we generate all or some of the API header? If so, what will be the "ground truth" version? Note that Vulkan and SPIR-V benefit from having ground-truth computer-readable definitions, allowing both header files and tooling code to be generated. @@ -278,7 +278,7 @@ namespace slang members initializers in `slang::SessionDesc`, but it *will* compile under C++14 and later. - If we want to deal with C++11 compatiblity in that case, we can, but + If we want to deal with C++11 compatibility in that case, we can, but it would slightly clutter up the way we declare these things. Realistically, we'd just split the two types: @@ -325,7 +325,7 @@ namespace slang struct SessionDesc0 { ... the original ... }; struct SessionDesc1 { ... the new one ... }; - typedef SessionDesc SesssionDesc1; + typedef SessionDesc SessionDesc1; At the point where we introduce a second version, it is probably the right time to enable developers to lock in to any version they choose. In the code above @@ -334,7 +334,7 @@ namespace slang at the point they compile. (If we wanted to get really "future-proof" we'd define every struct with the `0` - prefix right out of the gate, and always have the `typedef` in place. I'm not conviced + prefix right out of the gate, and always have the `typedef` in place. I'm not convinced that would ever pay off.) I expect most of this to be a non-issue if we are zealous about using fine-grained @@ -368,7 +368,7 @@ namespace slang UUID const& uuid, void** outObject) = 0; - /* Instead, most users will direclty call the operations only through + /* Instead, most users will directly call the operations only through wrappers that provide conveniently type-safe behavior: */ inline Result createCompileRequest( @@ -574,7 +574,7 @@ extern "C" and also to provide versioning support. We could define the same set of overloads here, with the same names, for - use by clients who don't actually care about C compatiblity but just like + use by clients who don't actually care about C compatibility but just like a C-style API. That is probably worth doing. Otherwise, we realistically need to start defining some de-facto naming @@ -612,7 +612,7 @@ extern "C" /* Finally, the C API level is where we should define the core factory entry point for creating and initializing the Slang global session (just like - in the current header). Here we jsut generalize it for creaitng "any" global + in the current header). Here we just generalize it for creaitng "any" global object, based on a UUID and a bunch of descs. */ SLANG_API SlangResult slang_createObject( @@ -645,7 +645,7 @@ generating as much of the API as possible anyway. /* Basic Types */ - /* We just define the basic types direclty, without the indirection + /* We just define the basic types directly, without the indirection through the declarations in the `slang::` namespace. */ @@ -846,7 +846,7 @@ use of exceptions instead of `Result`s: SLANG_SMART_PTR(ICompileRequest) createCompileRequest( CompileRequestDesc const& desc) { - SLANG_SMART_PTR(ICompileReqest) compileRequest; + SLANG_SMART_PTR(ICompileRequest) compileRequest; SLANG_THROW_IF_FAIL(_createCompileRequest( &desc, 1, SLANG_UUID_OF(IComileRequest), comileRequest.writeRef())); return compileRequest; @@ -857,7 +857,7 @@ use of exceptions instead of `Result`s: #endif } -Both for the sake of C API and especialy for gfx (both C and C++), we should consider +Both for the sake of C API and especially for gfx (both C and C++), we should consider defining some coarse-grained aggregate desc types as utilities: struct SimpleRasterizationPipelineStateDesc @@ -886,7 +886,7 @@ defining some coarse-grained aggregate desc types as utilities: // List members for attachments, etc. rather than just pointer-and-count: private: List colorAttachments; - public: AttachmentDesc& addColorAttachement(); + public: AttachmentDesc& addColorAttachment(); // There should also be convenience constructors common cases // (especially relevant for things like textures). @@ -924,7 +924,7 @@ defining some coarse-grained aggregate desc types as utilities: }; While the implementation of this monolithic desc types would not necessarily be pretty, -it would enable users who want the benefits of the "one big struct" appraoch to get +it would enable users who want the benefits of the "one big struct" approach to get what they seem to want. The next step down this road is to take these aggregate desc types and turn them into diff --git a/docs/proposals/legacy/003-error-handling.md b/docs/proposals/legacy/003-error-handling.md index 28652824f0..e8fb44402e 100644 --- a/docs/proposals/legacy/003-error-handling.md +++ b/docs/proposals/legacy/003-error-handling.md @@ -43,10 +43,10 @@ Related Work In the absence of language support, developers typically signal and propagate errors using *error codes*. The COM `HRESULT` type is a notable example of a well-defined system for using error codes in C/C++ and other languages. Error codes have the benefit of being easy to implement, and relatively light-weight. The main drawback of error codes is that developers often forget to check and/or propagate them, and when they do remember to do so it adds a lot of boilerplate. -Additonally, reserving the return value of every function for returning an error code makes code more complex because the *actual* return value must be passed via a function parameter. +Additionally, reserving the return value of every function for returning an error code makes code more complex because the *actual* return value must be passed via a function parameter. C++ uses *exceptions* for errors in various categories, including unpredictable but recoverable failures. -Propagation of errors up the call stack is entirely automatic, with unwinding of call frames and destruction of their local state occuring as part of the search for a handler. +Propagation of errors up the call stack is entirely automatic, with unwinding of call frames and destruction of their local state occurring as part of the search for a handler. Neither functions that may throw nor call sites to such functions are syntactically marked. Exceptions in C++ have often been implemented in ways that add overhead and require complicated support in platform ABIs and intermediate languages to support. @@ -66,7 +66,7 @@ Functions that return `X` and those that return `Result` are not directl Swift provides more syntactic support for errors than Rust, although the underlying mechanism is similar. A Swift function may have `throws` added between the parameter list and return type to indicate that a function may yield an error. All errors in Swift must implement the `Error` protocol, and all functions that can `throw` may produce any `Error` (although there are proposals to extend Swift with "typed `throws`"). -Any call site to a `throws` function must have a prefix `try` (e.g., `try f(a, b)`), which works simiarly to Rust's `?`; any error produced by the called function is propagated, and the ordinary result is returned. +Any call site to a `throws` function must have a prefix `try` (e.g., `try f(a, b)`), which works similarly to Rust's `?`; any error produced by the called function is propagated, and the ordinary result is returned. Swift provides an explicit `do { ... } catch ...` construct that allows handlers to be established. It also provides for conversion between exceptions and an explicit `Result` type, akin to Rust's. Higher-order functions may be declared as `rethrows` to indicate that whether or not they throw depends on whether or not any of their function-type parameters is actually a `throws` function at a call site. @@ -84,7 +84,7 @@ Proposed Approach We propose a modest starting point for error handling in Slang that can be extended over time. The model borrows heavily from Swift, but also focuses on strongly-typed errors. -The standard library will provide a built-in interface for errors, initially empty: +The core module will provide a built-in interface for errors, initially empty: ``` interface IError {} @@ -203,7 +203,7 @@ let y : int = 1 + _tmp; ### Desugar `throw` Expressions -For every `throw` site in a function body, there will either be no in-scope `catch` clause that matches the type thrown, or there will be eactly one most-deeply-nested `catch` that statically matches. +For every `throw` site in a function body, there will either be no in-scope `catch` clause that matches the type thrown, or there will be exactly one most-deeply-nested `catch` that statically matches. Front-end semantic checking should be able to associate each `throw` with the appropriate `catch` if any. For `throw` sites with no matching `catch`, the operation simply translates to a `return` of the thrown error (because of the way we transformed the function signature). diff --git a/docs/proposals/legacy/005-components.md b/docs/proposals/legacy/005-components.md index b257140a7b..ff53d0f770 100644 --- a/docs/proposals/legacy/005-components.md +++ b/docs/proposals/legacy/005-components.md @@ -239,7 +239,7 @@ class X ``` In the above, an instance of `X` can always find the `Y` it depends on easily and (relatively) efficiently. -There is no particularly high overhead to having `X` diretly store an indirect reference to `Y` (at least not for coarse-grained units), and it is trivial for multiple units like `X` to all share the same *instance* of `Y` (potentially even including mutable state, for applications that like that sort of thing). +There is no particularly high overhead to having `X` directly store an indirect reference to `Y` (at least not for coarse-grained units), and it is trivial for multiple units like `X` to all share the same *instance* of `Y` (potentially even including mutable state, for applications that like that sort of thing). In general most CPU languages (and especially OOP ones) can express the concepts of "is-a" and "has-a" but they often don't distinguish between when "has-as" means "refers-to-and-depends-on-a" vs. when it means "aggregates-and-owns-a". This is important when looking at a GPU language like Slang, where "aggergates-and-owns-a" is easy (we have `struct` types), but "refers-to-and-depends-on-a" is harder (not all of our targets can really support pointers). @@ -279,7 +279,7 @@ interface IMaterialSystem void doMaterialStuff(); } -__component_type DefualtMaterialSystem : IMaterialSystem +__component_type DefaultMaterialSystem : IMaterialSystem { __require lighting : ILightingSystem; @@ -365,7 +365,7 @@ At the point where an `__aggregate SomeType` member is declared, the front-end s For example, because `DefaultIntegratorSystem` declares `__require IMaterialSystem`, the compiler searches in the current context for a value that can provide that interface. It finds a single suitable value: the value implicitly defined by `__aggregate DefaultMaterialSystem`, and thus "wires up" the input dependency of the `DefaultIntegratorSystem`. -It is posible for a `__require` in an `__aggregate`d member to be satisfied via another `__require` of its outer type: +It is possible for a `__require` in an `__aggregate`d member to be satisfied via another `__require` of its outer type: ``` __component_type MyUnit @@ -384,7 +384,7 @@ While the above examples do not show it, component types should be allowed to co Detailed Explanation -------------------- -Component types need to be restricted in where and how they can be used, to avoid creating situations that would give them all the flexiblity of arbitrary `class`es. +Component types need to be restricted in where and how they can be used, to avoid creating situations that would give them all the flexibility of arbitrary `class`es. The only places where a component type may be used are: * `__require` and `__aggregate` declarations @@ -434,7 +434,7 @@ Note that when the generated code invokes an operation through one of the `__agg Effectively, the compiler generates all of the boilerplate parameter-passing that the programmer would have otherwise had to write by hand. -It might or might not be obvious that the notion of "component type" being described here has a clear correspondance to the `IComponentType` interface provided by the Slang runtime/compilation API. +It might or might not be obvious that the notion of "component type" being described here has a clear correspondence to the `IComponentType` interface provided by the Slang runtime/compilation API. It should be possible for us to provide reflection services that allow a programmer to look up a component type by name and get an `IComponentType`. The existing APIs for composing, specializing, and linking `IComponentType`s should Just Work for explicit `__component_type`s. Large aggregates akin to `MyProgram` above can be defined entirely via the C++ `IComponentType` API at program runtime. @@ -456,7 +456,7 @@ That last point is important, since a component type allows users to define a co ### Can the `__component_type` construct just be subsumed by either `struct` or `class`? -Maybe. The key challenge is that component types need to provide the "look and feel" of by-refernece re-use rather than by-value copying. A `__require T` should effectively act like a `T*` and not a bare `T` value, so I am reluctant to say that should map to `struct`. +Maybe. The key challenge is that component types need to provide the "look and feel" of by-reference re-use rather than by-value copying. A `__require T` should effectively act like a `T*` and not a bare `T` value, so I am reluctant to say that should map to `struct`. ### But what about `[mutating]` operations and writing to fields of component types, then? @@ -484,7 +484,7 @@ __component_type C { __require A; ... } __component_type D { __require B; __require C; ... } ``` -The Spark shading language research project used multiple mixin class inheritance to compose units of shader code akin to what are being proposed here as coponent types (hmm... I guess that should go into related work...). +The Spark shading language research project used multiple mixin class inheritance to compose units of shader code akin to what are being proposed here as component types (hmm... I guess that should go into related work...). In general, using inheritance to model something that isn't an "is-a" relationship is poor modeling. Inheritance as a modelling tool cannot capture some patterns that are possible with `__aggregate` (notably, with mixin inheritance you can't get multiple "copies" of a component). diff --git a/docs/proposals/legacy/006-artifact-container-format.md b/docs/proposals/legacy/006-artifact-container-format.md index 81910151b9..04daf3bd49 100644 --- a/docs/proposals/legacy/006-artifact-container-format.md +++ b/docs/proposals/legacy/006-artifact-container-format.md @@ -491,7 +491,7 @@ The grouping - how does it actually work? It might require specifying what group An advantage to this approach is that policy of how naming works as a user space problem. It is also powerful in that it allows control on compilation that has some independence from the name. -We could have some options that are named, but do not appear as part of the name/path within the container. The purpose of this is to allow customization of a compilation, without that customization necessarily appearing withing the application code. The container could store group of named options that is used, such that it is possible to recreate the compilation or perhaps to detect there is a difference. +We could have some options that are named, but do not appear as part of the name/path within the container. The purpose of this is to allow customization of a compilation, without that customization necessarily appearing within the application code. The container could store group of named options that is used, such that it is possible to recreate the compilation or perhaps to detect there is a difference. ### JSON options @@ -776,7 +776,7 @@ Discussion: Container A typical container will contain kernels - in effect blobs. The blobs themselves, or the blob names are not going to be sufficient to express the amount of information that is necessary to meet the goals laid out at the start of this document. Some extra information may be user supplied. Some extra information might be user based to know how to classify different kernels. Therefore it is necessary to have some system to handle this metadata. -As previously discussed the underlying container format is a file system. Some limited information could be infered from the filename. For example a .spv extension file is probably SPIR-V blob. For more rich meta data describing a kernel something more is needed. Two possible approaches could be to have a 'manifest' that described the contents of the container. Another approach would to have a file associated with the kernel that describes it's contents. +As previously discussed the underlying container format is a file system. Some limited information could be inferred from the filename. For example a .spv extension file is probably SPIR-V blob. For more rich meta data describing a kernel something more is needed. Two possible approaches could be to have a 'manifest' that described the contents of the container. Another approach would to have a file associated with the kernel that describes it's contents. Single Manifest Pros diff --git a/docs/repro.md b/docs/repro.md index 54ad8b9788..4d469fa280 100644 --- a/docs/repro.md +++ b/docs/repro.md @@ -3,9 +3,9 @@ Slang Compilation Reproduction Slang has both API and command line support for reproducing compilations, so called 'repro' functionality. -One use of the feature is if a compilation fails, or produces an unexpected or wrong result, it provides a simple to use mechanism where the compilation can be repeated or 'reproduced', most often on another machine. Instead of having to describe all the options, and make sure all of the files that are used are copied, and in such a way that it repeats the result, all that is required is for the compilation to be run on the host machine with repro capture enabled, and then that 'repro' used for a compilation on the test machine. There are also some mechanisms where the contents of the orginal compilation can be altered. +One use of the feature is if a compilation fails, or produces an unexpected or wrong result, it provides a simple to use mechanism where the compilation can be repeated or 'reproduced', most often on another machine. Instead of having to describe all the options, and make sure all of the files that are used are copied, and in such a way that it repeats the result, all that is required is for the compilation to be run on the host machine with repro capture enabled, and then that 'repro' used for a compilation on the test machine. There are also some mechanisms where the contents of the original compilation can be altered. -The actual data saved is the contents of the SlangCompileReqest. Currently no state is saved from the SlangSession. Saving and loading a SlangCompileRequest into a new SlangCompileRequest should provide two SlangCompileRequests with the same state, and with the second compile request having access to all the files contents the original request had directly in memory. +The actual data saved is the contents of the SlangCompileRequest. Currently no state is saved from the SlangSession. Saving and loading a SlangCompileRequest into a new SlangCompileRequest should provide two SlangCompileRequests with the same state, and with the second compile request having access to all the files contents the original request had directly in memory. There are a few command line options @@ -26,9 +26,9 @@ First it is worth just describing what is required to reproduce a compilation. M In order to capture a complete repro file typically a compilation has to be attempted. The state before compilation can be recorded (through the API for example), but it may not be enough to repeat a compilation, as files referenced by the compilation would not yet have been accessed. The repro feature records all of these accesses and contents of such files such that compilation can either be completed or at least to the same point as was reached on the host machine. -One of the more subtle issues around reproducing a compilation is around filenames. Using the API, a client can specify source files without names, or multiple files with the same name. If files are loaded via `ISlangFileSystem`, they are typically part of a hiearchical file system. This could mean they are referenced relatively. This means there can be distinct files with the same name but differenciated by directory. The files may not easily be reconstructed back into a similar hieararchical file system - as depending on the include paths (or perhaps other mechanisms) the 'files' and their contents could be arranged in a manner very hard to replicate. To work around this the repro feature does not attempt to replicate a hierarchical file system. Instead it gives every file a unique name based on their original name. If there are multiple files with the same name it will 'uniquify' them by appending an index. Doing so means that the contents of the file system can just be held as a flat collection of files. This is not enough to enable repeating the compilation though, as we now need Slang to know which files to reference when they are requested, as they are now no longer part of a hierarchical file system and their names may have been altered. To achieve this the repro functionality stores off a map of all path requests to their contents (or lack there of). Doing so means that the file system still appears to Slang as it did in the original compilation, even with all the files being actually stored using the simpler 'flat' arrangement. +One of the more subtle issues around reproducing a compilation is around filenames. Using the API, a client can specify source files without names, or multiple files with the same name. If files are loaded via `ISlangFileSystem`, they are typically part of a hierarchical file system. This could mean they are referenced relatively. This means there can be distinct files with the same name but differentiated by directory. The files may not easily be reconstructed back into a similar hieararchical file system - as depending on the include paths (or perhaps other mechanisms) the 'files' and their contents could be arranged in a manner very hard to replicate. To work around this the repro feature does not attempt to replicate a hierarchical file system. Instead it gives every file a unique name based on their original name. If there are multiple files with the same name it will 'uniquify' them by appending an index. Doing so means that the contents of the file system can just be held as a flat collection of files. This is not enough to enable repeating the compilation though, as we now need Slang to know which files to reference when they are requested, as they are now no longer part of a hierarchical file system and their names may have been altered. To achieve this the repro functionality stores off a map of all path requests to their contents (or lack there of). Doing so means that the file system still appears to Slang as it did in the original compilation, even with all the files being actually stored using the simpler 'flat' arrangement. -This means that when a repro is 'extracted' it does so to a directory which holds the files with their unique 'flat' names. The name of the directory is the name of the repro file without it's extension, or if it has no extension, with the postfix '-files'. This directory will be referered to from now on as the `repro directory`. +This means that when a repro is 'extracted' it does so to a directory which holds the files with their unique 'flat' names. The name of the directory is the name of the repro file without it's extension, or if it has no extension, with the postfix '-files'. This directory will be referred to from now on as the `repro directory`. When a repro is loaded, before files are loaded from the repro itself, they will first be looked for via their unique names in the `repro directory`. If they are not there the contents of the repro file will be used. If they are there, their contents will be used instead of the contents in the repro. This provides a simple mechanism to be able to alter the source in a repro. The steps more concretely would be... @@ -85,6 +85,6 @@ The function `spExtractRepro` allows for extracting the files used in a request The function `spLoadReproAsFileSystem` creates a file system that can access the contents of the repro with the same paths that were used on the originating system. The ISlangFileSystemExt produced can be set on a request and used for compilation. -Repro files are currently stored in a binary format. This format is sensitive to changes in the API, as well as internal state within a SlangCompileRequest. This means that the functionality can only be guarenteed to work with exactly the same version of Slang on the same version of compiler. In practice things are typically not so draconian, and future versions will aim to provide a more clear slang repro versioning system, and work will be performed to make more generally usable. +Repro files are currently stored in a binary format. This format is sensitive to changes in the API, as well as internal state within a SlangCompileRequest. This means that the functionality can only be guaranteed to work with exactly the same version of Slang on the same version of compiler. In practice things are typically not so draconian, and future versions will aim to provide a more clear slang repro versioning system, and work will be performed to make more generally usable. -Finally this version of the repo system does not take into account endianess at all. The system the repro is saved from must have the same endianess as the system loaded on. +Finally this version of the repo system does not take into account endianness at all. The system the repro is saved from must have the same endianness as the system loaded on. diff --git a/docs/scripts/Program.cs b/docs/scripts/Program.cs index d543f399ec..8a87f153de 100644 --- a/docs/scripts/Program.cs +++ b/docs/scripts/Program.cs @@ -1,7 +1,8 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; -using System.Collections.Generic; namespace toc { public class Builder @@ -10,12 +11,13 @@ public static string getAnchorId(string title) { StringBuilder sb = new StringBuilder(); title = title.Trim().ToLower(); + foreach (var ch in title) { if (ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9' - || ch == '-') + || ch == '-'|| ch =='_') sb.Append(ch); - else if (ch==' ' || ch =='_') + else if (ch == ' ' ) sb.Append('-'); } return sb.ToString(); @@ -128,7 +130,7 @@ public static string Run(string path) { StringBuilder outputSB = new StringBuilder(); outputSB.AppendFormat("Building table of contents from {0}...\n", path); - var files = System.IO.Directory.EnumerateFiles(path, "*.md"); + var files = System.IO.Directory.EnumerateFiles(path, "*.md").OrderBy(f => System.IO.Path.GetFileName(f)); List nodes = new List(); foreach (var f in files) { @@ -230,4 +232,4 @@ public static string Run(string path) return outputSB.ToString(); } } -} \ No newline at end of file +} diff --git a/docs/scripts/release-note.sh b/docs/scripts/release-note.sh index f1a93137ac..d63ee8736c 100644 --- a/docs/scripts/release-note.sh +++ b/docs/scripts/release-note.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/usr/bin/env bash # This script generates a release note. # It prints information about breaking-changes first and the rest. # The content is mostly based on `git log --oneline --since 202X-YY-ZZ`. @@ -16,27 +16,23 @@ verbose=true $verbose && echo "Reminder: PLEASE make sure your local repo is up-to-date before running the script." >&2 gh="" -for candidate in "$(which gh.exe)" "/mnt/c/Program Files/GitHub CLI/gh.exe" "/c/Program Files/GitHub CLI/gh.exe" -do - if [ -x "$candidate" ] - then - gh="$candidate" - break - fi +for candidate in "$(which gh.exe)" "/mnt/c/Program Files/GitHub CLI/gh.exe" "/c/Program Files/GitHub CLI/gh.exe" "/cygdrive/c/Program Files/GitHub CLI/gh.exe"; do + if [ -x "$candidate" ]; then + gh="$candidate" + break + fi done -if [ "x$gh" = "x" ] || ! [ -x "$gh" ] -then - echo "File not found: gh.exe" - echo "gh.exe can be downloaded from https://cli.github.com" - exit 1 +if [ "x$gh" = "x" ] || ! [ -x "$gh" ]; then + echo "File not found: gh.exe" + echo "gh.exe can be downloaded from https://cli.github.com" + exit 1 fi $verbose && echo "gh.exe is found from: $gh" >&2 -if [ "x$1" = "x" ] -then - echo "This script requires 'since' information for git-log command." - echo "Usage: $0 2024-07-30" - exit 1 +if [ "x$1" = "x" ]; then + echo "This script requires 'since' information for git-log command." + echo "Usage: $0 2024-07-30" + exit 1 fi since="$1" @@ -45,62 +41,55 @@ commitsCount="$(echo "$commits" | wc -l)" echo "=== Breaking changes ===" breakingChanges="" -for i in $(seq $commitsCount) -do - line="$(echo "$commits" | head -$i | tail -1)" - - # Get PR number from the git commit title - pr="$(echo "$line" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.* (\#\([1-9][0-9][0-9][0-9][0-9]*\))|\1|')" - [ "x$pr" = "x" ] && break - - # Check if the PR is marked as a breaking change - if "$gh" issue view $pr --json labels | grep -q 'pr: breaking change' - then - breakingChanges+="$line" - fi +for i in $(seq $commitsCount); do + line="$(echo "$commits" | head -$i | tail -1)" + + # Get PR number from the git commit title + pr="$(echo "$line" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.* (\#\([1-9][0-9][0-9][0-9][0-9]*\))|\1|')" + [ "x$pr" = "x" ] && continue + + # Check if the PR is marked as a breaking change + if "$gh" issue view $pr --json labels | grep -q 'pr: breaking change'; then + breakingChanges+="$line" + fi done -if [ "x$breakingChanges" = "x" ] -then - echo "No breaking changes" +if [ "x$breakingChanges" = "x" ]; then + echo "No breaking changes" else - echo "$breakingChanges" + echo "$breakingChanges" fi echo "" echo "=== All changes for this release ===" -for i in $(seq $commitsCount) -do - line="$(echo "$commits" | head -$i | tail -1)" - - result="$line" - for dummy in 1 - do - # Get PR number from the git commit title - pr="$(echo "$line" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.* (\#\([1-9][0-9][0-9][0-9][0-9]*\))|\1|')" - [ "x$pr" = "x" ] && break - - # Mark breaking changes with "[BREAKING]" - if "$gh" issue view $pr --json labels | grep -q 'pr: breaking change' - then - result="[BREAKING] $line" - fi - - # Get the issue number for the PR - body="$("$gh" issue view $pr --json body)" - [ "x$body" = "x" ] && break - issue="$(echo "$body" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.*\#\([1-9][0-9][0-9][0-9][0-9]*\).*|\1|')" - [ "x$issue" = "x" ] && break - - # Get the labels of the issue - label="$("$gh" issue view $issue --json labels)" - [ "x$label" = "x" ] && break - - # Get the goal type from the labels - goal="$(echo "$label" | grep '"goal:' | sed 's|.*"goal:\([^"]*\)".*|\1|')" - [ "x$goal" = "x" ] && break - - result+=" (#$issue:$goal)" - done - echo "$result" +for i in $(seq $commitsCount); do + line="$(echo "$commits" | head -$i | tail -1)" + + result="$line" + for dummy in 1; do + # Get PR number from the git commit title + pr="$(echo "$line" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.* (\#\([1-9][0-9][0-9][0-9][0-9]*\))|\1|')" + [ "x$pr" = "x" ] && break + + # Mark breaking changes with "[BREAKING]" + if "$gh" issue view $pr --json labels | grep -q 'pr: breaking change'; then + result="[BREAKING] $line" + fi + + # Get the issue number for the PR + body="$("$gh" issue view $pr --json body)" + [ "x$body" = "x" ] && break + issue="$(echo "$body" | grep '#[1-9][0-9][0-9][0-9][0-9]*' | sed 's|.*\#\([1-9][0-9][0-9][0-9][0-9]*\).*|\1|')" + [ "x$issue" = "x" ] && break + + # Get the labels of the issue + label="$("$gh" issue view $issue --json labels)" + [ "x$label" = "x" ] && break + + # Get the goal type from the labels + goal="$(echo "$label" | grep '"goal:' | sed 's|.*"goal:\([^"]*\)".*|\1|')" + [ "x$goal" = "x" ] && break + + result+=" (#$issue:$goal)" + done + echo "$result" done - diff --git a/docs/stdlib-doc.md b/docs/stdlib-doc.md index 1431fdfb2b..a3b69cbed6 100644 --- a/docs/stdlib-doc.md +++ b/docs/stdlib-doc.md @@ -60418,7 +60418,7 @@ matrix fwidth(matrix x); This function can be applied to scalars, vectors, and matrices of built-in scalar types. - Note: these functions are not curently implemented for Vulkan/SPIR-V output. + Note: these functions are not currently implemented for Vulkan/SPIR-V output. ## Signature diff --git a/docs/stdlib-docgen.md b/docs/stdlib-docgen.md new file mode 100644 index 0000000000..37c4d30e73 --- /dev/null +++ b/docs/stdlib-docgen.md @@ -0,0 +1,123 @@ +# Slang Core Module Documentation Generation Tool + +Slang's core module reference (https://shader-slang.com/stdlib-reference) is generated by `slangc` from the source of the core module. +This page covers how `slangc` can be used to generate this documentation. + +## Generating Documentation + +Follow these steps to generate the core module reference documentation and view the generated markdown files locally: + +``` +# clone stdlib-reference repo +git clone https://github.com/shader-slang/stdlib-reference +cd stdlib-reference + +# delete existing pages +rm -rf ./interfaces +rm -rf ./types +rm -rf ./global-decls +rm -rf ./attributes + +# generate updated pages +slangc -compile-core-module -doc + +# optional: move generated toc.html to `_includes` +mv toc.html ./_includes/stdlib-reference-toc.html +``` + +`slangc` will read the `config.txt` file in the stdlib-reference repository, and then generate all the markdown files +located in `types`, `attributes`, `interfaces` and `global-decls` directory. + +Note that the `index.md` in root is not generated. + +You should review the generated markdown file to make sure it is formatted correctly after making comment edits in the +`*.meta.slang` files. + + +## Writing and Updating Documentation + +The core module documentation is done directly in comments inside `source/slang/*.meta.slang` files. +A documentation comment should be placed directly above the declaration, either inside a `/** */` comment block, or +after `///`. The following directives are allowed in comments: + +- `@param paramName description` documents a parameter or a generic parameter. +- `@remarks` starts the remarks section. +- `@see` starts the "See also" section. +- `@return` starts the `Return value" section. +- `@example` starts the "Example" section. +- `@category categoryID Category Name` marks the decl to be in a category. The category name is only required for the first time `categoryID` is used, and omitted for the remaining `@category` lines. +- `@internal` marks the declaration as internal. +- `@experimental` marks the declaration as experimental. +- `@deprecated` marks the declaration as deprecated. + +You can use markdown syntax in any part of the comment. + +For overloaded functions, only document the first overload. List all parameters from all overloads in the same comment block for the first overload. Documentation on the remaining overloads will be ignored by the tool. If an overloaded decl has differing documentation on different overload candidates, the `slangc` tool will emit a warning. + +The following code is an example of how `_Texture.Sample` is documented. Notice that only the first overload is documented, and it also includes documentation for parameters which are only present in subsequent overloads, such as `offset`. + +```csharp + /// Samples the texture at the given location. + /// + ///@param s The `SamplerState` to use for the sampling operation. This parameter is omitted when `this` is a combined texture sampler type (`isCombined == 0`). + ///@param location The location to sample the texture at. + ///@param offset Texel offset to apply. + ///@param clamp The max level of detail to use. + ///@param[out] status The result status of the operation. + /// This parameter is currently only used when targeting HLSL. + /// For other targets, the result status is always 0. + ///@return The sampled texture value. + ///@see `SampleBias`, `SampleLevel`, `SampleGrad`, `SampleCmp`, `SampleCmpLevelZero`. + ///@remarks + /// The `Sample` function is defined for all read-only texture types, including + /// `Texture1D`, `Texture2D`, `Texture3D`, `TextureCube`, + /// `Texture1DArray`, `Texture2DArray` and `TextureCubeArray`. + /// + /// The function is not available for read-write texture types. + /// + /// For HLSL/D3D targets, the texture element type must be a scalar or vector of float or half types. + /// + [__readNone] + [ForceInline] + [require(cpp_cuda_glsl_hlsl_metal_spirv_wgsl, texture_sm_4_0_fragment)] + T Sample(vector location) + { + ... + } + + [__readNone] + [ForceInline] + [require(cpp_glsl_hlsl_metal_spirv_wgsl, texture_sm_4_0_fragment)] + T Sample(vector location, constexpr vector offset) + { + ... + } + +``` + +Note that unlike doxygen, the directives marks the start of a new section, and applies to all following paragraphs. You don't need to repetitively mark new paragraphs +as with `@remarks`. + +## What to document + +- Provide a brief description of the declaration in under three sentenses. +- Document all nuances, including target specific behaviors in the remarks section. +- Include examples if needed in the examples section. +- Provide a see also section with links to related declarations. + +After updating comments, build `slangc`, and run `slangc -compile-core-module -doc` in `stdlib-reference` directory to update the markdown files for preview. +Your PR only needs to include changes to *.meta.slang files. Once your PR is merged, slang CI will run `slangc` and push the updated markdown files to +the `stdlib-reference` repo. + +## Hiding a declaration + +Use `// @hidden:` to hide all declarations after the line for docgen purpose. +Use `// @public: ` to stop hiding all declarations after the line. These two special lines act like +C++'s visibility modifiers: they apply to everything after it. + +## How to preview generated html page locally + +To preview github pages locally, you need to follow instructions on setting up Jekyll: +https://docs.github.com/en/pages/setting-up-a-github-pages-site-with-jekyll/testing-your-github-pages-site-locally-with-jekyll + +You will need to use Jekyll to create a Gem file before serving it. diff --git a/docs/target-compatibility.md b/docs/target-compatibility.md index 0fdeeca8d2..d9ccb484ea 100644 --- a/docs/target-compatibility.md +++ b/docs/target-compatibility.md @@ -1,66 +1,68 @@ -Slang Target Compatibility -========================== +# Slang Target Compatibility Shader Model (SM) numbers are D3D Shader Model versions, unless explicitly stated otherwise. -OpenGL compatibility is not listed here, because OpenGL isn't an officially supported target. +OpenGL compatibility is not listed here, because OpenGL isn't an officially supported target. Items with a + means that the feature is anticipated to be added in the future. Items with ^ means there is some discussion about support later in the document for this target. -| Feature | D3D11 | D3D12 | VK | CUDA | CPU -|-----------------------------------------------------|--------------|--------------|------------|---------------|--------------- -| [Half Type](#half) | No | Yes ^ | Yes | Yes ^ | No + -| Double Type | Yes | Yes | Yes | Yes | Yes -| Double Intrinsics | No | Limited + | Limited | Most | Yes -| [u/int8_t Type](#int8_t) | No | No | Yes ^ | Yes | Yes -| [u/int16_t Type](#int16_t) | No | Yes ^ | Yes ^ | Yes | Yes -| [u/int64_t Type](#int64_t) | No | Yes ^ | Yes | Yes | Yes -| u/int64_t Intrinsics | No | No | Yes | Yes | Yes -| [int matrix](#int-matrix) | Yes | Yes | No + | Yes | Yes -| [tex.GetDimensions](#tex-get-dimensions) | Yes | Yes | Yes | No | Yes -| [SM6.0 Wave Intrinsics](#sm6-wave) | No | Yes | Partial | Yes ^ | No -| SM6.0 Quad Intrinsics | No | Yes | No + | No | No -| [SM6.5 Wave Intrinsics](#sm6.5-wave) | No | Yes ^ | No + | Yes ^ | No -| [WaveMask Intrinsics](#wave-mask) | Yes ^ | Yes ^ | Yes + | Yes | No -| [WaveShuffle](#wave-shuffle) | No | Limited ^ | Yes | Yes | No -| [Tesselation](#tesselation) | Yes ^ | Yes ^ | No + | No | No -| [Graphics Pipeline](#graphics-pipeline) | Yes | Yes | Yes | No | No -| [Ray Tracing DXR 1.0](#ray-tracing-1.0) | No | Yes ^ | Yes ^ | No | No -| Ray Tracing DXR 1.1 | No | Yes | No + | No | No -| [Native Bindless](#native-bindless) | No | No | No | Yes | Yes -| [Buffer bounds](#buffer-bounds) | Yes | Yes | Yes | Limited ^ | Limited ^ -| [Resource bounds](#resource-bounds) | Yes | Yes | Yes | Yes (optional)| Yes -| Atomics | Yes | Yes | Yes | Yes | Yes -| Group shared mem/Barriers | Yes | Yes | Yes | Yes | No + -| [TextureArray.Sample float](#tex-array-sample-float)| Yes | Yes | Yes | No | Yes -| [Separate Sampler](#separate-sampler) | Yes | Yes | Yes | No | Yes -| [tex.Load](#tex-load) | Yes | Yes | Yes | Limited ^ | Yes -| [Full bool](#full-bool) | Yes | Yes | Yes | No | Yes ^ -| [Mesh Shader](#mesh-shader) | No | Yes | Yes | No | No -| [`[unroll]`](#unroll] | Yes | Yes | Yes ^ | Yes | Limited + -| Atomics | Yes | Yes | Yes | Yes | No + -| [Atomics on RWBuffer](#rwbuffer-atomics) | Yes | Yes | Yes | No | No + -| [Sampler Feedback](#sampler-feedback) | No | Yes | No + | No | Yes ^ -| [RWByteAddressBuffer Atomic](#byte-address-atomic) | No | Yes ^ | Yes ^ | Yes | No + -| [Shader Execution Reordering](#ser) | No | Yes ^ | Yes ^ | No | No -| [debugBreak](#debug-break) | No | No | Yes | Yes | Yes -| [realtime clock](#realtime-clock) | No | Yes ^ | Yes | Yes | No +| Feature | D3D11 | D3D12 | VK | CUDA | Metal | CPU | +| ---------------------------------------------------- | ----- | --------- | ------- | -------------- | ----- | --------- | +| [Half Type](#half) | No | Yes ^ | Yes | Yes ^ | Yes | No + | +| Double Type | Yes | Yes | Yes | Yes | No | Yes | +| Double Intrinsics | No | Limited + | Limited | Most | No | Yes | +| [u/int8_t Type](#int8_t) | No | No | Yes ^ | Yes | Yes | Yes | +| [u/int16_t Type](#int16_t) | No | Yes ^ | Yes ^ | Yes | Yes | Yes | +| [u/int64_t Type](#int64_t) | No | Yes ^ | Yes | Yes | Yes | Yes | +| u/int64_t Intrinsics | No | No | Yes | Yes | Yes | Yes | +| [int matrix](#int-matrix) | Yes | Yes | No + | Yes | No | Yes | +| [tex.GetDimensions](#tex-get-dimensions) | Yes | Yes | Yes | No | Yes | Yes | +| [SM6.0 Wave Intrinsics](#sm6-wave) | No | Yes | Partial | Yes ^ | No | No | +| SM6.0 Quad Intrinsics | No | Yes | No + | No | No | No | +| [SM6.5 Wave Intrinsics](#sm6.5-wave) | No | Yes ^ | No + | Yes ^ | No | No | +| [WaveMask Intrinsics](#wave-mask) | Yes ^ | Yes ^ | Yes + | Yes | No | No | +| [WaveShuffle](#wave-shuffle) | No | Limited ^ | Yes | Yes | No | No | +| [Tesselation](#tesselation) | Yes ^ | Yes ^ | No + | No | No | No | +| [Graphics Pipeline](#graphics-pipeline) | Yes | Yes | Yes | No | Yes | No | +| [Ray Tracing DXR 1.0](#ray-tracing-1.0) | No | Yes ^ | Yes ^ | No | No | No | +| Ray Tracing DXR 1.1 | No | Yes | No + | No | No | No | +| [Native Bindless](#native-bindless) | No | No | No | Yes | No | Yes | +| [Buffer bounds](#buffer-bounds) | Yes | Yes | Yes | Limited ^ | No ^ | Limited ^ | +| [Resource bounds](#resource-bounds) | Yes | Yes | Yes | Yes (optional) | Yes | Yes | +| Atomics | Yes | Yes | Yes | Yes | Yes | Yes | +| Group shared mem/Barriers | Yes | Yes | Yes | Yes | Yes | No + | +| [TextureArray.Sample float](#tex-array-sample-float) | Yes | Yes | Yes | No | Yes | Yes | +| [Separate Sampler](#separate-sampler) | Yes | Yes | Yes | No | Yes | Yes | +| [tex.Load](#tex-load) | Yes | Yes | Yes | Limited ^ | Yes | Yes | +| [Full bool](#full-bool) | Yes | Yes | Yes | No | Yes | Yes ^ | +| [Mesh Shader](#mesh-shader) | No | Yes | Yes | No | Yes | No | +| [`[unroll]`](#unroll] | Yes | Yes | Yes ^ | Yes | No ^ | Limited + | +| Atomics | Yes | Yes | Yes | Yes | Yes | No + | +| [Atomics on RWBuffer](#rwbuffer-atomics) | Yes | Yes | Yes | No | Yes | No + | +| [Sampler Feedback](#sampler-feedback) | No | Yes | No + | No | No | Yes ^ | +| [RWByteAddressBuffer Atomic](#byte-address-atomic) | No | Yes ^ | Yes ^ | Yes | Yes | No + | +| [Shader Execution Reordering](#ser) | No | Yes ^ | Yes ^ | No | No | No | +| [debugBreak](#debug-break) | No | No | Yes | Yes | No | Yes | +| [realtime clock](#realtime-clock) | No | Yes ^ | Yes | Yes | No | No | + ## Half Type There appears to be a problem writing to a StructuredBuffer containing half on D3D12. D3D12 also appears to have problems doing calculations with half. -In order for half to work in CUDA, NVRTC must be able to include `cuda_fp16.h` and related files. Please read the [CUDA target documentation](cuda-target.md) for more details. +In order for half to work in CUDA, NVRTC must be able to include `cuda_fp16.h` and related files. Please read the [CUDA target documentation](cuda-target.md) for more details. + ## u/int8_t Type -Not currently supported in D3D11/D3D12 because not supported in HLSL/DXIL/DXBC. +Not currently supported in D3D11/D3D12 because not supported in HLSL/DXIL/DXBC. Supported in Vulkan via the extensions `GL_EXT_shader_explicit_arithmetic_types` and `GL_EXT_shader_8bit_storage`. + ## u/int16_t Type Requires SM6.2 which requires DXIL and therefore DXC and D3D12. For DXC this is discussed [here](https://github.com/Microsoft/DirectXShaderCompiler/wiki/16-Bit-Scalar-Types). @@ -68,78 +70,89 @@ Requires SM6.2 which requires DXIL and therefore DXC and D3D12. For DXC this is Supported in Vulkan via the extensions `GL_EXT_shader_explicit_arithmetic_types` and `GL_EXT_shader_16bit_storage`. + ## u/int64_t Type Requires SM6.0 which requires DXIL for D3D12. Therefore not available with DXBC on D3D11 or D3D12. + ## int matrix -Means can use matrix types containing integer types. +Means can use matrix types containing integer types. + ## tex.GetDimensions tex.GetDimensions is the GetDimensions method on 'texture' objects. This is not supported on CUDA as CUDA has no equivalent functionality to get these values. GetDimensions work on Buffer resource types on CUDA. + ## SM6.0 Wave Intrinsics -CUDA has premliminary support for Wave Intrinsics, introduced in [PR #1352](https://github.com/shader-slang/slang/pull/1352). Slang synthesizes the 'WaveMask' based on program flow and the implied 'programmer view' of exectution. This support is built on top of WaveMask intrinsics with Wave Intrinsics being replaced with WaveMask Intrinsic calls with Slang generating the code to calculate the appropriate WaveMasks. +CUDA has premliminary support for Wave Intrinsics, introduced in [PR #1352](https://github.com/shader-slang/slang/pull/1352). Slang synthesizes the 'WaveMask' based on program flow and the implied 'programmer view' of execution. This support is built on top of WaveMask intrinsics with Wave Intrinsics being replaced with WaveMask Intrinsic calls with Slang generating the code to calculate the appropriate WaveMasks. Please read [PR #1352](https://github.com/shader-slang/slang/pull/1352) for a better description of the status. + ## SM6.5 Wave Intrinsics -SM6.5 Wave Intrinsics are supported, but requires a downstream DXC compiler that supports SM6.5. As it stands the DXC shipping with windows does not. +SM6.5 Wave Intrinsics are supported, but requires a downstream DXC compiler that supports SM6.5. As it stands the DXC shipping with windows does not. + ## WaveMask Intrinsics -In order to map better to the CUDA sync/mask model Slang supports 'WaveMask' intrinsics. They operate in broadly the same way as the Wave intrinsics, but require the programmer to specify the lanes that are involved. To write code that uses wave intrinsics acrosss targets including CUDA, currently the WaveMask intrinsics must be used. For this to work, the masks passed to the WaveMask functions should exactly match the 'Active lanes' concept that HLSL uses, otherwise the result is undefined. +In order to map better to the CUDA sync/mask model Slang supports 'WaveMask' intrinsics. They operate in broadly the same way as the Wave intrinsics, but require the programmer to specify the lanes that are involved. To write code that uses wave intrinsics across targets including CUDA, currently the WaveMask intrinsics must be used. For this to work, the masks passed to the WaveMask functions should exactly match the 'Active lanes' concept that HLSL uses, otherwise the result is undefined. The WaveMask intrinsics are not part of HLSL and are only available on Slang. + ## WaveShuffle -`WaveShuffle` and `WaveBroadcastLaneAt` are Slang specific intrinsic additions to expand the options available around `WaveReadLaneAt`. +`WaveShuffle` and `WaveBroadcastLaneAt` are Slang specific intrinsic additions to expand the options available around `WaveReadLaneAt`. -To be clear this means they will not compile directly on 'standard' HLSL compilers such as `dxc`, but Slang HLSL *output* (which will not contain these intrinsics) can (and typically is) compiled via dxc. +To be clear this means they will not compile directly on 'standard' HLSL compilers such as `dxc`, but Slang HLSL _output_ (which will not contain these intrinsics) can (and typically is) compiled via dxc. The difference between them can be summarized as follows -* WaveBroadcastLaneAt - laneId must be a compile time constant -* WaveReadLaneAt - laneId can be dynamic but *MUST* be the same value across the Wave ie 'dynamically uniform' across the Wave -* WaveShuffle - laneId can be truly dynamic (NOTE! That it is not strictly truly available currently on all targets, specifically HLSL) +- WaveBroadcastLaneAt - laneId must be a compile time constant +- WaveReadLaneAt - laneId can be dynamic but _MUST_ be the same value across the Wave ie 'dynamically uniform' across the Wave +- WaveShuffle - laneId can be truly dynamic (NOTE! That it is not strictly truly available currently on all targets, specifically HLSL) Other than the different restrictions on laneId they act identically to WaveReadLaneAt. `WaveBroadcastLaneAt` and `WaveReadLaneAt` will work on all targets that support wave intrinsics, with the only current restriction being that on GLSL targets, only scalars and vectors are supported. -`WaveShuffle` will always work on CUDA/Vulkan. +`WaveShuffle` will always work on CUDA/Vulkan. -On HLSL based targets currently `WaveShuffle` will be converted into `WaveReadLaneAt`. Strictly speaking this means it *requires* the `laneId` to be `dynamically uniform` across the Wave. In practice some hardware supports the loosened usage, and others does not. In the future this may be fixed in Slang and/or HLSL to work across all hardware. For now if you use `WaveShuffle` on HLSL based targets it will be necessary to confirm that `WaveReadLaneAt` has the loosened behavior for all the hardware intended. If target hardware does not support the loosened restrictions it's behavior is undefined. +On HLSL based targets currently `WaveShuffle` will be converted into `WaveReadLaneAt`. Strictly speaking this means it _requires_ the `laneId` to be `dynamically uniform` across the Wave. In practice some hardware supports the loosened usage, and others does not. In the future this may be fixed in Slang and/or HLSL to work across all hardware. For now if you use `WaveShuffle` on HLSL based targets it will be necessary to confirm that `WaveReadLaneAt` has the loosened behavior for all the hardware intended. If target hardware does not support the loosened restrictions it's behavior is undefined. + ## Tesselation -Although tesselation stages should work on D3D11 and D3D12 they are not tested within our test framework, and may have problems. +Although tesselation stages should work on D3D11 and D3D12 they are not tested within our test framework, and may have problems. -## Native Bindless -Bindless is possible on targets that support it - but is not the default behavior for those targets, and typically require significant effort in Slang code. +## Native Bindless + +Bindless is possible on targets that support it - but is not the default behavior for those targets, and typically require significant effort in Slang code. 'Native Bindless' targets use a form of 'bindless' for all targets. On CUDA this requires the target to use 'texture object' style binding and for the device to have 'compute capability 3.0' or higher. -## Resource bounds + +## Resource bounds For CUDA this is optional as can be controlled via the SLANG_CUDA_BOUNDARY_MODE macro in the `slang-cuda-prelude.h`. By default it's behavior is `cudaBoundaryModeZero`. + ## Buffer Bounds This is the feature when accessing outside of the bounds of a Buffer there is well defined behavior - on read returning all 0s, and on write, the write being ignored. @@ -148,24 +161,30 @@ On CPU there is only bounds checking on debug compilation of C++ code. This will On CUDA out of bounds accesses default to element 0 (!). The behavior can be controlled via the SLANG_CUDA_BOUND_CHECK macro in the `slang-cuda-prelude.h`. This behavior may seem a little strange - and it requires a buffer that has at least one member to not do something nasty. It is really a 'least worst' answer to a difficult problem and is better than out of range accesses or worse writes. +In Metal, accessing a buffer out of bounds is undefined behavior. + -## TextureArray.Sample float + +## TextureArray.Sample float When using 'Sample' on a TextureArray, CUDA treats the array index parameter as an int, even though it is passed as a float. + ## Separate Sampler -This feature means that a multiple Samplers can be used with a Texture. In terms of the HLSL code this can be seen as the 'SamplerState' being a parameter passed to the 'Sample' method on a texture object. +This feature means that a multiple Samplers can be used with a Texture. In terms of the HLSL code this can be seen as the 'SamplerState' being a parameter passed to the 'Sample' method on a texture object. On CUDA the SamplerState is ignored, because on this target a 'texture object' is the Texture and Sampler combination. + ## Graphics Pipeline -CPU and CUDA only currently support compute shaders. +CPU and CUDA only currently support compute shaders. + ## Ray Tracing DXR 1.0 Vulkan does not support a local root signature, but there is the concept of a 'shader record'. In Slang a single constant buffer can be marked as a shader record with the `[[vk::shader_record]]` attribute, for example: @@ -175,53 +194,61 @@ Vulkan does not support a local root signature, but there is the concept of a 's cbuffer ShaderRecord { uint shaderRecordID; -} +} ``` -In practice to write shader code that works across D3D12 and VK you should have a single constant buffer marked as 'shader record' for VK and then on D3D that constant buffer should be bound in the local root signature on D3D. +In practice to write shader code that works across D3D12 and VK you should have a single constant buffer marked as 'shader record' for VK and then on D3D that constant buffer should be bound in the local root signature on D3D. + ## tex.Load -tex.Load is only supported on CUDA for Texture1D. Additionally CUDA only allows such access for linear memory, meaning the bound texture can also not have mip maps. Load *is* allowed on RWTexture types of other dimensions including 1D on CUDA. +tex.Load is only supported on CUDA for Texture1D. Additionally CUDA only allows such access for linear memory, meaning the bound texture can also not have mip maps. Load _is_ allowed on RWTexture types of other dimensions including 1D on CUDA. + ## Full bool -Means fully featured bool support. CUDA has issues around bool because there isn't a vector bool type built in. Currently bool aliases to an int vector type. +Means fully featured bool support. CUDA has issues around bool because there isn't a vector bool type built in. Currently bool aliases to an int vector type. -On CPU there are some issues in so far as bool's size is not well defined in size an alignment. Most C++ compilers now use a byte to represent a bool. In the past it has been backed by an int on some compilers. +On CPU there are some issues in so far as bool's size is not well defined in size an alignment. Most C++ compilers now use a byte to represent a bool. In the past it has been backed by an int on some compilers. + ## `[unroll]` -The unroll attribute allows for unrolling `for` loops. At the moment the feature is dependent on downstream compiler support which is mixed. In the longer term the intention is for Slang to contain it's own loop unroller - and therefore not be dependent on the feature on downstream compilers. +The unroll attribute allows for unrolling `for` loops. At the moment the feature is dependent on downstream compiler support which is mixed. In the longer term the intention is for Slang to contain it's own loop unroller - and therefore not be dependent on the feature on downstream compilers. -On C++ this attribute becomes SLANG_UNROLL which is defined in the prelude. This can be predefined if there is a suitable mechanism, if there isn't a definition SLANG_UNROLL will be an empty definition. +On C++ this attribute becomes SLANG_UNROLL which is defined in the prelude. This can be predefined if there is a suitable mechanism, if there isn't a definition SLANG_UNROLL will be an empty definition. On GLSL and VK targets loop unrolling uses the [GL_EXT_control_flow_attributes](https://github.com/KhronosGroup/GLSL/blob/master/extensions/ext/GL_EXT_control_flow_attributes.txt) extension. +Metal Shading Language does not support loop unrolling. + Slang does have a cross target mechanism to [unroll loops](language-reference/06-statements.md), in the section `Compile-Time For Statement`. + ## Atomics on RWBuffer For VK the GLSL output from Slang seems plausible, but VK binding fails in tests harness. -On CUDA RWBuffer becomes CUsurfObject, which is a 'texture' type and does not support atomics. +On CUDA RWBuffer becomes CUsurfObject, which is a 'texture' type and does not support atomics. On the CPU atomics are not supported, but will be in the future. + ## Sampler Feedback -The HLSL [sampler feedback feature](https://microsoft.github.io/DirectX-Specs/d3d/SamplerFeedback.html) is available for DirectX12. The features requires shader model 6.5 and therefore a version of [DXC](https://github.com/Microsoft/DirectXShaderCompiler) that supports that model or higher. The Shader Model 6.5 requirement also means only DXIL binary format is supported. +The HLSL [sampler feedback feature](https://microsoft.github.io/DirectX-Specs/d3d/SamplerFeedback.html) is available for DirectX12. The features requires shader model 6.5 and therefore a version of [DXC](https://github.com/Microsoft/DirectXShaderCompiler) that supports that model or higher. The Shader Model 6.5 requirement also means only DXIL binary format is supported. -There doesn't not appear to be a similar feature available in Vulkan yet, but when it is available support should be addeed. +There doesn't not appear to be a similar feature available in Vulkan yet, but when it is available support should be added. -For CPU targets there is the IFeedbackTexture interface that requires an implemention for use. Slang does not currently include CPU implementations for texture types. +For CPU targets there is the IFeedbackTexture interface that requires an implementation for use. Slang does not currently include CPU implementations for texture types. + ## RWByteAddressBuffer Atomic The additional supported methods on RWByteAddressBuffer are... @@ -246,18 +273,20 @@ uint64_t RWByteAddressBuffer::InterlockedXorU64(uint byteAddress, uint64_t value ``` On HLSL based targets this functionality is achieved using [NVAPI](https://developer.nvidia.com/nvapi). Support for NVAPI is described -in the separate [NVAPI Support](nvapi-support.md) document. +in the separate [NVAPI Support](nvapi-support.md) document. On Vulkan, for float the [`GL_EXT_shader_atomic_float`](https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_shader_atomic_float.html) extension is required. For int64 the [`GL_EXT_shader_atomic_int64`](https://raw.githubusercontent.com/KhronosGroup/GLSL/master/extensions/ext/GL_EXT_shader_atomic_int64.txt) extension is required. -CUDA requires SM6.0 or higher for int64 support. +CUDA requires SM6.0 or higher for int64 support. + ## Mesh Shader There is preliminary [Mesh Shader support](https://github.com/shader-slang/slang/pull/2464). + ## Shader Execution Reordering More information about [Shader Execution Reordering](shader-execution-reordering.md). @@ -265,20 +294,22 @@ More information about [Shader Execution Reordering](shader-execution-reordering Currently support is available in D3D12 via NVAPI, and for Vulkan via the [GL_NV_shader_invocation_reorder](https://github.com/KhronosGroup/GLSL/blob/master/extensions/nv/GLSL_NV_shader_invocation_reorder.txt) extension. + ## Debug Break Slang has preliminary support for `debugBreak()` intrinsic. With the appropriate tooling, when `debugBreak` is hit it will cause execution to halt and display in the attached debugger. -Currently this is supported in all targets except HLSL. Note that on some targets if there isn't an appropriate debugging environment the debugBreak might cause execution to fail or potentially it is ignored. +This is not supported on HLSL, GLSL, SPIR-V or Metal backends. Note that on some targets if there isn't an appropriate debugging environment the debugBreak might cause execution to fail or potentially it is ignored. -On C++ targets debugBreak is implemented using SLANG_BREAKPOINT defined in "slang-cpp-prelude.h". If there isn't a suitable intrinsic, this will default to attempting to write to `nullptr` leading to a crash. +On C++ targets debugBreak is implemented using SLANG_BREAKPOINT defined in "slang-cpp-prelude.h". If there isn't a suitable intrinsic, this will default to attempting to write to `nullptr` leading to a crash. Some additional details: -* If [slang-llvm](cpu-target.md#slang-llvm) is being used as the downstream compiler (as is typical with `host-callable`), it will crash into the debugger, but may not produce a usable stack trace. -* For "normal" C++ downstream compilers such as Clang/Gcc/Visual Studio, to break into readable source code, debug information is typically necessary. Disabling optimizations may be useful to break on the appropriate specific line, and have variables inspectable. +- If [slang-llvm](cpu-target.md#slang-llvm) is being used as the downstream compiler (as is typical with `host-callable`), it will crash into the debugger, but may not produce a usable stack trace. +- For "normal" C++ downstream compilers such as Clang/Gcc/Visual Studio, to break into readable source code, debug information is typically necessary. Disabling optimizations may be useful to break on the appropriate specific line, and have variables inspectable. + ## Realtime Clock Realtime clock support is available via the API @@ -290,10 +321,10 @@ uint getRealtimeClockLow(); uint2 getRealtimeClock(); ``` -On D3D this is supported through NVAPI via `NvGetSpecial`. +On D3D this is supported through NVAPI via `NvGetSpecial`. On Vulkan this is supported via [VK_KHR_shader_clock extension](https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VK_KHR_shader_clock.html) On CUDA this is supported via [clock](https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#time-function). -Currently this is not supported on CPU, although this will potentially be added in the future. \ No newline at end of file +Currently this is not supported on CPU, although this will potentially be added in the future. diff --git a/docs/update_spirv.md b/docs/update_spirv.md index 8463da3436..19dd474164 100644 --- a/docs/update_spirv.md +++ b/docs/update_spirv.md @@ -7,55 +7,95 @@ There are three directories under `external` that are related to SPIR-V: In order to use the latest or custom SPIR-V, they need to be updated. -## Update URLs to the repo -Open `.gitmodules` and update the following sections to have a desired `url` set. +## Fork `shader-slang/SPIRV-Tools` repo and update it + +Currently Slang uses [shader-slang/SPIRV-Tools](https://github.com/shader-slang/SPIRV-Tools) forked from [KhronosGroup/SPIRV-Tools](https://github.com/KhronosGroup/SPIRV-Tools). +In order for Slang to use the latest changes from `KhronosGroup/SPIRV-Tools`, `shader-slang/SPIRV-Tools` needs to be updated. + +1. Fork `shader-slang/SPIRV-Tools` to your personal github organization like `your-name/SPIRV-Tools`. +1. Clone it on your local machine. + ``` + git clone https://github.com/your-name/SPIRV-Tools.git # replace `your-name` to the actual URL + ``` +1. Fetch from `KhronosGroup/SPIRV-Tools`. + ``` + git remote add khronos https://github.com/KhronosGroup/SPIRV-Tools.git + git fetch khronos + ``` +1. Create a branch for a Pull Request. + ``` + git checkout -b merge/update + ``` +1. Rebase to khronos/main + ``` + git rebase khronos/main # use ToT + ``` +1. Push to Github. + ``` + git push origin merge/update + ``` + +The steps above will create a branch called `merge/update`. You can use a different name but this document will use the name. + + +## Modify `.gitmodules` and use the `merge/update` branch + +Before creating a Pull Request for `merge/update`, you should test and make sure everything works. + +On a Slang repo side, you need to create a branch for the following changes. +``` +git clone https://github.com/your-name/slang.git # replace `your-name` to the actual URL +cd slang +git checkout -b update_spirv +``` + +Open `.gitmodules` and modify the setting to the following, ``` [submodule "external/spirv-tools"] path = external/spirv-tools - url = https://github.com/shader-slang/SPIRV-Tools.git + url = https://github.com/your-name/SPIRV-Tools.git [submodule "external/spirv-headers"] path = external/spirv-headers url = https://github.com/KhronosGroup/SPIRV-Headers.git ``` +Note that you need to replace `your-name` with the actual URL from the previous step. -Run the following command to apply the change. +Apply the URL changes with the following commands, ``` git submodule sync git submodule update --init --recursive -``` -If you need to use a specific branch from the repos, you need to manually checkout the branch. -``` -cd external/spirv-tools -git checkout branch_name_to_use +cd spirv-headers +git fetch +git checkout origin/main # use ToT cd .. -git add spirv-tools -cd external/spirv-headers -git checkout branch_name_to_use -cd .. -git add spirv-headers +cd external +cd spirv-tools +git fetch +git checkout merge/update # use merger/update branch ``` + ## Build spirv-tools A directory, `external/spirv-tools/generated`, holds a set of files generated from spirv-tools directory. You need to build spirv-tools in order to generate them. ``` -cd external/spirv-tools -python3.exe utils/git-sync-deps # this step may require you to register your ssh public key to gitlab.khronos.org -mkdir build -cd build -cmake.exe .. -cmake.exe --build . --config Release +cd external +cd spirv-tools +python3.exe utils\git-sync-deps # this step may require you to register your ssh public key to gitlab.khronos.org +cmake.exe . -B build +cmake.exe --build build --config Release ``` -## Copy the generated files from spirv-tools -Copy some of generated files from `external/spirv-tools/build/` to `external/spirv-tools-generated`. -The following files are ones you need to copy at the momment, but the list will change in the future. +## Copy the generated files from `spirv-tools` to `spirv-tools-generated` + +Copy some of generated files from `external/spirv-tools/build/` to `external/spirv-tools-generated/`. +The following files are ones you need to copy at the moment, but the list may change in the future. ``` DebugInfo.h NonSemanticShaderDebugInfo100.h @@ -73,10 +113,83 @@ nonsemantic.vkspreflection.insts.inc opencl.debuginfo.100.insts.inc opencl.std.insts.inc operand.kinds-unified1.inc -options-pinned.h spv-amd-gcn-shader.insts.inc spv-amd-shader-ballot.insts.inc spv-amd-shader-explicit-vertex-parameter.insts.inc spv-amd-shader-trinary-minmax.insts.inc ``` + +## Build Slang and run slang-test + +There are many ways to build Slang executables. Refer to the [document](https://github.com/shader-slang/slang/blob/master/docs/building.md) for more detail. +For a quick reference, you can build with the following commands, +``` +cmake.exe --preset vs2019 +cmake.exe --build --preset release +``` + +After building Slang executables, run `slang-test` to see all tests are passing. +``` +set SLANG_RUN_SPIRV_VALIDATION=1 +build\Release\bin\slang-test.exe -use-test-server -server-count 8 +``` + +It is often the case that some of tests fail, because of the changes on SPIRV-Header. +You need to properly resolve them before proceed. + + +## Create A Pull Request on `shader-slang/SPIRV-Tools` + +After testing is done, you should create a Pull Request on `shader-slang/SPIRV-Tools` repo. + +1. The git-push command will show you a URL for creating a Pull Request like following, + > https://github.com/your-name/SPIRV-Tools/pull/new/merge/update # replace `your-name` to the actual URL + + Create a Pull Request. +1. Wait for all workflows to pass. +1. Merge the PR and take a note of the commit ID for the next step. + +Note that this process will update `shader-slang/SPIRV-Tools` repo, but your merge is not used by `slang` repo yet. + + +## Create a Pull Request on `shader-slang/slang` + +After the PR is merged to `shader-slang/SPIRV-Tools`, `slang` needs to start using it. + +On the clone of Slang repo, revert the changes in `.gitmodules` if modified. +``` +# revert the change in .gitmodules +git checkout .gitmodules +git submodule sync +git submodule update --init --recursive +``` + +You need to stage and commit the latest commit IDs of spirv-tools and spirv-headers. +Note that when you want to use a new commit IDs of the submodules, you have to stage with git-add command for the directly of the submodule itself. +``` +cd external + +# Add changes in spirv-tools-generated +git add spirv-tools-generated + +# Add commit ID of spirv-headers +cd spirv-headers +git fetch +git checkout origin/main # Use ToT +cd .. +git add spirv-headers + +# Add commit ID of spirv-tools +cd spirv-tools +git fetch +git checkout merge/update # Use merge/update branch +cd .. +git add spirv-tools + +# Add more if there are other changes to resolve the test failures. + +git commit +git push origin update_spirv +``` +Once all changes are pushed to GitHub, you can create a Pull Request on `shader-slang/slang`. diff --git a/docs/user-guide/00-introduction.md b/docs/user-guide/00-introduction.md index 07b860d9cc..023256b9c0 100644 --- a/docs/user-guide/00-introduction.md +++ b/docs/user-guide/00-introduction.md @@ -66,7 +66,7 @@ Who is this guide for? ---------------------- The content of this guide is written for real-time graphics programmers with a moderate or higher experience level. -It assumes the reader has previously used a real-time shading langauge like HLSL, GLSL, or MetalSL together with an API like Direct3D 11/12, Vulkan, or Metal. +It assumes the reader has previously used a real-time shading language like HLSL, GLSL, or MetalSL together with an API like Direct3D 11/12, Vulkan, or Metal. We also assume that the reader is familiar enough with C/C++ to understand code examples and API signatures in those languages. If you are new to programming entirely, this guide is unlikely to be helpful. @@ -98,6 +98,6 @@ Before we dive into actually _using_ Slang, let us step back and highlight some * **Predictability**: Code should do what it appears to, consistently, across as many platforms as possible. Whenever possible the compiler should conform to programmer expectation, even in the presence of "undefined behavior." Tools and optimization passes should keep their behavior as predictable as possible; simple tools empower the user to do smart things. -* **Limited Scope**: The Slang system is a language, compiler, and library. It is not an engine, not a renderer, and not a "framework." The Slang system explicitly does *not* assume responsibility for interacting with GPU APIs to load code, allocate resources, bind parameters, or kick off work. While a user *may* use the Slang runtime library in their application, they are not *required* to do so. +* **Limited Scope**: The Slang system is a language, compiler, and module. It is not an engine, not a renderer, and not a "framework." The Slang system explicitly does *not* assume responsibility for interacting with GPU APIs to load code, allocate resources, bind parameters, or kick off work. While a user *may* use the Slang runtime library in their application, they are not *required* to do so. The ordering here is significant, with earlier goals generally being more important than later ones. diff --git a/docs/user-guide/02-conventional-features.md b/docs/user-guide/02-conventional-features.md index 0e0f180960..f4d6816db0 100644 --- a/docs/user-guide/02-conventional-features.md +++ b/docs/user-guide/02-conventional-features.md @@ -39,8 +39,11 @@ The following integer types are provided: All targets support the 32-bit `int` and `uint` types, but support for the other types depends on the capabilities of each target platform. -Integer literals can be both decimal and hexadecimal, and default to the `int` type. -A literal can be explicitly made unsigned with a `u` suffix. +Integer literals can be both decimal and hexadecimal. An integer literal can be explicitly made unsigned +with a `u` suffix, and explicitly made 64-bit with the `ll` suffix. The type of a decimal non-suffixed integer literal is the first integer type from +the list [`int`, `int64_t`] which can represent the specified literal value. If the value cannot fit, the literal is represented as +an `uint64_t` and a warning is given. The type of hexadecimal non-suffixed integer literal is the first type from the list +[`int`, `uint`, `int64_t`, `uint64_t`] that can represent the specified literal value. For more information on 64 bit integer literals see the documentation on [64 bit type support](../64bit-type-support.md). The following floating-point type are provided: @@ -80,6 +83,8 @@ The type `vector` is a vector of `N` _elements_ (also called _components_) As a convenience, pre-defined vector types exist for each scalar type and valid element count, with a name using the formula `<><>`. For example, `float3` is a convenient name for `vector`. +> Note: Slang doesn't support vectors longer than 4 elements. They map to native vector types on many platforms, including CUDA, and none of these platforms support vectors longer than 4 elements. If needed, you can use an array like `float myArray[8]`. + ### Matrix Types Matrix types can be written as `matrix` where `T` is a scalar type and both `R` and `C` are integers from 2 to 4 (inclusive). @@ -121,7 +126,7 @@ void f( int b[] ) It is allowed to pass a sized array as argument to an unsized array parameter when calling a function. -Array types has a `getCount()` memeber function that returns the length of the array. +Array types has a `getCount()` member function that returns the length of the array. ```hlsl int f( int b[] ) @@ -275,7 +280,7 @@ enum Channel ### Opaque Types -The Slang standard library defines a large number of _opaque_ types which provide access to objects that are allocated via GPU APIs. +The Slang core module defines a large number of _opaque_ types which provide access to objects that are allocated via GPU APIs. What all opaque types have in common is that they are not "first-class" types on most platforms. Opaque types (and structure or array types that contain them) may be limited in the following ways (depending on the platform): @@ -382,7 +387,7 @@ The ordinary unary and binary operators can also be applied to vectors and matri > #### Note #### > In GLSL, most operators apply component-wise to vectors and matrices, but the multiplication operator `*` computes the traditional linear-algebraic product of two matrices, or a matrix and a vector. -> Where a GLSL programmer would write `m * v` to multiply a `vec3x4` by a `vec3`, a Slang programmer should write `mul(v,m)` to multiply a `float3` by a `float3x4`. +> Where a GLSL programmer would write `m * v` to multiply a `mat3x4` by a `vec3`, a Slang programmer should write `mul(v,m)` to multiply a `float3` by a `float3x4`. > In this example, the order of operands is reversed to account for the difference in row/column conventions. ### Swizzles @@ -799,143 +804,147 @@ Auto-Generated Constructors ### Auto-Generated Constructors - Struct Slang has the following rules: -1. Auto-generate a `__init()` if not already defined -> Assume -```csharp -struct DontGenerateCtor -{ - int a; - int b = 5; - - // Since the user has explicitly defined a constructor - // here, Slang will not synthesize a conflicting - // constructor. - __init() - { - // b = 5; - a = 5; - b = 6; - } -}; - -struct GenerateCtor -{ - int a; - int b = 5; - - // Slang will automatically generate an implicit constructor: - // __init() - // { - // b = 5; - // } -}; -``` +1. Auto-generate a `__init()` if not already defined. + + Assume: + ```csharp + struct DontGenerateCtor + { + int a; + int b = 5; + + // Since the user has explicitly defined a constructor + // here, Slang will not synthesize a conflicting + // constructor. + __init() + { + // b = 5; + a = 5; + b = 6; + } + }; + + struct GenerateCtor + { + int a; + int b = 5; + + // Slang will automatically generate an implicit constructor: + // __init() + // { + // b = 5; + // } + }; + ``` 2. If all members have equal visibility, auto-generate a 'member-wise constructor' if not conflicting with a user defined constructor. -```csharp -struct GenerateCtorInner -{ - int a; - - // Slang will automatically generate an implicit - // __init(int in_a) - // { - // a = in_a; - // } -}; -struct GenerateCtor : GenerateCtorInner -{ - int b; - int c = 5; + ```csharp + struct GenerateCtorInner + { + int a; + + // Slang will automatically generate an implicit + // __init(int in_a) + // { + // a = in_a; + // } + }; + struct GenerateCtor : GenerateCtorInner + { + int b; + int c = 5; + + // Slang will automatically generate an implicit + // __init(int in_a, int in_b, int in_c) + // { + // c = 5; + // + // this = GenerateCtorInner(in_a); + // + // b = in_b; + // c = in_c; + // } + }; + ``` - // Slang will automatically generate an implicit - // __init(int in_a, int in_b, int in_c) - // { - // c = 5; - // - // this = GenerateCtorInner(in_a); - // - // b = in_b; - // c = in_c; - // } -}; -``` 3. If not all members have equal visibility, auto-generate a 'member-wise constructor' based on member visibility if not conflicting with a user defined constructor. - * We generate 3 different visibilities of 'member-wise constructor's in order: - 1. `public` 'member-wise constructor' - * Contains members of visibility: `public` - * Do not generate if `internal` or `private` member lacks an init expression - 2. `internal` 'member-wise constructor' - * Contains members of visibility: `internal`, `public` - * Do not generate if `private` member lacks an init expression - 3. `private` 'member-wise constructor' - * Contains members of visibility: `private`, `internal`, `public` -```csharp -struct GenerateCtorInner1 -{ - internal int a = 0; - - // Slang will automatically generate an implicit - // internal __init(int in_a) - // { - // a = 0; - // - // a = in_a; - // } -}; -struct GenerateCtor1 : GenerateCtorInner1 -{ - internal int b = 0; - public int c; - // Slang will automatically generate an implicit - // internal __init(int in_a, int in_b, int in_c) - // { - // b = 0; - // - // this = GenerateCtorInner1(in_a); - // - // b = in_b; - // c = in_c; - // } - // - // public __init(int in_c) - // { - // b = 0; - // - // this = GenerateCtorInner1(); - // - // c = in_c; - // } -}; - -struct GenerateCtorInner2 -{ - internal int a; - // Slang will automatically generate an implicit - // internal __init(int in_a) - // { - // a = in_a; - // } -}; -struct GenerateCtor2 : GenerateCtorInner2 -{ - internal int b; - public int c; - - /// Note: `internal b` is missing init expression, - // Do not generate a `public` 'member-wise' constructor. - - // Slang will automatically generate an implicit - // internal __init(int in_a, int in_b, int in_c) - // { - // this = GenerateCtorInner2(in_a); - // - // b = in_b; - // c = in_c; - // } -}; -``` + We generate 3 different visibilities of 'member-wise constructor's in order: + 1. `public` 'member-wise constructor' + - Contains members of visibility: `public` + - Do not generate if `internal` or `private` member lacks an init expression + 2. `internal` 'member-wise constructor' + - Contains members of visibility: `internal`, `public` + - Do not generate if `private` member lacks an init expression + 3. `private` 'member-wise constructor' + - Contains members of visibility: `private`, `internal`, `public` + + ```csharp + struct GenerateCtorInner1 + { + internal int a = 0; + + // Slang will automatically generate an implicit + // internal __init(int in_a) + // { + // a = 0; + // + // a = in_a; + // } + }; + struct GenerateCtor1 : GenerateCtorInner1 + { + internal int b = 0; + public int c; + + // Slang will automatically generate an implicit + // internal __init(int in_a, int in_b, int in_c) + // { + // b = 0; + // + // this = GenerateCtorInner1(in_a); + // + // b = in_b; + // c = in_c; + // } + // + // public __init(int in_c) + // { + // b = 0; + // + // this = GenerateCtorInner1(); + // + // c = in_c; + // } + }; + + struct GenerateCtorInner2 + { + internal int a; + // Slang will automatically generate an implicit + // internal __init(int in_a) + // { + // a = in_a; + // } + }; + struct GenerateCtor2 : GenerateCtorInner2 + { + internal int b; + public int c; + + /// Note: `internal b` is missing init expression, + // Do not generate a `public` 'member-wise' constructor. + + // Slang will automatically generate an implicit + // internal __init(int in_a, int in_b, int in_c) + // { + // this = GenerateCtorInner2(in_a); + // + // b = in_b; + // c = in_c; + // } + }; + ``` Initializer Lists ---------- @@ -974,7 +983,7 @@ int a[2] = {1, 2} #### Array Of Aggregate's ```csharp -// Equivlent to `float3 a[2]; a[0] = {1,2,3}; b[1] = {4,5,6};` +// Equivalent to `float3 a[2]; a[0] = {1,2,3}; b[1] = {4,5,6};` float3 a[2] = { {1,2,3}, {4,5,6} }; ``` #### Flattened Array Initializer @@ -1048,7 +1057,7 @@ struct GenerateCtor1 : GenerateCtorInner1 GenerateCtor1 val[2] = { { 3 }, { 2 } }; ``` -In addition, Slang also provides compatbility support for C-style initializer lists with `struct`s. C-style initializer lists can use [Partial Initializer List's](#Partial-Initializer-List's) and [Flattened Array Initializer With Struct's](#Flattened-Array-Initializer-With-Struct) +In addition, Slang also provides compatibility support for C-style initializer lists with `struct`s. C-style initializer lists can use [Partial Initializer List's](#Partial-Initializer-List's) and [Flattened Array Initializer With Struct's](#Flattened-Array-Initializer-With-Struct) A struct is considered a C-style struct if: 1. User never defines a custom constructor with **more than** 0 parameters @@ -1107,40 +1116,41 @@ float3 val2 = {}; #### Struct Type -1. Atempt to call default constructor (`__init()`) of a `struct` +1. Attempt to call default constructor (`__init()`) of a `struct` + ```csharp + struct Foo + { + int a; + int b; + __init() + { + a = 5; + b = 5; + } + }; -```csharp -struct Foo -{ - int a; - int b; - __init() - { - a = 5; - b = 5; - } -}; + ... -... + // Equivalent to `Foo val = Foo();` + Foo val = {}; + ``` -// Equivalent to `Foo val = Foo();` -Foo val = {}; -``` 2. As a fallback, zero-initialize the struct -```csharp -struct Foo -{ - int a; - int b; -}; + ```csharp + struct Foo + { + int a; + int b; + }; -... + ... + + // Equivalent to `Foo val; val.a = 0; val.b = 0;` + Foo val = {}; + ``` -// Equivalent to `Foo val; val.a = 0; val.b = 0;` -Foo val = {}; -``` ### Initializer Lists - Other features Slang allows calling a default-initializer inside a default-constructor. @@ -1150,4 +1160,4 @@ __init() { this = {}; //zero-initialize `this` } -``` \ No newline at end of file +``` diff --git a/docs/user-guide/03-convenience-features.md b/docs/user-guide/03-convenience-features.md index 1561d6605c..aeec8eb280 100644 --- a/docs/user-guide/03-convenience-features.md +++ b/docs/user-guide/03-convenience-features.md @@ -431,7 +431,7 @@ struct MyType int useVal(Optional p) { - if (p == none) // Equivalent to `p.hasValue` + if (p == none) // Equivalent to `!p.hasValue` return 0; return p.value.val; } @@ -537,45 +537,6 @@ Pointer types can also be specified using the generic syntax: `Ptr` is e - Slang currently does not support pointers to immutable values, i.e. `const T*`. -## `struct` inheritance (limited) - -Slang supports a limited form of inheritance. A derived `struct` type has all the members defined in the base type it is inherited from: - -```csharp -struct Base -{ - int a; - void method() {} -} - -struct Derived : Base { int b; } - -void test() -{ - Derived c; - c.a = 1; // OK, a is inherited from `Base`. - c.b = 2; - c.method(); // OK, `method` is inherited from `Base`. -} -``` - -A derived type can be implicitly casted to its base type: -```csharp -void acceptBase(Base b) { ... } -void test() -{ - Derived c; - acceptBase(c); // OK, c is implicitly casted to `Base`. -} -``` - -Slang supports controlling whether a type can be inherited from with `[sealed]` and `[open]` attributes on types. -If a base type is marked as `[sealed]`, then inheritance from the type is not allowed anywhere outside the same module (file) that is defining the base type. If a base type is marked as `[open]`, then inheritance is allowed regardless of the location of the derived type. By default, a type is `[sealed]` if no attributes are declared, which means the type can only be inherited by other types in the same module. - -### Limitations - -Please note that the support for inheritance is currently very limited. Common features that come with inheritance, such as `virtual` functions and multiple inheritance are not supported by the Slang compiler. Implicit down-casting to the base type and use the result as a `mutable` argument in a function call is also not supported. - Extensions -------------------- Slang allows defining additional methods for a type outside its initial definition. For example, suppose we already have a type defined: @@ -606,7 +567,7 @@ void test() } ``` -This feature is similar to extensions in Swift and partial classes in C#. +This feature is similar to extensions in Swift and extension methods in C#. > #### Note: > You can only extend a type with additional methods. Extending with additional data fields is not allowed. @@ -711,7 +672,7 @@ struct MaxValueAttribute uniform int scaleFactor; ``` -In the above code, the `MaxValueAttribute` struct type is decorated with the `[__AttributeUsage]` attribute, which informs that `MaxValueAttribute` type should be interpreted as a definiton for a user-defined attribute, `[MaxValue]`, that can be used to decorate all variables or fields. The members of the struct defines the argument list for the attribute. +In the above code, the `MaxValueAttribute` struct type is decorated with the `[__AttributeUsage]` attribute, which informs that `MaxValueAttribute` type should be interpreted as a definition for a user-defined attribute, `[MaxValue]`, that can be used to decorate all variables or fields. The members of the struct defines the argument list for the attribute. The `scaleFactor` uniform parameter is declared with the user defined `[MaxValue]` attribute, providing two arguments for `value` and `description`. diff --git a/docs/user-guide/05-capabilities.md b/docs/user-guide/05-capabilities.md index 8f377f5a47..6426cb37c7 100644 --- a/docs/user-guide/05-capabilities.md +++ b/docs/user-guide/05-capabilities.md @@ -92,7 +92,7 @@ public void myFunc() } ``` -## Inferrence of Capability Requirements +## Inference of Capability Requirements By default, Slang will infer the capability requirements of a function given its definition, as long as the function has `internal` or `private` visibility. For example, given: ```csharp @@ -110,7 +110,7 @@ Slang will automatically deduce that `myFunc` has capability ``` Since `discard` statement requires capability `fragment`. -## Inferrence on target_switch +## Inference on target_switch A `__target_switch` statement will introduce disjunctions in its inferred capability requirement. For example: ```csharp diff --git a/docs/user-guide/06-interfaces-generics.md b/docs/user-guide/06-interfaces-generics.md index df51ac9509..7a42484420 100644 --- a/docs/user-guide/06-interfaces-generics.md +++ b/docs/user-guide/06-interfaces-generics.md @@ -464,7 +464,7 @@ struct ArrayFloatContainer ``` Because C++ does not require a template function to define _constraints_ on the templated type, there are no interfaces or inheritances involved in the definition of `ArrayFloatContainer`. However `ArrayFloatContainer` still needs to define what its `Iterator` type is, so the `sum` function can be successfully specialized with an `ArrayFloatContainer`. -Note that the biggest difference between C++ templates and generics is that templates are not type-checked prior to specialization, and therefore the code that consumes a templated type (`TContainer` in this example) can simply assume `container` has a method named `getElementAt`, and the `TContainer` scope provides a type definition for `TContainer::Iterator`. Compiler error only arises when the programmer is attempting to specialize the `sum` function with a type that does not meet these assumptions. Contrarily, Slang requires all possible uses of a generic type be declared through an interface. By stating that `TContainer:IContainer` in the generics declaration, the Slang compiler can verify that `container.getElementAt` is calling a valid function. Similarily, the interface also tells the compiler that `TContainer.Iterator` is a valid type and enables the compiler to fully type check the `sum` function without specializing it first. +Note that the biggest difference between C++ templates and generics is that templates are not type-checked prior to specialization, and therefore the code that consumes a templated type (`TContainer` in this example) can simply assume `container` has a method named `getElementAt`, and the `TContainer` scope provides a type definition for `TContainer::Iterator`. Compiler error only arises when the programmer is attempting to specialize the `sum` function with a type that does not meet these assumptions. Contrarily, Slang requires all possible uses of a generic type be declared through an interface. By stating that `TContainer:IContainer` in the generics declaration, the Slang compiler can verify that `container.getElementAt` is calling a valid function. Similarly, the interface also tells the compiler that `TContainer.Iterator` is a valid type and enables the compiler to fully type check the `sum` function without specializing it first. ### Similarity to Swift and Rust @@ -1036,7 +1036,8 @@ Slang supports the following builtin interfaces: - `IInteger`, represents a logical integer that supports both `IArithmetic` and `ILogical` operations. Implemented by all builtin integer scalar types. - `IDifferentiable`, represents a value that is differentiable. - `IFloat`, represents a logical float that supports both `IArithmetic`, `ILogical` and `IDifferentiable` operations. Also provides methods to convert to and from `float`. Implemented by all builtin floating-point scalar, vector and matrix types. -- `IArray`, represents a logical array that supports retrieving an element of type `T` from an index. Implemented by array types, vectors and matrices. +- `IArray`, represents a logical array that supports retrieving an element of type `T` from an index. Implemented by array types, vectors, matrices and `StructuredBuffer`. +- `IRWArray`, represents a logical array whose elements are mutable. Implemented by array types, vectors, matrices, `RWStructuredBuffer` and `RasterizerOrderedStructuredBuffer`. - `IFunc` represent a callable object (with `operator()`) that returns `TResult` and takes `TParams...` as argument. - `IMutatingFunc`, similar to `IFunc`, but the `operator()` method is `[mutating]`. - `IDifferentiableFunc`, similar to `IFunc`, but the `operator()` method is `[Differentiable]`. diff --git a/docs/user-guide/07-autodiff.md b/docs/user-guide/07-autodiff.md index b3a25358c8..2a766e1c08 100644 --- a/docs/user-guide/07-autodiff.md +++ b/docs/user-guide/07-autodiff.md @@ -136,8 +136,13 @@ Where the backward propagation function $$\mathbb{B}[f_i]$$ takes as input the p The higher order operator $$\mathbb{F}$$ and $$\mathbb{B}$$ represent the operations that converts an original or primal function $$f$$ to its forward or backward derivative propagation function. Slang's automatic differentiation feature provide built-in support for these operators to automatically generate the derivative propagation functions from a user defined primal function. The remaining documentation will discuss this feature from a programming language perspective. -## Differentiable Types -Slang will only generate differentiation code for values that has a *differentiable* type. A type is differentiable if it conforms to the built-in `IDifferentiable` interface. The definition of the `IDifferentiable` interface is: +## Differentiable Value Types +Slang will only generate differentiation code for values that has a *differentiable* type. +Differentiable types are defining through conformance to one of two built-in interfaces: +1. `IDifferentiable`: For value types (e.g. `float`, structs of value types, etc..) +2. `IDifferentiablePtrType`: For buffer, pointer & reference types that represent locations rather than values. + +The `IDifferentiable` interface requires the following definitions (which can be auto-generated by the compiler for most scenarios) ```csharp interface IDifferentiable { @@ -147,23 +152,41 @@ interface IDifferentiable static Differential dzero(); static Differential dadd(Differential, Differential); - - static Differential dmul(This, Differential); } ``` As defined by the `IDifferentiable` interface, a differentiable type must have a `Differential` associated type that stores the derivative of the value. A further requirement is that the type of the second-order derivative must be the same `Differential` type. In another word, given a type `T`, `T.Differential` can be different from `T`, but `T.Differential.Differential` must equal to `T.Differential`. -In addition, a differentiable type must define the `zero` value of its derivative, and how to add and multiply derivative values. +In addition, a differentiable type must define the `zero` value of its derivative, and how to add two derivative values together. These function are used during reverse-mode auto-diff, to initialize and accumulate derivatives of the given type. + +By contrast, `IDifferentiablePtrType` only requires a `Differential` associated type which also conforms to `IDifferentiablePtrType`. +```csharp +interface IDifferentiablePtrType +{ + associatedtype Differential : IDifferentiablePtrType; + where Differential.Differential == Differential; +} +``` + +> #### Note #### +> Support for `IDifferentiablePtrType` is still experimental. -### Builtin Differentiable Types +Types should not conform to both `IDifferentiablePtrType` and `IDifferentiable`. Such cases will result in a compiler error. + + +### Builtin Differentiable Value Types The following built-in types are differentiable: - Scalars: `float`, `double` and `half`. - Vector/Matrix: `vector` and `matrix` of `float`, `double` and `half` types. - Arrays: `T[n]` is differentiable if `T` is differentiable. +- Tuples: `Tuple` is differentiable if `T` is differentiable. + +### Builtin Differentiable Ptr Types +There are currently no built-in types that conform to `IDifferentiablePtrType` ### User Defined Differentiable Types -The user can make any `struct` types differentiable by implementing the `IDifferentiable` interface on the type. The requirements from `IDifferentiable` interface can be fulfilled automatically or manually. +The user can make any `struct` types differentiable by implementing either `IDifferentiable` & `IDifferentiablePtrType` interface on the type. +The requirements from `IDifferentiable` interface can be fulfilled automatically or manually, though `IDifferentiablePtrType` currently requires the user to provide the `Differential` type. #### Automatic Fulfillment of `IDifferentiable` Requirements Assume the user has defined the following type: @@ -191,7 +214,7 @@ Note that this code does not provide any explicit implementation of the `IDiffer 1. A new type is generated that stores the `Differential` of all differentiable fields. This new type itself will conform to the `IDifferentiable` interface, and it will be used to satisfy the `Differential` associated type requirement. 2. Each differential field will be associated to its corresponding field in the newly synthesized `Differential` type. 3. The `zero` value of the differential type is made from the `zero` value of each field in the differential type. -4. The `dadd` and `dmul` methods simply perform `dadd` and `dmul` operations on each field. +4. The `dadd` method invokes the `dadd` operations for each field whose type conforms to `IDifferentiable`. 5. If the synthesized `Differential` type contains exactly the same fields as the original type, and the type of each field is the same as the original field type, then the original type itself will be used as the `Differential` type instead of creating a new type to satisfy the `Differential` associated type requirement. This means that all the synthesized `Differential` type use itself to meet its own `IDifferentiable` requirements. #### Manual Fulfillment of `IDifferentiable` Requirements @@ -235,15 +258,6 @@ struct MyRay : IDifferentiable result.d_dir = v1.d_dir + v2.d_dir; return result; } - - // Define the multiply operation of a primal value and a derivative value. - static MyRayDifferential dmul(MyRay p, MyRayDifferential d) - { - MyRayDifferential result; - result.d_origin = p.origin * d.d_origin; - result.d_dir = p.dir * d.d_dir; - return result; - } } ``` @@ -257,7 +271,7 @@ struct MyRayDifferential : IDifferentiable float3 d_dir; } ``` -In this case, since all fields in `MyRayDifferential` are differentiable, and the `Differential` of each field is the same as the original type of each field (i.e. `float3.Differential == float3` as defined in built-in library), the compiler will automatically use the type itself as its own `Differential`, making `MyRayDifferential` suitable for use as `Differential` of `MyRay`. +In this case, since all fields in `MyRayDifferential` are differentiable, and the `Differential` of each field is the same as the original type of each field (i.e. `float3.Differential == float3` as defined in the core module), the compiler will automatically use the type itself as its own `Differential`, making `MyRayDifferential` suitable for use as `Differential` of `MyRay`. We can also choose to manually implement `IDifferentiable` interface for `MyRayDifferential` as in the following code: @@ -284,14 +298,6 @@ struct MyRayDifferential : IDifferentiable result.d_dir = v1.d_dir + v2.d_dir; return result; } - - static MyRayDifferential dmul(MyRayDifferential p, MyRayDifferential d) - { - MyRayDifferential result; - result.d_origin = p.d_origin * d.d_origin; - result.d_dir = p.d_dir * d.d_dir; - return result; - } } ``` In this specific case, the automatically generated `IDifferentiable` implementation will be exactly the same as the manually written code listed above. @@ -303,17 +309,19 @@ Functions in Slang can be marked as forward-differentiable or backward-different A forward derivative propagation function computes the derivative of the result value with regard to a specific set of input parameters. Given an original function, the signature of its forward propagation function is determined using the following rules: -- If the return type `R` is differentiable, the forward propagation function will return `DifferentialPair` that consists of both the computed original result value and the (partial) derivative of the result value. Otherwise, the return type is kept unmodified as `R`. -- If a parameter has type `T` that is differentiable, it will be translated into a `DifferentialPair` parameter in the derivative function, where the differential component of the `DifferentialPair` holds the initial derivatives of each parameter with regard to their upstream parameters. +- If the return type `R` implements `IDifferentiable` the forward propagation function will return a corresponding `DifferentialPair` that consists of both the computed original result value and the (partial) derivative of the result value. Otherwise, the return type is kept unmodified as `R`. +- If a parameter has type `T` that implements `IDifferentiable`, it will be translated into a `DifferentialPair` parameter in the derivative function, where the differential component of the `DifferentialPair` holds the initial derivatives of each parameter with regard to their upstream parameters. +- If a parameter has type `T` that implements `IDifferentiablePtrType`, it will be translated into a `DifferentialPtrPair` parameter where the differential component references the differential location or buffer. - All parameter directions are unchanged. For example, an `out` parameter in the original function will remain an `out` parameter in the derivative function. +- Differentiable methods cannot have a type implementing `IDifferentiablePtrType` as an `out` or `inout` parameter, or a return type. Types implementing `IDifferentiablePtrType` can only be used for input parameters to a differentiable method. Marking such a method as `[Differentiable]` will result in a compile-time diagnostic error. For example, given original function: ```csharp -R original(T0 p0, inout T1 p1, T2 p2); +R original(T0 p0, inout T1 p1, T2 p2, T3 p3); ``` -Where `R`, `T0`, and `T1` is differentiable and `T2` is non-differentiable, the forward derivative function will have the following signature: +Where `R`, `T0`, `T1 : IDifferentiable`, `T2` is non-differentiable, and `T3 : IDifferentiablePtrType`, the forward derivative function will have the following signature: ```csharp -DifferentialPair derivative(DifferentialPair p0, inout DifferentialPair p1, T2 p2); +DifferentialPair derivative(DifferentialPair p0, inout DifferentialPair p1, T2 p2, DifferentialPtrPair p3); ``` This forward propagation function takes the initial primal value of `p0` in `p0.p`, and the partial derivative of `p0` with regard to some upstream parameter in `p0.d`. It takes the initial primal and derivative values of `p1` and updates `p1` to hold the newly computed value and propagated derivative. Since `p2` is not differentiable, it remains unchanged. @@ -327,10 +335,11 @@ struct DifferentialPair : IDifferentiable property T.Differential d {get;} static Differential dzero(); static Differential dadd(Differential a, Differential b); - static Differential dmul(This a, Differential b); } ``` +For ptr-types, there is a corresponding built-in `DifferentialPtrPair` that does not have the `dzero` or `dadd` methods. + ### Automatic Implementation of Forward Derivative Functions A function can be made forward-differentiable with a `[ForwardDifferentiable]` attribute. This attribute will cause the compiler to automatically implement the forward propagation function. The syntax for using `[ForwardDifferentiable]` is: @@ -392,23 +401,25 @@ Given an original function `f`, the general rule for determining the signature o More specifically, the signature of its backward propagation function is determined using the following rules: - A backward propagation function always returns `void`. -- A differentiable `in` parameter of type `T` will become an `inout DifferentialPair` parameter, where the original value part of the differential pair contains the original value of the parameter to pass into the back-prop function. The original value will not be overwritten by the backward propagation function. The propagated derivative will be written to the derivative part of the differential pair after the backward propagation function returns. The initial derivative value of the pair is ignored as input. -- A differentiable `out` parameter of type `T` will become an `in T.Differential` parameter, carrying the partial derivative of some downstream term with regard to the return value. -- A differentiable `inout` parameter of type `T` will become an `inout DifferentialPair` parameter, where the original value of the argument, along with the downstream partial derivative with regard to the argument is passed as input to the backward propagation function as the original and derivative part of the pair. The propagated derivative with regard to this input parameter will be written back and replace the derivative part of the pair. The primal value part of the parameter will *not* be updated. +- A differentiable `in` parameter of type `T : IDifferentiable` will become an `inout DifferentialPair` parameter, where the original value part of the differential pair contains the original value of the parameter to pass into the back-prop function. The original value will not be overwritten by the backward propagation function. The propagated derivative will be written to the derivative part of the differential pair after the backward propagation function returns. The initial derivative value of the pair is ignored as input. +- A differentiable `out` parameter of type `T : IDifferentiable` will become an `in T.Differential` parameter, carrying the partial derivative of some downstream term with regard to the return value. +- A differentiable `inout` parameter of type `T : IDifferentiable` will become an `inout DifferentialPair` parameter, where the original value of the argument, along with the downstream partial derivative with regard to the argument is passed as input to the backward propagation function as the original and derivative part of the pair. The propagated derivative with regard to this input parameter will be written back and replace the derivative part of the pair. The primal value part of the parameter will *not* be updated. - A differentiable return value of type `R` will become an additional `in R.Differential` parameter at the end of the backward propagation function parameter list, carrying the result derivative of a downstream term with regard to the return value of the original function. - A non-differentiable return value of type `NDR` will be dropped. - A non-differentiable `in` parameter of type `ND` will remain unchanged in the backward propagation function. - A non-differentiable `out` parameter of type `ND` will be removed from the parameter list of the backward propagation function. - A non-differentiable `inout` parameter of type `ND` will become an `in ND` parameter. +- Types implemented `IDifferentiablePtrType` work the same was as the forward-mode case. They can only be used with `in` parameters, and are converted into `DifferentialPtrPair` types. Their directions are not affected. For example consider the following original function: ```csharp struct T : IDifferentiable {...} struct R : IDifferentiable {...} +struct P : IDifferentiablePtrType {...} struct ND {} // Non differentiable [Differentiable] -R original(T p0, out T p1, inout T p2, ND p3, out ND p4, inout ND p5); +R original(T p0, out T p1, inout T p2, ND p3, out ND p4, inout ND p5, P p6); ``` The signature of its backward propagation function is: ```csharp @@ -418,6 +429,7 @@ void back_prop( inout DifferentialPair p2, ND p3, ND p5, + DifferentialPtrPair

p6, R.Differential dResult); ``` Note that although `p2` is still `inout` in the backward propagation function, the backward propagation function will only write propagated derivative to `p2.d` and will not modify `p2.p`. @@ -447,6 +459,7 @@ void back_prop( inout DifferentialPair p2, ND p3, ND p5, + DifferentialPtrPair

p6, R.Differential dResult) { ... @@ -468,6 +481,7 @@ void back_prop( inout DifferentialPair p2, ND p3, ND p5, + DifferentialPtrPair

p6, R.Differential dResult) { ... @@ -476,7 +490,7 @@ void back_prop( ## Builtin Differentiable Functions -The following built-in functions are backward differentiable and both their forward-derivative and backward-propagation functions are already defined in the built-in library: +The following built-in functions are backward differentiable and both their forward-derivative and backward-propagation functions are already defined in the core module: - Arithmetic functions: `abs`, `max`, `min`, `sqrt`, `rcp`, `rsqrt`, `fma`, `mad`, `fmod`, `frac`, `radians`, `degrees` - Interpolation and clamping functions: `lerp`, `smoothstep`, `clamp`, `saturate` @@ -490,7 +504,7 @@ The following built-in functions are backward differentiable and both their forw ## Primal Substitute Functions -Sometimes it is desirable to replace a function with another when generating forward or backward derivative propagation code. For example, the following code shows a function that computes the integral of some term by sampling and we want to use a different sampling stragegy when computing the derivatives. +Sometimes it is desirable to replace a function with another when generating forward or backward derivative propagation code. For example, the following code shows a function that computes the integral of some term by sampling and we want to use a different sampling strategy when computing the derivatives. ```csharp float myTerm(float x) { @@ -524,7 +538,7 @@ float getSampleForDerivativeComputation(float a, float b) Here, the `[PrimalSubstituteOf(getSample)]` attributes marks the `getSampleForDerivativeComputation` function as the substitute for `getSample` in derivative propagation functions. When a function has a primal substitute, the compiler will treat all calls to that function as if it is a call to the substitute function when generating derivative code. Note that this only applies to compiler generated derivative function and does not affect user provided derivative functions. If a user provided derivative function calls `getSample`, it will not be replaced by `getSampleForDerivativeComputation` by the compiler. -Similar to `[ForwardDerivative]` and `[ForwardDerivativeOf]` attributes, The `[PrimalSubsitute(substFunc)]` attribute works the other way around: it specifies the primal substitute function of the function being marked. +Similar to `[ForwardDerivative]` and `[ForwardDerivativeOf]` attributes, The `[PrimalSubstitute(substFunc)]` attribute works the other way around: it specifies the primal substitute function of the function being marked. Primal substitute can be used as another way to make a function differentiable. A function is considered differentiable if it has a primal substitute that is differentiable. The following code illustrates this mechanism. ```csharp diff --git a/docs/user-guide/08-compiling.md b/docs/user-guide/08-compiling.md index c9771a89ea..765dba5a5a 100644 --- a/docs/user-guide/08-compiling.md +++ b/docs/user-guide/08-compiling.md @@ -54,19 +54,20 @@ It is allowed, and indeed common, for a translation unit to contain only a singl For example, when adapting an existing codebase with many `.hlsl` files, it is appropriate to compile each `.hlsl` file as its own translation unit. A modernized codebase that uses modular `include` feature as documented in [Modules and Access Control](modules) might decide to compile multiple `.slang` files in a single directory as a single translation unit. -The result of compiling a translation unit is a module in Slang's internal intermediate representation (IR). The compiled module can then be serialized to a `.slang-module` binary file and loaded/imported just as `.slang` files. +The result of compiling a translation unit is a module in Slang's internal intermediate representation (IR). The compiled module can then be serialized to a `.slang-module` binary file. The binary file can then be loaded via the +`ISession::loadModuleFromIRBlob` function or `import`ed in slang code the same way as modules written in `.slang` files. ### Entry Points A translation unit / module may contain zero or more entry points. Slang supports two models for identifying entry points when compiling. -### Entry Point Attributes +#### Entry Point Attributes By default, the compiler will scan a translation unit for function declarations marked with the `[shader(...)]` attribute; each such function will be identified as an entry point in the module. Developers are encouraged to use this model because it directly documents intention and makes source code less dependent on external compiler configuration options. -### Explicit Entry Point Options +#### Explicit Entry Point Options For compatibility with existing code, the Slang compiler also supports explicit specification of entry point functions using configuration options external to shader source code. When these options are used the compiler will *ignore* all `[shader(...)]` attributes and only use the explicitly-specified entry points instead. @@ -127,7 +128,7 @@ A _component type_ is a unit of shader code composition; both modules and entry A _composite_ component type is formed from a list of other component types (for example, one module and two entry points) and can be used to define a unit of shader code that is meant to be used together. Once a programmer has formed a composite of all the code they intend to use together, they can query the layout of the shader parameters in that composite, or invoke the linking step to -resolve all cross module refeerences. +resolve all cross module references. ### Linking @@ -147,7 +148,12 @@ Second, different compositions of shader code can result in different layouts, w The `slangc` tool, included in binary distributions of Slang, is a command-line compiler that can handle most simple compilation tasks. `slangc` is intended to be usable as a replacement for tools like `fxc` and `dxc`, and covers most of the same use cases. -### Example +### All Available Options + +See [slangc command line reference](https://github.com/shader-slang/slang/blob/master/docs/command-line-slangc-reference.md) for a complete list of compiler options supported by the `slangc` tool. + + +### A Simple `slangc` Example Here we will repeat the example used in the [Getting Started](01-get-started.md) chapter. Given the following Slang code: @@ -170,7 +176,7 @@ void computeMain(uint3 threadId : SV_DispatchThreadID) we can compile the `computeMain()` entry point to SPIR-V using the following command line: ```bat -slangc hello-world.slang -entry computeMain -target spirv -o hello-world.spv +slangc hello-world.slang -target spirv -o hello-world.spv ``` ### Source Files and Translation Units @@ -193,10 +199,15 @@ When using `slangc`, you will typically want to identify which entry point(s) yo The `-entry computeMain` option selects an entry point to be compiled to output code in this invocation of `slangc`. Because the `computeMain()` entry point in this example has a `[shader(...)]` attribute, the compiler is able to deduce that it should be compiled for the `compute` stage. + +```bat +slangc hello-world.slang -target spirv -o hello-world.spv +``` + In code that does not use `[shader(...)]` attributes, a `-entry` option should be followed by a `-stage` option to specify the stage of the entry point: ```bat -slangc hello-world.slang -entry computeMain -stage compute -o hello-world.spv +slangc hello-world.slang -entry computeMain -stage compute -target spirv -o hello-world.spv ``` ### Targets @@ -233,7 +244,7 @@ For example: Kernel `-o` options are the most complicated case, because they depend on both a target and entry point. A `-o` option applies to the preceding entry point, and the compiler will try to apply it to a matching target based on its file extension. -For example, a `.spv` output file will be matched to a `-target spriv`. +For example, a `.spv` output file will be matched to a `-target spirv`. The compiler makes a best effort to support complicated cases with multiple files, entry points, and targets. Users with very complicated compilation requirements will probably be better off using multiple `slangc` invocations or migrating to the compilation API. @@ -250,13 +261,109 @@ The main other options are: * `-O` can be used to control optimization levels when the Slang compiler invokes downstream code generator +See [slangc command line reference](https://github.com/shader-slang/slang/blob/master/docs/command-line-slangc-reference.md) for a complete list of compiler options supported by the `slangc` tool. + +### Downstream Arguments + +`slangc` may leverage a 'downstream' tool like 'dxc', 'fxc', 'glslang', or 'gcc' for some target compilations. Rather than replicate every possible downstream option, arguments can be passed directly to the downstream tool using the "-X" option in `slangc`. + +The mechanism used here is based on the `-X` mechanism used in GCC, to specify arguments to the linker. + +``` +-Xlinker option +``` + +When used, `option` is not interpreted by GCC, but is passed to the linker once compilation is complete. Slang extends this idea in several ways. First there are many more 'downstream' stages available to Slang than just `linker`. These different stages are known as `SlangPassThrough` types in the API and have the following names + +* `fxc` - FXC HLSL compiler +* `dxc` - DXC HLSL compiler +* `glslang` - GLSLANG GLSL compiler +* `visualstudio` - Visual Studio C/C++ compiler +* `clang` - Clang C/C++ compiler +* `gcc` - GCC C/C++ compiler +* `genericcpp` - A generic C++ compiler (can be any one of visual studio, clang or gcc depending on system and availability) +* `nvrtc` - NVRTC CUDA compiler + +The Slang command line allows you to specify an argument to these downstream compilers, by using their name after the `-X`. So for example to send an option `-Gfa` through to DXC you can use + +``` +-Xdxc -Gfa +``` + +Note that if an option is available via normal Slang command line options then these should be used. This will generally work across multiple targets, but also avoids options clashing which is undefined behavior currently. The `-X` mechanism is best used for options that are unavailable through normal Slang mechanisms. + +If you want to pass multiple options using this mechanism the `-Xdxc` needs to be in front of every options. For example + +``` +-Xdxc -Gfa -Xdxc -Vd +``` + +Would reach `dxc` as + +``` +-Gfa -Vd +``` + +This can get a little repetitive especially if there are many parameters, so Slang adds a mechanism to have multiple options passed by using an ellipsis `...`. The syntax is as follows + +``` +-Xdxc... -Gfa -Vd -X. +``` + +The `...` at the end indicates all the following parameters should be sent to `dxc` until it reaches the matching terminating `-X.` or the end of the command line. + +It is also worth noting that `-X...` options can be nested. This would allow a GCC downstream compilation to control linking, for example with + +``` +-Xgcc -Xlinker --split -X. +``` + +In this example gcc would see + +``` +-Xlinker --split +``` + +And the linker would see (as passed through by gcc) + +``` +--split +``` + +Setting options for tools that aren't used in a Slang compilation has no effect. This allows for setting `-X` options specific for all downstream tools on a command line, and they are only used as part of a compilation that needs them. + +NOTE! Not all tools that Slang uses downstream make command line argument parsing available. `FXC` and `GLSLANG` currently do not have any command line argument passing as part of their integration, although this could change in the future. + +The `-X` mechanism is also supported by render-test tool. In this usage `slang` becomes a downstream tool. Thus you can use the `dxc` option `-Gfa` in a render-test via + +``` +-Xslang... -Xdxc -Gfa -X. +``` + +Means that the dxc compilation in the render test (assuming dxc is invoked) will receive + +``` +-Gfa +``` + +Some options are made available via the same mechanism for all downstream compilers. + +* Use `-I` to specify include path for downstream compilers + +For example to specify an include path "somePath" to DXC you can use... + +``` +-Xdxc -IsomePath +``` + + ### Convenience Features The `slangc` compiler provides a few conveniences for command-line compilation: * Most options can appear out of order when they are unambiguous. For example, if there is only a single translation unit a `-entry` option can appear before or after any file. -* A `-target` option can be left out if it can be inferred from the only `-o` option present. For example, `-o hello-world.spv` already implies `-target spriv`. +* A `-target` option can be left out if it can be inferred from the only `-o` option present. For example, `-o hello-world.spv` already implies `-target spirv`. * If a `-o` option is left out then kernel code will be written to the standard output. This output can be piped to a file, or can be printed to a console. In the latter case, the compiler will automatically disassemble binary formats for printing. @@ -265,25 +372,21 @@ The `slangc` compiler provides a few conveniences for command-line compilation: You can compile a `.slang` file into a binary IR module. For example, given the following source: ```hlsl -// library.slang +// my_library.slang float myLibFunc() { return 5.0; } ``` -You can compile it into `library.slang-module` with the following slangc command line: +You can compile it into `my_library.slang-module` with the following slangc command line: ```bat -slangc library.slang -o library.slang-module +slangc my_library.slang -o my_library.slang-module ``` -This allows you to deploy just the `library.slang-module` file to users of the library, and it can be consumed in the user code with the same `import` syntax: +This allows you to deploy just the `my_library.slang-module` file to users of the module, and it can be consumed in the user code with the same `import` syntax: ```hlsl -import library; +import my_library; ``` -### More Options - -See [slangc command line reference](https://github.com/shader-slang/slang/blob/master/docs/command-line-slangc-reference.md) for a complete list of compiler options supported by the `slangc` tool. - ### Limitations The `slangc` tool is meant to serve the needs of many developers, including those who are currently using `fxc`, `dxc`, or similar tools. @@ -296,6 +399,167 @@ Notable features that Slang supports which cannot be accessed from `slangc` incl Applications that need more control over compilation are encouraged to use the C++ compilation API described in the next section. +### Examples of `slangc` usage + +#### Multiple targets and multiple entrypoints + +In this example, there are two shader entrypoints defined in one source file. + +```hlsl +// targets.slang + +struct VertexOutput +{ + nointerpolation int a : SOME_VALUE; + float3 b : SV_Position; +}; + +[shader("pixel")] +float4 psMain() : SV_Target +{ + return float4(1, 0, 0, 1); +} + +[shader("vertex")] +VertexOutput vsMain() +{ + VertexOutput out; + out.a = 0; + out.b = float4(0, 1, 0, 1); + return out; +} +``` + +A single entrypoint from the preceding shader can be compiled to both SPIR-V Assembly and HLSL targets in one command: +```bat +slangc targets.slang -entry psMain -target spirv-asm -o targets.spv-asm -target hlsl -o targets.hlsl +``` + +The following command compiles both entrypoints to SPIR-V: + +```bat +slangc targets.slang -entry vsMain -entry psMain -target spirv -o targets.spv +``` + +#### Creating a standalone executable example + +This example compiles and runs a CPU host-callable style Slang unit. + +```hlsl +// cpu.slang + +class MyClass +{ + int intMember; + __init() + { + intMember = 0; + } + int method() + { + printf("method\n"); + return intMember; + } +} + +export __extern_cpp int main() +{ + MyClass obj = new MyClass(); + return obj.method(); +} + +``` + +Compile the above code as standalone executable, using -I option to find dependent header files: +```bat +slangc cpu.slang -target executable -o cpu.exe -Xgenericcpp -I./include -Xgenericcpp -I./external/unordered_dense/include/ +``` + +Execute the resulting executable: +```bat +C:\slang> cpu +method + +``` + +#### Compiling and linking slang-modules + +This example demonstrates the compilation of a slang-module, and linking to a shader which uses that module. +Two scenarios are provided, one in which the entry-point is compiled in the same `slangc` invocation that links in the dependent slang-module, and another scenario where linking is a separate invocation. + +```hlsl +// lib.slang +public int foo(int a) +{ + return a + 1; +} +``` + +```hlsl +// entry.slang +import "lib"; + +RWStructuredBuffer outputBuffer; + +[shader("compute")] +[numthreads(4, 1, 1)] +void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) +{ + int index = (int)dispatchThreadID.x; + outputBuffer[index] = foo(index); +} +``` + +Compile lib.slang to lib.slang-module: +```bat +slangc lib.slang -o lib.slang-module +``` + +Scenario 1: Compile entry.slang and link lib and entry together in one step: +```bat +slangc entry.slang -target spirv -o program.spv # Compile and link +``` + +Scenario 2: Compile entry.slang to entry.slang-module and then link together lib and entry in a second invocation: +```bat +slangc entry.slang -o entry.slang-module # Compile +slangc lib.slang-module entry.slang-module -target spirv -o program.spv # Link +``` + +#### Compiling with debug symbols + +Debug symbols can be added with the "-g" option. + +Adding '-g1' (or higher) to a SPIR-V compilation will emit extended 'DebugInfo' instructions. +```bat +slangc vertex.slang -target spirv-asm -o v.spv-asm -g0 # Omit debug symbols +slangc vertex.slang -target spirv-asm -o v.spv-asm -g1 # Add debug symbols +``` + + +#### Compiling with additional preprocessor macros + +User-defined macros can be set on the command-line with the "-D" or "-D=" option. + +```hlsl +// macrodefine.slang + +[shader("pixel")] +float4 psMain() : SV_Target +{ +#if defined(mymacro) + return float4(1, 0, 0, 1); +#else + return float4(0, 1, 0, 1); +#endif +} +``` + +* Setting a user-defined macro "mymacro" +```bat +slangc macrodefine.slang -entry psMain -target spirv-asm -o targets.spvasm -Dmymacro +``` + ## Using the Compilation API The C++ API provided by Slang is meant to provide more complete control over compilation for applications that need it. @@ -313,6 +577,9 @@ Application code is expected to correctly maintain the reference counts of `ISla Many Slang API calls return `SlangResult` values; this type is equivalent to (and binary-compatible with) the standard COM `HRESULT` type. As a matter of convention, Slang API calls return a zero value (`SLANG_OK`) on success, and a negative value on errors. +> #### Note #### +> Slang API interfaces may be named with the suffix "_Experimental", indicating that the interface is not complete, may have known bugs, and may change or be removed between Slang API releases. + ### Creating a Global Session A Slang _global session_ uses the interface `slang::IGlobalSession` and it represents a connection from an application to a particular implementation of the Slang API. @@ -325,8 +592,8 @@ Slang::ComPtr globalSession; createGlobalSession(globalSession.writeRef()); ``` -When a global session is created, the Slang system will load its internal representation of the _standard library_ that the compiler provides to user code. -The standard library can take a significant amount of time to load, so applications are advised to use a single global session if possible, rather than creating and then disposing of one for each compile. +When a global session is created, the Slang system will load its internal representation of the _core module_ that the compiler provides to user code. +The core module can take a significant amount of time to load, so applications are advised to use a single global session if possible, rather than creating and then disposing of one for each compile. > #### Note #### > Currently, the global session type is *not* thread-safe. @@ -562,7 +829,7 @@ The details of how Slang computes layout, what guarantees it makes, and how to i Because the layout computed for shader parameters may depend on the compilation target, the `getLayout()` method actually takes a `targetIndex` parameter that is the zero-based index of the target for which layout information is being queried. This parameter defaults to zero as a convenience for the common case where applications use only a single compilation target at runtime. -See [Using the Reflection API] chapter for more details on the reflection API. +See [Using the Reflection API](reflection) chapter for more details on the reflection API. ### Linking @@ -607,8 +874,8 @@ The only functions which are currently thread safe are ```C++ SlangSession* spCreateSession(const char* deprecated); SlangResult slang_createGlobalSession(SlangInt apiVersion, slang::IGlobalSession** outGlobalSession); -SlangResult slang_createGlobalSessionWithoutStdLib(SlangInt apiVersion, slang::IGlobalSession** outGlobalSession); -ISlangBlob* slang_getEmbeddedStdLib(); +SlangResult slang_createGlobalSessionWithoutCoreModule(SlangInt apiVersion, slang::IGlobalSession** outGlobalSession); +ISlangBlob* slang_getEmbeddedCoreModule(); SlangResult slang::createGlobalSession(slang::IGlobalSession** outGlobalSession); const char* spGetBuildTagString(); ``` @@ -689,7 +956,7 @@ meanings of their `CompilerOptionValue` encodings. | VulkanUseGLLayout | When set, will use std430 layout instead of D3D buffer layout for raw buffer load/stores. `intValue0` specifies a bool value for the setting. | | VulkanEmitReflection | Specifies the `-fspv-reflect` option. When set will include additional reflection instructions in the output SPIRV. `intValue0` specifies a bool value for the setting. | | GLSLForceScalarLayout | Specifies the `-force-glsl-scalar-layout` option. When set will use `scalar` layout for all buffers when generating SPIRV. `intValue0` specifies a bool value for the setting. | -| EnableEffectAnnotations | When set will turn on compatibilty mode to parse legacy HLSL effect annoation syntax. `intValue0` specifies a bool value for the setting. | +| EnableEffectAnnotations | When set will turn on compatibility mode to parse legacy HLSL effect annotation syntax. `intValue0` specifies a bool value for the setting. | | EmitSpirvViaGLSL | When set will emit SPIRV by emitting GLSL first and then use glslang to produce the final SPIRV code. `intValue0` specifies a bool value for the setting. | | EmitSpirvDirectly | When set will use Slang's direct-to-SPIRV backend to generate SPIRV directly from Slang IR. `intValue0` specifies a bool value for the setting. | | SPIRVCoreGrammarJSON | When set will use the provided SPIRV grammar file to parse SPIRV assembly blocks. `stringValue0` specifies a path to the spirv core grammar json file. | diff --git a/docs/user-guide/09-reflection.md b/docs/user-guide/09-reflection.md index 0c93112123..4e810fd1f2 100644 --- a/docs/user-guide/09-reflection.md +++ b/docs/user-guide/09-reflection.md @@ -13,7 +13,7 @@ The Slang API allows layout to be queried on any program object represented by a slang::ProgramLayout* layout = program->getLayout(); ``` -Please see the [Compiling Code with Slang](/user-guide/compiling) section on creating program objects. +Please see the [Compiling Code with Slang](compiling) section on creating program objects. Note that just as with output code, the reflection object (and all other objects queried from it) is guaranteed to live as long as the request is alive, but no longer. Unlike the other data, there is no easy way to save the reflection data for later user (we do not currently implement serialization for reflection data). @@ -137,7 +137,7 @@ If you have a type layout with kind `Array` you can query information about the ```c++ size_t arrayElementCount = typeLayout->getElementCount(); slang::TypeLayoutReflection* elementTypeLayout = typeLayout->getElementTypeLayout(); -sie_t arrayElementStride = typeLayout->getElementStride(category); +size_t arrayElementStride = typeLayout->getElementStride(category); ``` An array of unknown size will currently report zero elements. @@ -196,7 +196,7 @@ In the case of a compute shader entry point, you can also query the user-specifi ```c++ SlangUInt threadGroupSize[3]; -entryPoint->getComputeThreadGruopSize(3, &threadGroupSize[0]); +entryPoint->getComputeThreadGroupSize(3, &threadGroupSize[0]); ``` ## Function Reflection @@ -224,4 +224,4 @@ unsigned int attribCount = funcReflection->getUserAttributeCount(); slang::UserAttribute* attrib = funcReflection->getUserAttributeByIndex(0); const char* attribName = attrib->getName(); -``` \ No newline at end of file +``` diff --git a/docs/user-guide/09-targets.md b/docs/user-guide/09-targets.md index d6aebab0c0..f2ae767183 100644 --- a/docs/user-guide/09-targets.md +++ b/docs/user-guide/09-targets.md @@ -3,13 +3,11 @@ layout: user-guide permalink: /user-guide/targets --- -Supported Compilation Targets -============================ +# Supported Compilation Targets This chapter provides a brief overview of the compilation targets supported by Slang, and their different capabilities. -Background and Terminology --------------------------- +## Background and Terminology ### Code Formats @@ -48,13 +46,13 @@ Just as applications can do computation outside of the dedicated compute pipelin The kernels that execute within a pipeline typically has access to four different kinds of data: -* _Varying inputs_ coming from the system or from a preceding pipeline stage +- _Varying inputs_ coming from the system or from a preceding pipeline stage -* _Varying outputs_ which will be passed along to the system or to a following pipeline stage +- _Varying outputs_ which will be passed along to the system or to a following pipeline stage -* _Temporaries_ which are scratch memory or registers used by each invocation of the kernel and then dismissed on exit. +- _Temporaries_ which are scratch memory or registers used by each invocation of the kernel and then dismissed on exit. -* _Shader parameters_ (sometimes also called _uniform parameters_), which provide access to data from outside the pipeline dataflow +- _Shader parameters_ (sometimes also called _uniform parameters_), which provide access to data from outside the pipeline dataflow The first three of these kinds of data are largely handled by the implementation of a pipeline. In contrast, an application programmer typically needs to manually prepare shader parameters, using the appropriate mechanisms and rules for each target platform. @@ -100,8 +98,7 @@ Using root constants can eliminate some overheads from passing parameters of ord Passing a single `float` using a root constant rather than a buffer obviously eliminates a level of indirection. More importantly, though, using a root constant can avoid application code having to allocate and manage the lifetime of a buffer in a concurrent CPU/GPU program. -Direct3D 11 ------------ +## Direct3D 11 Direct3D 11 (D3D11) is a older graphics API, but remains popular because it is much simpler to learn and use than some more recent APIs. In this section we will give an overview of the relevant features of D3D11 when used as a target platform for Slang. @@ -117,28 +114,28 @@ D3D11 exposes two pipelines: rasterization and compute. The D3D11 rasterization pipeline can include up to five programmable stages, although most of them are optional: -* The `vertex` stage (VS) transforms vertex data loaded from memory +- The `vertex` stage (VS) transforms vertex data loaded from memory -* The optional `hull` stage (HS) typically sets up and computes desired tessellation levels for a higher-order primitive +- The optional `hull` stage (HS) typically sets up and computes desired tessellation levels for a higher-order primitive -* The optional `domain` stage (DS) evaluates a higher-order surface at domain locations chosen by a fixed-function tessellator +- The optional `domain` stage (DS) evaluates a higher-order surface at domain locations chosen by a fixed-function tessellator -* The optional `geometry` stage (GS) receives as input a primitive and can produce zero or more new primitives as output +- The optional `geometry` stage (GS) receives as input a primitive and can produce zero or more new primitives as output -* The optional `fragment` stage transforms fragments produced by the fixed-function rasterizer, determining the values for those fragments that will be merged with values in zero or more render targets. The fragment stage is sometimes called a "pixel" stage (PS), even when it does not process pixels. +- The optional `fragment` stage transforms fragments produced by the fixed-function rasterizer, determining the values for those fragments that will be merged with values in zero or more render targets. The fragment stage is sometimes called a "pixel" stage (PS), even when it does not process pixels. ### Parameter Passing Shader parameters are passed to each D3D11 stage via slots. Each stage has its own slots of the following types: -* **Constant buffers** are used for passing relatively small (4KB or less) amounts of data that will be read by GPU code. Constant bufers are passed via `b` registers. +- **Constant buffers** are used for passing relatively small (4KB or less) amounts of data that will be read by GPU code. Constant buffers are passed via `b` registers. -* **Shader resource views** (SRVs) include most textures, buffers, and other opaque resource types thare are read or sampled by GPU code. SRVs use `t` registers. +- **Shader resource views** (SRVs) include most textures, buffers, and other opaque resource types there are read or sampled by GPU code. SRVs use `t` registers. -* **Unordered access views** (UAVs) include textures, buffers, and other opaque resource types used for write or read-write operations in GPU code. UAVs use `u` registers. +- **Unordered access views** (UAVs) include textures, buffers, and other opaque resource types used for write or read-write operations in GPU code. UAVs use `u` registers. -* **Samplers** are used to pass opaque texture-sampling stage, and use `s` registers. +- **Samplers** are used to pass opaque texture-sampling stage, and use `s` registers. In addition, the D3D11 pipeline provides _vertex buffer_ slots and a single _index buffer_ slot to be used as the source vertex and index data that defines primitives. User-defined varying vertex shader inputs are bound to _vertex attribute_ slots (referred to as "input elements" in D3D11) which define how data from vertex buffers should be fetched to provide values for vertex attributes. @@ -149,8 +146,7 @@ User-defined fragment shader varying outputs (with `SV_Target` binding semantics One notable detail of the D3D11 API is that the slots for fragment-stage UAVs and RTVs overlap. For example, a fragment kernel cannot use both `u0` and `SV_Target0` at once. -Direct3D 12 ------------ +## Direct3D 12 Direct3D 12 (D3D12) is the current major version of the Direct3D API. @@ -167,14 +163,15 @@ Revisions to D3D12 have added additional stages to the rasterization pipeline, a #### Mesh Shaders -> #### Note ### +> #### Note +> > The Slang system does not currently support mesh shaders. The D3D12 rasterization pipeline provides alternative geometry processing stages that may be used as an alternative to the `vertex`, `hull`, `domain`, and `geometry` stages: -* The `mesh` stage runs groups of threads which are responsible cooperating to produce both the vertex and index data for a _meshlet_ a bounded-size chunk of geometry. +- The `mesh` stage runs groups of threads which are responsible cooperating to produce both the vertex and index data for a _meshlet_ a bounded-size chunk of geometry. -* The optional `amplification` stage precedes the mesh stage and is responsible for determining how many mesh shader invocations should be run. +- The optional `amplification` stage precedes the mesh stage and is responsible for determining how many mesh shader invocations should be run. Compared to the D3D11 pipeline without tesselllation (hull and domain shaders), a mesh shader is kind of like a combined/generalized vertex and geometry shader. @@ -185,17 +182,17 @@ Compared to the D3D11 pipeline with tessellation, an amplification shader is kin The DirectX Ray Tracing (DXR) feature added a ray tracing pipeline to D3D12. The D3D12 ray tracing pipeline exposes the following programmable stages: -* The ray generation (`raygeneration`) stage is similar to a compute stage, but can trace zero or more rays and make use of the results of those traces. +- The ray generation (`raygeneration`) stage is similar to a compute stage, but can trace zero or more rays and make use of the results of those traces. -* The `intersection` stage runs kernels to compute whether a ray intersects a user-defined primitive type. The system also includes a default intersector that handles triangle meshes. +- The `intersection` stage runs kernels to compute whether a ray intersects a user-defined primitive type. The system also includes a default intersector that handles triangle meshes. -* The so-called any-hit (`anyhit`) stage runs on _candidate_ hits where a ray has intersected some geometry, but the hit must be either accepted or rejected by application logic. Note that the any-hit stage does not necessarily run on *all* hits, because configuration options on both scene geometry and rays can lead to these checks being bypassed. +- The so-called any-hit (`anyhit`) stage runs on _candidate_ hits where a ray has intersected some geometry, but the hit must be either accepted or rejected by application logic. Note that the any-hit stage does not necessarily run on _all_ hits, because configuration options on both scene geometry and rays can lead to these checks being bypassed. -* The closest-hit (`closesthit`) stage runs a single _accepted_ hit for a ray; under typical circumstances this will be the closest hit to the origin of the ray. A typical closest-hit shader might compute the apparent color of a surface, similar to a typical fragment shader. +- The closest-hit (`closesthit`) stage runs a single _accepted_ hit for a ray; under typical circumstances this will be the closest hit to the origin of the ray. A typical closest-hit shader might compute the apparent color of a surface, similar to a typical fragment shader. -* The `miss` stage runs for rays that do not find or accept any hits in a scene. A typical miss shader might return a background color or sample an environment map. +- The `miss` stage runs for rays that do not find or accept any hits in a scene. A typical miss shader might return a background color or sample an environment map. -* The `callable` stage allows user-defined kernels to be invoked like subroutines in the context of the ray tracing pipeline. +- The `callable` stage allows user-defined kernels to be invoked like subroutines in the context of the ray tracing pipeline. Compared to existing rasterization and compute pipelines, an important difference in the design of the D3D12 ray tracing pipeline is that multiple kernels can be loaded into the pipeline for each of the programming stages. The specific closest-hit, miss, or other kernel that runs for a given hit or ray is determined by indexing into an appropriate _shader table_, which is effectively an array of kernels. @@ -204,7 +201,6 @@ The indexing into a shader table can depend on many factors including the type o Note that DXR version 1.1 adds ray tracing types and operations that can be used outside of the dedicated ray tracing pipeline. These new mechanisms have less visible impact for a programmer using or integrating Slang. - ### Parameter Passing The mechanisms for parameter passing in D3D12 differ greatly from D3D11. @@ -218,21 +214,20 @@ While shader parameters are bound registers and spaces, those registers and spac Instead, the configuration of the root parameters and the correspondence of registers/spaces to root parameters, blocks, and/or slots are defined by a _pipeline layout_ that D3D12 calls a "root signature." Unlike D3D11, all of the stages in a D3D12 pipeline share the same root parameters. -A D3D12 pipeline layout can specify that certain root parameters or certain slots within blocks will only be accessed by a subset of stages, and can map the *same* register/space pair to different parameters/blocks/slots as long as this is done for disjoint subset of stages. +A D3D12 pipeline layout can specify that certain root parameters or certain slots within blocks will only be accessed by a subset of stages, and can map the _same_ register/space pair to different parameters/blocks/slots as long as this is done for disjoint subset of stages. #### Ray Tracing Specifics The D3D12 ray tracing pipeline adds a new mechanism for passing shader parameters. In addition to allowing shader parameters to be passed to the entire pipeline via root parameters, each shader table entry provides storage space for passing argument data specific to that entry. -Similar to the use of a pipline layout (root signature) to configure the use of root parameters, each kernel used within shader entries must be configured with a "local root signature" that defines how the storage space in the shader table entry is to be used. +Similar to the use of a pipeline layout (root signature) to configure the use of root parameters, each kernel used within shader entries must be configured with a "local root signature" that defines how the storage space in the shader table entry is to be used. Shader parameters are still bound to registers and spaces as for non-ray-tracing code, and the local root signature simply allows those same registers/spaces to be associated with locations in a shader table entry. One important detail is that some shader table entries are associated with a kernel for a single stage (e.g., a single miss shader), while other shader table entries are associated with a "hit group" consisting of up to one each of an intersection, any-hit, and closest-hit kernel. Because multiple kernels in a hit group share the same shader table entry, they also share the configured slots in that entry for binding root constants, blocks, etc. -Vulkan ------- +## Vulkan Vulkan is a cross-platform GPU API for graphics and compute with a detailed specification produced by a multi-vendor standards body. In contrast with OpenGL, Vulkan focuses on providing explicit control over as many aspects of GPU work as possible. @@ -266,10 +261,10 @@ That is, a buffer and a texture both using `binding=2` in `set=3` for Vulkan wil The Vulkan ray tracing pipeline also uses a shader table, and also forms hit groups similar to D3D12. Unlike D3D12, each shader table entry in Vulkan can only be used to pass ordinary values (akin to root constants), and cannot be configured for binding of opaque types or blocks. -OpenGL ------- +## OpenGL -> #### Note #### +> #### Note +> > Slang has only limited support for compiling code for OpenGL. OpenGL has existed for many years, and predates programmable GPU pipelines of the kind this chapter discusses; we will focus solely on use of OpenGL as an API for programmable GPU pipelines. @@ -296,32 +291,71 @@ The binding index of a parameter is the zero-based index of the slot (of the app Note that while OpenGL and Vulkan both use binding indices for shader parameters like textures, the semantics of those are different because OpenGL uses distinct slots for passing buffers and textures. For OpenGL it is legal to have a texture that uses `binding=2` and a buffer that uses `binding=2` in the same kernel, because those are indices of distinct kinds of slots, while this scenario would typically be invalid for Vulkan. -Metal ------ +## Metal -> #### Note #### +> #### Note +> > Slang support for Metal is a work in progress. -Metal is a shading language exclusive on Apple platforms. The functionality from Metal is similar to DX12 or Vulkan with more or less features. +Metal is Apple's proprietary graphics and compute API for iOS and macOS +platforms. It provides a modern, low-overhead architecture similar to Direct3D +12 and Vulkan. + +Metal kernels must be compiled to the Metal Shading Language (MSL), which is +based on C++14 with additional GPU-specific features and constraints. Unlike +some other APIs, Metal does not use an intermediate representation - MSL source +code is compiled directly to platform-specific binaries by Apple's compiler. ### Pipelines -Metal includes vertex, fragment, task, mesh and tessellation stages for rasterization, as well as compute, and ray tracing stages. +Metal supports rasterization, compute, and ray tracing pipelines. -> #### Note #### +> #### Note +> > Ray-tracing support for Metal is a work in progress. +The Metal rasterization pipeline includes the following programmable stages: + +- The vertex stage outputs vertex data + +- The optional mesh stage allows groups of threads to cooperatively generate geometry + +- The optional task stage can be used to control mesh shader invocations + +- The optional tessellation stages (kernel, post-tessellation vertex) enable hardware tessellation + +- The fragment stage processes fragments produced by the rasterizer + ### Parameter Passing -Metal uses slots for binding resources, and it has three types of bindings: buffer, texture and sampler. -In addition, it has argument buffer which is itself a buffer, but any further resource members of the argument buffer does not occupy any explicit binding points, and instead set via an offset within the buffer referred to as id in the metal spec. +Metal uses a combination of slots and blocks for parameter passing: -Note that Metal 3.1 currently doesn't support arrays of buffers. +- Resources (buffers, textures, samplers) are bound to slots using explicit + binding indices -CUDA and OptiX --------------- +- Argument buffers (similar to descriptor tables/sets in other APIs) can group + multiple resources together -> #### Note #### +- Each resource type (buffer, texture, sampler) has its own independent binding + space + +- Arguments within argument buffers are referenced by offset rather than + explicit bindings + +Unlike some other APIs, Metal: + +- Does not support arrays of buffers as of version 3.1 +- Shares binding slots across all pipeline stages +- Uses argument buffers that can contain nested resources without consuming additional binding slots + +The Metal ray tracing pipeline follows similar parameter passing conventions to +the rasterization and compute pipelines, while adding intersection, +closest-hit, and miss stages comparable to those in Direct3D 12 and Vulkan. + +## CUDA and OptiX + +> #### Note +> > Slang support for OptiX is a work in progress. CUDA C/C++ is a language for expressing heterogeneous CPU and GPU code with a simple interface to invoking GPU compute work. @@ -330,7 +364,6 @@ We focus here on OptiX version 7 and up. CUDA and OptiX allow kernels to be loaded as GPU-specific binaries, or using the PTX intermediate language. - ### Pipelines CUDA supports a compute pipeline that is similar to D3D12 or Vulkan, with additional features. @@ -358,10 +391,10 @@ OptiX supports use of constant memory storage for ray tracing pipelines, where a OptiX uses a shader table for managing kernels and hit groups, and allows kernels to access the bytes of their shader table entry via a pointer. Similar to the compute pipeline, application code can layer many different policies on top of these mechanisms. -CPU Compute ------------ +## CPU Compute -> #### Note #### +> #### Note +> > Slang's support for CPU compute is functional, but not feature- or performance-complete. > Backwards-incompatible changes to this target may come in future versions of Slang. @@ -379,8 +412,48 @@ Slang's CPU compute target supports only a compute pipeline. Because CPU target support flexible pointer-based addressing and large low-latency caches, a compute kernel can simply be passed a small fixed number of pointers and be relied upon to load parameter values of any types via indirection through those pointers. -Summary -------- +## WebGPU + +> #### Note +> +> Slang support for WebGPU is work in progress. + +WebGPU is a graphics and compute API. +It is similar in spirit to modern APIs, like Metal, Direct3D 12 and Vulkan, but with concessions to portability and privacy. + +WebGPU is available both in browsers as a JavaScript API, and natively as a C/C++ API. +[Dawn](https://github.com/google/dawn), is a native WebGPU implementation used by the Chrome browser. + +By combining Slang, [Dawn](https://github.com/google/dawn) and [Emscripten](https://emscripten.org/), +an application can easily target any native API, and the web, with a single codebase consisting of C++ and Slang code. + +WebGPU shader modules are created from WGSL (WebGPU Shading Language) source files. +WebGPU does not use an intermediate representation - WGSL code is compiled to backend-specific code by +compilers provided by the WebGPU implementation. + +### Pipelines + +WebGPU supports render and compute pipelines. + +The WebGPU render pipeline includes the following programmable stages: + +- The vertex stage outputs vertex data + +- The fragment stage outputs fragments + +### Parameter Passing + +WebGPU uses groups of bindings called bind groups to bind things like textures, buffers and samplers. +Bind group objects are passed as arguments when encoding bind group setting commands. + +There is a notion of equivalence for bind groups, and a notion of equivalence for pipelines defined in +terms of bind group equivalence. +This equivalence allows an application to save some bind group setting commands, when switching between +pipelines, if bindings are grouped together appropriately. + +Which bindings are grouped together can be controlled using Slang's `ParameterBlock` generic type. + +## Summary This chapter has reviewed the main target platforms supported by the Slang compiler and runtime system. A key point to take away is that there is great variation in the capabilities of these systems. diff --git a/docs/user-guide/10-link-time-specialization.md b/docs/user-guide/10-link-time-specialization.md index 4541a6f552..14b10c63e1 100644 --- a/docs/user-guide/10-link-time-specialization.md +++ b/docs/user-guide/10-link-time-specialization.md @@ -5,7 +5,7 @@ permalink: /user-guide/link-time-specialization # Link-time Specialization and Module Precompilation -Traditionally, graphics developers have been relying on the preprocesor defines to specialize their shader code for high-performance GPU execution. +Traditionally, graphics developers have been relying on the preprocessor defines to specialize their shader code for high-performance GPU execution. While functioning systems can be built around preprocessor macros, overusing them leads to many problems: - Long compilation time. With preprocessors defines, specialzation happens before parsing, which is a very early stage in the compilation flow. This means that the compiler must redo almost all work from the scratch with every specialized variant, including parsing, type checking, IR generation diff --git a/docs/user-guide/a1-01-matrix-layout.md b/docs/user-guide/a1-01-matrix-layout.md index 3a9921db88..cb301ce8f5 100644 --- a/docs/user-guide/a1-01-matrix-layout.md +++ b/docs/user-guide/a1-01-matrix-layout.md @@ -24,14 +24,14 @@ Two conventions of matrix transform math Depending on the platform a developer is used to, a matrix-vector transform can be expressed as either `v*m` (`mul(v, m)` in HLSL), or `m*v` (`mul(m,v)` in HLSL). This convention, together with the matrix layout (column-major or row-major), determines how a matrix should be filled out in host code. -In HLSL/Slang the order of vector and matrix parameters to `mul` determine how the *vector* is interpretted. This interpretation is required because a vector does not in as of it's self differentiate between being a row or a column. +In HLSL/Slang the order of vector and matrix parameters to `mul` determine how the *vector* is interpreted. This interpretation is required because a vector does not in as of it's self differentiate between being a row or a column. -* `mul(v, m)` - v is interpretted as a row vector -* `mul(m, v)` - v is interpretted as a column vector. +* `mul(v, m)` - v is interpreted as a row vector. +* `mul(m, v)` - v is interpreted as a column vector. Through this mechanism a developer is able to write transforms in their preferred style. -These two styles are not directly interchangable - for a given `v` and `m` then generally `mul(v, m) != mul(m, v)`. For that the matrix needs to be transposed so +These two styles are not directly interchangeable - for a given `v` and `m` then generally `mul(v, m) != mul(m, v)`. For that the matrix needs to be transposed so * `mul(v, m) == mul(transpose(m), v)` * `mul(m, v) == mul(v, transpose(m))` @@ -42,7 +42,7 @@ This behavior is *independent* of how a matrix layout in memory. Host code needs Another way to think about this difference is in terms of where translation terms should be placed in memory when filling a typical 4x4 transform matrix. When transforming a row vector (ie `mul(v, m)`) with a `row-major` matrix layout, translation will be at `m + 12, 13, 14`. For a `column-major` matrix layout, translation will be at `m + 3, 7, 11`. -Note it is a *HLSL*/*Slang* convention that the parameter ordering of `mul(v, m)` means v is a *row* vector. A host maths library *could* have a transform function `SomeLib::transform(v, m)` such that `v` is a interpretted as *column* vector. For simplicitys sake the remainder of this discussion assumes that the `mul(v, m)` in equivalent in host code follows the interpretation that `v` is *row* vector. +Note it is a *HLSL*/*Slang* convention that the parameter ordering of `mul(v, m)` means v is a *row* vector. A host maths library *could* have a transform function `SomeLib::transform(v, m)` such that `v` is a interpreted as *column* vector. For simplicitys sake the remainder of this discussion assumes that the `mul(v, m)` in equivalent in host code follows the interpretation that `v` is *row* vector. Discussion ---------- @@ -64,7 +64,7 @@ If we accept 2, then there are only two possible combinations - either both host This is simple, but is perhaps not the end of the story. First lets assume that we want our Slang code to be as portable as possible. As previously discussed for CUDA and C++/CPU targets Slang ignores the matrix layout settings - the matrix layout is *always* `row-major`. -Second lets consider performance. The matrix layout in a host maths libray is not arbitrary from a performance point of view. A performant host maths library will want to use SIMD instructions. With both x86/x64 SSE and ARM NEON SIMD it makes a performance difference which layout is used, depending on if `column` or `row` is the *prefered* vector interpretation. If the `row` vector interpretation is prefered, it is most performant to have `row-major` matrix layout. Conversely if `column` vector interpretation is prefered `column-major` matrix will be the most performant. +Second lets consider performance. The matrix layout in a host maths library is not arbitrary from a performance point of view. A performant host maths library will want to use SIMD instructions. With both x86/x64 SSE and ARM NEON SIMD it makes a performance difference which layout is used, depending on if `column` or `row` is the *preferred* vector interpretation. If the `row` vector interpretation is preferred, it is most performant to have `row-major` matrix layout. Conversely if `column` vector interpretation is preferred `column-major` matrix will be the most performant. The performance difference comes down to a SIMD implementation having to do a transpose if the layout doesn't match the preferred vector interpretation. @@ -78,7 +78,7 @@ The only combination that fulfills all aspects is `row-major` matrix layout and It's worth noting that for targets that honor the default matrix layout - that setting can act like a toggle transposing a matrix layout. If for some reason the combination of choices leads to inconsistent vector transforms, an implementation can perform this transform in *host* code at the boundary between host and the kernel. This is not the most performant or convenient scenario, but if supported in an implementation it could be used for targets that do not support kernel matrix layout settings. -If only targetting platforms that honor matrix layout, there is more flexibility, our constraints are +If only targeting platforms that honor matrix layout, there is more flexibility, our constraints are 1) Consistency : Same vector interpretation in shader and host code 2) Performance: Host vector interpretation should match host matrix layout @@ -88,7 +88,7 @@ Then there are two combinations that work 1) `row-major` matrix layout for host and kernel, and `row` vector interpretation. 2) `column-major` matrix layout for host and kernel, and `column` vector interpretation. -If the host maths library is not performance orientated, it may be arbitray from a performance point of view if a `row` or `column` vector interpretation is used. In that case assuming shader and host vector interpretation is the same it is only important that the kernel and maths library matrix layout match. +If the host maths library is not performance orientated, it may be arbitrary from a performance point of view if a `row` or `column` vector interpretation is used. In that case assuming shader and host vector interpretation is the same it is only important that the kernel and maths library matrix layout match. Another way of thinking about these combinations is to think of each change in `row-major`/`column-major` matrix layout and `row`/`column` vector interpretation is a transpose. If there are an *even* number of flips then all the transposes cancel out. Therefore the following combinations work diff --git a/docs/user-guide/a1-02-slangpy.md b/docs/user-guide/a1-02-slangpy.md index f00ca0a14b..8a98285574 100644 --- a/docs/user-guide/a1-02-slangpy.md +++ b/docs/user-guide/a1-02-slangpy.md @@ -308,7 +308,7 @@ float computeOutputPixel(TensorView input, uint2 pixelLoc) } } - // Comptue the average value. + // Compute the average value. sumValue /= count; return sumValue; @@ -390,7 +390,7 @@ float computeOutputPixel( } } - // Comptue the average value. + // Compute the average value. sumValue /= count; return sumValue; @@ -494,7 +494,7 @@ TorchTensor square(TorchTensor input) ``` Here, we mark the function with the `[TorchEntryPoint]` attribute, so it will be compiled to C++ and exported as a python callable. -Since this is a host function, we can perform tensor allocations. For instnace, `square()` calls `TorchTensor.zerosLike` to allocate a 2D-tensor that has the same size as the input. +Since this is a host function, we can perform tensor allocations. For instance, `square()` calls `TorchTensor.zerosLike` to allocate a 2D-tensor that has the same size as the input. `zerosLike` returns a `TorchTensor` object that represents a CPU handle of a PyTorch tensor. Then we launch `square_kernel` with the `__dispatch_kernel` syntax. Note that we can directly pass @@ -729,7 +729,7 @@ Marks a function for export to Python. Functions marked with `[TorchEntryPoint]` Marks a function as a CUDA device function, and ensures the compiler to include it in the generated CUDA source. #### `[AutoPyBindCUDA]` attribute -Markes a cuda kernel for automatic binding generation so that it may be invoked from python without having to hand-code the torch entry point. The marked function **must** also be marked with `[CudaKernel]`. If the marked function is also marked with `[Differentiable]`, this will also generate bindings for the derivative methods. +Marks a cuda kernel for automatic binding generation so that it may be invoked from python without having to hand-code the torch entry point. The marked function **must** also be marked with `[CudaKernel]`. If the marked function is also marked with `[Differentiable]`, this will also generate bindings for the derivative methods. Restriction: methods marked with `[AutoPyBindCUDA]` will not operate diff --git a/docs/user-guide/a1-03-obfuscation.md b/docs/user-guide/a1-03-obfuscation.md index abce92e123..dab216940a 100644 --- a/docs/user-guide/a1-03-obfuscation.md +++ b/docs/user-guide/a1-03-obfuscation.md @@ -169,13 +169,13 @@ slangc module-source.slang -o module.zip -g -obfuscate This will compile "module-source.slang" into SlangIR module (aka `slang-module`) and places the `.slang-module` inside of the zip. As obfuscation is enabled the .zip will also contain the obfuscated source map for the module. -The `.zip` file can now be used and referenced as a library +The `.zip` file can now be used and referenced as a module ``` slangc source.slang -target dxil -stage compute -entry computeMain -obfuscate -r module.zip ``` -Notice here that the `-r` library reference is to the `.zip` file rather than the more usual `.slang-module` that is contained in the zip file. By referencing the library in this way Slang will automatically associate the contained obfuscated source map with the module. It will use that mapping for outputting diagnostics. +Notice here that the `-r` module reference is to the `.zip` file rather than the more usual `.slang-module` that is contained in the zip file. By referencing the module in this way Slang will automatically associate the contained obfuscated source map with the module. It will use that mapping for outputting diagnostics. It is also worth noticing that in this second compilation, using `module.zip`, we need the `-obfuscate` flag set. If this isn't set linking will not work correctly. @@ -256,7 +256,7 @@ Why you might not want to use an emit source map * The `#line` mechanism doesn't require any special handling, and the mapping back is embedded directly into the emitted source/output binary * There is more housekeeping in getting keeping and using source maps * Currently Slang doesn't directly expose a source map processing API directly - * We do support source maps in library files, or produced as part of a compilation + * We do support source maps in module files, or produced as part of a compilation * A developer could use the slang `compiler-core` implementation * In the future the project could provide some API support diff --git a/docs/user-guide/a1-04-interop.md b/docs/user-guide/a1-04-interop.md index a13f75c48c..a13bb5ca22 100644 --- a/docs/user-guide/a1-04-interop.md +++ b/docs/user-guide/a1-04-interop.md @@ -110,7 +110,7 @@ void test_0() The strings in `__requirePrelude` are deduplicated: the same prelude string will only be emitted once no matter how many times an intrinsic function is invoked. Therefore, it is good practice to put `#include` lines as separate `__requirePrelude` statements to prevent duplicate `#include`s being generated in the output code. ## Managing Cross-Platform Code -If you are defining an intrinsic function that maps to multiple targets in different ways, you can use `__target_switch` construct to manage the target-specific definitions. For example, here is a snippet from Slang's builtin standard library that defines `getRealtimeClock`: +If you are defining an intrinsic function that maps to multiple targets in different ways, you can use `__target_switch` construct to manage the target-specific definitions. For example, here is a snippet from the Slang core module that defines `getRealtimeClock`: ```hlsl [__requiresNVAPI] __glsl_extension(GL_EXT_shader_realtime_clock) diff --git a/docs/user-guide/a1-05-uniformity.md b/docs/user-guide/a1-05-uniformity.md index 630dfb8024..be07f89c01 100644 --- a/docs/user-guide/a1-05-uniformity.md +++ b/docs/user-guide/a1-05-uniformity.md @@ -5,13 +5,13 @@ layout: user-guide Uniformity Analysis =========== -On certain hardwares, accessing resources with a non-uniform index may lead to significant performance degradation. Developers can often benefit from a compiler warning for unintentional non-uniform resource access. +On certain hardware, accessing resources with a non-uniform index may lead to significant performance degradation. Developers can often benefit from a compiler warning for unintentional non-uniform resource access. Starting from v2024.1.0, Slang provides uniformity analysis that can warn users if a non-dynamically-uniform value is being used unintentionally. This feature is not enabled by default but can be turned on with the `-validate-uniformity` commandline option when using `slangc`, or the `CompilerOptionName::ValidateUniformity` compiler option when using the API. In addition to specifying the compiler option, the source code must be augmented with the `dynamic_uniform` modifier to mark function parameters, struct fields or local variables as expecting a dynamic uniform value. -For example, the following code will triger a warning: +For example, the following code will trigger a warning: ```csharp // Indicate that the `v` parameter needs to be dynamic uniform. float f(dynamic_uniform float v) @@ -101,4 +101,4 @@ void main() { expectUniform(f()); // Warning. } -``` \ No newline at end of file +``` diff --git a/docs/user-guide/a2-01-spirv-target-specific.md b/docs/user-guide/a2-01-spirv-target-specific.md index e0d6fd69b2..048318a09a 100644 --- a/docs/user-guide/a2-01-spirv-target-specific.md +++ b/docs/user-guide/a2-01-spirv-target-specific.md @@ -31,44 +31,44 @@ System-Value semantics The system-value semantics are translated to the following SPIR-V code. -| SV semantic name | SPIR-V code | -|--|--| -| SV_Barycentrics | BuiltIn BaryCoordKHR | -| SV_ClipDistance | BuiltIn ClipDistance | -| SV_CullDistance | BuiltIn CullDistance | -| SV_Coverage | BuiltIn SampleMask | -| SV_CullPrimitive | BuiltIn CullPrimitiveEXT | -| SV_Depth | BuiltIn FragDepth | -| SV_DepthGreaterEqual | BuiltIn FragDepth | -| SV_DepthLessEqual | BuiltIn FragDepth | -| SV_DispatchThreadID | BuiltIn GlobalInvocationId | -| SV_DomainLocation | BuiltIn TessCoord | -| SV_GSInstanceID | BuiltIn InvocationId | -| SV_GroupID | BuiltIn WorkgroupId | -| SV_GroupIndex | BuiltIn LocalInvocationIndex | -| SV_GroupThreadID | BuiltIn LocalInvocationId | -| SV_InnerCoverage | BuiltIn FullyCoveredEXT | -| SV_InsideTessFactor | BuiltIn TessLevelInner | -| SV_InstanceID | BuiltIn InstanceIndex | -| SV_IntersectionAttributes | *Not supported* | -| SV_IsFrontFace | BuiltIn FrontFacing | -| SV_OutputControlPointID | BuiltIn InvocationId | -| SV_PointSizenote | BuiltIn PointSize | -| SV_Position | BuiltIn Position/FragCoord | -| SV_PrimitiveID | BuiltIn PrimitiveId | -| SV_RenderTargetArrayIndex | BuiltIn Layer | -| SV_SampleIndex | BuiltIn SampleId | -| SV_ShadingRate | BuiltIn PrimitiveShadingRateKHR | -| SV_StartVertexLocation | *Not supported* | -| SV_StartInstanceLocation | *Not suported* | -| SV_StencilRef | BuiltIn FragStencilRefEXT | -| SV_Target | Location | -| SV_TessFactor | BuiltIn TessLevelOuter | -| SV_VertexID | BuiltIn VertexIndex | -| SV_ViewID | BuiltIn ViewIndex | -| SV_ViewportArrayIndex | BuiltIn ViewportIndex | - -*Note* that `SV_PointSize` is a unique keyword that HLSL doesn't have. +| SV semantic name | SPIR-V code | +|-------------------------------|-----------------------------------| +| `SV_Barycentrics` | `BuiltIn BaryCoordKHR` | +| `SV_ClipDistance` | `BuiltIn ClipDistance` | +| `SV_CullDistance` | `BuiltIn CullDistance` | +| `SV_Coverage` | `BuiltIn SampleMask` | +| `SV_CullPrimitive` | `BuiltIn CullPrimitiveEXT` | +| `SV_Depth` | `BuiltIn FragDepth` | +| `SV_DepthGreaterEqual` | `BuiltIn FragDepth` | +| `SV_DepthLessEqual` | `BuiltIn FragDepth` | +| `SV_DispatchThreadID` | `BuiltIn GlobalInvocationId` | +| `SV_DomainLocation` | `BuiltIn TessCoord` | +| `SV_GSInstanceID` | `BuiltIn InvocationId` | +| `SV_GroupID` | `BuiltIn WorkgroupId` | +| `SV_GroupIndex` | `BuiltIn LocalInvocationIndex` | +| `SV_GroupThreadID` | `BuiltIn LocalInvocationId` | +| `SV_InnerCoverage` | `BuiltIn FullyCoveredEXT` | +| `SV_InsideTessFactor` | `BuiltIn TessLevelInner` | +| `SV_InstanceID` | `BuiltIn InstanceIndex` | +| `SV_IntersectionAttributes` | *Not supported* | +| `SV_IsFrontFace` | `BuiltIn FrontFacing` | +| `SV_OutputControlPointID` | `BuiltIn InvocationId` | +| `SV_PointSizenote` | `BuiltIn PointSize` | +| `SV_Position` | `BuiltIn Position/FragCoord` | +| `SV_PrimitiveID` | `BuiltIn PrimitiveId` | +| `SV_RenderTargetArrayIndex` | `BuiltIn Layer` | +| `SV_SampleIndex` | `BuiltIn SampleId` | +| `SV_ShadingRate` | `BuiltIn PrimitiveShadingRateKHR` | +| `SV_StartVertexLocation` | `*Not supported* | +| `SV_StartInstanceLocation` | `*Not supported* | +| `SV_StencilRef` | `BuiltIn FragStencilRefEXT` | +| `SV_Target` | `Location` | +| `SV_TessFactor` | `BuiltIn TessLevelOuter` | +| `SV_VertexID` | `BuiltIn VertexIndex` | +| `SV_ViewID` | `BuiltIn ViewIndex` | +| `SV_ViewportArrayIndex` | `BuiltIn ViewportIndex` | + +*Note* that `SV_PointSize` is a Slang-specific semantic that is not defined in HLSL. Behavior of `discard` after SPIR-V 1.6 @@ -113,7 +113,7 @@ Slang ignores the keywords above and all of them are treated as `highp`. Supported atomic types for each target -------------------------------------- -Shader Model 6.2 introduced [16-bit scalar types](https://github.com/microsoft/DirectXShaderCompiler/wiki/16-Bit-Scalar-Types) such as float16 and int16_t, but they didn't come with any atomic operations. +Shader Model 6.2 introduced [16-bit scalar types](https://github.com/microsoft/DirectXShaderCompiler/wiki/16-Bit-Scalar-Types) such as `float16` and `int16_t`, but they didn't come with any atomic operations. Shader Model 6.6 introduced [atomic operations for 64-bit integer types and bitwise atomic operations for 32-bit float type](https://microsoft.github.io/DirectX-Specs/d3d/HLSL_SM_6_6_Int64_and_Float_Atomics.html), but 16-bit integer types and 16-bit float types are not a part of it. [GLSL 4.3](https://registry.khronos.org/OpenGL/specs/gl/GLSLangSpec.4.30.pdf) introduced atomic operations for 32-bit integer types. @@ -131,17 +131,17 @@ SPIR-V 1.5 with [SPV_EXT_shader_atomic_float16_add](https://github.com/KhronosGr | SPIR-V | Yes | Yes | Yes (SPV1.5+ext) | Yes (SPV1.5+ext) | Yes (SPV1.5+ext) | -ConstantBuffer, (RW/RasterizerOrdered)StructuredBuffer, (RW/RasterizerOrdered)ByteAddressBuffer +ConstantBuffer, StructuredBuffer and ByteAddressBuffer ----------------------------------------------------------------------------------------------- Each member in a `ConstantBuffer` will be emitted as `uniform` parameter in a uniform block. -StructuredBuffer and ByteAddressBuffer are translated to a shader storage buffer with `readonly` layout. -RWStructuredBuffer and RWByteAddressBuffer are translated to a shader storage buffer with `read-write` layout. +StructuredBuffer and ByteAddressBuffer are translated to a shader storage buffer with `readonly` access. +RWStructuredBuffer and RWByteAddressBuffer are translated to a shader storage buffer with `read-write` access. RasterizerOrderedStructuredBuffer and RasterizerOrderedByteAddressBuffer will use an extension, `SPV_EXT_fragment_shader_interlock`. -If you need to apply a different buffer layout for indivisual StructuredBuffer, you can specify the layout as a second generic argument to StructuredBuffer. E.g., StructuredBuffer, StructuredBuffer or StructuredBuffer. +If you need to apply a different buffer layout for individual `ConstantBuffer` or `StructuredBuffer`, you can specify the layout as a second generic argument. E.g., `ConstantBuffer`, `StructuredBuffer`, `StructuredBuffer` or `StructuredBuffer`. -Note that there are compiler options, "-fvk-use-scalar-layout" and "-force-glsl-scalar-layout". +Note that there are compiler options, "-fvk-use-scalar-layout" / "-force-glsl-scalar-layout" and "-fvk-use-dx-layout". These options do the same but they are applied globally. @@ -149,9 +149,11 @@ ParameterBlock for SPIR-V target -------------------------------- `ParameterBlock` is a Slang generic type for binding uniform parameters. -It is similar to `ConstantBuffer` in HLSL, and `ParameterBlock` can include not only constant parameters but also descriptors such as Texture2D or StructuredBuffer. +In contrast to `ConstantBuffer`, a `ParameterBlock` introduces a new descriptor set ID for resource/sampler handles defined in the element type `T`. -`ParameterBlock` is designed specifically for d3d/vulkan/metal, so that parameters are laid out more naturally on these platforms. For Vulkan, when a ParameterBlock doesn't contain nested parameter block fields, it always maps to a single descriptor set, with a dedicated set number and every resources is placed into the set with binding index starting from 0. +`ParameterBlock` is designed specifically for D3D12/Vulkan/Metal/WebGPU, so that parameters defined in `T` can be placed into an independent descriptor table/descriptor set/argument buffer/binding group. + +For example, when targeting Vulkan, when a ParameterBlock doesn't contain nested parameter block fields, it will always map to a single descriptor set, with a dedicated set number and every resources is placed into the set with binding index starting from 0. This allows the user application to create and pre-populate the descriptor set and reuse it during command encoding, without explicitly specifying the binding index for each individual parameter. When both ordinary data fields and resource typed fields exist in a parameter block, all ordinary data fields will be grouped together into a uniform buffer and appear as a binding 0 of the resulting descriptor set. @@ -160,8 +162,8 @@ Push Constants --------------------- By default, a `uniform` parameter defined in the parameter list of an entrypoint function is translated to a push constant in SPIRV, if the type of the parameter is ordinary data type (no resources/textures). -All `uniform` parameter defined in global scope are grouped together and placed in a default constant bbuffer. You can make a global uniform parameter laid out as a push constant by using the `[vk::push_constant]` attribute -on the uniform parameter. +All `uniform` parameters defined in global scope are grouped together and placed in a default constant buffer. You can make a global uniform parameter laid out as a push constant by using the `[vk::push_constant]` attribute +on the uniform parameter. All push constants follow the std430 layout by default. Specialization Constants ------------------------ @@ -184,65 +186,6 @@ Alternatively, the GLSL `layout` syntax is also supported by Slang: layout(constant_id = 1) const int MyConst = 1; ``` -SPIR-V specific Compiler options --------------------------------- - -The following compiler options are specific to SPIR-V. - -### -emit-spirv-directly -Generate SPIR-V output directly (default) -It cannot be used with -emit-spirv-via-glsl - -### -emit-spirv-via-glsl -Generate SPIR-V output by compiling to glsl source first, then use glslang compiler to produce SPIRV from the glsl. -It cannot be used with -emit-spirv-directly - -### -g -Include debug information in the generated code, where possible. -When targeting SPIR-V, this option emits [SPIR-V NonSemantic Shader DebugInfo Instructions](https://github.com/KhronosGroup/SPIRV-Registry/blob/main/nonsemantic/NonSemantic.Shader.DebugInfo.100.asciidoc). - -### -O -Set the optimization level. -Under `-O0` option, Slang will not perform extensive inlining for all functions calls, instead it will preserve the call graph as much as possible to help with understanding the SPIRV structure and diagnosing any downstream toolchain issues. - -### -fvk-{b|s|t|u}-shift -For example '-fvk-b-shift ' shifts by N the inferred binding -numbers for all resources in 'b' registers of space . For a resource attached with :register(bX, ) -but not [vk::binding(...)], sets its Vulkan descriptor set to and binding number to X + N. If you need to -shift the inferred binding numbers for more than one space, provide more than one such option. If more than one -such option is provided for the same space, the last one takes effect. If you need to shift the inferred binding -numbers for all sets, use 'all' as . - -For more information, see the following pages: - - [DXC description](https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#implicit-binding-number-assignment) - - [GLSL wiki](https://github.com/KhronosGroup/glslang/wiki/HLSL-FAQ#auto-mapped-binding-numbers) - -### -fvk-bind-globals -Places the $Globals cbuffer at descriptor set and binding . -It lets you specify the descriptor for the source at a certain register. - -For more information, see the following pages: - - [DXC description](https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#hlsl-global-variables-and-vulkan-binding) - -### -fvk-use-scalar-layout, -force-glsl-scalar-layout -Make data accessed through ConstantBuffer, ParameterBlock, StructuredBuffer, ByteAddressBuffer and general pointers follow the 'scalar' layout when targeting GLSL or SPIRV. - -### -fvk-use-gl-layout -Use std430 layout instead of D3D buffer layout for raw buffer load/stores. - -### -fvk-use-dx-layout -Pack members using FXCs member packing rules when targeting GLSL or SPIRV. - -### -fvk-use-entrypoint-name -Uses the entrypoint name from the source instead of 'main' in the spirv output. - -### -fspv-reflect -Include reflection decorations in the resulting SPIRV for shader parameters. - -### -spirv-core-grammar -A path to a specific spirv.core.grammar.json to use when generating SPIR-V output - - SPIR-V specific Attributes -------------------------- @@ -291,13 +234,13 @@ When there are more than one entry point, the default behavior will prevent a sh To generate a valid SPIR-V with multiple entry points, use `-fvk-use-entrypoint-name` compiler option to disable the renaming behavior and preserve the entry point names. -Memory pointer is experimental +Global memory pointers ------------------------------ -Slang supports memory pointers when targetting SPIRV. See [an example and explanation](convenience-features.html#pointers-limited). +Slang supports global memory pointers when targeting SPIRV. See [an example and explanation](convenience-features.html#pointers-limited). -When a memory pointer points to a physical memory location, the pointer will be translated to a PhysicalStorageBuffer storage class in SPIRV. -When a slang module uses a pointer, the resulting SPIRV will be using the SpvAddressingModelPhysicalStorageBuffer64 addressing mode. Modules with pointers but they don't point to a physical memory location will use SpvAddressingModelLogical addressing mode. +`float4*` in user code will be translated to a pointer in PhysicalStorageBuffer storage class in SPIRV. +When a slang module uses a pointer type, the resulting SPIRV will be using the SpvAddressingModelPhysicalStorageBuffer64 addressing mode. Modules without use of pointers will use SpvAddressingModelLogical addressing mode. Matrix type translation @@ -409,4 +352,62 @@ void main() { This behavior is same to [how DXC translates Hull shader from HLSL to SPIR-V](https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#patch-constant-function). +SPIR-V specific Compiler options +-------------------------------- + +The following compiler options are specific to SPIR-V. + +### -emit-spirv-directly +Generate SPIR-V output directly (default) +It cannot be used with -emit-spirv-via-glsl + +### -emit-spirv-via-glsl +Generate SPIR-V output by compiling to glsl source first, then use glslang compiler to produce SPIRV from the glsl. +It cannot be used with -emit-spirv-directly + +### -g +Include debug information in the generated code, where possible. +When targeting SPIR-V, this option emits [SPIR-V NonSemantic Shader DebugInfo Instructions](https://github.com/KhronosGroup/SPIRV-Registry/blob/main/nonsemantic/NonSemantic.Shader.DebugInfo.100.asciidoc). + +### -O +Set the optimization level. +Under `-O0` option, Slang will not perform extensive inlining for all functions calls, instead it will preserve the call graph as much as possible to help with understanding the SPIRV structure and diagnosing any downstream toolchain issues. + +### -fvk-{b|s|t|u}-shift +For example '-fvk-b-shift ' shifts by N the inferred binding +numbers for all resources in 'b' registers of space . For a resource attached with :register(bX, ) +but not [vk::binding(...)], sets its Vulkan descriptor set to and binding number to X + N. If you need to +shift the inferred binding numbers for more than one space, provide more than one such option. If more than one +such option is provided for the same space, the last one takes effect. If you need to shift the inferred binding +numbers for all sets, use 'all' as . + +For more information, see the following pages: + - [DXC description](https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#implicit-binding-number-assignment) + - [GLSL wiki](https://github.com/KhronosGroup/glslang/wiki/HLSL-FAQ#auto-mapped-binding-numbers) + +### -fvk-bind-globals +Places the $Globals cbuffer at descriptor set and binding . +It lets you specify the descriptor for the source at a certain register. + +For more information, see the following pages: + - [DXC description](https://github.com/Microsoft/DirectXShaderCompiler/blob/main/docs/SPIR-V.rst#hlsl-global-variables-and-vulkan-binding) + +### -fvk-use-scalar-layout, -force-glsl-scalar-layout +Make data accessed through ConstantBuffer, ParameterBlock, StructuredBuffer, ByteAddressBuffer and general pointers follow the 'scalar' layout when targeting GLSL or SPIRV. + +### -fvk-use-gl-layout +Use std430 layout instead of D3D buffer layout for raw buffer load/stores. + +### -fvk-use-dx-layout +Pack members using FXCs member packing rules when targeting GLSL or SPIRV. + +### -fvk-use-entrypoint-name +Uses the entrypoint name from the source instead of 'main' in the spirv output. + +### -fspv-reflect +Include reflection decorations in the resulting SPIRV for shader parameters. + +### -spirv-core-grammar +A path to a specific spirv.core.grammar.json to use when generating SPIR-V output + diff --git a/docs/user-guide/a2-02-metal-target-specific.md b/docs/user-guide/a2-02-metal-target-specific.md new file mode 100644 index 0000000000..e2602eb77e --- /dev/null +++ b/docs/user-guide/a2-02-metal-target-specific.md @@ -0,0 +1,294 @@ +--- +layout: user-guide +permalink: /user-guide/metal-target-specific +--- + +# Metal-specific functionalities + +This chapter provides information for Metal-specific functionalities and +behaviors in Slang. + +## Entry Point Parameter Handling + +Slang performs several transformations on entry point parameters when targeting Metal: + +- Struct parameters are flattened to eliminate nested structures +- Input parameters with varying inputs are packed into a single struct +- System value semantics are translated to Metal attributes +- Parameters without semantics are given automatic attribute indices + +## System-Value semantics + +The system-value semantics are translated to the following Metal attributes: + +| SV semantic name | Metal attribute | +| --------------------------- | ---------------------------------------------------- | +| `SV_Position` | `[[position]]` | +| `SV_Coverage` | `[[sample_mask]]` | +| `SV_Depth` | `[[depth(any)]]` | +| `SV_DepthGreaterEqual` | `[[depth(greater)]]` | +| `SV_DepthLessEqual` | `[[depth(less)]]` | +| `SV_DispatchThreadID` | `[[thread_position_in_grid]]` | +| `SV_GroupID` | `[[threadgroup_position_in_grid]]` | +| `SV_GroupThreadID` | `[[thread_position_in_threadgroup]]` | +| `SV_GroupIndex` | Calculated from `SV_GroupThreadID` and group extents | +| `SV_InstanceID` | `[[instance_id]]` | +| `SV_IsFrontFace` | `[[front_facing]]` | +| `SV_PrimitiveID` | `[[primitive_id]]` | +| `SV_RenderTargetArrayIndex` | `[[render_target_array_index]]` | +| `SV_SampleIndex` | `[[sample_id]]` | +| `SV_Target` | `[[color(N)]]` | +| `SV_VertexID` | `[[vertex_id]]` | +| `SV_ViewportArrayIndex` | `[[viewport_array_index]]` | + +Custom semantics are mapped to user attributes: + +- `[[user(SEMANTIC_NAME)]]` For non-system value semantics +- `[[user(SEMANTIC_NAME_INDEX)]]` When semantic has an index + +## Interpolation Modifiers + +Slang maps interpolation modifiers to Metal's interpolation attributes: + +| Slang Interpolation | Metal Attribute | +| ------------------- | --------------------------- | +| `nointerpolation` | `[[flat]]` | +| `noperspective` | `[[center_no_perspective]]` | +| `linear` | `[[sample_no_perspective]]` | +| `sample` | `[[sample_perspective]]` | +| `centroid` | `[[center_perspective]]` | + +## Resource Types + +Resource types are translated with appropriate Metal qualifiers: + +| Slang Type | Metal Translation | +| --------------------- | ------------------ | +| `Texture2D` | `texture2d` | +| `RWTexture2D` | `texture2d` | +| `ByteAddressBuffer` | `uint32_t device*` | +| `StructuredBuffer` | `device* T` | +| `ConstantBuffer` | `constant* T` | + +| Slang Type | Metal Translation | +| --------------------------------- | ------------------------------------- | +| `Texture1D` | `texture1d` | +| `Texture1DArray` | `texture1d_array` | +| `RWTexture1D` | `texture1d` | +| `RWTexture1DArray` | `texture1d_array` | +| `Texture2D` | `texture2d` | +| `Texture2DArray` | `texture2d_array` | +| `RWTexture2D` | `texture2d` | +| `RWTexture2DArray` | `texture2d_array` | +| `Texture3D` | `texture3d` | +| `RWTexture3D` | `texture3d` | +| `TextureCube` | `texturecube` | +| `TextureCubeArray` | `texturecube_array` | +| `Buffer` | `device* T` | +| `RWBuffer` | `device* T` | +| `ByteAddressBuffer` | `device* uint32_t` | +| `RWByteAddressBuffer` | `device* uint32_t` | +| `StructuredBuffer` | `device* T` | +| `RWStructuredBuffer` | `device* T` | +| `AppendStructuredBuffer` | `device* T` | +| `ConsumeStructuredBuffer` | `device* T` | +| `ConstantBuffer` | `constant* T` | +| `SamplerState` | `sampler` | +| `SamplerComparisonState` | `sampler` | +| `RaytracingAccelerationStructure` | `(Not supported)` | +| `RasterizerOrderedTexture2D` | `texture2d [[raster_order_group(0)]]` | +| `RasterizerOrderedBuffer` | `device* T [[raster_order_group(0)]]` | + +Raster-ordered access resources receive the `[[raster_order_group(0)]]` +attribute, for example `texture2d tex +[[raster_order_group(0)]]`. + +# Array Types + +Array types in Metal are declared using the array template: + +| Slang Type | Metal Translation | +| ------------------- | -------------------------- | +| `ElementType[Size]` | `array` | + +# Matrix Layout + +Metal exclusively uses column-major matrix layout. Slang automatically handles +the translation of matrix operations to maintain correct semantics: + +- Matrix multiplication is transformed to account for layout differences +- Matrix types are declared as `matrix`, for example + `float3x4` is represented as `matrix` + +# Mesh Shader Support + +Mesh shaders can be targeted using the following types and syntax. The same as task/mesh shaders generally in Slang. + +```slang +[outputtopology("triangle")] +[numthreads(12, 1, 1)] +void meshMain( + in uint tig: SV_GroupIndex, + in payload MeshPayload meshPayload, + OutputVertices verts, + OutputIndices triangles, + OutputPrimitives primitives + ) +``` + +## Header Inclusions and Namespace + +When targeting Metal, Slang automatically includes the following headers, these +are available to any intrinsic code. + +```cpp +#include +#include +#include +using namespace metal; +``` + +## Parameter blocks and Argument Buffers + +`ParameterBlock` values are translated into _Argument Buffers_ potentially +containing nested resources. For example this Slang code... + +```slang +struct MyParameters +{ + int x; + int y; + StructuredBuffer buffer1; + RWStructuredBuffer buffer2; +} + +ParameterBlock gObj; + +void main(){ ... gObj ... } +``` + +... results in this Metal output: + +```cpp +struct MyParameters +{ + int x; + int y; + float device* buffer1; + uint3 device* buffer2; +}; + +[[kernel]] void main(MyParameters constant* gObj [[buffer(1)]]) +``` + +## Struct Parameter Flattening + +When targeting Metal, top-level nested struct parameters are automatically +flattened. For example: + +```slang +struct NestedStruct +{ + float2 uv; +}; +struct InputStruct +{ + float4 position; + float3 normal; + NestedStruct nested; +}; +``` + +Will be flattened to: + +```cpp +struct InputStruct +{ + float4 position; + float3 normal; + float2 uv; +}; +``` + +## Return Value Handling + +Non-struct return values from entry points are automatically wrapped in a +struct with appropriate semantics. For example: + +```slang +float4 main() : SV_Target +{ + return float4(1,2,3,4); +} +``` + +becomes: + +```c++ +struct FragmentOutput +{ + float4 value : SV_Target; +}; +FragmentOutput main() +{ + return { float4(1,2,3,4) }; +} +``` + +## Value Type Conversion + +Metal enforces strict type requirements for certain operations. Slang +automatically performs the following conversions: + +- Vector size expansion (e.g., float2 to float4), for example when the user + specified `float2` but the semantic type in Metal is float4. +- Image store value expansion to 4-components + +For example: + +```slang +RWTexture2D tex; +tex[coord] = float2(1,2); // Automatically expanded to float4(1,2,0,0) +``` + +## Conservative Rasterization + +Since Metal doesn't support conservative rasterization, SV_InnerCoverage is always false. + +## Address Space Assignment + +Metal requires explicit address space qualifiers. Slang automatically assigns appropriate address spaces: + +| Variable Type | Metal Address Space | +| --------------------- | ------------------- | +| Local Variables | `thread` | +| Global Variables | `device` | +| Uniform Buffers | `constant` | +| RW/Structured Buffers | `device` | +| Group Shared | `threadgroup` | +| Parameter Blocks | `constant` | + +## Explicit Parameter Binding + +The HLSL `:register()` semantic is respected when emitting Metal code. + +Since metal does not differentiate a constant buffer, a shader resource (read-only) buffer and an unordered access buffer, Slang will map `register(tN)`, `register(uN)` and `register(bN)` to `[[buffer(N)]]` when such `register` semantic is declared on a buffer typed parameter. + +`spaceN` specifiers inside `register` semantics are ignored. + +## Specialization Constants + +Specialization constants declared with the `[SpecializationConstant]` or `[vk::constant_id]` attribute will be translated into a `function_constant` when generating Metal source. +For example: + +```csharp +[vk::constant_id(7)] +const int a = 2; +``` + +Translates to: + +```metal +constant int fc_a_0 [[function_constant(7)]]; +constant int a_0 = is_function_constant_defined(fc_a_0) ? fc_a_0 : 2; +``` \ No newline at end of file diff --git a/docs/user-guide/a2-03-wgsl-target-specific.md b/docs/user-guide/a2-03-wgsl-target-specific.md new file mode 100644 index 0000000000..743928a5fe --- /dev/null +++ b/docs/user-guide/a2-03-wgsl-target-specific.md @@ -0,0 +1,180 @@ +--- +layout: user-guide +permalink: /user-guide/wgsl-target-specific +--- + +WGSL specific functionalities +============================= + +This chapter provides information for WGSL (WebGPU Shading Language) -specific functionalities and behaviors. + + +System-Value semantics +---------------------- + +The system-value semantics are translated to the following WGSL code. + +| SV semantic name | WGSL code | +|--|--| +| SV_Barycentrics | *Not supported* | +| SV_ClipDistance | *Not supported* | +| SV_CullDistance | *Not supported* | +| SV_Coverage | `@builtin(sample_mask)` | +| SV_CullPrimitive | *Not supported* | +| SV_Depth | `@builtin(frag_depth)` | +| SV_DepthGreaterEqual | *Not supported* | +| SV_DepthLessEqual | *Not supported* | +| SV_DispatchThreadID | `@builtin(global_invocation_id)` | +| SV_DomainLocation | *Not supported* | +| SV_GSInstanceID | *Not supported* | +| SV_GroupID | `@builtin(workgroup_id)` | +| SV_GroupIndex | `@builtin(local_invocation_index)` | +| SV_GroupThreadID | `@builtin(local_invocation_id)` | +| SV_InnerCoverage | *Not supported* | +| SV_InsideTessFactor | *Not supported* | +| SV_InstanceID | `@builtin(instance_index)` | +| SV_IntersectionAttributes | *Not supported* | +| SV_IsFrontFace | `@builtin(front_facing)` | +| SV_OutputControlPointID | *Not supported* | +| SV_PointSize | *Not supported* | +| SV_Position | `@builtin(position)` | +| SV_PrimitiveID | *Not supported* | +| SV_RenderTargetArrayIndex | *Not supported* | +| SV_SampleIndex | `@builtin(sample_index)` | +| SV_ShadingRate | *Not supported* | +| SV_StartVertexLocation | *Not supported* | +| SV_StartInstanceLocation | *Not supported* | +| SV_StencilRef | *Not supported* | +| SV_Target | *Not supported* | +| SV_TessFactor | *Not supported* | +| SV_VertexID | `@builtin(vertex_index)` | +| SV_ViewID | *Not supported* | +| SV_ViewportArrayIndex | *Not supported* | + + +Supported HLSL features when targeting WGSL +------------------------------------------- + +The following table lists Slang's support for various HLSL feature sets, when targeting WGSL. + +| Feature set | Supported | +| -- | -- | +| ray tracing | No | +| inline ray tracing | No | +| mesh shader | No | +| tessellation shader | No | +| geometry shader | No | +| wave intrinsics | No | +| barriers | Yes | +| atomics | Yes | + + +Supported atomic types +---------------------- + +The following table shows what is supported when targeting WGSL: + +| | 32-bit integer | 64-bit integer | 32-bit float | 64-bit float | 16-bit float | +|--------------|-----------------|-----------------|-----------------------|------------------|------------------| +| Supported? | Yes | No | No | No | No | + + +ConstantBuffer, (RW/RasterizerOrdered)StructuredBuffer, (RW/RasterizerOrdered)ByteAddressBuffer +----------------------------------------------------------------------------------------------- + +ConstantBuffer translates to the `uniform` address space with `read` access mode in WGSL. +ByteAddressBuffer and RWByteAddressBuffer translate to `array` in the `storage` address space, with the `read` and `read_write` access modes in WGSL, respectively. +StructuredBuffer and RWStructuredBuffer with struct type T translate to `array` in the `storage` address space, with with the `read` and `read_write` access modes in WGSL, respectively. + + +Specialization Constants +------------------------ + +Specialization constants are not supported when targeting WGSL, at the moment. +They should map to 'override declarations' in WGSL, however this is not yet implemented. + + +Interlocked operations +---------------------- + +The InterlockedAdd, InterlockedAnd, etc... functions are not supported when targeting WGSL. +Instead, operations on [`Atomic`](https://shader-slang.com/stdlib-reference/types/atomic-0/index) types should be used. + + +Entry Point Parameter Handling +------------------------------ + +Slang performs several transformations on entry point parameters when targeting WGSL: + +- Struct parameters and returned structs are flattened to eliminate nested structures. +- System value semantics are translated to WGSL built-ins. (See the `@builtin` attribute, and the table above.) +- Parameters without semantics are given automatic location indices. (See the `@location` attribute.) + + +Parameter blocks +---------------- + +Each `ParameterBlock` is assigned its own bind group in WGSL. + + +Write-only Textures +--------------- + +Many image formats supported by WebGPU can only be accessed in compute shader as a write-only image. +Use `WTexture2D` type (similar to `RWTexture2D`) to write to an image when possible. +The write-only texture types are also supported when targeting HLSL/GLSL/SPIR-V/Metal and CUDA. + + +Pointers +-------- + +`out` and `inout` parameters in Slang are translated to pointer-typed parameters in WGSL. +At callsites, a pointer value is formed and passed as argument using the `&` operator in WGSL. + +Since WGSL cannot form pointers to fields of structs (or fields of fields of structs, etc...), the described transformation cannot be done in a direct way when a function argument expression is an "access chain" like `myStruct.myField` or `myStruct.myStructField.someField`. +In those cases, the argument is copied to a local variable, the address of the local variable is passed to the function, and then the local +variable is written back to the struct field after the function call. + +Address Space Assignment +------------------------ + +WGSL requires explicit address space qualifiers. Slang automatically assigns appropriate address spaces: + +| Variable Type | WGSL Address Space | +| --------------------- | ------------------- | +| Local Variables | `function` | +| Global Variables | `private` | +| Uniform Buffers | `uniform` | +| RW/Structured Buffers | `storage` | +| Group Shared | `workgroup` | +| Parameter Blocks | `uniform` | + + +Matrix type translation +----------------------- + +A m-row-by-n-column matrix in Slang, represented as float`m`x`n` or matrix, is translated to `mat[n]x[m]` in WGSL, i.e. a matrix with `n` columns and `m` rows. +The rationale for this inversion of terminology is the same as [the rationale for SPIR-V](a2-01-spirv-target-specific.md#matrix-type-translation). +Since the WGSL matrix multiplication convention is the normal one, where inner products of rows of the matrix on the left are taken with columns of the matrix on the right, the order of matrix products is also reversed in WGSL. This is relying on the fact that the transpose of a matrix product equals the product of the transposed matrix operands in reverse order. + +## Explicit Parameter Binding + +The `[vk::binding(index,set)]` attribute is respected when emitting WGSL code, and will translate to `@binding(index) @group(set)` in WGSL. + +If the `[vk::binding()]` attribute is not specified by a `:register()` semantic is present, Slang will derive the binding from the `register` semantic the same way as the SPIRV and GLSL backends. + +## Specialization Constants + +Specialization constants declared with the `[SpecializationConstant]` or `[vk::constant_id]` attribute will be translated into a global `override` declaration when generating WGSL source. +For example: + +```csharp +[vk::constant_id(7)] +const int a = 2; +``` + +Translates to: + +```wgsl +@id(7) override a : i32 = 2; +``` \ No newline at end of file diff --git a/docs/user-guide/a2-target-specific-features.md b/docs/user-guide/a2-target-specific-features.md index 2761d84e59..32be22f086 100644 --- a/docs/user-guide/a2-target-specific-features.md +++ b/docs/user-guide/a2-target-specific-features.md @@ -2,12 +2,12 @@ layout: user-guide --- -Target-specific features -============================ +# Target-specific features Slang can produce code for a variety of targets. When producing code for a target, Slang attempts to translate HLSL intrinsics to the closes functionality provided by the target. In addition, Slang also support target specific intrinsics and language extensions that allow users to make best use of the target. This chapter documents all the important target-specific behaviors. In this chapter: -1. [SPIR-V target specific](a2-01-spirv-target-specific.md) -2. Metal target specific -3. WebGPU + +1. [SPIR-V target specific](./a2-01-spirv-target-specific.md) +2. [Metal target specific](./a2-02-metal-target-specific.md) +3. [WGSL target specific](./a2-03-wgsl-target-specific.md) diff --git a/docs/user-guide/a3-01-reference-capability-profiles.md b/docs/user-guide/a3-01-reference-capability-profiles.md index 175a764965..43fe8eedb9 100644 --- a/docs/user-guide/a3-01-reference-capability-profiles.md +++ b/docs/user-guide/a3-01-reference-capability-profiles.md @@ -9,41 +9,41 @@ Capability Profiles > Note: To 'make' your own 'profile's, try mixing capabilities with `-capability`. -sm_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`sm_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model -vs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`vs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + vertex shader -ps_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`ps_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + pixel shader -hs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`hs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + hull shader -gs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`gs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + geometry shader -ds_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`ds_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + domain shader -cs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7} +`cs_{4_0,4_1,5_0,5_1,6_0,6_1,6_2,6_3,6_4,6_5,6_6,6_7}` * HLSL shader model + compute shader -ms_6_{5,6,7} +`ms_6_{5,6,7}` * HLSL shader model + mesh shader -as_6_{5,6,7} +`as_6_{5,6,7}` * HLSL shader model + amplification shader -lib_6_{1,2,3,4,5,6,7} +`lib_6_{1,2,3,4,5,6,7}` * HLSL shader model for libraries -glsl_{110,120,130,140,150,330,400,410,420,430,440,450,460} +`glsl_{110,120,130,140,150,330,400,410,420,430,440,450,460}` * GLSL versions -spirv_1_{1,2,3,4,5,6} +`spirv_1_{1,2,3,4,5,6}` * SPIRV versions -metallib_2_{3,4} -* Metal versions \ No newline at end of file +`metallib_2_{3,4}` +* Metal versions diff --git a/docs/user-guide/a3-02-reference-capability-atoms.md b/docs/user-guide/a3-02-reference-capability-atoms.md index 993c581b6d..e7a9b1bb41 100644 --- a/docs/user-guide/a3-02-reference-capability-atoms.md +++ b/docs/user-guide/a3-02-reference-capability-atoms.md @@ -42,6 +42,9 @@ Targets `spirv` > Represents the SPIR-V code generation target. +`wgsl` +> Represents the WebGPU shading language code generation target. + Stages ---------------------- *Capabilities to specify code generation stages (`vertex`, `fragment`...)* @@ -404,6 +407,9 @@ Extensions `spvAtomicFloat16AddEXT` > Represents the SPIR-V capability for atomic float 16 add operations. +`spvAtomicFloat64AddEXT` +> Represents the SPIR-V capability for atomic float 64 add operations. + `spvInt64Atomics` > Represents the SPIR-V capability for 64-bit integer atomics. @@ -413,6 +419,9 @@ Extensions `spvAtomicFloat16MinMaxEXT` > Represents the SPIR-V capability for atomic float 16 min/max operations. +`spvAtomicFloat64MinMaxEXT` +> Represents the SPIR-V capability for atomic float 64 min/max operations. + `spvDerivativeControl` > Represents the SPIR-V capability for 'derivative control' operations. @@ -681,6 +690,9 @@ Compound Capabilities `cpp_cuda_spirv` > CPP, CUDA and SPIRV code-gen targets +`cuda_spirv` +> CUDA and SPIRV code-gen targets + `cpp_cuda_glsl_spirv` > CPP, CUDA, GLSL and SPIRV code-gen targets @@ -690,9 +702,15 @@ Compound Capabilities `cpp_cuda_glsl_hlsl_spirv` > CPP, CUDA, GLSL, HLSL, and SPIRV code-gen targets +`cpp_cuda_glsl_hlsl_spirv_wgsl` +> CPP, CUDA, GLSL, HLSL, SPIRV and WGSL code-gen targets + `cpp_cuda_glsl_hlsl_metal_spirv` > CPP, CUDA, GLSL, HLSL, Metal and SPIRV code-gen targets +`cpp_cuda_glsl_hlsl_metal_spirv_wgsl` +> CPP, CUDA, GLSL, HLSL, Metal, SPIRV and WGSL code-gen targets + `cpp_cuda_hlsl` > CPP, CUDA, and HLSL code-gen targets @@ -708,9 +726,15 @@ Compound Capabilities `cpp_glsl_hlsl_spirv` > CPP, GLSL, HLSL, and SPIRV code-gen targets +`cpp_glsl_hlsl_spirv_wgsl` +> CPP, GLSL, HLSL, SPIRV and WGSL code-gen targets + `cpp_glsl_hlsl_metal_spirv` > CPP, GLSL, HLSL, Metal, and SPIRV code-gen targets +`cpp_glsl_hlsl_metal_spirv_wgsl` +> CPP, GLSL, HLSL, Metal, SPIRV and WGSL code-gen targets + `cpp_hlsl` > CPP, and HLSL code-gen targets @@ -726,12 +750,18 @@ Compound Capabilities `cuda_glsl_hlsl_metal_spirv` > CUDA, GLSL, HLSL, Metal, and SPIRV code-gen targets +`cuda_glsl_hlsl_metal_spirv_wgsl` +> CUDA, GLSL, HLSL, Metal, SPIRV and WGSL code-gen targets + `cuda_glsl_spirv` > CUDA, GLSL, and SPIRV code-gen targets `cuda_glsl_metal_spirv` > CUDA, GLSL, Metal, and SPIRV code-gen targets +`cuda_glsl_metal_spirv_wgsl` +> CUDA, GLSL, Metal, SPIRV and WGSL code-gen targets + `cuda_hlsl` > CUDA, and HLSL code-gen targets @@ -741,12 +771,21 @@ Compound Capabilities `glsl_hlsl_spirv` > GLSL, HLSL, and SPIRV code-gen targets +`glsl_hlsl_spirv_wgsl` +> GLSL, HLSL, SPIRV and WGSL code-gen targets + `glsl_hlsl_metal_spirv` > GLSL, HLSL, Metal, and SPIRV code-gen targets +`glsl_hlsl_metal_spirv_wgsl` +> GLSL, HLSL, Metal, SPIRV and WGSL code-gen targets + `glsl_metal_spirv` > GLSL, Metal, and SPIRV code-gen targets +`glsl_metal_spirv_wgsl` +> GLSL, Metal, SPIRV and WGSL code-gen targets + `glsl_spirv` > GLSL, and SPIRV code-gen targets @@ -1007,7 +1046,7 @@ Compound Capabilities > Capabilities required to use GLSL-style subgroup operations 'subgroup_shuffle' `subgroup_shufflerelative` -> Capabilities required to use GLSL-style subgroup operations 'subgroup_shufle_relative' +> Capabilities required to use GLSL-style subgroup operations 'subgroup_shuffle_relative' `subgroup_clustered` > Capabilities required to use GLSL-style subgroup operations 'subgroup_clustered' diff --git a/docs/user-guide/nav.html b/docs/user-guide/nav.html index 569eabf2a4..af7498646b 100644 --- a/docs/user-guide/nav.html +++ b/docs/user-guide/nav.html @@ -1,6 +1,6 @@

diff --git a/docs/user-guide/toc.html b/docs/user-guide/toc.html index 77c4f16d83..283706adc9 100644 --- a/docs/user-guide/toc.html +++ b/docs/user-guide/toc.html @@ -42,10 +42,9 @@
  • Subscript Operator
  • Tuple Types
  • `Optional<T>` type
  • -
  • `if_let` syntax
  • +
  • `if_let` syntax
  • `reinterpret<T>` operation
  • Pointers (limited)
  • -
  • `struct` inheritance (limited)
  • Extensions
  • Multi-level break
  • Force inlining
  • @@ -66,8 +65,8 @@
  • Capability Atoms and Capability Requirements
  • Conflicting Capabilities
  • Requirements in Parent Scope
  • -
  • Inferrence of Capability Requirements
  • -
  • Inferrence on target_switch
  • +
  • Inference of Capability Requirements
  • +
  • Inference on target_switch
  • Capability Aliases
  • Validation of Capability Requirements
  • @@ -94,7 +93,7 @@
    • Using Automatic Differentiation in Slang
    • Mathematic Concepts and Terminologies
    • -
    • Differentiable Types
    • +
    • Differentiable Value Types
    • Forward Derivative Propagation Function
    • Backward Derivative Propagation Function
    • Builtin Differentiable Functions
    • @@ -136,6 +135,7 @@
    • Metal
    • CUDA and OptiX
    • CPU Compute
    • +
    • WebGPU
    • Summary
    @@ -207,17 +207,52 @@
  • Supported HLSL features when targeting SPIR-V
  • Unsupported GLSL keywords when targeting SPIR-V
  • Supported atomic types for each target
  • -
  • ConstantBuffer, (RW/RasterizerOrdered)StructuredBuffer, (RW/RasterizerOrdered)ByteAddressBuffer
  • +
  • ConstantBuffer, StructuredBuffer and ByteAddressBuffer
  • ParameterBlock for SPIR-V target
  • Push Constants
  • Specialization Constants
  • -
  • SPIR-V specific Compiler options
  • SPIR-V specific Attributes
  • Multiple entry points support
  • -
  • Memory pointer is experimental
  • +
  • Global memory pointers
  • Matrix type translation
  • Legalization
  • Tessellation
  • +
  • SPIR-V specific Compiler options
  • + + +
  • Metal-specific functionalities +
      +
    • Entry Point Parameter Handling
    • +
    • System-Value semantics
    • +
    • Interpolation Modifiers
    • +
    • Resource Types
    • +
    • Header Inclusions and Namespace
    • +
    • Parameter blocks and Argument Buffers
    • +
    • Struct Parameter Flattening
    • +
    • Return Value Handling
    • +
    • Value Type Conversion
    • +
    • Conservative Rasterization
    • +
    • Address Space Assignment
    • +
    • Explicit Parameter Binding
    • +
    • Specialization Constants
    • +
    +
  • +
  • WGSL specific functionalities +
      +
    • System-Value semantics
    • +
    • Supported HLSL features when targeting WGSL
    • +
    • Supported atomic types
    • +
    • ConstantBuffer, (RW/RasterizerOrdered)StructuredBuffer, (RW/RasterizerOrdered)ByteAddressBuffer
    • +
    • Specialization Constants
    • +
    • Interlocked operations
    • +
    • Entry Point Parameter Handling
    • +
    • Parameter blocks
    • +
    • Write-only Textures
    • +
    • Pointers
    • +
    • Address Space Assignment
    • +
    • Matrix type translation
    • +
    • Explicit Parameter Binding
    • +
    • Specialization Constants
  • diff --git a/docs/wave-intrinsics.md b/docs/wave-intrinsics.md index 640158f79b..aa46f72a1e 100644 --- a/docs/wave-intrinsics.md +++ b/docs/wave-intrinsics.md @@ -31,7 +31,7 @@ Using WaveMask intrinsics is generally more verbose and prone to error than the * Might allow for higher performance (for example it gives more control of divergence) * Maps most closely to CUDA -On D3D12 and Vulkan the WaveMask instrinsics can be used, but the mask is effectively ignored. For this to work across targets including CUDA, the mask must be calculated such that it exactly matches that of HLSL defined 'active' lanes, else the behavior is undefined. +On D3D12 and Vulkan the WaveMask intrinsics can be used, but the mask is effectively ignored. For this to work across targets including CUDA, the mask must be calculated such that it exactly matches that of HLSL defined 'active' lanes, else the behavior is undefined. The WaveMask intrinsics are a non standard Slang feature, and may change in the future. @@ -41,7 +41,7 @@ RWStructuredBuffer outputBuffer; [numthreads(4, 1, 1)] void computeMain(uint3 dispatchThreadID : SV_DispatchThreadID) { - // It is the programmers responsibility to determine the inital mask, and that is dependent on the launch + // It is the programmers responsibility to determine the initial mask, and that is dependent on the launch // It's common to launch such that all lanes are active - with CUDA this would mean 32 lanes. // Here the launch only has 4 lanes active, and so the initial mask is 0xf. const WaveMask mask0 = 0xf; @@ -212,7 +212,7 @@ T WaveBroadcastLaneAt(T value, constexpr int lane); ``` All lanes receive the value specified in lane. Lane must be an active lane, otherwise the result is undefined. -This is a more restricive version of `WaveReadLaneAt` - which can take a non constexpr lane, *but* must be the same value for all lanes in the warp. Or 'dynamically uniform' as described in the HLSL documentation. +This is a more restrictive version of `WaveReadLaneAt` - which can take a non constexpr lane, *but* must be the same value for all lanes in the warp. Or 'dynamically uniform' as described in the HLSL documentation. ``` T WaveShuffle(T value, int lane); @@ -220,7 +220,7 @@ T WaveShuffle(T value, int lane); Shuffle is a less restrictive version of `WaveReadLaneAt` in that it has no restriction on the lane value - it does *not* require the value to be same on all lanes. -There isn't explicit support for WaveShuffle in HLSL, and for now it will emit `WaveReadLaneAt`. As it turns out for a sizable set of hardware WaveReadLaneAt does work correctly when the lane is not 'dynamically uniform'. This is not necessarily the case for hardware general though, so if targetting HLSL it is important to make sure that this does work correctly on your target hardware. +There isn't explicit support for WaveShuffle in HLSL, and for now it will emit `WaveReadLaneAt`. As it turns out for a sizable set of hardware WaveReadLaneAt does work correctly when the lane is not 'dynamically uniform'. This is not necessarily the case for hardware general though, so if targeting HLSL it is important to make sure that this does work correctly on your target hardware. Our intention is that Slang will support the appropriate HLSL mechanism that makes this work on all hardware when it's available. @@ -338,5 +338,3 @@ T WaveMaskReadLaneAt(WaveMask mask, T value, int lane); T WaveMaskShuffle(WaveMask mask, T value, int lane); ``` - - \ No newline at end of file diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000000..960db6b395 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,92 @@ +function(example dir) + set(debug_dir ${CMAKE_CURRENT_BINARY_DIR}/${dir}) + + file( + GLOB asset_files + CONFIGURE_DEPENDS + "${dir}/*.slang" + "${dir}/*.jpg" + "${dir}/*.obj" + "${dir}/*.mtl" + "${dir}/*.h" + ) + + list(LENGTH asset_files asset_files_length) + if(asset_files_length GREATER 0) + set(copy_assets_target "${dir}-copy-assets") + + add_custom_target( + ${copy_assets_target} + COMMAND ${CMAKE_COMMAND} -E make_directory ${debug_dir} + COMMAND + ${CMAKE_COMMAND} -E copy_if_different ${asset_files} + ${debug_dir} + COMMENT "Copy example assets to ${debug_dir}" + ) + + set_target_properties( + ${copy_assets_target} + PROPERTIES FOLDER "examples/copy_assets" + ) + endif() + + slang_add_target( + ${dir} + EXECUTABLE + USE_FEWER_WARNINGS + LINK_WITH_PRIVATE + core + example-base + slang + gfx + gfx-util + platform + $<$:CUDA::cuda_driver> + EXTRA_COMPILE_DEFINITIONS_PRIVATE + $<$:SLANG_ENABLE_XLIB> + REQUIRED_BY all-examples + OPTIONAL_REQUIRES ${copy_assets_target} copy-prebuilt-binaries + FOLDER examples + DEBUG_DIR ${debug_dir} + ${ARGN} + ) +endfunction() + +if(SLANG_ENABLE_EXAMPLES) + # + # Examples + # + slang_add_target( + example-base + STATIC + LINK_WITH_PRIVATE + core + slang + gfx + platform + stb + $<$:CUDA::cuda_driver> + FOLDER examples + ) + + add_custom_target( + all-examples + COMMENT "meta target which depends on all examples" + ) + set_target_properties(all-examples PROPERTIES FOLDER examples) + example(autodiff-texture WIN32_EXECUTABLE) + example(cpu-com-example) + example(cpu-hello-world) + example(gpu-printing) + example(hello-world LINK_WITH_PRIVATE Vulkan-Headers) + example(model-viewer WIN32_EXECUTABLE) + example(platform-test WIN32_EXECUTABLE) + example(ray-tracing WIN32_EXECUTABLE) + example(ray-tracing-pipeline WIN32_EXECUTABLE) + example(shader-object) + example(shader-toy WIN32_EXECUTABLE) + example(triangle WIN32_EXECUTABLE) + if(SLANG_ENABLE_AFTERMATH) + example(nv-aftermath-example WIN32_EXECUTABLE) + endif() +endif() diff --git a/examples/autodiff-texture/main.cpp b/examples/autodiff-texture/main.cpp index 8bffadd84b..647929e70e 100644 --- a/examples/autodiff-texture/main.cpp +++ b/examples/autodiff-texture/main.cpp @@ -1,10 +1,10 @@ +#include "core/slang-basic.h" #include "examples/example-base/example-base.h" #include "gfx-util/shader-cursor.h" +#include "platform/vector-math.h" +#include "platform/window.h" #include "slang-com-ptr.h" #include "slang-gfx.h" -#include "source/core/slang-basic.h" -#include "tools/platform/vector-math.h" -#include "tools/platform/window.h" #include "slang.h" using namespace gfx; @@ -41,14 +41,18 @@ struct AutoDiffTexture : public WindowedAppBase } gfx::Result loadRenderProgram( - gfx::IDevice* device, const char* fileName, const char* fragmentShader, gfx::IShaderProgram** outProgram) + gfx::IDevice* device, + const char* fileName, + const char* fragmentShader, + gfx::IShaderProgram** outProgram) { ComPtr slangSession; slangSession = device->getSlangSession(); ComPtr diagnosticsBlob; Slang::String path = resourceBase.resolveResource(fileName); - slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); + slang::IModule* module = + slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); diagnoseIfNeeded(diagnosticsBlob); if (!module) return SLANG_FAIL; @@ -91,14 +95,17 @@ struct AutoDiffTexture : public WindowedAppBase } gfx::Result loadComputeProgram( - gfx::IDevice* device, const char* fileName, gfx::IShaderProgram** outProgram) + gfx::IDevice* device, + const char* fileName, + gfx::IShaderProgram** outProgram) { ComPtr slangSession; slangSession = device->getSlangSession(); ComPtr diagnosticsBlob; Slang::String path = resourceBase.resolveResource(fileName); - slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); + slang::IModule* module = + slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); diagnoseIfNeeded(diagnosticsBlob); if (!module) return SLANG_FAIL; @@ -174,7 +181,11 @@ struct AutoDiffTexture : public WindowedAppBase ClearValue kClearValue; bool resetLearntTexture = false; - ComPtr createRenderTargetTexture(gfx::Format format, int w, int h, int levels) + ComPtr createRenderTargetTexture( + gfx::Format format, + int w, + int h, + int levels) { gfx::ITextureResource::Desc textureDesc = {}; textureDesc.allowedStates.add(ResourceState::ShaderResource); @@ -239,7 +250,8 @@ struct AutoDiffTexture : public WindowedAppBase return gDevice->createTextureView(tex, rtvDesc); } ComPtr createRenderPipelineState( - IInputLayout* inputLayout, IShaderProgram* program) + IInputLayout* inputLayout, + IShaderProgram* program) { GraphicsPipelineStateDesc desc; desc.inputLayout = inputLayout; @@ -269,7 +281,7 @@ struct AutoDiffTexture : public WindowedAppBase desc.subresourceRange.layerCount = 1; desc.subresourceRange.mipLevel = level; desc.subresourceRange.baseArrayLayer = 0; - return gDevice->createTextureView(texture,desc); + return gDevice->createTextureView(texture, desc); } Slang::Result initialize() { @@ -320,20 +332,29 @@ struct AutoDiffTexture : public WindowedAppBase { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL( - loadRenderProgram(gDevice, "train.slang", "fragmentMain", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL(loadRenderProgram( + gDevice, + "train.slang", + "fragmentMain", + shaderProgram.writeRef())); gRefPipelineState = createRenderPipelineState(inputLayout, shaderProgram); } { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL( - loadRenderProgram(gDevice, "train.slang", "diffFragmentMain", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL(loadRenderProgram( + gDevice, + "train.slang", + "diffFragmentMain", + shaderProgram.writeRef())); gIterPipelineState = createRenderPipelineState(inputLayout, shaderProgram); } { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL( - loadRenderProgram(gDevice, "draw-quad.slang", "fragmentMain", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL(loadRenderProgram( + gDevice, + "draw-quad.slang", + "fragmentMain", + shaderProgram.writeRef())); gDrawQuadPipelineState = createRenderPipelineState(inputLayout, shaderProgram); } { @@ -344,17 +365,20 @@ struct AutoDiffTexture : public WindowedAppBase } { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "convert.slang", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL( + loadComputeProgram(gDevice, "convert.slang", shaderProgram.writeRef())); gConvertPipelineState = createComputePipelineState(shaderProgram); } { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "buildmip.slang", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL( + loadComputeProgram(gDevice, "buildmip.slang", shaderProgram.writeRef())); gBuildMipPipelineState = createComputePipelineState(shaderProgram); } { ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadComputeProgram(gDevice, "learnmip.slang", shaderProgram.writeRef())); + SLANG_RETURN_ON_FAIL( + loadComputeProgram(gDevice, "learnmip.slang", shaderProgram.writeRef())); gLearnMipPipelineState = createComputePipelineState(shaderProgram); } @@ -394,7 +418,7 @@ struct AutoDiffTexture : public WindowedAppBase gDiffTextureUAVs.add(createUAV(gDiffTexture, i)); gfx::ISamplerState::Desc samplerDesc = {}; - //samplerDesc.maxLOD = 0.0f; + // samplerDesc.maxLOD = 0.0f; gSampler = gDevice->createSamplerState(samplerDesc); gDepthTexture = createDepthTexture(); @@ -404,7 +428,8 @@ struct AutoDiffTexture : public WindowedAppBase gRefImageRTV = createRTV(gRefImage, Format::R8G8B8A8_UNORM); gRefImageSRV = createSRV(gRefImage); - gIterImage = createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1); + gIterImage = + createRenderTargetTexture(Format::R8G8B8A8_UNORM, windowWidth, windowHeight, 1); gIterImageRTV = createRTV(gIterImage, Format::R8G8B8A8_UNORM); gIterImageSRV = createSRV(gIterImage); @@ -414,17 +439,38 @@ struct AutoDiffTexture : public WindowedAppBase { ComPtr commandBuffer = gTransientHeaps[0]->createCommandBuffer(); auto encoder = commandBuffer->encodeResourceCommands(); - encoder->textureBarrier(gLearningTexture, ResourceState::RenderTarget, ResourceState::UnorderedAccess); - encoder->textureBarrier(gDiffTexture, ResourceState::RenderTarget, ResourceState::UnorderedAccess); - encoder->textureBarrier(gRefImage, ResourceState::RenderTarget, ResourceState::ShaderResource); - encoder->textureBarrier(gIterImage, ResourceState::RenderTarget, ResourceState::ShaderResource); + encoder->textureBarrier( + gLearningTexture, + ResourceState::RenderTarget, + ResourceState::UnorderedAccess); + encoder->textureBarrier( + gDiffTexture, + ResourceState::RenderTarget, + ResourceState::UnorderedAccess); + encoder->textureBarrier( + gRefImage, + ResourceState::RenderTarget, + ResourceState::ShaderResource); + encoder->textureBarrier( + gIterImage, + ResourceState::RenderTarget, + ResourceState::ShaderResource); for (int i = 0; i < gLearningTextureUAVs.getCount(); i++) { ClearValue clearValue = {}; - encoder->clearResourceView(gLearningTextureUAVs[i], &clearValue, ClearResourceViewFlags::None); - encoder->clearResourceView(gDiffTextureUAVs[i], &clearValue, ClearResourceViewFlags::None); + encoder->clearResourceView( + gLearningTextureUAVs[i], + &clearValue, + ClearResourceViewFlags::None); + encoder->clearResourceView( + gDiffTextureUAVs[i], + &clearValue, + ClearResourceViewFlags::None); } - encoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource); + encoder->textureBarrier( + gLearningTexture, + ResourceState::UnorderedAccess, + ResourceState::ShaderResource); encoder->endEncoding(); commandBuffer->close(); @@ -453,7 +499,10 @@ struct AutoDiffTexture : public WindowedAppBase float rotX = (rand() / (float)RAND_MAX) * 0.3f; float rotY = (rand() / (float)RAND_MAX) * 0.2f; glm::mat4x4 matProj = glm::perspectiveRH_ZO( - glm::radians(60.0f), (float)windowWidth / (float)windowHeight, 0.1f, 1000.0f); + glm::radians(60.0f), + (float)windowWidth / (float)windowHeight, + 0.1f, + 1000.0f); auto identity = glm::mat4(1.0f); auto translate = glm::translate( identity, @@ -468,9 +517,11 @@ struct AutoDiffTexture : public WindowedAppBase return transformMatrix; } - template + template void renderImage( - int transientHeapIndex, IFramebuffer* fb, const SetupPipelineFunc& setupPipeline) + int transientHeapIndex, + IFramebuffer* fb, + const SetupPipelineFunc& setupPipeline) { ComPtr commandBuffer = gTransientHeaps[transientHeapIndex]->createCommandBuffer(); @@ -496,9 +547,13 @@ struct AutoDiffTexture : public WindowedAppBase void renderReferenceImage(int transientHeapIndex, glm::mat4x4 transformMatrix) { { - ComPtr commandBuffer = gTransientHeaps[transientHeapIndex]->createCommandBuffer(); + ComPtr commandBuffer = + gTransientHeaps[transientHeapIndex]->createCommandBuffer(); auto encoder = commandBuffer->encodeResourceCommands(); - encoder->textureBarrier(gRefImage, ResourceState::ShaderResource, ResourceState::RenderTarget); + encoder->textureBarrier( + gRefImage, + ResourceState::ShaderResource, + ResourceState::RenderTarget); encoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); @@ -512,12 +567,16 @@ struct AutoDiffTexture : public WindowedAppBase auto rootObject = encoder->bindPipeline(gRefPipelineState); ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["modelViewProjection"].setData( - &transformMatrix, sizeof(float) * 16); + &transformMatrix, + sizeof(float) * 16); rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gTexView); rootCursor["Uniforms"]["sampler"].setSampler(gSampler); - rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); + rootCursor["Uniforms"]["mipOffset"].setData( + mipMapOffset.getBuffer(), + sizeof(uint32_t) * mipMapOffset.getCount()); rootCursor["Uniforms"]["texRef"].setResource(gTexView); - rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(gAccumulateBufferView); + rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource( + gAccumulateBufferView); }); } @@ -527,25 +586,52 @@ struct AutoDiffTexture : public WindowedAppBase frameCount++; auto transformMatrix = getTransformMatrix(); renderReferenceImage(frameBufferIndex, transformMatrix); - + // Barriers. { ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); auto resEncoder = commandBuffer->encodeResourceCommands(); ClearValue clearValue = {}; - resEncoder->bufferBarrier(gAccumulateBuffer, ResourceState::Undefined, ResourceState::UnorderedAccess); - resEncoder->bufferBarrier(gReconstructBuffer, ResourceState::Undefined, ResourceState::UnorderedAccess); - resEncoder->textureBarrier(gRefImage, ResourceState::Present, ResourceState::ShaderResource); - resEncoder->textureBarrier(gIterImage, ResourceState::ShaderResource, ResourceState::RenderTarget); - resEncoder->clearResourceView(gAccumulateBufferView, &clearValue, ClearResourceViewFlags::None); - resEncoder->clearResourceView(gReconstructBufferView, &clearValue, ClearResourceViewFlags::None); + resEncoder->bufferBarrier( + gAccumulateBuffer, + ResourceState::Undefined, + ResourceState::UnorderedAccess); + resEncoder->bufferBarrier( + gReconstructBuffer, + ResourceState::Undefined, + ResourceState::UnorderedAccess); + resEncoder->textureBarrier( + gRefImage, + ResourceState::Present, + ResourceState::ShaderResource); + resEncoder->textureBarrier( + gIterImage, + ResourceState::ShaderResource, + ResourceState::RenderTarget); + resEncoder->clearResourceView( + gAccumulateBufferView, + &clearValue, + ClearResourceViewFlags::None); + resEncoder->clearResourceView( + gReconstructBufferView, + &clearValue, + ClearResourceViewFlags::None); if (resetLearntTexture) { - resEncoder->textureBarrier(gLearningTexture, ResourceState::ShaderResource, ResourceState::UnorderedAccess); - for (Index i =0; i clearResourceView(gLearningTextureUAVs[i], &clearValue, ClearResourceViewFlags::None); - resEncoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource); + resEncoder->textureBarrier( + gLearningTexture, + ResourceState::ShaderResource, + ResourceState::UnorderedAccess); + for (Index i = 0; i < gLearningTextureUAVs.getCount(); i++) + resEncoder->clearResourceView( + gLearningTextureUAVs[i], + &clearValue, + ClearResourceViewFlags::None); + resEncoder->textureBarrier( + gLearningTexture, + ResourceState::UnorderedAccess, + ResourceState::ShaderResource); resetLearntTexture = false; } resEncoder->endEncoding(); @@ -561,16 +647,19 @@ struct AutoDiffTexture : public WindowedAppBase { auto rootObject = encoder->bindPipeline(gIterPipelineState); ShaderCursor rootCursor(rootObject); - + rootCursor["Uniforms"]["modelViewProjection"].setData( - &transformMatrix, sizeof(float) * 16); + &transformMatrix, + sizeof(float) * 16); rootCursor["Uniforms"]["bwdTexture"]["texture"].setResource(gLearningTextureSRV); rootCursor["Uniforms"]["sampler"].setSampler(gSampler); - rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); + rootCursor["Uniforms"]["mipOffset"].setData( + mipMapOffset.getBuffer(), + sizeof(uint32_t) * mipMapOffset.getCount()); rootCursor["Uniforms"]["texRef"].setResource(gRefImageSRV); - rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource(gAccumulateBufferView); + rootCursor["Uniforms"]["bwdTexture"]["accumulateBuffer"].setResource( + gAccumulateBufferView); rootCursor["Uniforms"]["bwdTexture"]["minLOD"].setData(5.0); - }); // Propagete gradients through mip map layers from top (lowest res) to bottom (highest res). @@ -578,12 +667,17 @@ struct AutoDiffTexture : public WindowedAppBase ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); auto encoder = commandBuffer->encodeComputeCommands(); - encoder->textureBarrier(gLearningTexture, ResourceState::ShaderResource, ResourceState::UnorderedAccess); + encoder->textureBarrier( + gLearningTexture, + ResourceState::ShaderResource, + ResourceState::UnorderedAccess); auto rootObject = encoder->bindPipeline(gReconstructPipelineState); for (int i = (int)mipMapOffset.getCount() - 2; i >= 0; i--) { ShaderCursor rootCursor(rootObject); - rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); + rootCursor["Uniforms"]["mipOffset"].setData( + mipMapOffset.getBuffer(), + sizeof(uint32_t) * mipMapOffset.getCount()); rootCursor["Uniforms"]["dstLayer"].setData(i); rootCursor["Uniforms"]["layerCount"].setData(mipMapOffset.getCount() - 1); rootCursor["Uniforms"]["width"].setData(textureWidth); @@ -591,22 +685,31 @@ struct AutoDiffTexture : public WindowedAppBase rootCursor["Uniforms"]["accumulateBuffer"].setResource(gAccumulateBufferView); rootCursor["Uniforms"]["dstBuffer"].setResource(gReconstructBufferView); encoder->dispatchCompute( - ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); - encoder->bufferBarrier(gReconstructBuffer, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess); + ((textureWidth >> i) + 15) / 16, + ((textureHeight >> i) + 15) / 16, + 1); + encoder->bufferBarrier( + gReconstructBuffer, + ResourceState::UnorderedAccess, + ResourceState::UnorderedAccess); } // Convert bottom layer mip from buffer to texture. rootObject = encoder->bindPipeline(gConvertPipelineState); ShaderCursor rootCursor(rootObject); - rootCursor["Uniforms"]["mipOffset"].setData(mipMapOffset.getBuffer(), sizeof(uint32_t) * mipMapOffset.getCount()); + rootCursor["Uniforms"]["mipOffset"].setData( + mipMapOffset.getBuffer(), + sizeof(uint32_t) * mipMapOffset.getCount()); rootCursor["Uniforms"]["dstLayer"].setData(0); rootCursor["Uniforms"]["width"].setData(textureWidth); rootCursor["Uniforms"]["height"].setData(textureHeight); rootCursor["Uniforms"]["srcBuffer"].setResource(gReconstructBufferView); rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[0]); - encoder->dispatchCompute( - (textureWidth + 15) / 16, (textureHeight + 15) / 16, 1); - encoder->textureBarrier(gDiffTexture, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess); + encoder->dispatchCompute((textureWidth + 15) / 16, (textureHeight + 15) / 16, 1); + encoder->textureBarrier( + gDiffTexture, + ResourceState::UnorderedAccess, + ResourceState::UnorderedAccess); // Build higher level mip map layers. rootObject = encoder->bindPipeline(gBuildMipPipelineState); @@ -615,11 +718,16 @@ struct AutoDiffTexture : public WindowedAppBase ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["dstWidth"].setData(textureWidth >> i); rootCursor["Uniforms"]["dstHeight"].setData(textureHeight >> i); - rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i-1]); + rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i - 1]); rootCursor["Uniforms"]["dstTexture"].setResource(gDiffTextureUAVs[i]); encoder->dispatchCompute( - ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); - encoder->textureBarrier(gDiffTexture, ResourceState::UnorderedAccess, ResourceState::UnorderedAccess); + ((textureWidth >> i) + 15) / 16, + ((textureHeight >> i) + 15) / 16, + 1); + encoder->textureBarrier( + gDiffTexture, + ResourceState::UnorderedAccess, + ResourceState::UnorderedAccess); } // Accumulate gradients to learnt texture. @@ -633,10 +741,18 @@ struct AutoDiffTexture : public WindowedAppBase rootCursor["Uniforms"]["srcTexture"].setResource(gDiffTextureUAVs[i]); rootCursor["Uniforms"]["dstTexture"].setResource(gLearningTextureUAVs[i]); encoder->dispatchCompute( - ((textureWidth >> i) + 15) / 16, ((textureHeight >> i) + 15) / 16, 1); + ((textureWidth >> i) + 15) / 16, + ((textureHeight >> i) + 15) / 16, + 1); } - encoder->textureBarrier(gLearningTexture, ResourceState::UnorderedAccess, ResourceState::ShaderResource); - encoder->textureBarrier(gIterImage, ResourceState::Present, ResourceState::ShaderResource); + encoder->textureBarrier( + gLearningTexture, + ResourceState::UnorderedAccess, + ResourceState::ShaderResource); + encoder->textureBarrier( + gIterImage, + ResourceState::Present, + ResourceState::ShaderResource); encoder->endEncoding(); commandBuffer->close(); @@ -647,12 +763,25 @@ struct AutoDiffTexture : public WindowedAppBase { ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + auto renderEncoder = + commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); drawTexturedQuad(renderEncoder, 0, 0, textureWidth, textureHeight, gLearningTextureSRV); int refImageWidth = windowWidth - textureWidth - 10; int refImageHeight = refImageWidth * windowHeight / windowWidth; - drawTexturedQuad(renderEncoder, textureWidth + 10, 0, refImageWidth, refImageHeight, gRefImageSRV); - drawTexturedQuad(renderEncoder, textureWidth + 10, refImageHeight + 10, refImageWidth, refImageHeight, gIterImageSRV); + drawTexturedQuad( + renderEncoder, + textureWidth + 10, + 0, + refImageWidth, + refImageHeight, + gRefImageSRV); + drawTexturedQuad( + renderEncoder, + textureWidth + 10, + refImageHeight + 10, + refImageWidth, + refImageHeight, + gIterImageSRV); renderEncoder->endEncoding(); commandBuffer->close(); gQueue->executeCommandBuffer(commandBuffer); @@ -664,7 +793,13 @@ struct AutoDiffTexture : public WindowedAppBase } } - void drawTexturedQuad(IRenderCommandEncoder* renderEncoder, int x, int y, int w, int h, IResourceView* srv) + void drawTexturedQuad( + IRenderCommandEncoder* renderEncoder, + int x, + int y, + int w, + int h, + IResourceView* srv) { gfx::Viewport viewport = {}; viewport.maxZ = 1.0f; @@ -686,7 +821,6 @@ struct AutoDiffTexture : public WindowedAppBase renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleStrip); renderEncoder->draw(4); } - }; PLATFORM_UI_MAIN(innerMain) diff --git a/examples/cpu-com-example/main.cpp b/examples/cpu-com-example/main.cpp index 6da2aa0df0..382b3cacd0 100644 --- a/examples/cpu-com-example/main.cpp +++ b/examples/cpu-com-example/main.cpp @@ -1,11 +1,10 @@ // main.cpp -#include - +#include "slang-com-helper.h" +#include "slang-com-ptr.h" #include "slang.h" -#include "slang-com-ptr.h" -#include "slang-com-helper.h" +#include // This includes a useful small function for setting up the prelude (described more further below). #include "../../source/core/slang-test-tool-util.h" @@ -17,9 +16,9 @@ using namespace Slang; static const ExampleResources resourceBase("cpu-com-example"); -// For the moment we have to explicitly write the Slang COM interface in C++ code. It *MUST* match +// For the moment we have to explicitly write the Slang COM interface in C++ code. It *MUST* match // the interface in the slang source -// As it stands all interfaces need to derive from ISlangUnknown (or IUnknown). +// As it stands all interfaces need to derive from ISlangUnknown (or IUnknown). class IDoThings : public ISlangUnknown { public: @@ -43,19 +42,33 @@ class DoThings : public IDoThings { public: // We don't need queryInterface for this impl, or ref counting - virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE { return SLANG_E_NOT_IMPLEMENTED; } - virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } - virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE + { + return SLANG_E_NOT_IMPLEMENTED; + } + virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } + virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } // IDoThings - virtual SLANG_NO_THROW int SLANG_MCALL doThing(int a, int b) SLANG_OVERRIDE { return a + b + 1; } - virtual SLANG_NO_THROW int SLANG_MCALL calcHash(const char* in) SLANG_OVERRIDE { return (int)_calcHash(in); } - virtual SLANG_NO_THROW void SLANG_MCALL printMessage(const char* in) SLANG_OVERRIDE { printf("%s\n", in); } + virtual SLANG_NO_THROW int SLANG_MCALL doThing(int a, int b) SLANG_OVERRIDE + { + return a + b + 1; + } + virtual SLANG_NO_THROW int SLANG_MCALL calcHash(const char* in) SLANG_OVERRIDE + { + return (int)_calcHash(in); + } + virtual SLANG_NO_THROW void SLANG_MCALL printMessage(const char* in) SLANG_OVERRIDE + { + printf("%s\n", in); + } }; static SlangResult _innerMain(int argc, char** argv) { - // NOTE! This example only works if `slang-llvm` or a C++ compiler that Slang supports is available. + // NOTE! This example only works if `slang-llvm` or a C++ compiler that Slang supports is + // available. // Create the session ComPtr slangSession; @@ -67,19 +80,22 @@ static SlangResult _innerMain(int argc, char** argv) // Create a compile request Slang::ComPtr request; + SLANG_ALLOW_DEPRECATED_BEGIN SLANG_RETURN_ON_FAIL(slangSession->createCompileRequest(request.writeRef())); + SLANG_ALLOW_DEPRECATED_END // We want to compile to 'HOST_CALLABLE' here such that we can execute the Slang code. - // - // Note that it is possible to use HOST_HOST_CALLABLE, but this currently only works with 'regular' C++ compilers - // not with `slang-llvm`. + // + // Note that it is possible to use HOST_HOST_CALLABLE, but this currently only works with + // 'regular' C++ compilers not with `slang-llvm`. const int targetIndex = request->addCodeGenTarget(SLANG_SHADER_HOST_CALLABLE); // Set the target flag to indicate that we want to compile all into a library. request->setTargetFlags(targetIndex, SLANG_TARGET_FLAG_GENERATE_WHOLE_PROGRAM); // Add the translation unit - const int translationUnitIndex = request->addTranslationUnit(SLANG_SOURCE_LANGUAGE_SLANG, nullptr); + const int translationUnitIndex = + request->addTranslationUnit(SLANG_SOURCE_LANGUAGE_SLANG, nullptr); // Set the source file for the translation unit Slang::String path = resourceBase.resolveResource("shader.slang"); @@ -91,13 +107,13 @@ static SlangResult _innerMain(int argc, char** argv) // compiler may have produced "diagnostic" output such as warnings. // We will go ahead and print that output here. // - if(auto diagnostics = request->getDiagnosticOutput()) + if (auto diagnostics = request->getDiagnosticOutput()) { printf("%s", diagnostics); } - // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a shared library - // it's just an interface to executable code). + // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a + // shared library it's just an interface to executable code). ComPtr sharedLibrary; SLANG_RETURN_ON_FAIL(request->getTargetHostCallable(0, sharedLibrary.writeRef())); diff --git a/examples/cpu-hello-world/main.cpp b/examples/cpu-hello-world/main.cpp index 059efc8d3e..60a24fa8c1 100644 --- a/examples/cpu-hello-world/main.cpp +++ b/examples/cpu-hello-world/main.cpp @@ -3,7 +3,7 @@ #include // This file implements an extremely simple example of loading and -// executing a Slang shader program on the CPU. +// executing a Slang shader program on the CPU. // // More information about generation C++ or CPU code can be found in docs/cpu-target.md // @@ -20,7 +20,7 @@ // Allows use of ComPtr - which we can use to scope any 'com-like' pointers easily #include "slang-com-ptr.h" -// Provides macros for handling SlangResult values easily +// Provides macros for handling SlangResult values easily #include "slang-com-helper.h" // This includes a useful small function for setting up the prelude (described more further below). @@ -34,10 +34,10 @@ using namespace Slang; // Slang source is converted into C++ code which is compiled by a backend compiler. // That process uses a 'prelude' which defines types and functions that are needed // for everything else to work. -// +// // We include the prelude here, so we can directly use the types as were used by the // compiled code. It is not necessary to include the prelude, as long as memory is -// laid out in the manner that the generated slang code expects. +// laid out in the manner that the generated slang code expects. #define SLANG_PRELUDE_NAMESPACE CPPPrelude #include "../../prelude/slang-cpp-types.h" @@ -75,11 +75,13 @@ static SlangResult _innerMain(int argc, char** argv) // // Most downstream C++ compilers work on files. In that case slang may generate temporary // files that contain the generated code. Typically the generated files will not be in the - // same directory as the original source so handling includes becomes awkward. The mechanism used here - // is for the prelude code to be an *absolute* path to the 'slang-cpp-prelude.h' - which means - // this will work wherever the generated code is, and allows accessing other files via relative paths. + // same directory as the original source so handling includes becomes awkward. The mechanism + // used here is for the prelude code to be an *absolute* path to the 'slang-cpp-prelude.h' - + // which means this will work wherever the generated code is, and allows accessing other files + // via relative paths. // - // Look at the source to TestToolUtil::setSessionDefaultPreludeFromExePath to see what's involed. + // Look at the source to TestToolUtil::setSessionDefaultPreludeFromExePath to see what's + // involed. TestToolUtil::setSessionDefaultPreludeFromExePath(argv[0], slangSession); slang::SessionDesc sessionDesc = {}; @@ -122,13 +124,16 @@ static SlangResult _innerMain(int argc, char** argv) SLANG_RETURN_ON_FAIL(result); } - // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a shared library - // it's just an interface to executable code). + // Get the 'shared library' (note that this doesn't necessarily have to be implemented as a + // shared library it's just an interface to executable code). ComPtr sharedLibrary; { ComPtr diagnosticsBlob; SlangResult result = composedProgram->getEntryPointHostCallable( - 0, 0, sharedLibrary.writeRef(), diagnosticsBlob.writeRef()); + 0, + 0, + sharedLibrary.writeRef(), + diagnosticsBlob.writeRef()); diagnoseIfNeeded(diagnosticsBlob); SLANG_RETURN_ON_FAIL(result); if (testBase.isTestMode()) @@ -137,55 +142,58 @@ static SlangResult _innerMain(int argc, char** argv) } } // Once we have the sharedLibrary, we no longer need the request - // unless we want to use reflection, to for example workout how 'UniformState' and 'UniformEntryPointParams' are laid out - // at runtime. We don't do that here - as we hard code the structures. + // unless we want to use reflection, to for example workout how 'UniformState' and + // 'UniformEntryPointParams' are laid out at runtime. We don't do that here - as we hard code + // the structures. // Get the function we are going to execute const char entryPointName[] = "computeMain"; - CPPPrelude::ComputeFunc func = (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName); + CPPPrelude::ComputeFunc func = + (CPPPrelude::ComputeFunc)sharedLibrary->findFuncByName(entryPointName); if (!func) { return SLANG_FAIL; } // Define the uniform state structure that is *specific* to our shader defined in shader.slang - // That the layout of the structure can be determined through reflection, or can be inferred from - // the original slang source. Look at the documentation in docs/cpu-target.md which describes - // how different resources map. - // The order of the resources is in the order that they are defined in the source. + // That the layout of the structure can be determined through reflection, or can be inferred + // from the original slang source. Look at the documentation in docs/cpu-target.md which + // describes how different resources map. The order of the resources is in the order that they + // are defined in the source. struct UniformState { CPPPrelude::RWStructuredBuffer ioBuffer; }; - // the uniformState will be passed as a pointer to the CPU code + // the uniformState will be passed as a pointer to the CPU code UniformState uniformState; // The contents of the buffer are modified, so we'll copy it - const float startBufferContents[] = { 2.0f, -10.0f, -3.0f, 5.0f }; + const float startBufferContents[] = {2.0f, -10.0f, -3.0f, 5.0f}; float bufferContents[SLANG_COUNT_OF(startBufferContents)]; memcpy(bufferContents, startBufferContents, sizeof(startBufferContents)); // Set up the ioBuffer such that it uses bufferContents. It is important to set the .count - // such that bounds checking can be performed in the kernel. + // such that bounds checking can be performed in the kernel. uniformState.ioBuffer.data = bufferContents; uniformState.ioBuffer.count = SLANG_COUNT_OF(bufferContents); - // In shader.slang, then entry point is attributed with `[numthreads(4, 1, 1)]` meaning each group - // consists of 4 'thread' in x. Our input buffer is 4 wide, and we index the input array via `SV_DispatchThreadID` - // so we only need to run a single group to execute over all of the 4 elements here. - // The group range from { 0, 0, 0 } -> { 1, 1, 1 } means it will execute over the single group { 0, 0, 0 }. + // In shader.slang, then entry point is attributed with `[numthreads(4, 1, 1)]` meaning each + // group consists of 4 'thread' in x. Our input buffer is 4 wide, and we index the input array + // via `SV_DispatchThreadID` so we only need to run a single group to execute over all of the 4 + // elements here. The group range from { 0, 0, 0 } -> { 1, 1, 1 } means it will execute over the + // single group { 0, 0, 0 }. - const CPPPrelude::uint3 startGroupID = { 0, 0, 0}; - const CPPPrelude::uint3 endGroupID = { 1, 1, 1 }; + const CPPPrelude::uint3 startGroupID = {0, 0, 0}; + const CPPPrelude::uint3 endGroupID = {1, 1, 1}; CPPPrelude::ComputeVaryingInput varyingInput; varyingInput.startGroupID = startGroupID; varyingInput.endGroupID = endGroupID; // We don't have any entry point parameters so that's passed as NULL - // We need to cast our definition of the uniform state to the undefined CPPPrelude::UniformState as - // that type is just a name to indicate what kind of thing needs to be passed in. + // We need to cast our definition of the uniform state to the undefined CPPPrelude::UniformState + // as that type is just a name to indicate what kind of thing needs to be passed in. func(&varyingInput, NULL, &uniformState); // bufferContents holds the output diff --git a/examples/example-base/example-base.cpp b/examples/example-base/example-base.cpp index 344611bedd..9d5f1bcaed 100644 --- a/examples/example-base/example-base.cpp +++ b/examples/example-base/example-base.cpp @@ -1,4 +1,5 @@ #include "example-base.h" + #include #ifdef _WIN32 @@ -6,7 +7,7 @@ #endif #define STB_IMAGE_IMPLEMENTATION -#include "external/stb/stb_image.h" +#include "stb_image.h" using namespace Slang; using namespace gfx; @@ -123,7 +124,11 @@ void WindowedAppBase::offlineRender() gTransientHeaps[0]->finish(); } -void WindowedAppBase::createFramebuffers(uint32_t width, uint32_t height, gfx::Format colorFormat, uint32_t frameBufferCount) +void WindowedAppBase::createFramebuffers( + uint32_t width, + uint32_t height, + gfx::Format colorFormat, + uint32_t frameBufferCount) { for (uint32_t i = 0; i < frameBufferCount; i++) { @@ -150,7 +155,8 @@ void WindowedAppBase::createFramebuffers(uint32_t width, uint32_t height, gfx::F colorBufferDesc.size.depth = 1; colorBufferDesc.format = colorFormat; colorBufferDesc.defaultState = ResourceState::RenderTarget; - colorBufferDesc.allowedStates = ResourceStateSet(ResourceState::RenderTarget, ResourceState::CopyDestination); + colorBufferDesc.allowedStates = + ResourceStateSet(ResourceState::RenderTarget, ResourceState::CopyDestination); colorBuffer = gDevice->createTextureResource(colorBufferDesc, nullptr); } else @@ -194,14 +200,21 @@ void WindowedAppBase::createOfflineFramebuffers() void WindowedAppBase::createSwapchainFramebuffers() { gFramebuffers.clear(); - createFramebuffers(gSwapchain->getDesc().width, gSwapchain->getDesc().height, - gSwapchain->getDesc().format, kSwapchainImageCount); + createFramebuffers( + gSwapchain->getDesc().width, + gSwapchain->getDesc().height, + gSwapchain->getDesc().format, + kSwapchainImageCount); } -ComPtr WindowedAppBase::createTextureFromFile(String fileName, int& textureWidth, int& textureHeight) +ComPtr WindowedAppBase::createTextureFromFile( + String fileName, + int& textureWidth, + int& textureHeight) { int channelsInFile = 0; - auto textureContent = stbi_load(fileName.getBuffer(), &textureWidth, &textureHeight, &channelsInFile, 4); + auto textureContent = + stbi_load(fileName.getBuffer(), &textureWidth, &textureHeight, &channelsInFile, 4); gfx::ITextureResource::Desc textureDesc = {}; textureDesc.allowedStates.add(ResourceState::ShaderResource); textureDesc.format = gfx::Format::R8G8B8A8_UNORM; @@ -222,9 +235,22 @@ ComPtr WindowedAppBase::createTextureFromFile(String fileNam subresData[0].strideZ = textureWidth * textureHeight * 4; // Build mipmaps. - struct RGBA { uint8_t v[4]; }; - auto castToRGBA = [](uint32_t v) { RGBA result; memcpy(&result, &v, 4); return result; }; - auto castToUint = [](RGBA v) { uint32_t result; memcpy(&result, &v, 4); return result; }; + struct RGBA + { + uint8_t v[4]; + }; + auto castToRGBA = [](uint32_t v) + { + RGBA result; + memcpy(&result, &v, 4); + return result; + }; + auto castToUint = [](RGBA v) + { + uint32_t result; + memcpy(&result, &v, 4); + return result; + }; int lastMipWidth = textureWidth; int lastMipHeight = textureHeight; @@ -248,7 +274,8 @@ ComPtr WindowedAppBase::createTextureFromFile(String fileNam RGBA pix; for (int c = 0; c < 4; c++) { - pix.v[c] = (uint8_t)(((uint32_t)pix1.v[c] + pix2.v[c] + pix3.v[c] + pix4.v[c]) / 4); + pix.v[c] = + (uint8_t)(((uint32_t)pix1.v[c] + pix2.v[c] + pix3.v[c] + pix4.v[c]) / 4); } mipMapData[m][y * w + x] = castToUint(pix); } @@ -286,15 +313,21 @@ void WindowedAppBase::windowSizeChanged() } } -int64_t getCurrentTime() { return std::chrono::high_resolution_clock::now().time_since_epoch().count(); } +int64_t getCurrentTime() +{ + return std::chrono::high_resolution_clock::now().time_since_epoch().count(); +} -int64_t getTimerFrequency() { return std::chrono::high_resolution_clock::period::den; } +int64_t getTimerFrequency() +{ + return std::chrono::high_resolution_clock::period::den; +} class DebugCallback : public IDebugCallback { public: virtual SLANG_NO_THROW void SLANG_MCALL - handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override + handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) override { const char* typeStr = ""; switch (type) @@ -338,5 +371,8 @@ void initDebugCallback() } #ifdef _WIN32 -void _Win32OutputDebugString(const char* str) { OutputDebugStringW(Slang::String(str).toWString().begin()); } +void _Win32OutputDebugString(const char* str) +{ + OutputDebugStringW(Slang::String(str).toWString().begin()); +} #endif diff --git a/examples/example-base/example-base.h b/examples/example-base/example-base.h index b97728e176..0cb3de7e97 100644 --- a/examples/example-base/example-base.h +++ b/examples/example-base/example-base.h @@ -1,9 +1,9 @@ #pragma once +#include "core/slang-basic.h" +#include "core/slang-io.h" +#include "platform/window.h" #include "slang-gfx.h" -#include "tools/platform/window.h" -#include "source/core/slang-basic.h" -#include "source/core/slang-io.h" #include "test-base.h" #ifdef _WIN32 @@ -34,38 +34,52 @@ struct WindowedAppBase : public TestBase int height, gfx::DeviceType deviceType = gfx::DeviceType::Default); - void createFramebuffers(uint32_t width, uint32_t height, gfx::Format colorFormat, uint32_t frameBufferCount); + void createFramebuffers( + uint32_t width, + uint32_t height, + gfx::Format colorFormat, + uint32_t frameBufferCount); void createSwapchainFramebuffers(); void createOfflineFramebuffers(); void mainLoop(); - Slang::ComPtr createTextureFromFile(Slang::String fileName, int& textureWidth, int& textureHeight); + Slang::ComPtr createTextureFromFile( + Slang::String fileName, + int& textureWidth, + int& textureHeight); virtual void windowSizeChanged(); protected: virtual void renderFrame(int framebufferIndex) = 0; + public: platform::Window* getWindow() { return gWindow.Ptr(); } virtual void finalize() { gQueue->waitOnHost(); } void offlineRender(); }; -struct ExampleResources { +struct ExampleResources +{ Slang::String baseDir; - ExampleResources(const Slang::String &dir) : baseDir(dir) {} - - Slang::String resolveResource(const char* fileName) const { - static const Slang::List directories { + ExampleResources(const Slang::String& dir) + : baseDir(dir) + { + } + + Slang::String resolveResource(const char* fileName) const + { + static const Slang::List directories{ "examples", "../examples", "../../examples", }; - - for (const Slang::String& dir : directories) { + + for (const Slang::String& dir : directories) + { Slang::StringBuilder pathSb; - pathSb << dir << "/" << baseDir << "/" << fileName; + pathSb << dir << "/" << baseDir << "/" << fileName; if (Slang::File::exists(pathSb.getBuffer())) return pathSb.toString(); } @@ -77,7 +91,8 @@ struct ExampleResources { int64_t getCurrentTime(); int64_t getTimerFrequency(); -template inline void reportError(const char* format, TArgs... args) +template +inline void reportError(const char* format, TArgs... args) { printf(format, args...); #ifdef _WIN32 @@ -87,7 +102,8 @@ template inline void reportError(const char* format, TArgs.. #endif } -template inline void log(const char* format, TArgs... args) +template +inline void log(const char* format, TArgs... args) { reportError(format, args...); } diff --git a/examples/example-base/test-base.cpp b/examples/example-base/test-base.cpp index 0e0f8a69c4..5d40f2d802 100644 --- a/examples/example-base/test-base.cpp +++ b/examples/example-base/test-base.cpp @@ -1,8 +1,11 @@ #include "test-base.h" #ifdef _WIN32 -#include -#include +// clang-format off +// include ordering sensitive +# include +# include +// clang-format on #endif int TestBase::parseOption(int argc, char** argv) @@ -27,23 +30,30 @@ int TestBase::parseOption(int argc, char** argv) return 0; } -void TestBase::printEntrypointHashes(int entryPointCount, int targetCount, ComPtr& composedProgram) +void TestBase::printEntrypointHashes( + int entryPointCount, + int targetCount, + ComPtr& composedProgram) { for (int targetIndex = 0; targetIndex < targetCount; targetIndex++) { for (int entryPointIndex = 0; entryPointIndex < entryPointCount; entryPointIndex++) { ComPtr entryPointHashBlob; - composedProgram->getEntryPointHash(entryPointIndex, targetIndex, entryPointHashBlob.writeRef()); + composedProgram->getEntryPointHash( + entryPointIndex, + targetIndex, + entryPointHashBlob.writeRef()); Slang::StringBuilder strBuilder; - strBuilder << "callIdx: " << m_globalCounter << ", entrypoint: "<< entryPointIndex << ", target: " << targetIndex << ", hash: "; + strBuilder << "callIdx: " << m_globalCounter << ", entrypoint: " << entryPointIndex + << ", target: " << targetIndex << ", hash: "; m_globalCounter++; uint8_t* buffer = (uint8_t*)entryPointHashBlob->getBufferPointer(); for (size_t i = 0; i < entryPointHashBlob->getBufferSize(); i++) { - strBuilder<& composedProgram); + void printEntrypointHashes( + int entryPointCount, + int targetCount, + ComPtr& composedProgram); bool isTestMode() const { return m_isTestMode; } private: - bool m_isTestMode = false; - uint64_t m_globalCounter = 0; + bool m_isTestMode = false; + uint64_t m_globalCounter = 0; }; diff --git a/examples/gpu-printing/gpu-printing.cpp b/examples/gpu-printing/gpu-printing.cpp index aeca7aa9a7..f715785544 100644 --- a/examples/gpu-printing/gpu-printing.cpp +++ b/examples/gpu-printing/gpu-printing.cpp @@ -2,7 +2,6 @@ #include "gpu-printing.h" #include - #include // This file implements the CPU side of a simple GPU printing @@ -39,7 +38,7 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection) // that appear in the linked program. // SlangUInt hashedStringCount = slangReflection->getHashedStringCount(); - for( SlangUInt ii = 0; ii < hashedStringCount; ++ii ) + for (SlangUInt ii = 0; ii < hashedStringCount; ++ii) { // For each string we can fetch its bytes from the Slang // reflection data. @@ -59,7 +58,8 @@ void GPUPrinting::loadStrings(slang::ProgramLayout* slangReflection) // The `GPUPrinting` implementation will store the mapping // from hash codes back to strings in a simple STL `map`. // - m_hashedStrings.insert(std::make_pair(hash, std::string(stringData, stringData + stringSize))); + m_hashedStrings.insert( + std::make_pair(hash, std::string(stringData, stringData + stringSize))); } } @@ -73,12 +73,12 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // a granularity of 32-bits words, so we start by computing // how many words, total, will fit in the buffer. // - uint32_t dataWordCount = uint32_t(dataSize/ sizeof(uint32_t)); + uint32_t dataWordCount = uint32_t(dataSize / sizeof(uint32_t)); // // If the buffer doesn't even have enough space for the leading counter, // then there is nothing to print. // - if( dataWordCount < 1 ) + if (dataWordCount < 1) { fprintf(stderr, "error: expected at least 4 bytes in GPU printing buffer\n"); return; @@ -87,7 +87,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // Otherwise, we set ourselves up to start reading data from the buffer // at a granularity of 32-bit words. // - const uint32_t* dataCursor = (const uint32_t*) data; + const uint32_t* dataCursor = (const uint32_t*)data; // The first word of a printing buffer gives us the total number of // words that were appended by GPU printing operations. @@ -106,20 +106,25 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // larger buffer. // size_t totalBytesWritten = sizeof(uint32_t) * (wordsAppended + 1); - if( totalBytesWritten > dataSize ) + if (totalBytesWritten > dataSize) { - fprintf(stderr, "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu bytes were available\n", (unsigned long long)totalBytesWritten, (unsigned long long)dataSize); + fprintf( + stderr, + "warning: GPU code attempted to write %llu bytes to the printing buffer, but only %llu " + "bytes were available\n", + (unsigned long long)totalBytesWritten, + (unsigned long long)dataSize); // If the buffer is full, then we only want to read through // to the end of what is available. // - dataEnd = ((const uint32_t*) data) + dataWordCount; + dataEnd = ((const uint32_t*)data) + dataWordCount; } // We will now proceed to read off "commands" from the buffer, // and execute those commands to print things to `stdout`. // - while( dataCursor < dataEnd ) + while (dataCursor < dataEnd) { // The first word of each command is encoded to hold both // an "opcode" for the command, and the number of "payload" @@ -135,7 +140,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // avoid crashes from a command trying to fetch data past // the end of the buffer. // - if( payloadWordCount > size_t(dataCursor - dataEnd) ) + if (payloadWordCount > size_t(dataCursor - dataEnd)) { break; } @@ -149,7 +154,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) dataCursor += payloadWordCount; // What to do with a command depends a lot on which "op" was selected. - switch( op ) + switch (op) { default: // If we encounter an op that we don't understand, there is a change @@ -176,21 +181,21 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // We will use a macro to avoid duplication the code shared // between these cases. // - #define CASE(OP, FORMAT, TYPE) \ - case GPUPrintingOp::OP: \ - { \ - TYPE value; \ - assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \ - memcpy(&value, payloadWords, sizeof(value)); \ - printf(FORMAT, value); \ - } \ - break - - CASE(Int32, "%d", int); - CASE(UInt32, "%u", unsigned int); - CASE(Float32, "%f", float); - - #undef CASE +#define CASE(OP, FORMAT, TYPE) \ + case GPUPrintingOp::OP: \ + { \ + TYPE value; \ + assert(payloadWordCount >= (sizeof(value) / sizeof(uint32_t))); \ + memcpy(&value, payloadWords, sizeof(value)); \ + printf(FORMAT, value); \ + } \ + break + + CASE(Int32, "%d", int); + CASE(UInt32, "%u", unsigned int); + CASE(Float32, "%f", float); + +#undef CASE case GPUPrintingOp::String: { @@ -214,7 +219,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // to appear in the GPU code. // auto iter = m_hashedStrings.find(hash); - if(iter == m_hashedStrings.end()) + if (iter == m_hashedStrings.end()) { // If we didn't have a string to match that hash code in // our map, we can continue trying to print, but it is @@ -230,7 +235,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // // TODO: This code isn't robust against strings with // embeded null bytes. - //s + // s printf("%s", iter->second.c_str()); } break; @@ -248,7 +253,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) StringHash formatHash = *payloadWords++; auto iter = m_hashedStrings.find(formatHash); - if(iter == m_hashedStrings.end()) + if (iter == m_hashedStrings.end()) { // If we didn't have a string to match that hash code in // our map, we can continue trying to print, but it is @@ -270,14 +275,14 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // const char* cursor = format.c_str(); const char* end = cursor + format.length(); - while( cursor != end ) + while (cursor != end) { int c = *cursor++; // If we see a byte other than `%`, then we can just // output it directly and keep scanning the format string. // - if( c != '%' ) + if (c != '%') { putchar(c); continue; @@ -289,7 +294,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // If we are somehow at the end of the format // string, then the format was bad. // - if( cursor == end ) + if (cursor == end) { fprintf(stderr, "error: unexpected '%%' at and of format string\n"); break; @@ -299,7 +304,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // the `%` character, then it is an escaped // `%` so we should just emit it as-is and move along. // - if( *cursor == '%' ) + if (*cursor == '%') { putchar(*cursor++); continue; @@ -317,52 +322,56 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) // read a single-byte specifier. // int specifier = *cursor++; - switch( specifier ) + switch (specifier) { default: - fprintf(stderr, "error: unexpected format specifier '%c' (0x%X)\n", specifier, specifier); + fprintf( + stderr, + "error: unexpected format specifier '%c' (0x%X)\n", + specifier, + specifier); break; - // When processing each format speecifier, we will - // read words from the payload, as necessary - // to yield a value of the expected type. - // - // To reduce the amount of boilerplate, we will - // use a macro to capture the shared code for - // common cases. - // - #define CASE(CHAR, FORMAT, TYPE) \ - case CHAR: \ - { \ - assert(payloadWords != payloadWordsEnd); \ - TYPE value; \ - memcpy(&value, payloadWords, sizeof(value)); \ - payloadWords += sizeof(value) / sizeof(uint32_t); \ - printf(FORMAT, value); \ - } \ - break + // When processing each format speecifier, we will + // read words from the payload, as necessary + // to yield a value of the expected type. + // + // To reduce the amount of boilerplate, we will + // use a macro to capture the shared code for + // common cases. + // +#define CASE(CHAR, FORMAT, TYPE) \ + case CHAR: \ + { \ + assert(payloadWords != payloadWordsEnd); \ + TYPE value; \ + memcpy(&value, payloadWords, sizeof(value)); \ + payloadWords += sizeof(value) / sizeof(uint32_t); \ + printf(FORMAT, value); \ + } \ + break case 'i': // `%i` is just an alias for `%d` - CASE('d', "%d", int); - CASE('u', "%u", unsigned int); - CASE('x', "%x", unsigned int); - CASE('X', "%X", unsigned int); - - // Note: all of our printing support for floating-point - // values will use the `float` type instead of `double`. - // This isn't compatible with C rules, but makes more sense - // for GPU code. - // - CASE('f', "%f", float); - CASE('F', "%F", float); - CASE('e', "%e", float); - CASE('E', "%E", float); - CASE('g', "%g", float); - CASE('G', "%G", float); - CASE('c', "%c", int); - - #undef CASE + CASE('d', "%d", int); + CASE('u', "%u", unsigned int); + CASE('x', "%x", unsigned int); + CASE('X', "%X", unsigned int); + + // Note: all of our printing support for floating-point + // values will use the `float` type instead of `double`. + // This isn't compatible with C rules, but makes more sense + // for GPU code. + // + CASE('f', "%f", float); + CASE('F', "%F", float); + CASE('e', "%e", float); + CASE('E', "%E", float); + CASE('g', "%g", float); + CASE('G', "%G", float); + CASE('c', "%c", int); + +#undef CASE case 's': { @@ -373,7 +382,7 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) assert(payloadWords != payloadWordsEnd); StringHash hash = *payloadWords++; auto iter = m_hashedStrings.find(hash); - if(iter == m_hashedStrings.end()) + if (iter == m_hashedStrings.end()) { fprintf(stderr, "error: string with unknown hash 0x%x\n", hash); continue; @@ -387,6 +396,4 @@ void GPUPrinting::processGPUPrintCommands(const void* data, size_t dataSize) break; } } - - } diff --git a/examples/gpu-printing/gpu-printing.h b/examples/gpu-printing/gpu-printing.h index 64eaf770ac..84c0365480 100644 --- a/examples/gpu-printing/gpu-printing.h +++ b/examples/gpu-printing/gpu-printing.h @@ -19,39 +19,39 @@ #include #include - /// Stores state used for executing print commands generated by GPU shaders +/// Stores state used for executing print commands generated by GPU shaders struct GPUPrinting { public: - /// Load any string literals used by a Slang program. - /// - /// The `slangReflection` should be the layout and reflection - /// object for a Slang shader program that might need to produce - /// printed output. This function will load any strings - /// referenced by the program into its database for mapping - /// string hashes back to the original strings. - /// + /// Load any string literals used by a Slang program. + /// + /// The `slangReflection` should be the layout and reflection + /// object for a Slang shader program that might need to produce + /// printed output. This function will load any strings + /// referenced by the program into its database for mapping + /// string hashes back to the original strings. + /// void loadStrings(slang::ProgramLayout* slangReflection); - /// Process a buffer of GPU printing commands and write output to `stdout`. - /// - /// This function attempts to read print commands from the buffer - /// pointed to by `data` and execute them to produce output. - /// - /// The buffer pointed at by `data` (of size `dataSize`) should be allocated - /// in host-visible memory. - /// - /// Before executing GPU work, the first four bytes pointed to by `data` - /// should have been cleared to zero. - /// - /// If GPU work has attempted to write more data than the buffer - /// can fit, a warning will be printed to `stderr`, and printing commands - /// that could not fit completely in the buffer will be skipped. - /// + /// Process a buffer of GPU printing commands and write output to `stdout`. + /// + /// This function attempts to read print commands from the buffer + /// pointed to by `data` and execute them to produce output. + /// + /// The buffer pointed at by `data` (of size `dataSize`) should be allocated + /// in host-visible memory. + /// + /// Before executing GPU work, the first four bytes pointed to by `data` + /// should have been cleared to zero. + /// + /// If GPU work has attempted to write more data than the buffer + /// can fit, a warning will be printed to `stderr`, and printing commands + /// that could not fit completely in the buffer will be skipped. + /// void processGPUPrintCommands(const void* data, size_t dataSize); private: typedef int StringHash; - std::map m_hashedStrings; + std::map m_hashedStrings; }; diff --git a/examples/gpu-printing/main.cpp b/examples/gpu-printing/main.cpp index fd15661dda..bbc300dba4 100644 --- a/examples/gpu-printing/main.cpp +++ b/examples/gpu-printing/main.cpp @@ -1,17 +1,16 @@ // main.cpp -#include - +#include "slang-com-ptr.h" #include "slang.h" -#include "slang-com-ptr.h" +#include using Slang::ComPtr; +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" +#include "gfx-util/shader-cursor.h" #include "gpu-printing.h" +#include "platform/window.h" #include "slang-gfx.h" -#include "gfx-util/shader-cursor.h" -#include "tools/platform/window.h" -#include "source/core/slang-basic.h" -#include "examples/example-base/example-base.h" using namespace gfx; @@ -23,7 +22,9 @@ ComPtr createSlangSession(gfx::IDevice* device) return slangSession; } -ComPtr compileShaderModuleFromFile(slang::ISession* slangSession, char const* filePath) +ComPtr compileShaderModuleFromFile( + slang::ISession* slangSession, + char const* filePath) { ComPtr slangModule; ComPtr diagnosticBlob; @@ -34,113 +35,121 @@ ComPtr compileShaderModuleFromFile(slang::ISession* slangSession return slangModule; } -struct ExampleProgram: public TestBase +struct ExampleProgram : public TestBase { -int gWindowWidth = 640; -int gWindowHeight = 480; - -ComPtr gDevice; + int gWindowWidth = 640; + int gWindowHeight = 480; -ComPtr gSlangSession; -ComPtr gSlangModule; -ComPtr gProgram; + ComPtr gDevice; -ComPtr gPipelineState; + ComPtr gSlangSession; + ComPtr gSlangModule; + ComPtr gProgram; -Slang::Dictionary gHashedStrings; + ComPtr gPipelineState; -GPUPrinting gGPUPrinting; + Slang::Dictionary gHashedStrings; -ComPtr loadComputeProgram(slang::IModule* slangModule, char const* entryPointName) -{ - ComPtr entryPoint; - slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef()); - - ComPtr linkedProgram; - entryPoint->link(linkedProgram.writeRef()); + GPUPrinting gGPUPrinting; - if (isTestMode()) + ComPtr loadComputeProgram( + slang::IModule* slangModule, + char const* entryPointName) { - printEntrypointHashes(1, 1, linkedProgram); - } + ComPtr entryPoint; + slangModule->findEntryPointByName(entryPointName, entryPoint.writeRef()); - gGPUPrinting.loadStrings(linkedProgram->getLayout()); + ComPtr linkedProgram; + entryPoint->link(linkedProgram.writeRef()); - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram; + if (isTestMode()) + { + printEntrypointHashes(1, 1, linkedProgram); + } - auto shaderProgram = gDevice->createProgram(programDesc); + gGPUPrinting.loadStrings(linkedProgram->getLayout()); - return shaderProgram; -} + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram; -Result execute(int argc, char* argv[]) -{ - parseOption(argc, argv); - IDevice::Desc deviceDesc; - Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); - if(SLANG_FAILED(res)) return res; - - Slang::String path = resourceBase.resolveResource("kernels.slang"); - - gSlangSession = createSlangSession(gDevice); - gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer()); - if(!gSlangModule) - return SLANG_FAIL; - - gProgram = loadComputeProgram(gSlangModule, "computeMain"); - if(!gProgram) - return SLANG_FAIL; - - ComputePipelineStateDesc desc; - desc.program = gProgram; - auto pipelineState = gDevice->createComputePipelineState(desc); - if(!pipelineState) return SLANG_FAIL; - - gPipelineState = pipelineState; - - size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output - - IBufferResource::Desc printBufferDesc = {}; - printBufferDesc.type = IResource::Type::Buffer; - printBufferDesc.sizeInBytes = printBufferSize; - printBufferDesc.elementSize = sizeof(uint32_t); - printBufferDesc.defaultState = ResourceState::UnorderedAccess; - printBufferDesc.allowedStates = ResourceStateSet( - ResourceState::CopySource, ResourceState::CopyDestination, ResourceState::UnorderedAccess); - printBufferDesc.memoryType = MemoryType::DeviceLocal; - auto printBuffer = gDevice->createBufferResource(printBufferDesc); - - IResourceView::Desc printBufferViewDesc = {}; - printBufferViewDesc.type = IResourceView::Type::UnorderedAccess; - printBufferViewDesc.format = Format::Unknown; - auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc); - - ITransientResourceHeap::Desc transientResourceHeapDesc = {}; - transientResourceHeapDesc.constantBufferSize = 256; - auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc); - - ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; - auto queue = gDevice->createCommandQueue(queueDesc); - auto commandBuffer = transientHeap->createCommandBuffer(); - auto encoder = commandBuffer->encodeComputeCommands(); - auto rootShaderObject = encoder->bindPipeline(gPipelineState); - auto cursor = ShaderCursor(rootShaderObject); - cursor["gPrintBuffer"].setResource(printBufferView); - encoder->dispatchCompute(1, 1, 1); - encoder->bufferBarrier(printBuffer, ResourceState::UnorderedAccess, ResourceState::CopySource); - encoder->endEncoding(); - commandBuffer->close(); - queue->executeCommandBuffer(commandBuffer); - - ComPtr blob; - gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef()); - - gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize); - - return SLANG_OK; -} + auto shaderProgram = gDevice->createProgram(programDesc); + + return shaderProgram; + } + Result execute(int argc, char* argv[]) + { + parseOption(argc, argv); + IDevice::Desc deviceDesc; + Result res = gfxCreateDevice(&deviceDesc, gDevice.writeRef()); + if (SLANG_FAILED(res)) + return res; + + Slang::String path = resourceBase.resolveResource("kernels.slang"); + + gSlangSession = createSlangSession(gDevice); + gSlangModule = compileShaderModuleFromFile(gSlangSession, path.getBuffer()); + if (!gSlangModule) + return SLANG_FAIL; + + gProgram = loadComputeProgram(gSlangModule, "computeMain"); + if (!gProgram) + return SLANG_FAIL; + + ComputePipelineStateDesc desc; + desc.program = gProgram; + auto pipelineState = gDevice->createComputePipelineState(desc); + if (!pipelineState) + return SLANG_FAIL; + + gPipelineState = pipelineState; + + size_t printBufferSize = 4 * 1024; // use a small-ish (4KB) buffer for print output + + IBufferResource::Desc printBufferDesc = {}; + printBufferDesc.type = IResource::Type::Buffer; + printBufferDesc.sizeInBytes = printBufferSize; + printBufferDesc.elementSize = sizeof(uint32_t); + printBufferDesc.defaultState = ResourceState::UnorderedAccess; + printBufferDesc.allowedStates = ResourceStateSet( + ResourceState::CopySource, + ResourceState::CopyDestination, + ResourceState::UnorderedAccess); + printBufferDesc.memoryType = MemoryType::DeviceLocal; + auto printBuffer = gDevice->createBufferResource(printBufferDesc); + + IResourceView::Desc printBufferViewDesc = {}; + printBufferViewDesc.type = IResourceView::Type::UnorderedAccess; + printBufferViewDesc.format = Format::Unknown; + auto printBufferView = gDevice->createBufferView(printBuffer, nullptr, printBufferViewDesc); + + ITransientResourceHeap::Desc transientResourceHeapDesc = {}; + transientResourceHeapDesc.constantBufferSize = 256; + auto transientHeap = gDevice->createTransientResourceHeap(transientResourceHeapDesc); + + ICommandQueue::Desc queueDesc = {ICommandQueue::QueueType::Graphics}; + auto queue = gDevice->createCommandQueue(queueDesc); + auto commandBuffer = transientHeap->createCommandBuffer(); + auto encoder = commandBuffer->encodeComputeCommands(); + auto rootShaderObject = encoder->bindPipeline(gPipelineState); + auto cursor = ShaderCursor(rootShaderObject); + cursor["gPrintBuffer"].setResource(printBufferView); + encoder->dispatchCompute(1, 1, 1); + encoder->bufferBarrier( + printBuffer, + ResourceState::UnorderedAccess, + ResourceState::CopySource); + encoder->endEncoding(); + commandBuffer->close(); + queue->executeCommandBuffer(commandBuffer); + + ComPtr blob; + gDevice->readBufferResource(printBuffer, 0, printBufferSize, blob.writeRef()); + + gGPUPrinting.processGPUPrintCommands(blob->getBufferPointer(), printBufferSize); + + return SLANG_OK; + } }; int main(int argc, char* argv[]) diff --git a/examples/hello-world/main.cpp b/examples/hello-world/main.cpp index 87d4409014..7e84d83e5c 100644 --- a/examples/hello-world/main.cpp +++ b/examples/hello-world/main.cpp @@ -7,13 +7,12 @@ // The goal is to demonstrate how to use the Slang API to cross compile // shader code. // -#include "slang.h" -#include "slang-com-ptr.h" - -#include "vulkan-api.h" +#include "core/slang-string-util.h" #include "examples/example-base/example-base.h" #include "examples/example-base/test-base.h" -#include "source/core/slang-string-util.h" +#include "slang-com-ptr.h" +#include "slang.h" +#include "vulkan-api.h" using Slang::ComPtr; @@ -65,7 +64,6 @@ struct HelloWorldExample : public TestBase int run(); ~HelloWorldExample(); - }; int main(int argc, char* argv[]) @@ -102,8 +100,7 @@ int HelloWorldExample::initVulkanInstanceAndDevice() poolCreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; poolCreateInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; poolCreateInfo.queueFamilyIndex = vkAPI.queueFamilyIndex; - RETURN_ON_FAIL(vkAPI.vkCreateCommandPool( - vkAPI.device, &poolCreateInfo, nullptr, &commandPool)); + RETURN_ON_FAIL(vkAPI.vkCreateCommandPool(vkAPI.device, &poolCreateInfo, nullptr, &commandPool)); vkAPI.vkGetDeviceQueue(vkAPI.device, vkAPI.queueFamilyIndex, 0, &queue); return 0; @@ -120,11 +117,19 @@ int HelloWorldExample::createComputePipelineFromShader() slang::TargetDesc targetDesc = {}; targetDesc.format = SLANG_SPIRV; targetDesc.profile = slangGlobalSession->findProfile("spirv_1_5"); - targetDesc.flags = SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY; + targetDesc.flags = 0; + sessionDesc.targets = &targetDesc; sessionDesc.targetCount = 1; + std::vector options; + options.push_back( + {slang::CompilerOptionName::EmitSpirvDirectly, + {slang::CompilerOptionValueKind::Int, 1, 0, nullptr, nullptr}}); + sessionDesc.compilerOptionEntries = options.data(); + sessionDesc.compilerOptionEntryCount = options.size(); + ComPtr session; RETURN_ON_FAIL(slangGlobalSession->createSession(sessionDesc, session.writeRef())); @@ -204,7 +209,10 @@ int HelloWorldExample::createComputePipelineFromShader() { ComPtr diagnosticsBlob; SlangResult result = composedProgram->getEntryPointCode( - 0, 0, spirvCode.writeRef(), diagnosticsBlob.writeRef()); + 0, + 0, + spirvCode.writeRef(), + diagnosticsBlob.writeRef()); diagnoseIfNeeded(diagnosticsBlob); RETURN_ON_FAIL(result); @@ -238,13 +246,19 @@ int HelloWorldExample::createComputePipelineFromShader() } descSetLayoutCreateInfo.pBindings = bindings; RETURN_ON_FAIL(vkAPI.vkCreateDescriptorSetLayout( - vkAPI.device, &descSetLayoutCreateInfo, nullptr, &descriptorSetLayout)); + vkAPI.device, + &descSetLayoutCreateInfo, + nullptr, + &descriptorSetLayout)); VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO}; pipelineLayoutCreateInfo.setLayoutCount = 1; pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout; RETURN_ON_FAIL(vkAPI.vkCreatePipelineLayout( - vkAPI.device, &pipelineLayoutCreateInfo, nullptr, &pipelineLayout)); + vkAPI.device, + &pipelineLayoutCreateInfo, + nullptr, + &pipelineLayout)); // Next we create a shader module from the compiled SPIRV code. VkShaderModuleCreateInfo shaderCreateInfo = {VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO}; @@ -263,7 +277,12 @@ int HelloWorldExample::createComputePipelineFromShader() pipelineCreateInfo.stage.pName = "main"; pipelineCreateInfo.layout = pipelineLayout; RETURN_ON_FAIL(vkAPI.vkCreateComputePipelines( - vkAPI.device, VK_NULL_HANDLE, 1, &pipelineCreateInfo, nullptr, &pipeline)); + vkAPI.device, + VK_NULL_HANDLE, + 1, + &pipelineCreateInfo, + nullptr, + &pipeline)); // We can destroy shader module now since it will no longer be used. vkAPI.vkDestroyShaderModule(vkAPI.device, vkShaderModule, nullptr); @@ -287,7 +306,8 @@ int HelloWorldExample::createInOutBuffers() vkAPI.vkGetBufferMemoryRequirements(vkAPI.device, inOutBuffers[i], &memoryReqs); int memoryTypeIndex = vkAPI.findMemoryTypeIndex( - memoryReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + memoryReqs.memoryTypeBits, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); assert(memoryTypeIndex >= 0); VkMemoryPropertyFlags actualMemoryProperites = @@ -347,7 +367,10 @@ int HelloWorldExample::createInOutBuffers() commandBufferAllocInfo.commandBufferCount = 1; commandBufferAllocInfo.commandPool = commandPool; commandBufferAllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - RETURN_ON_FAIL(vkAPI.vkAllocateCommandBuffers(vkAPI.device, &commandBufferAllocInfo, &uploadCommandBuffer)); + RETURN_ON_FAIL(vkAPI.vkAllocateCommandBuffers( + vkAPI.device, + &commandBufferAllocInfo, + &uploadCommandBuffer)); VkCommandBufferBeginInfo beginInfo = {VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO}; vkAPI.vkBeginCommandBuffer(uploadCommandBuffer, &beginInfo); @@ -378,7 +401,10 @@ int HelloWorldExample::dispatchCompute() descriptorPoolCreateInfo.flags = 0; VkDescriptorPool descriptorPool = VK_NULL_HANDLE; RETURN_ON_FAIL(vkAPI.vkCreateDescriptorPool( - vkAPI.device, &descriptorPoolCreateInfo, nullptr, &descriptorPool)); + vkAPI.device, + &descriptorPoolCreateInfo, + nullptr, + &descriptorPool)); // Allocate descriptor set. VkDescriptorSetAllocateInfo descSetAllocInfo = {VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO}; diff --git a/examples/hello-world/vulkan-api.cpp b/examples/hello-world/vulkan-api.cpp index 3581563d4f..95c4a512e9 100644 --- a/examples/hello-world/vulkan-api.cpp +++ b/examples/hello-world/vulkan-api.cpp @@ -1,16 +1,17 @@ #include "vulkan-api.h" + #include "slang.h" -#include -#include #include +#include +#include #include #include #if SLANG_WINDOWS_FAMILY -# include +#include #else -# include +#include #endif #if _DEBUG @@ -25,7 +26,8 @@ VKAPI_ATTR VkBool32 VKAPI_CALL debugMessageCallback( int32_t /*msgCode*/, const char* pLayerPrefix, const char* pMsg, - void* /*pUserData*/) + void* /*pUserData*/ +) { printf("[%s]: %s\n", pLayerPrefix, pMsg); return 1; @@ -62,7 +64,7 @@ int initializeVulkanDevice(VulkanAPI& api) uint32_t propertyCount; if (api.vkEnumerateInstanceLayerProperties(&propertyCount, nullptr) != 0) return -1; - std::vector< VkLayerProperties> properties(propertyCount); + std::vector properties(propertyCount); if (api.vkEnumerateInstanceLayerProperties(&propertyCount, properties.data()) != 0) return -1; for (const auto& p : properties) @@ -119,17 +121,19 @@ int initializeVulkanDevice(VulkanAPI& api) debugCreateInfo.flags = debugFlags; RETURN_ON_FAIL(api.vkCreateDebugReportCallbackEXT( - api.instance, &debugCreateInfo, nullptr, &api.debugReportCallback)); + api.instance, + &debugCreateInfo, + nullptr, + &api.debugReportCallback)); } // Enumerate physical devices. uint32_t numPhysicalDevices = 0; - RETURN_ON_FAIL( - api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, nullptr)); + RETURN_ON_FAIL(api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, nullptr)); std::vector physicalDevices; physicalDevices.resize(numPhysicalDevices); - RETURN_ON_FAIL(api.vkEnumeratePhysicalDevices( - api.instance, &numPhysicalDevices, &physicalDevices[0])); + RETURN_ON_FAIL( + api.vkEnumeratePhysicalDevices(api.instance, &numPhysicalDevices, &physicalDevices[0])); // We will use device 0. api.initPhysicalDevice(physicalDevices[0]); @@ -145,7 +149,9 @@ int initializeVulkanDevice(VulkanAPI& api) std::vector queueFamilies; queueFamilies.resize(numQueueFamilies); api.vkGetPhysicalDeviceQueueFamilyProperties( - api.physicalDevice, &numQueueFamilies, &queueFamilies[0]); + api.physicalDevice, + &numQueueFamilies, + &queueFamilies[0]); // Find a queue that can service our needs. auto requiredQueueFlags = VK_QUEUE_COMPUTE_BIT; diff --git a/examples/hello-world/vulkan-api.h b/examples/hello-world/vulkan-api.h index 17d0465a68..ab0822569d 100644 --- a/examples/hello-world/vulkan-api.h +++ b/examples/hello-world/vulkan-api.h @@ -7,6 +7,7 @@ // the Vulkan API. // The Vulkan function pointers we will use in this example. +// clang-format off #define VK_API_GLOBAL_PROCS(x) \ x(vkGetInstanceProcAddr) \ x(vkCreateInstance) \ @@ -87,6 +88,7 @@ /* */ #define VK_API_DECLARE_PROC(NAME) PFN_##NAME NAME = nullptr; +// clang-format on struct VulkanAPI { @@ -119,12 +121,12 @@ struct VulkanAPI }; #define RETURN_ON_FAIL(x) \ - { \ - auto _res = x; \ - if (_res != 0) \ - { \ - return -1; \ - } \ + { \ + auto _res = x; \ + if (_res != 0) \ + { \ + return -1; \ + } \ } // Loads Vulkan library and creates a VkDevice. diff --git a/examples/model-viewer/main.cpp b/examples/model-viewer/main.cpp index 7ca5eeb74d..8b75381be9 100644 --- a/examples/model-viewer/main.cpp +++ b/examples/model-viewer/main.cpp @@ -16,21 +16,21 @@ // We still need to include the Slang header to use the Slang API // -#include "slang.h" #include "slang-com-helper.h" +#include "slang.h" // We will again make use of a graphics API abstraction // layer that implements the shader-object idiom based on Slang's // `ParameterBlock` and `interface` features to simplify shader specialization // and parameter binding. // -#include "slang-gfx.h" -#include "tools/gfx-util/shader-cursor.h" -#include "tools/platform/model.h" -#include "tools/platform/vector-math.h" -#include "tools/platform/window.h" -#include "tools/platform/gui.h" #include "examples/example-base/example-base.h" +#include "gfx-util/shader-cursor.h" +#include "platform/gui.h" +#include "platform/model.h" +#include "platform/vector-math.h" +#include "platform/window.h" +#include "slang-gfx.h" #include #include @@ -51,7 +51,7 @@ struct RendererContext slang::TypeReflection* perViewShaderType; slang::TypeReflection* perModelShaderType; - TestBase *pTestBase; + TestBase* pTestBase; Result init(IDevice* inDevice, TestBase* inTestBase) { @@ -60,9 +60,8 @@ struct RendererContext pTestBase = inTestBase; Slang::String path = resourceBase.resolveResource("shaders.slang").getBuffer(); - shaderModule = device->getSlangSession()->loadModule( - path.getBuffer(), - diagnostic.writeRef()); + shaderModule = + device->getSlangSession()->loadModule(path.getBuffer(), diagnostic.writeRef()); diagnoseIfNeeded(diagnostic); if (!shaderModule) return SLANG_FAIL; @@ -165,9 +164,9 @@ struct Material : RefObject // struct SimpleMaterial : Material { - glm::vec3 diffuseColor; - glm::vec3 specularColor; - float specularity = 1.0f; + glm::vec3 diffuseColor; + glm::vec3 specularColor; + float specularity = 1.0f; // Create a shader object that contains the type info and parameter values // that represent an instance of `SimpleMaterial`. @@ -194,20 +193,20 @@ struct SimpleMaterial : Material // struct Mesh : RefObject { - RefPtr material; - int firstIndex; - int indexCount; + RefPtr material; + int firstIndex; + int indexCount; }; struct Model : RefObject { typedef platform::ModelLoader::Vertex Vertex; - ComPtr vertexBuffer; - ComPtr indexBuffer; - PrimitiveTopology primitiveTopology; - int vertexCount; - int indexCount; - std::vector> meshes; + ComPtr vertexBuffer; + ComPtr indexBuffer; + PrimitiveTopology primitiveTopology; + int vertexCount; + int indexCount; + std::vector> meshes; }; // // Loading a model from disk is done with the help of some utility @@ -216,10 +215,10 @@ struct Model : RefObject // used for its representation. // RefPtr loadModel( - RendererContext* context, - char const* inputPath, + RendererContext* context, + char const* inputPath, platform::ModelLoader::LoadFlags loadFlags = 0, - float scale = 1.0f) + float scale = 1.0f) { // The model loading interface using a C++ interface of // callback functions to handle creating the application-specific @@ -308,7 +307,7 @@ struct Light : RefObject // The shader object for a light will be stashed here // after it is created. -// ComPtr shaderObject; + // ComPtr shaderObject; }; // Helper function to retrieve the underlying shader type of `T`. @@ -411,8 +410,7 @@ struct LightEnvLayout : public RefObject { auto program = context->slangReflection; std::stringstream typeNameBuilder; - typeNameBuilder << "LightArray<" << lightType->getName() << "," << maximumCount - << ">"; + typeNameBuilder << "LightArray<" << lightType->getName() << "," << maximumCount << ">"; layout.typeName = typeNameBuilder.str(); } @@ -420,7 +418,8 @@ struct LightEnvLayout : public RefObject mapLightTypeToArrayIndex.insert(std::make_pair(lightType, arrayIndex)); } - template void addLightType(RendererContext* context, Int maximumCount) + template + void addLightType(RendererContext* context, Int maximumCount) { addLightType(context, getShaderType(context), maximumCount); } @@ -459,8 +458,7 @@ struct LightEnv : public RefObject RefPtr layout; RendererContext* context; LightEnv(RefPtr layout, RendererContext* inContext) - : layout(layout) - , context(inContext) + : layout(layout), context(inContext) { for (auto arrayLayout : layout->lightArrayLayouts) { @@ -640,329 +638,333 @@ struct LightEnv : public RefObject // struct ModelViewer : WindowedAppBase { -RendererContext context; + RendererContext context; -// Most of the application state is stored in the list of loaded models, -// as well as the active light source (a single light for now). -// -std::vector> gModels; -RefPtr lightEnv; + // Most of the application state is stored in the list of loaded models, + // as well as the active light source (a single light for now). + // + std::vector> gModels; + RefPtr lightEnv; -// The pipeline state object we will use to draw models. -ComPtr gPipelineState; + // The pipeline state object we will use to draw models. + ComPtr gPipelineState; -// During startup the application will load one or more models and -// add them to the `gModels` list. -// -void loadAndAddModel( - char const* inputPath, - platform::ModelLoader::LoadFlags loadFlags = 0, - float scale = 1.0f) -{ - auto model = loadModel(&context, inputPath, loadFlags, scale); - if(!model) return; - gModels.push_back(model); -} + // During startup the application will load one or more models and + // add them to the `gModels` list. + // + void loadAndAddModel( + char const* inputPath, + platform::ModelLoader::LoadFlags loadFlags = 0, + float scale = 1.0f) + { + auto model = loadModel(&context, inputPath, loadFlags, scale); + if (!model) + return; + gModels.push_back(model); + } -// Our "simulation" state consists of just a few values. -// -uint64_t lastTime = 0; + // Our "simulation" state consists of just a few values. + // + uint64_t lastTime = 0; -//glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); -//glm::vec3 lightColor = glm::vec3(1, 1, 1); + // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); + // glm::vec3 lightColor = glm::vec3(1, 1, 1); -glm::vec3 cameraPosition = glm::vec3(1.75, 1.25, 5); -glm::quat cameraOrientation = glm::quat(1, glm::vec3(0)); + glm::vec3 cameraPosition = glm::vec3(1.75, 1.25, 5); + glm::quat cameraOrientation = glm::quat(1, glm::vec3(0)); -float translationScale = 0.5f; -float rotationScale = 0.025f; + float translationScale = 0.5f; + float rotationScale = 0.025f; -// In order to control camera movement, we will -// use good old WASD -bool wPressed = false; -bool aPressed = false; -bool sPressed = false; -bool dPressed = false; + // In order to control camera movement, we will + // use good old WASD + bool wPressed = false; + bool aPressed = false; + bool sPressed = false; + bool dPressed = false; -bool isMouseDown = false; -float lastMouseX = 0.0f; -float lastMouseY = 0.0f; + bool isMouseDown = false; + float lastMouseX = 0.0f; + float lastMouseY = 0.0f; -void setKeyState(platform::KeyCode key, bool state) -{ - switch (key) + void setKeyState(platform::KeyCode key, bool state) { - default: - break; - case platform::KeyCode::W: - wPressed = state; - break; - case platform::KeyCode::A: - aPressed = state; - break; - case platform::KeyCode::S: - sPressed = state; - break; - case platform::KeyCode::D: - dPressed = state; - break; + switch (key) + { + default: + break; + case platform::KeyCode::W: + wPressed = state; + break; + case platform::KeyCode::A: + aPressed = state; + break; + case platform::KeyCode::S: + sPressed = state; + break; + case platform::KeyCode::D: + dPressed = state; + break; + } } -} -void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } -void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } - -void onMouseDown(platform::MouseEventArgs args) -{ - isMouseDown = true; - lastMouseX = (float)args.x; - lastMouseY = (float)args.y; -} + void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } + void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } -void onMouseMove(platform::MouseEventArgs args) -{ - if (isMouseDown) + void onMouseDown(platform::MouseEventArgs args) { - float deltaX = args.x - lastMouseX; - float deltaY = args.y - lastMouseY; - - cameraOrientation = - glm::rotate(cameraOrientation, -deltaX * rotationScale, glm::vec3(0, 1, 0)); - cameraOrientation = - glm::rotate(cameraOrientation, -deltaY * rotationScale, glm::vec3(1, 0, 0)); - - cameraOrientation = normalize(cameraOrientation); - + isMouseDown = true; lastMouseX = (float)args.x; lastMouseY = (float)args.y; } -} -void onMouseUp(platform::MouseEventArgs args) -{ - isMouseDown = false; -} -// The overall initialization logic is quite similar to -// the earlier example. The biggest difference is that we -// create instances of our application-specific parameter -// block layout and effect types instead of just creating -// raw graphics API objects. -// -Result initialize() -{ - initializeBase("Model Viewer", 1024, 768); - if (!isTestMode()) + void onMouseMove(platform::MouseEventArgs args) { - gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; - gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; - gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; - gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; - gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; - } + if (isMouseDown) + { + float deltaX = args.x - lastMouseX; + float deltaY = args.y - lastMouseY; - // Initialize `RendererContext`, which loads the shader module from file. - SLANG_RETURN_ON_FAIL(context.init(gDevice, this)); + cameraOrientation = + glm::rotate(cameraOrientation, -deltaX * rotationScale, glm::vec3(0, 1, 0)); + cameraOrientation = + glm::rotate(cameraOrientation, -deltaY * rotationScale, glm::vec3(1, 0, 0)); + cameraOrientation = normalize(cameraOrientation); - InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, position) }, - {"NORMAL", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, normal) }, - {"UV", 0, Format::R32G32_FLOAT, offsetof(Model::Vertex, uv) }, - }; - auto inputLayout = gDevice->createInputLayout( - sizeof(Model::Vertex), - &inputElements[0], - 3); - if(!inputLayout) return SLANG_FAIL; - - // Create the pipeline state object for drawing models. - GraphicsPipelineStateDesc pipelineStateDesc = {}; - pipelineStateDesc.program = context.shaderProgram; - pipelineStateDesc.framebufferLayout = gFramebufferLayout; - pipelineStateDesc.inputLayout = inputLayout; - pipelineStateDesc.primitiveType = PrimitiveType::Triangle; - pipelineStateDesc.depthStencil.depthFunc = ComparisonFunc::LessEqual; - pipelineStateDesc.depthStencil.depthTestEnable = true; - gPipelineState = gDevice->createGraphicsPipelineState(pipelineStateDesc); - - // We will create a lighting environment layout that can hold a few point - // and directional lights, and then initialize a lighting environment - // with just a single point light. + lastMouseX = (float)args.x; + lastMouseY = (float)args.y; + } + } + void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; } + + // The overall initialization logic is quite similar to + // the earlier example. The biggest difference is that we + // create instances of our application-specific parameter + // block layout and effect types instead of just creating + // raw graphics API objects. // - RefPtr lightEnvLayout = new LightEnvLayout(); - lightEnvLayout->addLightType(&context, 10); - lightEnvLayout->addLightType(&context, 2); + Result initialize() + { + initializeBase("Model Viewer", 1024, 768); + if (!isTestMode()) + { + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) + { onMouseMove(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) + { onMouseDown(e); }; + gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; + gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + } - lightEnv = new LightEnv(lightEnvLayout, &context); + // Initialize `RendererContext`, which loads the shader module from file. + SLANG_RETURN_ON_FAIL(context.init(gDevice, this)); - RefPtr pointLight = new PointLight(); - pointLight->position = glm::vec3(5, 3, 1); - pointLight->intensity = glm::vec3(10); - lightEnv->add(pointLight); - // Once we have created all our graphcis API and application resources, - // we can start to load models. For now we are keeping things extremely - // simple by using a trivial `.obj` file that can be checked into source - // control. - // - // Support for loading more interesting/complex models will be added - // to this example over time (although model loading is *not* the focus). - // - Slang::String path = resourceBase.resolveResource("cube.obj").getBuffer(); - loadAndAddModel(path.getBuffer()); + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, position)}, + {"NORMAL", 0, Format::R32G32B32_FLOAT, offsetof(Model::Vertex, normal)}, + {"UV", 0, Format::R32G32_FLOAT, offsetof(Model::Vertex, uv)}, + }; + auto inputLayout = gDevice->createInputLayout(sizeof(Model::Vertex), &inputElements[0], 3); + if (!inputLayout) + return SLANG_FAIL; - return SLANG_OK; -} + // Create the pipeline state object for drawing models. + GraphicsPipelineStateDesc pipelineStateDesc = {}; + pipelineStateDesc.program = context.shaderProgram; + pipelineStateDesc.framebufferLayout = gFramebufferLayout; + pipelineStateDesc.inputLayout = inputLayout; + pipelineStateDesc.primitiveType = PrimitiveType::Triangle; + pipelineStateDesc.depthStencil.depthFunc = ComparisonFunc::LessEqual; + pipelineStateDesc.depthStencil.depthTestEnable = true; + gPipelineState = gDevice->createGraphicsPipelineState(pipelineStateDesc); + + // We will create a lighting environment layout that can hold a few point + // and directional lights, and then initialize a lighting environment + // with just a single point light. + // + RefPtr lightEnvLayout = new LightEnvLayout(); + lightEnvLayout->addLightType(&context, 10); + lightEnvLayout->addLightType(&context, 2); -// With the setup work done, we can look at the per-frame rendering -// logic to see how the application will drive the `RenderContext` -// type to perform both shader parameter binding and code specialization. -// -void renderFrame(int frameIndex) override -{ - // In order to see that things are rendering properly we need some - // kind of animation, so we will compute a crude delta-time value here. - // - if(!lastTime) lastTime = getCurrentTime(); - uint64_t currentTime = getCurrentTime(); - float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); - lastTime = currentTime; + lightEnv = new LightEnv(lightEnvLayout, &context); - // We will use the GLM library to do the matrix math required - // to set up our various transformation matrices. - // - glm::mat4x4 identity = glm::mat4x4(1.0f); + RefPtr pointLight = new PointLight(); + pointLight->position = glm::vec3(5, 3, 1); + pointLight->intensity = glm::vec3(10); + lightEnv->add(pointLight); - platform::Rect clientRect{}; - if (isTestMode()) - { - clientRect.width = 1024; - clientRect.height = 768; - } - else - { - clientRect = getWindow()->getClientRect(); - } - if (clientRect.height == 0) - return; - glm::mat4x4 projection = glm::perspectiveRH_ZO( - glm::radians(60.0f), float(clientRect.width) / float(clientRect.height), - 0.1f, - 1000.0f); - - // We are implementing a *very* basic 6DOF first-person - // camera movement model. - // - glm::mat3x3 cameraOrientationMat(cameraOrientation); - glm::vec3 forward = -cameraOrientationMat[2]; - glm::vec3 right = cameraOrientationMat[0]; - - glm::vec3 movement = glm::vec3(0); - if(wPressed) movement += forward; - if(sPressed) movement -= forward; - if(aPressed) movement -= right; - if(dPressed) movement += right; - - cameraPosition += deltaTime * translationScale * movement; - - glm::mat4x4 view = identity; - view *= glm::mat4x4(inverse(cameraOrientation)); - view = glm::translate(view, -cameraPosition); - - glm::mat4x4 viewProjection = projection * view; - auto deviceInfo = gDevice->getDeviceInfo(); - glm::mat4x4 correctionMatrix; - memcpy(&correctionMatrix, deviceInfo.identityProjectionMatrix, sizeof(float)*16); - viewProjection = correctionMatrix * viewProjection; - // glm uses column-major layout, we need to translate it to row-major. - viewProjection = glm::transpose(viewProjection); - - auto drawCommandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); - auto drawCommandEncoder = - drawCommandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)clientRect.width; - viewport.extentY = (float)clientRect.height; - drawCommandEncoder->setViewportAndScissor(viewport); - drawCommandEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - - // We are only rendering one view, so we can fill in a per-view - // shader object once and use it across all draw calls. - // + // Once we have created all our graphcis API and application resources, + // we can start to load models. For now we are keeping things extremely + // simple by using a trivial `.obj` file that can be checked into source + // control. + // + // Support for loading more interesting/complex models will be added + // to this example over time (although model loading is *not* the focus). + // + Slang::String path = resourceBase.resolveResource("cube.obj").getBuffer(); + loadAndAddModel(path.getBuffer()); - auto viewShaderObject = gDevice->createShaderObject(context.perViewShaderType); - { - ShaderCursor cursor(viewShaderObject); - cursor["viewProjection"].setData(&viewProjection, sizeof(viewProjection)); - cursor["eyePosition"].setData(&cameraPosition, sizeof(cameraPosition)); + return SLANG_OK; } - // The majority of our rendering logic is handled as a loop - // over the models in the scene, and their meshes. + + // With the setup work done, we can look at the per-frame rendering + // logic to see how the application will drive the `RenderContext` + // type to perform both shader parameter binding and code specialization. // - for(auto& model : gModels) + void renderFrame(int frameIndex) override { - drawCommandEncoder->setVertexBuffer(0, model->vertexBuffer); - drawCommandEncoder->setIndexBuffer(model->indexBuffer, Format::R32_UINT); - // For each model we provide a parameter - // block that holds the per-model transformation - // parameters, corresponding to the `PerModel` type - // in the shader code. - glm::mat4x4 modelTransform = identity; - glm::mat4x4 inverseTransposeModelTransform = inverse(transpose(modelTransform)); - auto modelShaderObject = gDevice->createShaderObject(context.perModelShaderType); + // In order to see that things are rendering properly we need some + // kind of animation, so we will compute a crude delta-time value here. + // + if (!lastTime) + lastTime = getCurrentTime(); + uint64_t currentTime = getCurrentTime(); + float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); + lastTime = currentTime; + + // We will use the GLM library to do the matrix math required + // to set up our various transformation matrices. + // + glm::mat4x4 identity = glm::mat4x4(1.0f); + + platform::Rect clientRect{}; + if (isTestMode()) { - ShaderCursor cursor(modelShaderObject); - cursor["modelTransform"].setData(&modelTransform, sizeof(modelTransform)); - cursor["inverseTransposeModelTransform"].setData( - &inverseTransposeModelTransform, sizeof(inverseTransposeModelTransform)); + clientRect.width = 1024; + clientRect.height = 768; } - - auto lightShaderObject = lightEnv->createShaderObject(); - - // Now we loop over the meshes in the model. + else + { + clientRect = getWindow()->getClientRect(); + } + if (clientRect.height == 0) + return; + glm::mat4x4 projection = glm::perspectiveRH_ZO( + glm::radians(60.0f), + float(clientRect.width) / float(clientRect.height), + 0.1f, + 1000.0f); + + // We are implementing a *very* basic 6DOF first-person + // camera movement model. // - // A more advanced rendering loop would sort things by material - // rather than by model, to avoid overly frequent state changes. - // We are just doing something simple for the purposes of an - // exmple program. + glm::mat3x3 cameraOrientationMat(cameraOrientation); + glm::vec3 forward = -cameraOrientationMat[2]; + glm::vec3 right = cameraOrientationMat[0]; + + glm::vec3 movement = glm::vec3(0); + if (wPressed) + movement += forward; + if (sPressed) + movement -= forward; + if (aPressed) + movement -= right; + if (dPressed) + movement += right; + + cameraPosition += deltaTime * translationScale * movement; + + glm::mat4x4 view = identity; + view *= glm::mat4x4(inverse(cameraOrientation)); + view = glm::translate(view, -cameraPosition); + + glm::mat4x4 viewProjection = projection * view; + auto deviceInfo = gDevice->getDeviceInfo(); + glm::mat4x4 correctionMatrix; + memcpy(&correctionMatrix, deviceInfo.identityProjectionMatrix, sizeof(float) * 16); + viewProjection = correctionMatrix * viewProjection; + // glm uses column-major layout, we need to translate it to row-major. + viewProjection = glm::transpose(viewProjection); + + auto drawCommandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); + auto drawCommandEncoder = + drawCommandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)clientRect.width; + viewport.extentY = (float)clientRect.height; + drawCommandEncoder->setViewportAndScissor(viewport); + drawCommandEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + + // We are only rendering one view, so we can fill in a per-view + // shader object once and use it across all draw calls. // - for(auto& mesh : model->meshes) + + auto viewShaderObject = gDevice->createShaderObject(context.perViewShaderType); { - // Set the pipeline and binding state for drawing each mesh. - auto rootObject = drawCommandEncoder->bindPipeline(gPipelineState); - ShaderCursor rootCursor(rootObject); - rootCursor["gViewParams"].setObject(viewShaderObject); - rootCursor["gModelParams"].setObject(modelShaderObject); - rootCursor["gLightEnv"].setObject(lightShaderObject); - - // Each mesh has a material, and each material has its own - // parameter block that was created at load time, so we - // can just re-use the persistent parameter block for the - // chosen material. + ShaderCursor cursor(viewShaderObject); + cursor["viewProjection"].setData(&viewProjection, sizeof(viewProjection)); + cursor["eyePosition"].setData(&cameraPosition, sizeof(cameraPosition)); + } + // The majority of our rendering logic is handled as a loop + // over the models in the scene, and their meshes. + // + for (auto& model : gModels) + { + drawCommandEncoder->setVertexBuffer(0, model->vertexBuffer); + drawCommandEncoder->setIndexBuffer(model->indexBuffer, Format::R32_UINT); + // For each model we provide a parameter + // block that holds the per-model transformation + // parameters, corresponding to the `PerModel` type + // in the shader code. + glm::mat4x4 modelTransform = identity; + glm::mat4x4 inverseTransposeModelTransform = inverse(transpose(modelTransform)); + auto modelShaderObject = gDevice->createShaderObject(context.perModelShaderType); + { + ShaderCursor cursor(modelShaderObject); + cursor["modelTransform"].setData(&modelTransform, sizeof(modelTransform)); + cursor["inverseTransposeModelTransform"].setData( + &inverseTransposeModelTransform, + sizeof(inverseTransposeModelTransform)); + } + + auto lightShaderObject = lightEnv->createShaderObject(); + + // Now we loop over the meshes in the model. // - // Note that binding the material parameter block here is - // both selecting the values to use for various material - // parameters as well as the *code* to use for material - // evaluation (based on the concrete shader type that - // is implementing the `IMaterial` interface). + // A more advanced rendering loop would sort things by material + // rather than by model, to avoid overly frequent state changes. + // We are just doing something simple for the purposes of an + // exmple program. // - rootCursor["gMaterial"].setObject(mesh->material->shaderObject); + for (auto& mesh : model->meshes) + { + // Set the pipeline and binding state for drawing each mesh. + auto rootObject = drawCommandEncoder->bindPipeline(gPipelineState); + ShaderCursor rootCursor(rootObject); + rootCursor["gViewParams"].setObject(viewShaderObject); + rootCursor["gModelParams"].setObject(modelShaderObject); + rootCursor["gLightEnv"].setObject(lightShaderObject); + + // Each mesh has a material, and each material has its own + // parameter block that was created at load time, so we + // can just re-use the persistent parameter block for the + // chosen material. + // + // Note that binding the material parameter block here is + // both selecting the values to use for various material + // parameters as well as the *code* to use for material + // evaluation (based on the concrete shader type that + // is implementing the `IMaterial` interface). + // + rootCursor["gMaterial"].setObject(mesh->material->shaderObject); - // All the shader parameters and pipeline states have been set up, - // we can now issue a draw call for the mesh. - drawCommandEncoder->drawIndexed(mesh->indexCount, mesh->firstIndex); + // All the shader parameters and pipeline states have been set up, + // we can now issue a draw call for the mesh. + drawCommandEncoder->drawIndexed(mesh->indexCount, mesh->firstIndex); + } } - } - drawCommandEncoder->endEncoding(); - drawCommandBuffer->close(); - gQueue->executeCommandBuffer(drawCommandBuffer); + drawCommandEncoder->endEncoding(); + drawCommandBuffer->close(); + gQueue->executeCommandBuffer(drawCommandBuffer); - if (!isTestMode()) - { - gSwapchain->present(); + if (!isTestMode()) + { + gSwapchain->present(); + } } -} - }; // This macro instantiates an appropriate main function to diff --git a/examples/nv-aftermath-example/main.cpp b/examples/nv-aftermath-example/main.cpp index 9850586c8b..9d85f1ff4f 100644 --- a/examples/nv-aftermath-example/main.cpp +++ b/examples/nv-aftermath-example/main.cpp @@ -1,16 +1,15 @@ // main.cpp -#include "slang.h" -#include "slang-gfx.h" -#include "gfx-util/shader-cursor.h" -#include "tools/platform/window.h" -#include "slang-com-ptr.h" #include "../../source/core/slang-io.h" -#include "source/core/slang-basic.h" -#include "examples/example-base/example-base.h" - #include "GFSDK_Aftermath.h" #include "GFSDK_Aftermath_GpuCrashDump.h" +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" +#include "gfx-util/shader-cursor.h" +#include "platform/window.h" +#include "slang-com-ptr.h" +#include "slang-gfx.h" +#include "slang.h" using namespace gfx; using namespace Slang; @@ -21,10 +20,10 @@ static const ExampleResources resourceBase("nv-aftermath-example"); // // This examples purpose is to show how to use the aftermath SDK to capture // a crash dump. -// +// // * [nsight aftermath](https://developer.nvidia.com/nsight-aftermath) -// -// In addition it uses obfuscation and source maps to allow source level +// +// In addition it uses obfuscation and source maps to allow source level // debugging via aftermath even with obfuscation. // // * [obfuscation](https://github.com/shader-slang/slang/blob/master/docs/user-guide/a1-03-obfuscation.md) @@ -37,29 +36,28 @@ struct Vertex }; static const int kVertexCount = 3; -static const Vertex kVertexData[kVertexCount] = -{ - { { 0, 0, 0.5 }, { 1, 0, 0 } }, - { { 0, 1, 0.5 }, { 0, 0, 1 } }, - { { 1, 0, 0.5 }, { 0, 1, 0 } }, +static const Vertex kVertexData[kVertexCount] = { + {{0, 0, 0.5}, {1, 0, 0}}, + {{0, 1, 0.5}, {0, 0, 1}}, + {{1, 0, 0.5}, {0, 1, 0}}, }; struct AftermathCrashExample : public WindowedAppBase { void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob); - - gfx::Result loadShaderProgram( gfx::IDevice* device, gfx::IShaderProgram** outProgram); - + + gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram); + Slang::Result initialize(); virtual void renderFrame(int frameBufferIndex) override; - + void onAftermathCrash(const void* data, const uint32_t dataSizeInBytes); void onAftermathDebugInfo(const void* pGpuCrashDump, const uint32_t gpuCrashDumpSize); void onAftermathCrashDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description); - + void onAftermathMarker(const void* pMarker, void** resolvedMarkerData, uint32_t* markerSize); // Create accessors so we don't have to use g prefixed variables. @@ -69,12 +67,15 @@ struct AftermathCrashExample : public WindowedAppBase gfx::ISwapchain* getSwapChain() { return gSwapchain; } gfx::IRenderPassLayout* getRenderPassLayout() { return gRenderPass; } Slang::List>& getFrameBuffers() { return gFramebuffers; } - Slang::List>& getTransientHeaps() { return gTransientHeaps; } + Slang::List>& getTransientHeaps() + { + return gTransientHeaps; + } ComPtr m_pipelineState; ComPtr m_vertexBuffer; - /// A counter such that we can make aftermath dump file names unique + /// A counter such that we can make aftermath dump file names unique std::atomic m_uniqueId = 0; }; @@ -94,13 +95,15 @@ void AftermathCrashExample::onAftermathCrash(const void* data, const uint32_t da // Dump out as a file Slang::StringBuilder filename; filename << "aftermath-dump-" << id << ".bin"; - + File::writeAllBytes(filename, data, dataSizeInBytes); - - //SLANG_BREAKPOINT(0); + + // SLANG_BREAKPOINT(0); } -void AftermathCrashExample::onAftermathDebugInfo(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize) +void AftermathCrashExample::onAftermathDebugInfo( + const void* gpuCrashDump, + const uint32_t gpuCrashDumpSize) { const auto id = m_uniqueId++; @@ -111,41 +114,49 @@ void AftermathCrashExample::onAftermathDebugInfo(const void* gpuCrashDump, const File::writeAllBytes(filename, gpuCrashDump, gpuCrashDumpSize); } -void AftermathCrashExample::onAftermathCrashDescription(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description) +void AftermathCrashExample::onAftermathCrashDescription( + PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription description) { // Ignore for now } -void AftermathCrashExample::onAftermathMarker(const void* marker, void** resolvedMarkerData, uint32_t* markerSize) +void AftermathCrashExample::onAftermathMarker( + const void* marker, + void** resolvedMarkerData, + uint32_t* markerSize) { // Ignore for now } struct FileSystemEntry { - SlangPathType type; ///< The type of the entry - String path; ///< The path to the entr + SlangPathType type; ///< The type of the entry + String path; ///< The path to the entr }; struct CompileProduct { - String fileName; ///< The filename to write the compile product out to - ComPtr blob; ///< A blob holding the products contents + String fileName; ///< The filename to write the compile product out to + ComPtr blob; ///< A blob holding the products contents }; -/* Currently the mechanism to access the contents of a compilation that might consist of many products is through -representing the contents as a "file system". +/* Currently the mechanism to access the contents of a compilation that might consist of many +products is through representing the contents as a "file system". -The file system is just a somewhat convenient/simple in memory representation of the compilation products. +The file system is just a somewhat convenient/simple in memory representation of the compilation +products. This function transverses the file system and adds everything found into outEntries. */ -static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, const char* rootPath, List& outEntries) +static SlangResult _findFileSystemContents( + ISlangFileSystemExt* fileSystem, + const char* rootPath, + List& outEntries) { { SlangPathType type; SLANG_RETURN_ON_FAIL(fileSystem->getPathType(rootPath, &type)); - outEntries.add(FileSystemEntry{ type, rootPath }); + outEntries.add(FileSystemEntry{type, rootPath}); } // A context used to hold state, when using enumeratePathContents @@ -162,16 +173,18 @@ static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, cons // If it's a directory we want to traverse it's contents if (entry.type == SLANG_PATH_TYPE_DIRECTORY) { - Context context{outEntries, entry.path }; + Context context{outEntries, entry.path}; - fileSystem->enumeratePathContents(entry.path.getBuffer(), - [](SlangPathType pathType, const char* name, void* userData) -> void { + fileSystem->enumeratePathContents( + entry.path.getBuffer(), + [](SlangPathType pathType, const char* name, void* userData) -> void + { Context* context = reinterpret_cast(userData); const String path = Path::simplify(Path::combine(context->path, name)); context->entries.add({pathType, path}); - }, + }, &context); } } @@ -179,14 +192,18 @@ static SlangResult _findFileSystemContents(ISlangFileSystemExt* fileSystem, cons return SLANG_OK; } -/* This function takes a compile results file system, and finds items that should be written out. +/* This function takes a compile results file system, and finds items that should be written out. -This is somewhat complicated because the names of products from different compilations might have the same names. -So a "prefix" is passed in, and for files that don't have unique names, they are uniqified via the prefix. +This is somewhat complicated because the names of products from different compilations might have +the same names. So a "prefix" is passed in, and for files that don't have unique names, they are +uniqified via the prefix. -The same product may appear in multiple compilations, for example obfuscated source maps so a product is not added -if there is already a product with the same name */ -static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const char* prefix, List& ioProducts) +The same product may appear in multiple compilations, for example obfuscated source maps so a +product is not added if there is already a product with the same name */ +static SlangResult _addCompileProducts( + ISlangFileSystemExt* fileSystem, + const char* prefix, + List& ioProducts) { List fileSystemEntries; SLANG_RETURN_ON_FAIL(_findFileSystemContents(fileSystem, ".", fileSystemEntries)); @@ -201,17 +218,18 @@ static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const ch const auto ext = Path::getPathExt(fileSystemEntry.path); String outFileName; - + // Some filenames need special handling, and their names are already unique - // Others will be the same between differen fileSystem that represent the - // compilation products. + // Others will be the same between differen fileSystem that represent the + // compilation products. // // Source maps that are obfuscated are unique. { String inFileName = Path::getFileNameWithoutExt(fileSystemEntry.path); - + // If it's an obfuscated source map, it's name is already unique (it includes the hash) - const bool isUniqueName = (ext == toSlice("map") && inFileName.endsWith(toSlice("-obfuscated"))); + const bool isUniqueName = + (ext == toSlice("map") && inFileName.endsWith(toSlice("-obfuscated"))); StringBuilder buf; // If it's not a uniquename make it unique via the prefix @@ -224,20 +242,21 @@ static SlangResult _addCompileProducts(ISlangFileSystemExt* fileSystem, const ch buf << inFileName << "." << ext; outFileName = buf; } - + // If we have an output filename if (outFileName.getLength()) { // And that filename isn't already used - if (ioProducts.findFirstIndex([&](const CompileProduct& product) -> bool { - return product.fileName == outFileName; - }) < 0) + if (ioProducts.findFirstIndex( + [&](const CompileProduct& product) -> bool + { return product.fileName == outFileName; }) < 0) { ComPtr blob; - SLANG_RETURN_ON_FAIL(fileSystem->loadFile(fileSystemEntry.path.getBuffer(), blob.writeRef())); + SLANG_RETURN_ON_FAIL( + fileSystem->loadFile(fileSystemEntry.path.getBuffer(), blob.writeRef())); // Add to the results - ioProducts.add(CompileProduct{ outFileName, blob }); + ioProducts.add(CompileProduct{outFileName, blob}); } } } @@ -252,11 +271,11 @@ gfx::Result AftermathCrashExample::loadShaderProgram( ComPtr slangSession; slangSession = device->getSlangSession(); - // This is a little bit of a work around. - // + // This is a little bit of a work around. + // // We want to set some options that are only available // via processCommandLineArguments, but we need a request to be able to set them up - // The setting actually sets the parameters on the Linkage, so they will be used for the later + // The setting actually sets the parameters on the Linkage, so they will be used for the later // actual compilation { ComPtr request; @@ -264,20 +283,20 @@ gfx::Result AftermathCrashExample::loadShaderProgram( SLANG_RETURN_ON_FAIL(slangSession->createCompileRequest(request.writeRef())); // Turn on obfuscation - // + // // Turns on source map as the line directive, this will lead to an "emit source map" // and no #line directives in generated source. // // It isn't necessary to use the "source-map" line directive mode, and just use // #line directives, and have source locations to obfuscated source file directly embedded. - // + // // To do this replace the line below with // // ``` // const char* args[] = { "-obfuscate" }; // ``` - const char* args[] = { "-obfuscate", "-line-directive-mode", "source-map" }; - + const char* args[] = {"-obfuscate", "-line-directive-mode", "source-map"}; + request->processCommandLineArguments(args, SLANG_COUNT_OF(args)); // Enable debug info @@ -296,7 +315,8 @@ gfx::Result AftermathCrashExample::loadShaderProgram( SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef())); // ComPtr fragmentEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef())); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef())); // At this point we have a few different Slang API objects that represent // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. @@ -348,36 +368,53 @@ gfx::Result AftermathCrashExample::loadShaderProgram( ComPtr code; ComPtr diagnostics; - SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(vertexEntryPointIndex, targetIndex, code.writeRef(), diagnostics.writeRef())); - SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode(fragmentEntryPointIndex, targetIndex, code.writeRef(), diagnostics.writeRef())); + SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode( + vertexEntryPointIndex, + targetIndex, + code.writeRef(), + diagnostics.writeRef())); + SLANG_RETURN_ON_FAIL(linkedProgram->getEntryPointCode( + fragmentEntryPointIndex, + targetIndex, + code.writeRef(), + diagnostics.writeRef())); } { - // We want to find all the compilation products. In particular we want to get the emit source map, and the obfuscated - // source maps + // We want to find all the compilation products. In particular we want to get the emit + // source map, and the obfuscated source maps List compileProducts; - // The current mechanism for getting access to compilation products other than result blob/diagnostics is to - // return it as a compilation result "file system". + // The current mechanism for getting access to compilation products other than result + // blob/diagnostics is to return it as a compilation result "file system". ComPtr vertexFileSystem; - SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(vertexEntryPointIndex, targetIndex, vertexFileSystem.writeRef())); + SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem( + vertexEntryPointIndex, + targetIndex, + vertexFileSystem.writeRef())); ComPtr fragmentFileSystem; - SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem(fragmentEntryPointIndex, targetIndex, fragmentFileSystem.writeRef())); + SLANG_RETURN_ON_FAIL(linkedProgram->getResultAsFileSystem( + fragmentEntryPointIndex, + targetIndex, + fragmentFileSystem.writeRef())); // Add the contents of the compile result file systems into compileProducts - // Some products might appear in both file systems, so compileProducts is just the unique products. - // Additionally because some products may have the same name, we pass in a "prefix" to make the products name - // unique. + // Some products might appear in both file systems, so compileProducts is just the unique + // products. Additionally because some products may have the same name, we pass in a + // "prefix" to make the products name unique. SLANG_RETURN_ON_FAIL(_addCompileProducts(vertexFileSystem, "vertex", compileProducts)); SLANG_RETURN_ON_FAIL(_addCompileProducts(fragmentFileSystem, "fragment", compileProducts)); - // Now write all of the products out + // Now write all of the products out for (const auto& product : compileProducts) { - SLANG_RETURN_ON_FAIL(File::writeAllBytes(product.fileName, product.blob->getBufferPointer(), product.blob->getBufferSize())); + SLANG_RETURN_ON_FAIL(File::writeAllBytes( + product.fileName, + product.blob->getBufferPointer(), + product.blob->getBufferSize())); } } @@ -393,36 +430,53 @@ gfx::Result AftermathCrashExample::loadShaderProgram( return SLANG_OK; } -static void GFSDK_AFTERMATH_CALL _crashCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData) +static void GFSDK_AFTERMATH_CALL +_crashCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData) { - reinterpret_cast(userData)->onAftermathCrash(gpuCrashDump, gpuCrashDumpSize); + reinterpret_cast(userData)->onAftermathCrash( + gpuCrashDump, + gpuCrashDumpSize); } -static void GFSDK_AFTERMATH_CALL _debugInfoCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData) +static void GFSDK_AFTERMATH_CALL +_debugInfoCallback(const void* gpuCrashDump, const uint32_t gpuCrashDumpSize, void* userData) { - reinterpret_cast(userData)->onAftermathDebugInfo(gpuCrashDump, gpuCrashDumpSize); + reinterpret_cast(userData)->onAftermathDebugInfo( + gpuCrashDump, + gpuCrashDumpSize); } -static void GFSDK_AFTERMATH_CALL _crashDescriptionCallback(PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription, void* userData) +static void GFSDK_AFTERMATH_CALL _crashDescriptionCallback( + PFN_GFSDK_Aftermath_AddGpuCrashDumpDescription addDescription, + void* userData) { reinterpret_cast(userData)->onAftermathCrashDescription(addDescription); } -static void GFSDK_AFTERMATH_CALL _markerCallback(const void* marker, void* pUserData, void** resolvedMarkerData, uint32_t* markerSize) +static void GFSDK_AFTERMATH_CALL _markerCallback( + const void* marker, + void* pUserData, + void** resolvedMarkerData, + uint32_t* markerSize) { - reinterpret_cast(pUserData)->onAftermathMarker(marker, resolvedMarkerData, markerSize); + reinterpret_cast(pUserData)->onAftermathMarker( + marker, + resolvedMarkerData, + markerSize); } Slang::Result AftermathCrashExample::initialize() { // Defer shader debug information callbacks until an actual GPU crash dump // is generated. Increases memory footprint. - const uint32_t aftermathFeatureFlags = GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks; + const uint32_t aftermathFeatureFlags = + GFSDK_Aftermath_GpuCrashDumpFeatureFlags_DeferDebugInfoCallbacks; // As per docs must be called before any device is created GFSDK_Aftermath_EnableGpuCrashDumps( GFSDK_Aftermath_Version_API, - GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX | GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, + GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_DX | + GFSDK_Aftermath_GpuCrashDumpWatchedApiFlags_Vulkan, aftermathFeatureFlags, _crashCallback, _debugInfoCallback, @@ -431,14 +485,14 @@ Slang::Result AftermathCrashExample::initialize() this); // Set to a specific render API as needed. Valid values are... - // + // // * gfx::DeviceType::Default // * gfx::DeviceType::Vulkan // * gfx::DeviceType::DirectX12 // * gfx::DeviceType::DirectX11 const gfx::DeviceType deviceType = gfx::DeviceType::Default; - + initializeBase("aftermath-crash-example", 1024, 768, deviceType); auto device = getDevice(); @@ -449,14 +503,12 @@ Slang::Result AftermathCrashExample::initialize() // First, we create an input layout: // InputElementDesc inputElements[] = { - { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position) }, - { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color) }, + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)}, + {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)}, }; - auto inputLayout = gDevice->createInputLayout( - sizeof(Vertex), - &inputElements[0], - 2); - if (!inputLayout) return SLANG_FAIL; + auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2); + if (!inputLayout) + return SLANG_FAIL; // Next we allocate a vertex buffer for our pre-initialized // vertex data. @@ -466,7 +518,8 @@ Slang::Result AftermathCrashExample::initialize() vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); vertexBufferDesc.defaultState = ResourceState::VertexBuffer; m_vertexBuffer = device->createBufferResource(vertexBufferDesc, &kVertexData[0]); - if (!m_vertexBuffer) return SLANG_FAIL; + if (!m_vertexBuffer) + return SLANG_FAIL; // Now we will use our `loadShaderProgram` function to load // the code from `shaders.slang` into the graphics API. @@ -490,10 +543,12 @@ Slang::Result AftermathCrashExample::initialize() return SLANG_OK; } -void AftermathCrashExample::renderFrame(int frameBufferIndex) +void AftermathCrashExample::renderFrame(int frameBufferIndex) { - ComPtr commandBuffer = getTransientHeaps()[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, getFrameBuffers()[frameBufferIndex]); + ComPtr commandBuffer = + getTransientHeaps()[frameBufferIndex]->createCommandBuffer(); + auto renderEncoder = + commandBuffer->encodeRenderCommands(gRenderPass, getFrameBuffers()[frameBufferIndex]); gfx::Viewport viewport = {}; viewport.maxZ = 1.0f; @@ -508,9 +563,10 @@ void AftermathCrashExample::renderFrame(int frameBufferIndex) ShaderCursor rootCursor(rootObject); rootCursor["Uniforms"]["modelViewProjection"].setData( - deviceInfo.identityProjectionMatrix, sizeof(float) * 16); + deviceInfo.identityProjectionMatrix, + sizeof(float) * 16); - // We are going to extra efforts to create a shader that we know will time + // We are going to extra efforts to create a shader that we know will time // out because we *want* a GPU "crash", such we can capture via nsight aftermath. // The failCount is just a number that is large enought to make things take too long. int32_t failCount = 0x3fffffff; diff --git a/examples/platform-test/main.cpp b/examples/platform-test/main.cpp index f20a5a7165..373c15e093 100644 --- a/examples/platform-test/main.cpp +++ b/examples/platform-test/main.cpp @@ -1,6 +1,6 @@ -#include "slang.h" -#include "tools/platform/window.h" #include "examples/example-base/example-base.h" +#include "platform/window.h" +#include "slang.h" using namespace gfx; using namespace Slang; @@ -8,93 +8,105 @@ using namespace Slang; struct PlatformTest : public WindowedAppBase { -void onSizeChanged() -{ - printf("onSizeChanged\n"); -} - -void onFocus() -{ - printf("onFocus\n"); -} - -void onLostFocus() -{ - printf("onLostFocus\n"); -} - -void onKeyDown(platform::KeyEventArgs args) -{ - printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); -} - -void onKeyUp(platform::KeyEventArgs args) -{ - printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); -} - -void onKeyPress(platform::KeyEventArgs args) -{ - printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar); -} - -void onMouseMove(platform::MouseEventArgs args) -{ - printf("onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); -} - -void onMouseDown(platform::MouseEventArgs args) -{ - printf("onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); -} - -void onMouseUp(platform::MouseEventArgs args) -{ - printf("onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); -} - -void onMouseWheel(platform::MouseEventArgs args) -{ - printf("onMouseWheel(x=%d, y=%d, delta=%d, buttons=0x%02x\n", args.x, args.y, args.delta, args.buttons); -} - -Slang::Result initialize() -{ - initializeBase("platform-test", 1024, 768); - - gWindow->events.sizeChanged = [this]() { onSizeChanged(); }; - gWindow->events.focus = [this]() { onFocus(); }; - gWindow->events.lostFocus = [this]() { onLostFocus(); }; - gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; - gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; - gWindow->events.keyPress = [this](const platform::KeyEventArgs& e) { onKeyPress(e); }; - gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; - gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; - gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; - gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); }; - - return SLANG_OK; -} - -virtual void renderFrame(int frameBufferIndex) override -{ - ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - - auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); - - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - - gSwapchain->present(); -} - + void onSizeChanged() { printf("onSizeChanged\n"); } + + void onFocus() { printf("onFocus\n"); } + + void onLostFocus() { printf("onLostFocus\n"); } + + void onKeyDown(platform::KeyEventArgs args) + { + printf("onKeyDown(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); + } + + void onKeyUp(platform::KeyEventArgs args) + { + printf("okKeyUp(key=0x%02x, buttons=0x%02x)\n", (uint32_t)args.key, args.buttons); + } + + void onKeyPress(platform::KeyEventArgs args) + { + printf("onKeyPress(keyChar=0x%02x)\n", args.keyChar); + } + + void onMouseMove(platform::MouseEventArgs args) + { + printf( + "onMouseMove(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + args.x, + args.y, + args.delta, + args.buttons); + } + + void onMouseDown(platform::MouseEventArgs args) + { + printf( + "onMouseDown(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + args.x, + args.y, + args.delta, + args.buttons); + } + + void onMouseUp(platform::MouseEventArgs args) + { + printf( + "onMouseUp(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + args.x, + args.y, + args.delta, + args.buttons); + } + + void onMouseWheel(platform::MouseEventArgs args) + { + printf( + "onMouseWheel(x=%d, y=%d, delta=%d, buttons=0x%02x\n", + args.x, + args.y, + args.delta, + args.buttons); + } + + Slang::Result initialize() + { + initializeBase("platform-test", 1024, 768); + + gWindow->events.sizeChanged = [this]() { onSizeChanged(); }; + gWindow->events.focus = [this]() { onFocus(); }; + gWindow->events.lostFocus = [this]() { onLostFocus(); }; + gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; + gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + gWindow->events.keyPress = [this](const platform::KeyEventArgs& e) { onKeyPress(e); }; + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; + gWindow->events.mouseWheel = [this](const platform::MouseEventArgs& e) { onMouseWheel(e); }; + + return SLANG_OK; + } + + virtual void renderFrame(int frameBufferIndex) override + { + ComPtr commandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + + auto renderEncoder = + commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + renderEncoder->setViewportAndScissor(viewport); + + renderEncoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + + gSwapchain->present(); + } }; // This macro instantiates an appropriate main function to diff --git a/examples/ray-tracing-pipeline/main.cpp b/examples/ray-tracing-pipeline/main.cpp index 562eca4dc8..1e55c7eb13 100644 --- a/examples/ray-tracing-pipeline/main.cpp +++ b/examples/ray-tracing-pipeline/main.cpp @@ -3,14 +3,14 @@ // This file implements an example of hardware ray-tracing using // Slang shaders and the `gfx` graphics API. -#include "slang.h" -#include "slang-gfx.h" +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" #include "gfx-util/shader-cursor.h" -#include "tools/platform/window.h" -#include "tools/platform/vector-math.h" +#include "platform/vector-math.h" +#include "platform/window.h" #include "slang-com-ptr.h" -#include "source/core/slang-basic.h" -#include "examples/example-base/example-base.h" +#include "slang-gfx.h" +#include "slang.h" using namespace gfx; using namespace Slang; @@ -36,8 +36,7 @@ struct Vertex // Define geometry data for our test scene. // The scene contains a floor plane, and a cube placed on top of it at the center. static const int kVertexCount = 24; -static const Vertex kVertexData[kVertexCount] = -{ +static const Vertex kVertexData[kVertexCount] = { // Floor plane {{-100.0f, 0, 100.0f}}, {{100.0f, 0, 100.0f}}, @@ -70,15 +69,9 @@ static const Vertex kVertexData[kVertexCount] = {{1.0f, 0.0, -1.0f}}, }; static const int kIndexCount = 36; -static const int kIndexData[kIndexCount] = -{ - 0, 1, 2, 0, 2, 3, - 4, 5, 6, 4, 6, 7, - 8, 9, 10, 8, 10, 11, - 12, 13, 14, 12, 14, 15, - 16, 17, 18, 16, 18, 19, - 20, 21, 22, 20, 22, 23 -}; +static const int kIndexData[kIndexCount] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, + 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, + 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23}; struct Primitive { @@ -86,8 +79,7 @@ struct Primitive float color[4]; }; static const int kPrimitiveCount = 12; -static const Primitive kPrimitiveData[kPrimitiveCount] = -{ +static const Primitive kPrimitiveData[kPrimitiveCount] = { {{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}}, {{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}}, {{0.0f, 1.0f, 0.0f, 0.0f}, {0.95f, 0.85f, 0.05f, 1.0f}}, @@ -134,559 +126,584 @@ struct RayTracing : public WindowedAppBase { -Uniforms gUniforms = {}; + Uniforms gUniforms = {}; -// Many Slang API functions return detailed diagnostic information -// (error messages, warnings, etc.) as a "blob" of data, or return -// a null blob pointer instead if there were no issues. -// -// For convenience, we define a subroutine that will dump the information -// in a diagnostic blob if one is produced, and skip it otherwise. -// -void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) -{ - if( diagnosticsBlob != nullptr ) + // Many Slang API functions return detailed diagnostic information + // (error messages, warnings, etc.) as a "blob" of data, or return + // a null blob pointer instead if there were no issues. + // + // For convenience, we define a subroutine that will dump the information + // in a diagnostic blob if one is produced, and skip it otherwise. + // + void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) { - printf("%s", (const char*) diagnosticsBlob->getBufferPointer()); + if (diagnosticsBlob != nullptr) + { + printf("%s", (const char*)diagnosticsBlob->getBufferPointer()); #ifdef _WIN32 - _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer()); + _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer()); #endif + } } -} -// Load and compile shader code from souce. -gfx::Result loadShaderProgram( - gfx::IDevice* device, bool isRayTracingPipeline, gfx::IShaderProgram** outProgram) -{ - ComPtr slangSession; - slangSession = device->getSlangSession(); - - ComPtr diagnosticsBlob; - Slang::String path = resourceBase.resolveResource("shaders.slang"); - slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if(!module) - return SLANG_FAIL; - - Slang::List componentTypes; - componentTypes.add(module); - if (isRayTracingPipeline) + // Load and compile shader code from souce. + gfx::Result loadShaderProgram( + gfx::IDevice* device, + bool isRayTracingPipeline, + gfx::IShaderProgram** outProgram) { - ComPtr entryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("rayGenShader", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShader", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName("closestHitShader", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL( - module->findEntryPointByName("shadowRayHitShader", entryPoint.writeRef())); - componentTypes.add(entryPoint); - } - else - { - ComPtr entryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", entryPoint.writeRef())); - componentTypes.add(entryPoint); - } - - ComPtr linkedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - linkedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); + ComPtr slangSession; + slangSession = device->getSlangSession(); + + ComPtr diagnosticsBlob; + Slang::String path = resourceBase.resolveResource("shaders.slang"); + slang::IModule* module = + slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; - if (isTestMode()) - { - printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); + Slang::List componentTypes; + componentTypes.add(module); + if (isRayTracingPipeline) + { + ComPtr entryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("rayGenShader", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("missShader", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("closestHitShader", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("shadowRayHitShader", entryPoint.writeRef())); + componentTypes.add(entryPoint); + } + else + { + ComPtr entryPoint; + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("fragmentMain", entryPoint.writeRef())); + componentTypes.add(entryPoint); + } + + ComPtr linkedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + linkedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + if (isTestMode()) + { + printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); + } + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram; + SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + + return SLANG_OK; } - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); - - return SLANG_OK; -} - -ComPtr gPresentPipelineState; -ComPtr gRenderPipelineState; -ComPtr gFullScreenVertexBuffer; -ComPtr gVertexBuffer; -ComPtr gIndexBuffer; -ComPtr gPrimitiveBuffer; -ComPtr gTransformBuffer; -ComPtr gPrimitiveBufferSRV; -ComPtr gInstanceBuffer; -ComPtr gBLASBuffer; -ComPtr gBLAS; -ComPtr gTLASBuffer; -ComPtr gTLAS; -ComPtr gResultTexture; -ComPtr gResultTextureUAV; -ComPtr gShaderTable; - -uint64_t lastTime = 0; - -// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); -// glm::vec3 lightColor = glm::vec3(1, 1, 1); - -glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f); -float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi). - -float translationScale = 0.5f; -float rotationScale = 0.01f; - -// In order to control camera movement, we will -// use good old WASD -bool wPressed = false; -bool aPressed = false; -bool sPressed = false; -bool dPressed = false; - -bool isMouseDown = false; -float lastMouseX = 0.0f; -float lastMouseY = 0.0f; - -void setKeyState(platform::KeyCode key, bool state) -{ - switch (key) + ComPtr gPresentPipelineState; + ComPtr gRenderPipelineState; + ComPtr gFullScreenVertexBuffer; + ComPtr gVertexBuffer; + ComPtr gIndexBuffer; + ComPtr gPrimitiveBuffer; + ComPtr gTransformBuffer; + ComPtr gPrimitiveBufferSRV; + ComPtr gInstanceBuffer; + ComPtr gBLASBuffer; + ComPtr gBLAS; + ComPtr gTLASBuffer; + ComPtr gTLAS; + ComPtr gResultTexture; + ComPtr gResultTextureUAV; + ComPtr gShaderTable; + + uint64_t lastTime = 0; + + // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); + // glm::vec3 lightColor = glm::vec3(1, 1, 1); + + glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f); + float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi). + + float translationScale = 0.5f; + float rotationScale = 0.01f; + + // In order to control camera movement, we will + // use good old WASD + bool wPressed = false; + bool aPressed = false; + bool sPressed = false; + bool dPressed = false; + + bool isMouseDown = false; + float lastMouseX = 0.0f; + float lastMouseY = 0.0f; + + void setKeyState(platform::KeyCode key, bool state) { - default: - break; - case platform::KeyCode::W: - wPressed = state; - break; - case platform::KeyCode::A: - aPressed = state; - break; - case platform::KeyCode::S: - sPressed = state; - break; - case platform::KeyCode::D: - dPressed = state; - break; + switch (key) + { + default: + break; + case platform::KeyCode::W: + wPressed = state; + break; + case platform::KeyCode::A: + aPressed = state; + break; + case platform::KeyCode::S: + sPressed = state; + break; + case platform::KeyCode::D: + dPressed = state; + break; + } } -} -void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } -void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } - -void onMouseDown(platform::MouseEventArgs args) -{ - isMouseDown = true; - lastMouseX = (float)args.x; - lastMouseY = (float)args.y; -} + void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } + void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } -void onMouseMove(platform::MouseEventArgs args) -{ - if (isMouseDown) + void onMouseDown(platform::MouseEventArgs args) { - float deltaX = args.x - lastMouseX; - float deltaY = args.y - lastMouseY; - - cameraOrientationAngles[0] += -deltaX * rotationScale; - cameraOrientationAngles[1] += -deltaY * rotationScale; + isMouseDown = true; lastMouseX = (float)args.x; lastMouseY = (float)args.y; } -} -void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; } -Slang::Result initialize() -{ - initializeBase("Ray Tracing Pipeline", 1024, 768); - if (!isTestMode()) + void onMouseMove(platform::MouseEventArgs args) { - gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; - gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; - gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; - gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; - gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + if (isMouseDown) + { + float deltaX = args.x - lastMouseX; + float deltaY = args.y - lastMouseY; + + cameraOrientationAngles[0] += -deltaX * rotationScale; + cameraOrientationAngles[1] += -deltaY * rotationScale; + lastMouseX = (float)args.x; + lastMouseY = (float)args.y; + } } + void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; } - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::ShaderResource; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); - if(!gVertexBuffer) return SLANG_FAIL; - - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); - indexBufferDesc.defaultState = ResourceState::ShaderResource; - gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); - if (!gIndexBuffer) - return SLANG_FAIL; - - IBufferResource::Desc primitiveBufferDesc; - primitiveBufferDesc.type = IResource::Type::Buffer; - primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); - primitiveBufferDesc.elementSize = sizeof(Primitive); - primitiveBufferDesc.defaultState = ResourceState::ShaderResource; - gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); - if (!gPrimitiveBuffer) - return SLANG_FAIL; - - IResourceView::Desc primitiveSRVDesc = {}; - primitiveSRVDesc.format = Format::Unknown; - primitiveSRVDesc.type = IResourceView::Type::ShaderResource; - gPrimitiveBufferSRV = gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); - - IBufferResource::Desc transformBufferDesc; - transformBufferDesc.type = IResource::Type::Buffer; - transformBufferDesc.sizeInBytes = sizeof(float) * 12; - transformBufferDesc.defaultState = ResourceState::ShaderResource; - float transformData[12] = { - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); - if (!gTransformBuffer) - return SLANG_FAIL; - // Build bottom level acceleration structure. + Slang::Result initialize() { - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; - accelerationStructureBuildInputs.flags = - IAccelerationStructure::BuildFlags::AllowCompaction; - IAccelerationStructure::GeometryDesc geomDesc; - geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; - geomDesc.type = IAccelerationStructure::GeometryType::Triangles; - geomDesc.content.triangles.indexCount = kIndexCount; - geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); - geomDesc.content.triangles.indexFormat = Format::R32_UINT; - geomDesc.content.triangles.vertexCount = kVertexCount; - geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); - geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; - geomDesc.content.triangles.vertexStride = sizeof(Vertex); - geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); - accelerationStructureBuildInputs.geometryDescs = &geomDesc; - - // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - // Allocate buffers for acceleration structure. - IBufferResource::Desc asDraftBufferDesc; - asDraftBufferDesc.type = IResource::Type::Buffer; - asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; - asDraftBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - ComPtr draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr scratchBuffer = gDevice->createBufferResource(scratchBufferDesc); - - // Build acceleration structure. - ComPtr compactedSizeQuery; - IQueryPool::Desc queryPoolDesc; - queryPoolDesc.count = 1; - queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; - SLANG_RETURN_ON_FAIL( - gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); - - ComPtr draftAS; - IAccelerationStructure::CreateDesc draftCreateDesc; - draftCreateDesc.buffer = draftBuffer; - draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; - draftCreateDesc.offset = 0; - draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; - SLANG_RETURN_ON_FAIL( - gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); - - compactedSizeQuery->reset(); - - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = draftAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; - compactedSizeQueryDesc.queryPool = compactedSizeQuery; - compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; - encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - - uint64_t compactedSize = 0; - compactedSizeQuery->getResult(0, 1, &compactedSize); - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)compactedSize; - gBLASBuffer = gDevice->createBufferResource(asBufferDesc); - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gBLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::BottomLevel; - createDesc.offset = 0; - createDesc.size = (size_t)compactedSize; - gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); - - commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - encoder = commandBuffer->encodeRayTracingCommands(); - encoder->copyAccelerationStructure(gBLAS, draftAS, AccelerationStructureCopyMode::Compact); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - } + initializeBase("Ray Tracing Pipeline", 1024, 768); + if (!isTestMode()) + { + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) + { onMouseMove(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) + { onMouseDown(e); }; + gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; + gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + } + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::ShaderResource; + gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + if (!gVertexBuffer) + return SLANG_FAIL; - // Build top level acceleration structure. - { - List instanceDescs; - instanceDescs.setCount(1); - instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); - instanceDescs[0].flags = - IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; - instanceDescs[0].instanceContributionToHitGroupIndex = 0; - instanceDescs[0].instanceID = 0; - instanceDescs[0].instanceMask = 0xFF; - float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); - - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = - instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); - instanceBufferDesc.defaultState = ResourceState::ShaderResource; - gInstanceBuffer = gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); - if (!gInstanceBuffer) + IBufferResource::Desc indexBufferDesc; + indexBufferDesc.type = IResource::Type::Buffer; + indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); + indexBufferDesc.defaultState = ResourceState::ShaderResource; + gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); + if (!gIndexBuffer) return SLANG_FAIL; - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; - accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); - - // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - gTLASBuffer = gDevice->createBufferResource(asBufferDesc); - - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr scratchBuffer = gDevice->createBufferResource(scratchBufferDesc); - - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gTLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::TopLevel; - createDesc.offset = 0; - createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; - SLANG_RETURN_ON_FAIL(gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); - - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = gTLAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - encoder->buildAccelerationStructure(buildDesc, 0, nullptr); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - } + IBufferResource::Desc primitiveBufferDesc; + primitiveBufferDesc.type = IResource::Type::Buffer; + primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); + primitiveBufferDesc.elementSize = sizeof(Primitive); + primitiveBufferDesc.defaultState = ResourceState::ShaderResource; + gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); + if (!gPrimitiveBuffer) + return SLANG_FAIL; - IBufferResource::Desc fullScreenVertexBufferDesc; - fullScreenVertexBufferDesc.type = IResource::Type::Buffer; - fullScreenVertexBufferDesc.sizeInBytes = - FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); - fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gFullScreenVertexBuffer = gDevice->createBufferResource( - fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]); - if (!gFullScreenVertexBuffer) - return SLANG_FAIL; - - InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, - }; - auto inputLayout = gDevice->createInputLayout(sizeof(FullScreenTriangle::Vertex), &inputElements[0], SLANG_COUNT_OF(inputElements)); - if (!inputLayout) - return SLANG_FAIL; - - ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); - GraphicsPipelineStateDesc desc; - desc.inputLayout = inputLayout; - desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); - if (!gPresentPipelineState) - return SLANG_FAIL; - - const char* hitgroupNames[] = {"hitgroup0", "hitgroup1"}; - - ComPtr rayTracingProgram; - SLANG_RETURN_ON_FAIL( - loadShaderProgram(gDevice, true, rayTracingProgram.writeRef())); - RayTracingPipelineStateDesc rtpDesc = {}; - rtpDesc.program = rayTracingProgram; - rtpDesc.hitGroupCount = 2; - HitGroupDesc hitGroups[2]; - hitGroups[0].closestHitEntryPoint = "closestHitShader"; - hitGroups[0].hitGroupName = hitgroupNames[0]; - hitGroups[1].closestHitEntryPoint = "shadowRayHitShader"; - hitGroups[1].hitGroupName = hitgroupNames[1]; - rtpDesc.hitGroups = hitGroups; - rtpDesc.maxRayPayloadSize = 64; - rtpDesc.maxRecursion = 2; - SLANG_RETURN_ON_FAIL( - gDevice->createRayTracingPipelineState(rtpDesc, gRenderPipelineState.writeRef())); - if (!gRenderPipelineState) - return SLANG_FAIL; - - IShaderTable::Desc shaderTableDesc = {}; - const char* raygenName = "rayGenShader"; - const char* missName = "missShader"; - shaderTableDesc.program = rayTracingProgram; - shaderTableDesc.hitGroupCount = 2; - shaderTableDesc.hitGroupNames = hitgroupNames; - shaderTableDesc.rayGenShaderCount = 1; - shaderTableDesc.rayGenShaderEntryPointNames = &raygenName; - shaderTableDesc.missShaderCount = 1; - shaderTableDesc.missShaderEntryPointNames = &missName; - SLANG_RETURN_ON_FAIL(gDevice->createShaderTable(shaderTableDesc, gShaderTable.writeRef())); - - createResultTexture(); - return SLANG_OK; -} - -void createResultTexture() -{ - ITextureResource::Desc resultTextureDesc = {}; - resultTextureDesc.type = IResource::Type::Texture2D; - resultTextureDesc.numMipLevels = 1; - resultTextureDesc.size.width = windowWidth; - resultTextureDesc.size.height = windowHeight; - resultTextureDesc.size.depth = 1; - resultTextureDesc.defaultState = ResourceState::UnorderedAccess; - resultTextureDesc.format = Format::R16G16B16A16_FLOAT; - gResultTexture = gDevice->createTextureResource(resultTextureDesc); - IResourceView::Desc resultUAVDesc = {}; - resultUAVDesc.format = resultTextureDesc.format; - resultUAVDesc.type = IResourceView::Type::UnorderedAccess; - gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); -} - -virtual void windowSizeChanged() override -{ - WindowedAppBase::windowSizeChanged(); - createResultTexture(); -} + IResourceView::Desc primitiveSRVDesc = {}; + primitiveSRVDesc.format = Format::Unknown; + primitiveSRVDesc.type = IResourceView::Type::ShaderResource; + gPrimitiveBufferSRV = + gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); + + IBufferResource::Desc transformBufferDesc; + transformBufferDesc.type = IResource::Type::Buffer; + transformBufferDesc.sizeInBytes = sizeof(float) * 12; + transformBufferDesc.defaultState = ResourceState::ShaderResource; + float transformData[12] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); + if (!gTransformBuffer) + return SLANG_FAIL; + // Build bottom level acceleration structure. + { + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; + accelerationStructureBuildInputs.flags = + IAccelerationStructure::BuildFlags::AllowCompaction; + IAccelerationStructure::GeometryDesc geomDesc; + geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; + geomDesc.type = IAccelerationStructure::GeometryType::Triangles; + geomDesc.content.triangles.indexCount = kIndexCount; + geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); + geomDesc.content.triangles.indexFormat = Format::R32_UINT; + geomDesc.content.triangles.vertexCount = kVertexCount; + geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); + geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; + geomDesc.content.triangles.vertexStride = sizeof(Vertex); + geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); + accelerationStructureBuildInputs.geometryDescs = &geomDesc; + + // Query buffer size for acceleration structure build. + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + // Allocate buffers for acceleration structure. + IBufferResource::Desc asDraftBufferDesc; + asDraftBufferDesc.type = IResource::Type::Buffer; + asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; + asDraftBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + ComPtr draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr scratchBuffer = + gDevice->createBufferResource(scratchBufferDesc); + + // Build acceleration structure. + ComPtr compactedSizeQuery; + IQueryPool::Desc queryPoolDesc; + queryPoolDesc.count = 1; + queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; + SLANG_RETURN_ON_FAIL( + gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); + + ComPtr draftAS; + IAccelerationStructure::CreateDesc draftCreateDesc; + draftCreateDesc.buffer = draftBuffer; + draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; + draftCreateDesc.offset = 0; + draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + SLANG_RETURN_ON_FAIL( + gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); + + compactedSizeQuery->reset(); + + auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = draftAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; + compactedSizeQueryDesc.queryPool = compactedSizeQuery; + compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; + encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + + uint64_t compactedSize = 0; + compactedSizeQuery->getResult(0, 1, &compactedSize); + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = (size_t)compactedSize; + gBLASBuffer = gDevice->createBufferResource(asBufferDesc); + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = gBLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::BottomLevel; + createDesc.offset = 0; + createDesc.size = (size_t)compactedSize; + gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); + + commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + encoder = commandBuffer->encodeRayTracingCommands(); + encoder->copyAccelerationStructure( + gBLAS, + draftAS, + AccelerationStructureCopyMode::Compact); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + } + + // Build top level acceleration structure. + { + List instanceDescs; + instanceDescs.setCount(1); + instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); + instanceDescs[0].flags = + IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; + instanceDescs[0].instanceContributionToHitGroupIndex = 0; + instanceDescs[0].instanceID = 0; + instanceDescs[0].instanceMask = 0xFF; + float transformMatrix[] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); + + IBufferResource::Desc instanceBufferDesc; + instanceBufferDesc.type = IResource::Type::Buffer; + instanceBufferDesc.sizeInBytes = + instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); + instanceBufferDesc.defaultState = ResourceState::ShaderResource; + gInstanceBuffer = + gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); + if (!gInstanceBuffer) + return SLANG_FAIL; + + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; + accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); + + // Query buffer size for acceleration structure build. + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + gTLASBuffer = gDevice->createBufferResource(asBufferDesc); + + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = + (size_t)accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr scratchBuffer = + gDevice->createBufferResource(scratchBufferDesc); + + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = gTLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::TopLevel; + createDesc.offset = 0; + createDesc.size = (size_t)accelerationStructurePrebuildInfo.resultDataMaxSize; + SLANG_RETURN_ON_FAIL( + gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); + + auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = gTLAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + encoder->buildAccelerationStructure(buildDesc, 0, nullptr); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + } + + IBufferResource::Desc fullScreenVertexBufferDesc; + fullScreenVertexBufferDesc.type = IResource::Type::Buffer; + fullScreenVertexBufferDesc.sizeInBytes = + FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); + fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; + gFullScreenVertexBuffer = gDevice->createBufferResource( + fullScreenVertexBufferDesc, + &FullScreenTriangle::kVertices[0]); + if (!gFullScreenVertexBuffer) + return SLANG_FAIL; -glm::vec3 getVectorFromSphericalAngles(float theta, float phi) -{ - auto sinTheta = sin(theta); - auto cosTheta = cos(theta); - auto sinPhi = sin(phi); - auto cosPhi = cos(phi); - return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi); -} -void updateUniforms() -{ - gUniforms.screenWidth = (float)windowWidth; - gUniforms.screenHeight = (float)windowHeight; - if (!lastTime) - lastTime = getCurrentTime(); - uint64_t currentTime = getCurrentTime(); - float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); - lastTime = currentTime; - - auto camDir = - getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]); - auto camUp = getVectorFromSphericalAngles( - cameraOrientationAngles[0], cameraOrientationAngles[1] + glm::pi() * 0.5f); - auto camRight = glm::cross(camDir, camUp); - - glm::vec3 movement = glm::vec3(0); - if (wPressed) - movement += camDir; - if (sPressed) - movement -= camDir; - if (aPressed) - movement -= camRight; - if (dPressed) - movement += camRight; - - cameraPosition += deltaTime * translationScale * movement; - - memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3); - memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3); - memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3); - memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3); - auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f)); - memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); -} - -virtual void renderFrame(int frameBufferIndex) override -{ - updateUniforms(); + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + }; + auto inputLayout = gDevice->createInputLayout( + sizeof(FullScreenTriangle::Vertex), + &inputElements[0], + SLANG_COUNT_OF(inputElements)); + if (!inputLayout) + return SLANG_FAIL; + + ComPtr shaderProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); + GraphicsPipelineStateDesc desc; + desc.inputLayout = inputLayout; + desc.program = shaderProgram; + desc.framebufferLayout = gFramebufferLayout; + gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); + if (!gPresentPipelineState) + return SLANG_FAIL; + + const char* hitgroupNames[] = {"hitgroup0", "hitgroup1"}; + + ComPtr rayTracingProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, rayTracingProgram.writeRef())); + RayTracingPipelineStateDesc rtpDesc = {}; + rtpDesc.program = rayTracingProgram; + rtpDesc.hitGroupCount = 2; + HitGroupDesc hitGroups[2]; + hitGroups[0].closestHitEntryPoint = "closestHitShader"; + hitGroups[0].hitGroupName = hitgroupNames[0]; + hitGroups[1].closestHitEntryPoint = "shadowRayHitShader"; + hitGroups[1].hitGroupName = hitgroupNames[1]; + rtpDesc.hitGroups = hitGroups; + rtpDesc.maxRayPayloadSize = 64; + rtpDesc.maxRecursion = 2; + SLANG_RETURN_ON_FAIL( + gDevice->createRayTracingPipelineState(rtpDesc, gRenderPipelineState.writeRef())); + if (!gRenderPipelineState) + return SLANG_FAIL; + + IShaderTable::Desc shaderTableDesc = {}; + const char* raygenName = "rayGenShader"; + const char* missName = "missShader"; + shaderTableDesc.program = rayTracingProgram; + shaderTableDesc.hitGroupCount = 2; + shaderTableDesc.hitGroupNames = hitgroupNames; + shaderTableDesc.rayGenShaderCount = 1; + shaderTableDesc.rayGenShaderEntryPointNames = &raygenName; + shaderTableDesc.missShaderCount = 1; + shaderTableDesc.missShaderEntryPointNames = &missName; + SLANG_RETURN_ON_FAIL(gDevice->createShaderTable(shaderTableDesc, gShaderTable.writeRef())); + + createResultTexture(); + return SLANG_OK; + } + + void createResultTexture() { - ComPtr renderCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); - IShaderObject* rootObject = nullptr; - renderEncoder->bindPipeline(gRenderPipelineState, &rootObject); - auto cursor = ShaderCursor(rootObject); - cursor["resultTexture"].setResource(gResultTextureUAV); - cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); - cursor["sceneBVH"].setResource(gTLAS); - cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); - renderEncoder->dispatchRays(0, gShaderTable, windowWidth, windowHeight, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - gQueue->executeCommandBuffer(renderCommandBuffer); + ITextureResource::Desc resultTextureDesc = {}; + resultTextureDesc.type = IResource::Type::Texture2D; + resultTextureDesc.numMipLevels = 1; + resultTextureDesc.size.width = windowWidth; + resultTextureDesc.size.height = windowHeight; + resultTextureDesc.size.depth = 1; + resultTextureDesc.defaultState = ResourceState::UnorderedAccess; + resultTextureDesc.format = Format::R16G16B16A16_FLOAT; + gResultTexture = gDevice->createTextureResource(resultTextureDesc); + IResourceView::Desc resultUAVDesc = {}; + resultUAVDesc.format = resultTextureDesc.format; + resultUAVDesc.type = IResourceView::Type::UnorderedAccess; + gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); } + virtual void windowSizeChanged() override { - ComPtr presentCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto presentEncoder = presentCommandBuffer->encodeRenderCommands( - gRenderPass, gFramebuffers[frameBufferIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - presentEncoder->setViewportAndScissor(viewport); - auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); - cursor["t"].setResource(gResultTextureUAV); - presentEncoder->setVertexBuffer( - 0, gFullScreenVertexBuffer); - presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - presentEncoder->draw(3); - presentEncoder->endEncoding(); - presentCommandBuffer->close(); - gQueue->executeCommandBuffer(presentCommandBuffer); + WindowedAppBase::windowSizeChanged(); + createResultTexture(); } - if (!isTestMode()) + glm::vec3 getVectorFromSphericalAngles(float theta, float phi) { - // With that, we are done drawing for one frame, and ready for the next. - // - gSwapchain->present(); + auto sinTheta = sin(theta); + auto cosTheta = cos(theta); + auto sinPhi = sin(phi); + auto cosPhi = cos(phi); + return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi); + } + void updateUniforms() + { + gUniforms.screenWidth = (float)windowWidth; + gUniforms.screenHeight = (float)windowHeight; + if (!lastTime) + lastTime = getCurrentTime(); + uint64_t currentTime = getCurrentTime(); + float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); + lastTime = currentTime; + + auto camDir = + getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]); + auto camUp = getVectorFromSphericalAngles( + cameraOrientationAngles[0], + cameraOrientationAngles[1] + glm::pi() * 0.5f); + auto camRight = glm::cross(camDir, camUp); + + glm::vec3 movement = glm::vec3(0); + if (wPressed) + movement += camDir; + if (sPressed) + movement -= camDir; + if (aPressed) + movement -= camRight; + if (dPressed) + movement += camRight; + + cameraPosition += deltaTime * translationScale * movement; + + memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3); + memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3); + memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3); + memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3); + auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f)); + memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); } -} + virtual void renderFrame(int frameBufferIndex) override + { + updateUniforms(); + { + ComPtr renderCommandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + auto renderEncoder = renderCommandBuffer->encodeRayTracingCommands(); + IShaderObject* rootObject = nullptr; + renderEncoder->bindPipeline(gRenderPipelineState, &rootObject); + auto cursor = ShaderCursor(rootObject); + cursor["resultTexture"].setResource(gResultTextureUAV); + cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); + cursor["sceneBVH"].setResource(gTLAS); + cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); + renderEncoder->dispatchRays(0, gShaderTable, windowWidth, windowHeight, 1); + renderEncoder->endEncoding(); + renderCommandBuffer->close(); + gQueue->executeCommandBuffer(renderCommandBuffer); + } + + { + ComPtr presentCommandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + auto presentEncoder = presentCommandBuffer->encodeRenderCommands( + gRenderPass, + gFramebuffers[frameBufferIndex]); + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + presentEncoder->setViewportAndScissor(viewport); + auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); + auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); + cursor["t"].setResource(gResultTextureUAV); + presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer); + presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + presentEncoder->draw(3); + presentEncoder->endEncoding(); + presentCommandBuffer->close(); + gQueue->executeCommandBuffer(presentCommandBuffer); + } + + if (!isTestMode()) + { + // With that, we are done drawing for one frame, and ready for the next. + // + gSwapchain->present(); + } + } }; // This macro instantiates an appropriate main function to diff --git a/examples/ray-tracing/main.cpp b/examples/ray-tracing/main.cpp index 4ec5070d84..7878550f85 100644 --- a/examples/ray-tracing/main.cpp +++ b/examples/ray-tracing/main.cpp @@ -3,14 +3,14 @@ // This file implements an example of hardware ray-tracing using // Slang shaders and the `gfx` graphics API. -#include "slang.h" -#include "slang-gfx.h" +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" #include "gfx-util/shader-cursor.h" -#include "tools/platform/window.h" -#include "tools/platform/vector-math.h" +#include "platform/vector-math.h" +#include "platform/window.h" #include "slang-com-ptr.h" -#include "source/core/slang-basic.h" -#include "examples/example-base/example-base.h" +#include "slang-gfx.h" +#include "slang.h" using namespace gfx; using namespace Slang; @@ -36,8 +36,7 @@ struct Vertex // Define geometry data for our test scene. // The scene contains a floor plane, and a cube placed on top of it at the center. static const int kVertexCount = 24; -static const Vertex kVertexData[kVertexCount] = -{ +static const Vertex kVertexData[kVertexCount] = { // Floor plane {{-100.0f, 0, 100.0f}}, {{100.0f, 0, 100.0f}}, @@ -70,15 +69,9 @@ static const Vertex kVertexData[kVertexCount] = {{1.0f, 0.0, -1.0f}}, }; static const int kIndexCount = 36; -static const int kIndexData[kIndexCount] = -{ - 0, 1, 2, 0, 2, 3, - 4, 5, 6, 4, 6, 7, - 8, 9, 10, 8, 10, 11, - 12, 13, 14, 12, 14, 15, - 16, 17, 18, 16, 18, 19, - 20, 21, 22, 20, 22, 23 -}; +static const int kIndexData[kIndexCount] = {0, 1, 2, 0, 2, 3, 4, 5, 6, 4, 6, 7, + 8, 9, 10, 8, 10, 11, 12, 13, 14, 12, 14, 15, + 16, 17, 18, 16, 18, 19, 20, 21, 22, 20, 22, 23}; struct Primitive { @@ -86,8 +79,7 @@ struct Primitive float color[4]; }; static const int kPrimitiveCount = 12; -static const Primitive kPrimitiveData[kPrimitiveCount] = -{ +static const Primitive kPrimitiveData[kPrimitiveCount] = { {{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}}, {{0.0f, 1.0f, 0.0f, 0.0f}, {0.75f, 0.8f, 0.85f, 1.0f}}, {{0.0f, 1.0f, 0.0f, 0.0f}, {0.95f, 0.85f, 0.05f, 1.0f}}, @@ -134,525 +126,548 @@ struct RayTracing : public WindowedAppBase { -Uniforms gUniforms = {}; + Uniforms gUniforms = {}; -// Many Slang API functions return detailed diagnostic information -// (error messages, warnings, etc.) as a "blob" of data, or return -// a null blob pointer instead if there were no issues. -// -// For convenience, we define a subroutine that will dump the information -// in a diagnostic blob if one is produced, and skip it otherwise. -// -void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) -{ - if( diagnosticsBlob != nullptr ) + // Many Slang API functions return detailed diagnostic information + // (error messages, warnings, etc.) as a "blob" of data, or return + // a null blob pointer instead if there were no issues. + // + // For convenience, we define a subroutine that will dump the information + // in a diagnostic blob if one is produced, and skip it otherwise. + // + void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) { - printf("%s", (const char*) diagnosticsBlob->getBufferPointer()); + if (diagnosticsBlob != nullptr) + { + printf("%s", (const char*)diagnosticsBlob->getBufferPointer()); #ifdef _WIN32 - _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer()); + _Win32OutputDebugString((const char*)diagnosticsBlob->getBufferPointer()); #endif + } } -} -// Load and compile shader code from souce. -gfx::Result loadShaderProgram( - gfx::IDevice* device, bool isComputePipeline, gfx::IShaderProgram** outProgram) -{ - ComPtr slangSession; - slangSession = device->getSlangSession(); - - ComPtr diagnosticsBlob; - Slang::String path = resourceBase.resolveResource("shaders.slang"); - slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if(!module) - return SLANG_FAIL; - - Slang::List componentTypes; - componentTypes.add(module); - if (isComputePipeline) - { - ComPtr computeEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); - componentTypes.add(computeEntryPoint); - } - else + // Load and compile shader code from souce. + gfx::Result loadShaderProgram( + gfx::IDevice* device, + bool isComputePipeline, + gfx::IShaderProgram** outProgram) { - ComPtr entryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef())); - componentTypes.add(entryPoint); - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", entryPoint.writeRef())); - componentTypes.add(entryPoint); - } - - ComPtr linkedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - linkedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); + ComPtr slangSession; + slangSession = device->getSlangSession(); + + ComPtr diagnosticsBlob; + Slang::String path = resourceBase.resolveResource("shaders.slang"); + slang::IModule* module = + slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; - if (isTestMode()) - { - printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); + Slang::List componentTypes; + componentTypes.add(module); + if (isComputePipeline) + { + ComPtr computeEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("computeMain", computeEntryPoint.writeRef())); + componentTypes.add(computeEntryPoint); + } + else + { + ComPtr entryPoint; + SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", entryPoint.writeRef())); + componentTypes.add(entryPoint); + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("fragmentMain", entryPoint.writeRef())); + componentTypes.add(entryPoint); + } + + ComPtr linkedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + linkedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + if (isTestMode()) + { + printEntrypointHashes(componentTypes.getCount() - 1, 1, linkedProgram); + } + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram; + SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); + + return SLANG_OK; } - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); - - return SLANG_OK; -} - -ComPtr gPresentPipelineState; -ComPtr gRenderPipelineState; -ComPtr gFullScreenVertexBuffer; -ComPtr gVertexBuffer; -ComPtr gIndexBuffer; -ComPtr gPrimitiveBuffer; -ComPtr gTransformBuffer; -ComPtr gPrimitiveBufferSRV; -ComPtr gInstanceBuffer; -ComPtr gBLASBuffer; -ComPtr gBLAS; -ComPtr gTLASBuffer; -ComPtr gTLAS; -ComPtr gResultTexture; -ComPtr gResultTextureUAV; - -uint64_t lastTime = 0; - -// glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); -// glm::vec3 lightColor = glm::vec3(1, 1, 1); - -glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f); -float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi). - -float translationScale = 0.5f; -float rotationScale = 0.01f; - -// In order to control camera movement, we will -// use good old WASD -bool wPressed = false; -bool aPressed = false; -bool sPressed = false; -bool dPressed = false; - -bool isMouseDown = false; -float lastMouseX = 0.0f; -float lastMouseY = 0.0f; - -void setKeyState(platform::KeyCode key, bool state) -{ - switch (key) + ComPtr gPresentPipelineState; + ComPtr gRenderPipelineState; + ComPtr gFullScreenVertexBuffer; + ComPtr gVertexBuffer; + ComPtr gIndexBuffer; + ComPtr gPrimitiveBuffer; + ComPtr gTransformBuffer; + ComPtr gPrimitiveBufferSRV; + ComPtr gInstanceBuffer; + ComPtr gBLASBuffer; + ComPtr gBLAS; + ComPtr gTLASBuffer; + ComPtr gTLAS; + ComPtr gResultTexture; + ComPtr gResultTextureUAV; + + uint64_t lastTime = 0; + + // glm::vec3 lightDir = normalize(glm::vec3(10, 10, 10)); + // glm::vec3 lightColor = glm::vec3(1, 1, 1); + + glm::vec3 cameraPosition = glm::vec3(-2.53f, 2.72f, 4.3f); + float cameraOrientationAngles[2] = {-0.475f, -0.35f}; // Spherical angles (theta, phi). + + float translationScale = 0.5f; + float rotationScale = 0.01f; + + // In order to control camera movement, we will + // use good old WASD + bool wPressed = false; + bool aPressed = false; + bool sPressed = false; + bool dPressed = false; + + bool isMouseDown = false; + float lastMouseX = 0.0f; + float lastMouseY = 0.0f; + + void setKeyState(platform::KeyCode key, bool state) { - default: - break; - case platform::KeyCode::W: - wPressed = state; - break; - case platform::KeyCode::A: - aPressed = state; - break; - case platform::KeyCode::S: - sPressed = state; - break; - case platform::KeyCode::D: - dPressed = state; - break; + switch (key) + { + default: + break; + case platform::KeyCode::W: + wPressed = state; + break; + case platform::KeyCode::A: + aPressed = state; + break; + case platform::KeyCode::S: + sPressed = state; + break; + case platform::KeyCode::D: + dPressed = state; + break; + } } -} -void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } -void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } - -void onMouseDown(platform::MouseEventArgs args) -{ - isMouseDown = true; - lastMouseX = (float)args.x; - lastMouseY = (float)args.y; -} + void onKeyDown(platform::KeyEventArgs args) { setKeyState(args.key, true); } + void onKeyUp(platform::KeyEventArgs args) { setKeyState(args.key, false); } -void onMouseMove(platform::MouseEventArgs args) -{ - if (isMouseDown) + void onMouseDown(platform::MouseEventArgs args) { - float deltaX = args.x - lastMouseX; - float deltaY = args.y - lastMouseY; - - cameraOrientationAngles[0] += -deltaX * rotationScale; - cameraOrientationAngles[1] += -deltaY * rotationScale; + isMouseDown = true; lastMouseX = (float)args.x; lastMouseY = (float)args.y; } -} -void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; } - -Slang::Result initialize() -{ - initializeBase("Ray Tracing", 1024, 768); - if (!isTestMode()) + void onMouseMove(platform::MouseEventArgs args) { - gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { onMouseMove(e); }; - gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; - gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { onMouseDown(e); }; - gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; - gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + if (isMouseDown) + { + float deltaX = args.x - lastMouseX; + float deltaY = args.y - lastMouseY; + + cameraOrientationAngles[0] += -deltaX * rotationScale; + cameraOrientationAngles[1] += -deltaY * rotationScale; + lastMouseX = (float)args.x; + lastMouseY = (float)args.y; + } } + void onMouseUp(platform::MouseEventArgs args) { isMouseDown = false; } - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::ShaderResource; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); - if(!gVertexBuffer) return SLANG_FAIL; - - IBufferResource::Desc indexBufferDesc; - indexBufferDesc.type = IResource::Type::Buffer; - indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); - indexBufferDesc.defaultState = ResourceState::ShaderResource; - gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); - if (!gIndexBuffer) - return SLANG_FAIL; - - IBufferResource::Desc primitiveBufferDesc; - primitiveBufferDesc.type = IResource::Type::Buffer; - primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); - primitiveBufferDesc.elementSize = sizeof(Primitive); - primitiveBufferDesc.defaultState = ResourceState::ShaderResource; - gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); - if (!gPrimitiveBuffer) - return SLANG_FAIL; - - IResourceView::Desc primitiveSRVDesc = {}; - primitiveSRVDesc.format = Format::Unknown; - primitiveSRVDesc.type = IResourceView::Type::ShaderResource; - gPrimitiveBufferSRV = gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); - - IBufferResource::Desc transformBufferDesc; - transformBufferDesc.type = IResource::Type::Buffer; - transformBufferDesc.sizeInBytes = sizeof(float) * 12; - transformBufferDesc.defaultState = ResourceState::ShaderResource; - float transformData[12] = { - 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); - if (!gTransformBuffer) - return SLANG_FAIL; - // Build bottom level acceleration structure. + Slang::Result initialize() { - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; - accelerationStructureBuildInputs.flags = - IAccelerationStructure::BuildFlags::AllowCompaction; - IAccelerationStructure::GeometryDesc geomDesc; - geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; - geomDesc.type = IAccelerationStructure::GeometryType::Triangles; - geomDesc.content.triangles.indexCount = kIndexCount; - geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); - geomDesc.content.triangles.indexFormat = Format::R32_UINT; - geomDesc.content.triangles.vertexCount = kVertexCount; - geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); - geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; - geomDesc.content.triangles.vertexStride = sizeof(Vertex); - geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); - accelerationStructureBuildInputs.geometryDescs = &geomDesc; - - // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - // Allocate buffers for acceleration structure. - IBufferResource::Desc asDraftBufferDesc; - asDraftBufferDesc.type = IResource::Type::Buffer; - asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; - asDraftBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; - ComPtr draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr scratchBuffer = gDevice->createBufferResource(scratchBufferDesc); - - // Build acceleration structure. - ComPtr compactedSizeQuery; - IQueryPool::Desc queryPoolDesc; - queryPoolDesc.count = 1; - queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; - SLANG_RETURN_ON_FAIL( - gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); - - ComPtr draftAS; - IAccelerationStructure::CreateDesc draftCreateDesc; - draftCreateDesc.buffer = draftBuffer; - draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; - draftCreateDesc.offset = 0; - draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; - SLANG_RETURN_ON_FAIL( - gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); - - compactedSizeQuery->reset(); - - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = draftAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; - compactedSizeQueryDesc.queryPool = compactedSizeQuery; - compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; - encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - - uint64_t compactedSize = 0; - compactedSizeQuery->getResult(0, 1, &compactedSize); - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = (Size)compactedSize; - gBLASBuffer = gDevice->createBufferResource(asBufferDesc); - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gBLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::BottomLevel; - createDesc.offset = 0; - createDesc.size = (Size)compactedSize; - gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); - - commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - encoder = commandBuffer->encodeRayTracingCommands(); - encoder->copyAccelerationStructure(gBLAS, draftAS, AccelerationStructureCopyMode::Compact); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - } + initializeBase("Ray Tracing", 1024, 768); + + if (!isTestMode()) + { + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) + { onMouseMove(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { onMouseUp(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) + { onMouseDown(e); }; + gWindow->events.keyDown = [this](const platform::KeyEventArgs& e) { onKeyDown(e); }; + gWindow->events.keyUp = [this](const platform::KeyEventArgs& e) { onKeyUp(e); }; + } + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::ShaderResource; + gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + if (!gVertexBuffer) + return SLANG_FAIL; - // Build top level acceleration structure. - { - List instanceDescs; - instanceDescs.setCount(1); - instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); - instanceDescs[0].flags = - IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; - instanceDescs[0].instanceContributionToHitGroupIndex = 0; - instanceDescs[0].instanceID = 0; - instanceDescs[0].instanceMask = 0xFF; - float transformMatrix[] = {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; - memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); - - IBufferResource::Desc instanceBufferDesc; - instanceBufferDesc.type = IResource::Type::Buffer; - instanceBufferDesc.sizeInBytes = - instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); - instanceBufferDesc.defaultState = ResourceState::ShaderResource; - gInstanceBuffer = gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); - if (!gInstanceBuffer) + IBufferResource::Desc indexBufferDesc; + indexBufferDesc.type = IResource::Type::Buffer; + indexBufferDesc.sizeInBytes = kIndexCount * sizeof(int32_t); + indexBufferDesc.defaultState = ResourceState::ShaderResource; + gIndexBuffer = gDevice->createBufferResource(indexBufferDesc, &kIndexData[0]); + if (!gIndexBuffer) return SLANG_FAIL; - IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; - IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; - accelerationStructureBuildInputs.descCount = 1; - accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; - accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); - - // Query buffer size for acceleration structure build. - SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( - accelerationStructureBuildInputs, &accelerationStructurePrebuildInfo)); - - IBufferResource::Desc asBufferDesc; - asBufferDesc.type = IResource::Type::Buffer; - asBufferDesc.defaultState = ResourceState::AccelerationStructure; - asBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; - gTLASBuffer = gDevice->createBufferResource(asBufferDesc); - - IBufferResource::Desc scratchBufferDesc; - scratchBufferDesc.type = IResource::Type::Buffer; - scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; - scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; - ComPtr scratchBuffer = gDevice->createBufferResource(scratchBufferDesc); - - IAccelerationStructure::CreateDesc createDesc; - createDesc.buffer = gTLASBuffer; - createDesc.kind = IAccelerationStructure::Kind::TopLevel; - createDesc.offset = 0; - createDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; - SLANG_RETURN_ON_FAIL(gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); - - auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); - auto encoder = commandBuffer->encodeRayTracingCommands(); - IAccelerationStructure::BuildDesc buildDesc = {}; - buildDesc.dest = gTLAS; - buildDesc.inputs = accelerationStructureBuildInputs; - buildDesc.scratchData = scratchBuffer->getDeviceAddress(); - encoder->buildAccelerationStructure(buildDesc, 0, nullptr); - encoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); - gQueue->waitOnHost(); - } + IBufferResource::Desc primitiveBufferDesc; + primitiveBufferDesc.type = IResource::Type::Buffer; + primitiveBufferDesc.sizeInBytes = kPrimitiveCount * sizeof(Primitive); + primitiveBufferDesc.elementSize = sizeof(Primitive); + primitiveBufferDesc.defaultState = ResourceState::ShaderResource; + gPrimitiveBuffer = gDevice->createBufferResource(primitiveBufferDesc, &kPrimitiveData[0]); + if (!gPrimitiveBuffer) + return SLANG_FAIL; - IBufferResource::Desc fullScreenVertexBufferDesc; - fullScreenVertexBufferDesc.type = IResource::Type::Buffer; - fullScreenVertexBufferDesc.sizeInBytes = - FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); - fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gFullScreenVertexBuffer = gDevice->createBufferResource( - fullScreenVertexBufferDesc, &FullScreenTriangle::kVertices[0]); - if (!gFullScreenVertexBuffer) - return SLANG_FAIL; - - InputElementDesc inputElements[] = { - {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, - }; - auto inputLayout = gDevice->createInputLayout(sizeof(FullScreenTriangle::Vertex), &inputElements[0], SLANG_COUNT_OF(inputElements)); - if (!inputLayout) - return SLANG_FAIL; - - ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); - GraphicsPipelineStateDesc desc; - desc.inputLayout = inputLayout; - desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); - if (!gPresentPipelineState) - return SLANG_FAIL; - - ComPtr computeProgram; - SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, computeProgram.writeRef())); - ComputePipelineStateDesc computeDesc; - computeDesc.program = computeProgram; - gRenderPipelineState = gDevice->createComputePipelineState(computeDesc); - if (!gRenderPipelineState) - return SLANG_FAIL; - - createResultTexture(); - return SLANG_OK; -} - -void createResultTexture() -{ - ITextureResource::Desc resultTextureDesc = {}; - resultTextureDesc.type = IResource::Type::Texture2D; - resultTextureDesc.numMipLevels = 1; - resultTextureDesc.size.width = windowWidth; - resultTextureDesc.size.height = windowHeight; - resultTextureDesc.size.depth = 1; - resultTextureDesc.defaultState = ResourceState::UnorderedAccess; - resultTextureDesc.format = Format::R16G16B16A16_FLOAT; - gResultTexture = gDevice->createTextureResource(resultTextureDesc); - IResourceView::Desc resultUAVDesc = {}; - resultUAVDesc.format = resultTextureDesc.format; - resultUAVDesc.type = IResourceView::Type::UnorderedAccess; - gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); -} - -virtual void windowSizeChanged() override -{ - WindowedAppBase::windowSizeChanged(); - createResultTexture(); -} + IResourceView::Desc primitiveSRVDesc = {}; + primitiveSRVDesc.format = Format::Unknown; + primitiveSRVDesc.type = IResourceView::Type::ShaderResource; + gPrimitiveBufferSRV = + gDevice->createBufferView(gPrimitiveBuffer, nullptr, primitiveSRVDesc); + + IBufferResource::Desc transformBufferDesc; + transformBufferDesc.type = IResource::Type::Buffer; + transformBufferDesc.sizeInBytes = sizeof(float) * 12; + transformBufferDesc.defaultState = ResourceState::ShaderResource; + float transformData[12] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + gTransformBuffer = gDevice->createBufferResource(transformBufferDesc, &transformData); + if (!gTransformBuffer) + return SLANG_FAIL; + // Build bottom level acceleration structure. + { + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::BottomLevel; + accelerationStructureBuildInputs.flags = + IAccelerationStructure::BuildFlags::AllowCompaction; + IAccelerationStructure::GeometryDesc geomDesc; + geomDesc.flags = IAccelerationStructure::GeometryFlags::Opaque; + geomDesc.type = IAccelerationStructure::GeometryType::Triangles; + geomDesc.content.triangles.indexCount = kIndexCount; + geomDesc.content.triangles.indexData = gIndexBuffer->getDeviceAddress(); + geomDesc.content.triangles.indexFormat = Format::R32_UINT; + geomDesc.content.triangles.vertexCount = kVertexCount; + geomDesc.content.triangles.vertexData = gVertexBuffer->getDeviceAddress(); + geomDesc.content.triangles.vertexFormat = Format::R32G32B32_FLOAT; + geomDesc.content.triangles.vertexStride = sizeof(Vertex); + geomDesc.content.triangles.transform3x4 = gTransformBuffer->getDeviceAddress(); + accelerationStructureBuildInputs.geometryDescs = &geomDesc; + + // Query buffer size for acceleration structure build. + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + // Allocate buffers for acceleration structure. + IBufferResource::Desc asDraftBufferDesc; + asDraftBufferDesc.type = IResource::Type::Buffer; + asDraftBufferDesc.defaultState = ResourceState::AccelerationStructure; + asDraftBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; + ComPtr draftBuffer = gDevice->createBufferResource(asDraftBufferDesc); + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr scratchBuffer = + gDevice->createBufferResource(scratchBufferDesc); + + // Build acceleration structure. + ComPtr compactedSizeQuery; + IQueryPool::Desc queryPoolDesc; + queryPoolDesc.count = 1; + queryPoolDesc.type = QueryType::AccelerationStructureCompactedSize; + SLANG_RETURN_ON_FAIL( + gDevice->createQueryPool(queryPoolDesc, compactedSizeQuery.writeRef())); + + ComPtr draftAS; + IAccelerationStructure::CreateDesc draftCreateDesc; + draftCreateDesc.buffer = draftBuffer; + draftCreateDesc.kind = IAccelerationStructure::Kind::BottomLevel; + draftCreateDesc.offset = 0; + draftCreateDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + SLANG_RETURN_ON_FAIL( + gDevice->createAccelerationStructure(draftCreateDesc, draftAS.writeRef())); + + compactedSizeQuery->reset(); + + auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = draftAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + AccelerationStructureQueryDesc compactedSizeQueryDesc = {}; + compactedSizeQueryDesc.queryPool = compactedSizeQuery; + compactedSizeQueryDesc.queryType = QueryType::AccelerationStructureCompactedSize; + encoder->buildAccelerationStructure(buildDesc, 1, &compactedSizeQueryDesc); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + + uint64_t compactedSize = 0; + compactedSizeQuery->getResult(0, 1, &compactedSize); + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = (Size)compactedSize; + gBLASBuffer = gDevice->createBufferResource(asBufferDesc); + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = gBLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::BottomLevel; + createDesc.offset = 0; + createDesc.size = (Size)compactedSize; + gDevice->createAccelerationStructure(createDesc, gBLAS.writeRef()); + + commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + encoder = commandBuffer->encodeRayTracingCommands(); + encoder->copyAccelerationStructure( + gBLAS, + draftAS, + AccelerationStructureCopyMode::Compact); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + } + + // Build top level acceleration structure. + { + List instanceDescs; + instanceDescs.setCount(1); + instanceDescs[0].accelerationStructure = gBLAS->getDeviceAddress(); + instanceDescs[0].flags = + IAccelerationStructure::GeometryInstanceFlags::TriangleFacingCullDisable; + instanceDescs[0].instanceContributionToHitGroupIndex = 0; + instanceDescs[0].instanceID = 0; + instanceDescs[0].instanceMask = 0xFF; + float transformMatrix[] = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f}; + memcpy(&instanceDescs[0].transform[0][0], transformMatrix, sizeof(float) * 12); + + IBufferResource::Desc instanceBufferDesc; + instanceBufferDesc.type = IResource::Type::Buffer; + instanceBufferDesc.sizeInBytes = + instanceDescs.getCount() * sizeof(IAccelerationStructure::InstanceDesc); + instanceBufferDesc.defaultState = ResourceState::ShaderResource; + gInstanceBuffer = + gDevice->createBufferResource(instanceBufferDesc, instanceDescs.getBuffer()); + if (!gInstanceBuffer) + return SLANG_FAIL; + + IAccelerationStructure::BuildInputs accelerationStructureBuildInputs = {}; + IAccelerationStructure::PrebuildInfo accelerationStructurePrebuildInfo = {}; + accelerationStructureBuildInputs.descCount = 1; + accelerationStructureBuildInputs.kind = IAccelerationStructure::Kind::TopLevel; + accelerationStructureBuildInputs.instanceDescs = gInstanceBuffer->getDeviceAddress(); + + // Query buffer size for acceleration structure build. + SLANG_RETURN_ON_FAIL(gDevice->getAccelerationStructurePrebuildInfo( + accelerationStructureBuildInputs, + &accelerationStructurePrebuildInfo)); + + IBufferResource::Desc asBufferDesc; + asBufferDesc.type = IResource::Type::Buffer; + asBufferDesc.defaultState = ResourceState::AccelerationStructure; + asBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.resultDataMaxSize; + gTLASBuffer = gDevice->createBufferResource(asBufferDesc); + + IBufferResource::Desc scratchBufferDesc; + scratchBufferDesc.type = IResource::Type::Buffer; + scratchBufferDesc.defaultState = ResourceState::UnorderedAccess; + scratchBufferDesc.sizeInBytes = accelerationStructurePrebuildInfo.scratchDataSize; + ComPtr scratchBuffer = + gDevice->createBufferResource(scratchBufferDesc); + + IAccelerationStructure::CreateDesc createDesc; + createDesc.buffer = gTLASBuffer; + createDesc.kind = IAccelerationStructure::Kind::TopLevel; + createDesc.offset = 0; + createDesc.size = accelerationStructurePrebuildInfo.resultDataMaxSize; + SLANG_RETURN_ON_FAIL( + gDevice->createAccelerationStructure(createDesc, gTLAS.writeRef())); + + auto commandBuffer = gTransientHeaps[0]->createCommandBuffer(); + auto encoder = commandBuffer->encodeRayTracingCommands(); + IAccelerationStructure::BuildDesc buildDesc = {}; + buildDesc.dest = gTLAS; + buildDesc.inputs = accelerationStructureBuildInputs; + buildDesc.scratchData = scratchBuffer->getDeviceAddress(); + encoder->buildAccelerationStructure(buildDesc, 0, nullptr); + encoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + gQueue->waitOnHost(); + } + + IBufferResource::Desc fullScreenVertexBufferDesc; + fullScreenVertexBufferDesc.type = IResource::Type::Buffer; + fullScreenVertexBufferDesc.sizeInBytes = + FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); + fullScreenVertexBufferDesc.defaultState = ResourceState::VertexBuffer; + gFullScreenVertexBuffer = gDevice->createBufferResource( + fullScreenVertexBufferDesc, + &FullScreenTriangle::kVertices[0]); + if (!gFullScreenVertexBuffer) + return SLANG_FAIL; -glm::vec3 getVectorFromSphericalAngles(float theta, float phi) -{ - auto sinTheta = sin(theta); - auto cosTheta = cos(theta); - auto sinPhi = sin(phi); - auto cosPhi = cos(phi); - return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi); -} -void updateUniforms() -{ - gUniforms.screenWidth = (float)windowWidth; - gUniforms.screenHeight = (float)windowHeight; - if (!lastTime) - lastTime = getCurrentTime(); - uint64_t currentTime = getCurrentTime(); - float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); - lastTime = currentTime; - - auto camDir = - getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]); - auto camUp = getVectorFromSphericalAngles( - cameraOrientationAngles[0], cameraOrientationAngles[1] + glm::pi() * 0.5f); - auto camRight = glm::cross(camDir, camUp); - - glm::vec3 movement = glm::vec3(0); - if (wPressed) - movement += camDir; - if (sPressed) - movement -= camDir; - if (aPressed) - movement -= camRight; - if (dPressed) - movement += camRight; - - cameraPosition += deltaTime * translationScale * movement; - - memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3); - memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3); - memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3); - memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3); - auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f)); - memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); -} - -virtual void renderFrame(int frameBufferIndex) override -{ - updateUniforms(); + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + }; + auto inputLayout = gDevice->createInputLayout( + sizeof(FullScreenTriangle::Vertex), + &inputElements[0], + SLANG_COUNT_OF(inputElements)); + if (!inputLayout) + return SLANG_FAIL; + + ComPtr shaderProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, false, shaderProgram.writeRef())); + GraphicsPipelineStateDesc desc; + desc.inputLayout = inputLayout; + desc.program = shaderProgram; + desc.framebufferLayout = gFramebufferLayout; + gPresentPipelineState = gDevice->createGraphicsPipelineState(desc); + if (!gPresentPipelineState) + return SLANG_FAIL; + + ComPtr computeProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, true, computeProgram.writeRef())); + ComputePipelineStateDesc computeDesc; + computeDesc.program = computeProgram; + gRenderPipelineState = gDevice->createComputePipelineState(computeDesc); + if (!gRenderPipelineState) + return SLANG_FAIL; + + createResultTexture(); + return SLANG_OK; + } + + void createResultTexture() { - ComPtr renderCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = renderCommandBuffer->encodeComputeCommands(); - auto rootObject = renderEncoder->bindPipeline(gRenderPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(0)); - cursor["resultTexture"].setResource(gResultTextureUAV); - cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); - cursor["sceneBVH"].setResource(gTLAS); - cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); - renderEncoder->dispatchCompute((windowWidth + 15) / 16, (windowHeight + 15) / 16, 1); - renderEncoder->endEncoding(); - renderCommandBuffer->close(); - gQueue->executeCommandBuffer(renderCommandBuffer); + ITextureResource::Desc resultTextureDesc = {}; + resultTextureDesc.type = IResource::Type::Texture2D; + resultTextureDesc.numMipLevels = 1; + resultTextureDesc.size.width = windowWidth; + resultTextureDesc.size.height = windowHeight; + resultTextureDesc.size.depth = 1; + resultTextureDesc.defaultState = ResourceState::UnorderedAccess; + resultTextureDesc.format = Format::R16G16B16A16_FLOAT; + gResultTexture = gDevice->createTextureResource(resultTextureDesc); + IResourceView::Desc resultUAVDesc = {}; + resultUAVDesc.format = resultTextureDesc.format; + resultUAVDesc.type = IResourceView::Type::UnorderedAccess; + gResultTextureUAV = gDevice->createTextureView(gResultTexture, resultUAVDesc); } + virtual void windowSizeChanged() override { - ComPtr presentCommandBuffer = - gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto presentEncoder = presentCommandBuffer->encodeRenderCommands( - gRenderPass, gFramebuffers[frameBufferIndex]); - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - presentEncoder->setViewportAndScissor(viewport); - auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); - auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); - cursor["t"].setResource(gResultTextureUAV); - presentEncoder->setVertexBuffer( - 0, gFullScreenVertexBuffer); - presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - presentEncoder->draw(3); - presentEncoder->endEncoding(); - presentCommandBuffer->close(); - gQueue->executeCommandBuffer(presentCommandBuffer); + WindowedAppBase::windowSizeChanged(); + createResultTexture(); } - if (!isTestMode()) + glm::vec3 getVectorFromSphericalAngles(float theta, float phi) + { + auto sinTheta = sin(theta); + auto cosTheta = cos(theta); + auto sinPhi = sin(phi); + auto cosPhi = cos(phi); + return glm::vec3(-sinTheta * cosPhi, sinPhi, -cosTheta * cosPhi); + } + void updateUniforms() { - // With that, we are done drawing for one frame, and ready for the next. - // - gSwapchain->present(); + gUniforms.screenWidth = (float)windowWidth; + gUniforms.screenHeight = (float)windowHeight; + if (!lastTime) + lastTime = getCurrentTime(); + uint64_t currentTime = getCurrentTime(); + float deltaTime = float(double(currentTime - lastTime) / double(getTimerFrequency())); + lastTime = currentTime; + + auto camDir = + getVectorFromSphericalAngles(cameraOrientationAngles[0], cameraOrientationAngles[1]); + auto camUp = getVectorFromSphericalAngles( + cameraOrientationAngles[0], + cameraOrientationAngles[1] + glm::pi() * 0.5f); + auto camRight = glm::cross(camDir, camUp); + + glm::vec3 movement = glm::vec3(0); + if (wPressed) + movement += camDir; + if (sPressed) + movement -= camDir; + if (aPressed) + movement -= camRight; + if (dPressed) + movement += camRight; + + cameraPosition += deltaTime * translationScale * movement; + + memcpy(gUniforms.cameraDir, &camDir, sizeof(float) * 3); + memcpy(gUniforms.cameraUp, &camUp, sizeof(float) * 3); + memcpy(gUniforms.cameraRight, &camRight, sizeof(float) * 3); + memcpy(gUniforms.cameraPosition, &cameraPosition, sizeof(float) * 3); + auto lightDir = glm::normalize(glm::vec3(1.0f, 3.0f, 2.0f)); + memcpy(gUniforms.lightDir, &lightDir, sizeof(float) * 3); } -} + virtual void renderFrame(int frameBufferIndex) override + { + updateUniforms(); + { + ComPtr renderCommandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + auto renderEncoder = renderCommandBuffer->encodeComputeCommands(); + auto rootObject = renderEncoder->bindPipeline(gRenderPipelineState); + auto cursor = ShaderCursor(rootObject->getEntryPoint(0)); + cursor["resultTexture"].setResource(gResultTextureUAV); + cursor["uniforms"].setData(&gUniforms, sizeof(Uniforms)); + cursor["sceneBVH"].setResource(gTLAS); + cursor["primitiveBuffer"].setResource(gPrimitiveBufferSRV); + renderEncoder->dispatchCompute((windowWidth + 15) / 16, (windowHeight + 15) / 16, 1); + renderEncoder->endEncoding(); + renderCommandBuffer->close(); + gQueue->executeCommandBuffer(renderCommandBuffer); + } + + { + ComPtr presentCommandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + auto presentEncoder = presentCommandBuffer->encodeRenderCommands( + gRenderPass, + gFramebuffers[frameBufferIndex]); + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + presentEncoder->setViewportAndScissor(viewport); + auto rootObject = presentEncoder->bindPipeline(gPresentPipelineState); + auto cursor = ShaderCursor(rootObject->getEntryPoint(1)); + cursor["t"].setResource(gResultTextureUAV); + presentEncoder->setVertexBuffer(0, gFullScreenVertexBuffer); + presentEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + presentEncoder->draw(3); + presentEncoder->endEncoding(); + presentCommandBuffer->close(); + gQueue->executeCommandBuffer(presentCommandBuffer); + } + + if (!isTestMode()) + { + // With that, we are done drawing for one frame, and ready for the next. + // + gSwapchain->present(); + } + } }; // This macro instantiates an appropriate main function to diff --git a/examples/shader-object/main.cpp b/examples/shader-object/main.cpp index 603278bcf0..f5c02141f2 100644 --- a/examples/shader-object/main.cpp +++ b/examples/shader-object/main.cpp @@ -8,14 +8,14 @@ // simplifies shader specialization and parameter binding when using `interface` typed // shader parameters. // -#include "slang.h" #include "slang-com-ptr.h" +#include "slang.h" using Slang::ComPtr; -#include "slang-gfx.h" -#include "gfx-util/shader-cursor.h" -#include "source/core/slang-basic.h" +#include "core/slang-basic.h" #include "examples/example-base/example-base.h" +#include "gfx-util/shader-cursor.h" +#include "slang-gfx.h" using namespace gfx; @@ -37,7 +37,7 @@ Result loadShaderProgram( // creates a Slang compilation session for us, so we just grab and use it here. ComPtr slangSession; SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - + // Once the session has been obtained, we can start loading code into it. // // The simplest way to load code is by calling `loadModule` with the name of a Slang @@ -61,7 +61,7 @@ Result loadShaderProgram( Slang::String path = resourceBase.resolveResource("shader-object.slang"); slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); diagnoseIfNeeded(diagnosticsBlob); - if(!module) + if (!module) return SLANG_FAIL; // Loading the `shader-object` module will compile and check all the shader code in it, @@ -74,13 +74,13 @@ Result loadShaderProgram( // is no umambiguous way for the compiler to know which functions represent entry // points when it parses your code via `loadModule()`. // - char const* computeEntryPointName = "computeMain"; + char const* computeEntryPointName = "computeMain"; ComPtr computeEntryPoint; SLANG_RETURN_ON_FAIL( module->findEntryPointByName(computeEntryPointName, computeEntryPoint.writeRef())); - + // At this point we have a few different Slang API objects that represent - // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. + // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. // // A single Slang module could contain many different entry points (e.g., // four vertex entry points, three fragment entry points, and two compute @@ -177,10 +177,8 @@ int main(int argc, char* argv[]) bufferDesc.memoryType = MemoryType::DeviceLocal; ComPtr numbersBuffer; - SLANG_RETURN_ON_FAIL(device->createBufferResource( - bufferDesc, - (void*)initialData, - numbersBuffer.writeRef())); + SLANG_RETURN_ON_FAIL( + device->createBufferResource(bufferDesc, (void*)initialData, numbersBuffer.writeRef())); // Create a resource view for the buffer. ComPtr bufferView; @@ -217,7 +215,9 @@ int main(int argc, char* argv[]) // Now we can use this type to create a shader object that can be bound to the root object. ComPtr transformer; SLANG_RETURN_ON_FAIL(device->createShaderObject( - addTransformerType, ShaderObjectContainerType::None, transformer.writeRef())); + addTransformerType, + ShaderObjectContainerType::None, + transformer.writeRef())); // Set the `c` field of the `AddTransformer`. float c = 1.0f; gfx::ShaderCursor(transformer).getPath("c").setData(&c, sizeof(float)); @@ -244,7 +244,10 @@ int main(int argc, char* argv[]) // Read back the results. ComPtr resultBlob; SLANG_RETURN_ON_FAIL(device->readBufferResource( - numbersBuffer, 0, numberCount * sizeof(float), resultBlob.writeRef())); + numbersBuffer, + 0, + numberCount * sizeof(float), + resultBlob.writeRef())); auto result = reinterpret_cast(resultBlob->getBufferPointer()); for (int i = 0; i < numberCount; i++) printf("%f\n", result[i]); diff --git a/examples/shader-toy/main.cpp b/examples/shader-toy/main.cpp index 13a79c7eee..1ab85c0b20 100644 --- a/examples/shader-toy/main.cpp +++ b/examples/shader-toy/main.cpp @@ -10,8 +10,8 @@ // This example uses the Slang C/C++ API, alonmg with its optional type // for managing COM-style reference-counted pointers. // -#include "slang.h" #include "slang-com-ptr.h" +#include "slang.h" using Slang::ComPtr; // This example uses a graphics API abstraction layer that is implemented inside @@ -19,12 +19,12 @@ using Slang::ComPtr; // this layer is *not* required or assumed when using the Slang language, // compiler, and API. // -#include "slang-gfx.h" -#include "tools/gfx-util/shader-cursor.h" -#include "tools/platform/window.h" -#include "tools/platform/performance-counter.h" +#include "core/slang-basic.h" #include "examples/example-base/example-base.h" -#include "source/core/slang-basic.h" +#include "gfx-util/shader-cursor.h" +#include "platform/performance-counter.h" +#include "platform/window.h" +#include "slang-gfx.h" #include @@ -43,15 +43,17 @@ struct FullScreenTriangle float position[2]; }; - enum { kVertexCount = 3 }; + enum + { + kVertexCount = 3 + }; static const Vertex kVertices[kVertexCount]; }; -const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangle::kVertexCount] = -{ - { { -1, -1 } }, - { { -1, 3 } }, - { { 3, -1 } }, +const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangle::kVertexCount] = { + {{-1, -1}}, + {{-1, 3}}, + {{3, -1}}, }; // The application itself will be encapsulated in a C++ `struct` type @@ -60,333 +62,336 @@ const FullScreenTriangle::Vertex FullScreenTriangle::kVertices[FullScreenTriangl struct ShaderToyApp : public WindowedAppBase { -// The uniform data used by the shader is defined here as a simple -// POD ("plain old data") type. -// -// Note: This type must match the declaration of `ShaderToyUniforms` -// in the file `shader-toy.slang`. -// -// An application could instead use a shared header file to define -// this type, or use Slang's reflection capabilities to allocate -// and set parameters at runtime. For this simple example we did -// the expedient thing of having distinct Slang and C++ declarations. -// -struct Uniforms -{ - float iMouse[4]; - float iResolution[2]; - float iTime; -}; - -// The main interesting part of the host application code is where we -// load, compile, inspect, and compose the Slang shader code. -// -Result loadShaderProgram(gfx::IDevice* device, ComPtr& outShaderProgram) -{ - // We need to obatin a compilation session (`slang::ISession`) that will provide - // a scope to all the compilation and loading of code we do. - // - // Our example application uses the `gfx` graphics API abstraction layer, which already - // creates a Slang compilation session for us, so we just grab and use it here. - ComPtr slangSession; - SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - - // Once the session has been obtained, we can start loading code into it. - // - // The simplest way to load code is by calling `loadModule` with the name of a Slang - // module. A call to `loadModule("MyStuff")` will behave more or less as if you - // wrote: - // - // import MyStuff; - // - // In a Slang shader file. The compiler will use its search paths to try to locate - // `MyModule.slang`, then compile and load that file. If a matching module had - // already been loaded previously, that would be used directly. - // - // Note: The only interesting wrinkle here is that our file is named `shader-toy` with - // a hyphen in it, so the name is not directly usable as an identifier in Slang code. - // Instead, when trying to import this module in the context of Slang code, a user - // needs to replace the hyphens with underscores: - // - // import shader_toy; - // - ComPtr diagnosticsBlob; - Slang::String shaderToyPath = resourceBase.resolveResource("shader-toy.slang"); - slang::IModule* module = slangSession->loadModule(shaderToyPath.getBuffer(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if(!module) - return SLANG_FAIL; - - // Loading the `shader-toy` module will compile and check all the shader code in it, - // including the shader entry points we want to use. Now that the module is loaded - // we can look up those entry points by name. + // The uniform data used by the shader is defined here as a simple + // POD ("plain old data") type. // - // Note: If you are using this `loadModule` approach to load your shader code it is - // important to tag your entry point functions with the `[shader("...")]` attribute - // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there - // is no umambiguous way for the compiler to know which functions represent entry - // points when it parses your code via `loadModule()`. + // Note: This type must match the declaration of `ShaderToyUniforms` + // in the file `shader-toy.slang`. // - char const* vertexEntryPointName = "vertexMain"; - char const* fragmentEntryPointName = "fragmentMain"; + // An application could instead use a shared header file to define + // this type, or use Slang's reflection capabilities to allocate + // and set parameters at runtime. For this simple example we did + // the expedient thing of having distinct Slang and C++ declarations. // - ComPtr vertexEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef())); - // - ComPtr fragmentEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef())); + struct Uniforms + { + float iMouse[4]; + float iResolution[2]; + float iTime; + }; - // At this point we have a few different Slang API objects that represent - // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. - // - // A single Slang module could contain many different entry points (e.g., - // four vertex entry points, three fragment entry points, and two compute - // shaders), and before we try to generate output code for our target API - // we need to identify which entry points we plan to use together. - // - // Modules and entry points are both examples of *component types* in the - // Slang API. The API also provides a way to build a *composite* out of - // other pieces, and that is what we are going to do with our module - // and entry points. - // - Slang::List componentTypes; - componentTypes.add(module); - - // Later on when we go to extract compiled kernel code for our vertex - // and fragment shaders, we will need to make use of their order within - // the composition, so we will record the relative ordering of the entry - // points here as we add them. - int entryPointCount = 0; - int vertexEntryPointIndex = entryPointCount++; - componentTypes.add(vertexEntryPoint); - - int fragmentEntryPointIndex = entryPointCount++; - componentTypes.add(fragmentEntryPoint); - - // Actually creating the composite component type is a single operation - // on the Slang session, but the operation could potentially fail if - // something about the composite was invalid (e.g., you are trying to - // combine multiple copies of the same module), so we need to deal - // with the possibility of diagnostic output. - // - ComPtr composedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - composedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - // At this point, `composedProgram` represents the shader program - // we want to run, and the vertex and fragment shader there have - // been checked. - // - // We could use the Slang reflection API on `composedProgram` at this - // point to query things like the locations and offsets of the - // various uniform parameters, textures, etc. - // - // What *cannot* be done yet at this point is actually generating - // kernel code, because `composedProgram` includes a generic type - // parameter as part of the `fragmentMain` entry point: - // - // void fragmentMain(...) - // - // Our next task is to load code for a type we'd like to plug in - // for `T` there. + // The main interesting part of the host application code is where we + // load, compile, inspect, and compose the Slang shader code. // - // Because Slang supports modular programming, there is no requirement - // that a type we want to plug in for `T` has to come from the - // same module, and to demonstrate that we will load a different - // module to provide the effect type we will plug in. - // - const char* effectTypeName = "ExampleEffect"; - Slang::String effectModulePath = resourceBase.resolveResource("example-effect.slang"); - slang::IModule* effectModule = slangSession->loadModule(effectModulePath.getBuffer(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if(!module) - return SLANG_FAIL; - - // Once we've loaded the code module that defines out effect type, - // we can look it up by name using the reflection information on - // the module. - // - // Note: A future version of the Slang API will support enumerating - // the types declared in a module so that we do not have to hard-code - // the name here. - // - auto effectType = effectModule->getLayout()->findTypeByName(effectTypeName); + Result loadShaderProgram(gfx::IDevice* device, ComPtr& outShaderProgram) + { + // We need to obatin a compilation session (`slang::ISession`) that will provide + // a scope to all the compilation and loading of code we do. + // + // Our example application uses the `gfx` graphics API abstraction layer, which already + // creates a Slang compilation session for us, so we just grab and use it here. + ComPtr slangSession; + SLANG_RETURN_ON_FAIL(device->getSlangSession(slangSession.writeRef())); - // Now that we have the `effectType` we want to plug in to our generic - // shader, we need to specialize the shader to that type. - // - // Because a shader program could have zero or more specialization parameters, - // we need to build up an array of specialization arguments. - // - Slang::List specializationArgs; + // Once the session has been obtained, we can start loading code into it. + // + // The simplest way to load code is by calling `loadModule` with the name of a Slang + // module. A call to `loadModule("MyStuff")` will behave more or less as if you + // wrote: + // + // import MyStuff; + // + // In a Slang shader file. The compiler will use its search paths to try to locate + // `MyModule.slang`, then compile and load that file. If a matching module had + // already been loaded previously, that would be used directly. + // + // Note: The only interesting wrinkle here is that our file is named `shader-toy` with + // a hyphen in it, so the name is not directly usable as an identifier in Slang code. + // Instead, when trying to import this module in the context of Slang code, a user + // needs to replace the hyphens with underscores: + // + // import shader_toy; + // + ComPtr diagnosticsBlob; + Slang::String shaderToyPath = resourceBase.resolveResource("shader-toy.slang"); + slang::IModule* module = + slangSession->loadModule(shaderToyPath.getBuffer(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + // Loading the `shader-toy` module will compile and check all the shader code in it, + // including the shader entry points we want to use. Now that the module is loaded + // we can look up those entry points by name. + // + // Note: If you are using this `loadModule` approach to load your shader code it is + // important to tag your entry point functions with the `[shader("...")]` attribute + // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there + // is no umambiguous way for the compiler to know which functions represent entry + // points when it parses your code via `loadModule()`. + // + char const* vertexEntryPointName = "vertexMain"; + char const* fragmentEntryPointName = "fragmentMain"; + // + ComPtr vertexEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(vertexEntryPointName, vertexEntryPoint.writeRef())); + // + ComPtr fragmentEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName(fragmentEntryPointName, fragmentEntryPoint.writeRef())); - { - // In our case, we only have a single specialization argument we plan - // to use, and it is a type argument. + // At this point we have a few different Slang API objects that represent + // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. + // + // A single Slang module could contain many different entry points (e.g., + // four vertex entry points, three fragment entry points, and two compute + // shaders), and before we try to generate output code for our target API + // we need to identify which entry points we plan to use together. + // + // Modules and entry points are both examples of *component types* in the + // Slang API. The API also provides a way to build a *composite* out of + // other pieces, and that is what we are going to do with our module + // and entry points. + // + Slang::List componentTypes; + componentTypes.add(module); + + // Later on when we go to extract compiled kernel code for our vertex + // and fragment shaders, we will need to make use of their order within + // the composition, so we will record the relative ordering of the entry + // points here as we add them. + int entryPointCount = 0; + int vertexEntryPointIndex = entryPointCount++; + componentTypes.add(vertexEntryPoint); + + int fragmentEntryPointIndex = entryPointCount++; + componentTypes.add(fragmentEntryPoint); + + // Actually creating the composite component type is a single operation + // on the Slang session, but the operation could potentially fail if + // something about the composite was invalid (e.g., you are trying to + // combine multiple copies of the same module), so we need to deal + // with the possibility of diagnostic output. + // + ComPtr composedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + composedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + // At this point, `composedProgram` represents the shader program + // we want to run, and the vertex and fragment shader there have + // been checked. + // + // We could use the Slang reflection API on `composedProgram` at this + // point to query things like the locations and offsets of the + // various uniform parameters, textures, etc. + // + // What *cannot* be done yet at this point is actually generating + // kernel code, because `composedProgram` includes a generic type + // parameter as part of the `fragmentMain` entry point: + // + // void fragmentMain(...) + // + // Our next task is to load code for a type we'd like to plug in + // for `T` there. + // + // Because Slang supports modular programming, there is no requirement + // that a type we want to plug in for `T` has to come from the + // same module, and to demonstrate that we will load a different + // module to provide the effect type we will plug in. + // + const char* effectTypeName = "ExampleEffect"; + Slang::String effectModulePath = resourceBase.resolveResource("example-effect.slang"); + slang::IModule* effectModule = + slangSession->loadModule(effectModulePath.getBuffer(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + // Once we've loaded the code module that defines out effect type, + // we can look it up by name using the reflection information on + // the module. + // + // Note: A future version of the Slang API will support enumerating + // the types declared in a module so that we do not have to hard-code + // the name here. + // + auto effectType = effectModule->getLayout()->findTypeByName(effectTypeName); + + // Now that we have the `effectType` we want to plug in to our generic + // shader, we need to specialize the shader to that type. // - slang::SpecializationArg effectTypeArg; - effectTypeArg.kind = slang::SpecializationArg::Kind::Type; - effectTypeArg.type = effectType; - specializationArgs.add(effectTypeArg); + // Because a shader program could have zero or more specialization parameters, + // we need to build up an array of specialization arguments. + // + Slang::List specializationArgs; + + { + // In our case, we only have a single specialization argument we plan + // to use, and it is a type argument. + // + slang::SpecializationArg effectTypeArg; + effectTypeArg.kind = slang::SpecializationArg::Kind::Type; + effectTypeArg.type = effectType; + specializationArgs.add(effectTypeArg); + } + + // Specialization of a component type is a single Slang API call, but + // we need to deal with the possibility of diagnostic output on failure. + // For example, if we tried to specialize the shader program to a + // type like `int` that doesn't support the `IShaderToyImageShader` interface, + // this is the step where we'd get an error message saying so. + // + ComPtr specializedProgram; + result = composedProgram->specialize( + specializationArgs.getBuffer(), + specializationArgs.getCount(), + specializedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + // At this point we have a specialized shader program that represents our + // intention to run the `vertexMain` and `fragmentMain` entry points, + // specialized to the `ExampleEffect` type we loaded. + // + // We can now *link* the program, which ensures that all of the code that + // it transitively depends on has been pulled together into a single + // component type. + // + ComPtr linkedProgram; + result = specializedProgram->link(linkedProgram.writeRef(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram.get(); + auto shaderProgram = device->createProgram(programDesc); + outShaderProgram = shaderProgram; + return SLANG_OK; } - // Specialization of a component type is a single Slang API call, but - // we need to deal with the possibility of diagnostic output on failure. - // For example, if we tried to specialize the shader program to a - // type like `int` that doesn't support the `IShaderToyImageShader` interface, - // this is the step where we'd get an error message saying so. - // - ComPtr specializedProgram; - result = composedProgram->specialize( - specializationArgs.getBuffer(), - specializationArgs.getCount(), - specializedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - // At this point we have a specialized shader program that represents our - // intention to run the `vertexMain` and `fragmentMain` entry points, - // specialized to the `ExampleEffect` type we loaded. - // - // We can now *link* the program, which ensures that all of the code that - // it transitively depends on has been pulled together into a single - // component type. - // - ComPtr linkedProgram; - result = specializedProgram->link( - linkedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram.get(); - auto shaderProgram = device->createProgram(programDesc); - outShaderProgram = shaderProgram; - return SLANG_OK; -} - -ComPtr gShaderProgram; -ComPtr gPipelineState; -ComPtr gVertexBuffer; - -Result initialize() -{ - initializeBase("Shader Toy", 1024, 768); - gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; - gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; - gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; + ComPtr gShaderProgram; + ComPtr gPipelineState; + ComPtr gVertexBuffer; - InputElementDesc inputElements[] = { - { "POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position) }, - }; - auto inputLayout = gDevice->createInputLayout( - sizeof(FullScreenTriangle::Vertex), - &inputElements[0], - SLANG_COUNT_OF(inputElements)); - if(!inputLayout) return SLANG_FAIL; - - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gVertexBuffer = gDevice->createBufferResource( - vertexBufferDesc, - &FullScreenTriangle::kVertices[0]); - if(!gVertexBuffer) return SLANG_FAIL; - - SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram)); - - // Create pipeline. - GraphicsPipelineStateDesc desc; - desc.inputLayout = inputLayout; - desc.program = gShaderProgram; - desc.framebufferLayout = gFramebufferLayout; - auto pipelineState = gDevice->createGraphicsPipelineState(desc); - if (!pipelineState) - return SLANG_FAIL; - - gPipelineState = pipelineState; - - return SLANG_OK; -} - -bool wasMouseDown = false; -bool isMouseDown = false; -float lastMouseX = 0.0f; -float lastMouseY = 0.0f; -float clickMouseX = 0.0f; -float clickMouseY = 0.0f; - -bool firstTime = true; -platform::TimePoint startTime; - -virtual void renderFrame(int frameIndex) override -{ - auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); - if( firstTime ) + Result initialize() { - startTime = platform::PerformanceCounter::now(); - firstTime = false; + initializeBase("Shader Toy", 1024, 768); + gWindow->events.mouseMove = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; + gWindow->events.mouseUp = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; + gWindow->events.mouseDown = [this](const platform::MouseEventArgs& e) { handleEvent(e); }; + + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::R32G32_FLOAT, offsetof(FullScreenTriangle::Vertex, position)}, + }; + auto inputLayout = gDevice->createInputLayout( + sizeof(FullScreenTriangle::Vertex), + &inputElements[0], + SLANG_COUNT_OF(inputElements)); + if (!inputLayout) + return SLANG_FAIL; + + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = + FullScreenTriangle::kVertexCount * sizeof(FullScreenTriangle::Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + gVertexBuffer = + gDevice->createBufferResource(vertexBufferDesc, &FullScreenTriangle::kVertices[0]); + if (!gVertexBuffer) + return SLANG_FAIL; + + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, gShaderProgram)); + + // Create pipeline. + GraphicsPipelineStateDesc desc; + desc.inputLayout = inputLayout; + desc.program = gShaderProgram; + desc.framebufferLayout = gFramebufferLayout; + auto pipelineState = gDevice->createGraphicsPipelineState(desc); + if (!pipelineState) + return SLANG_FAIL; + + gPipelineState = pipelineState; + + return SLANG_OK; } - // Update uniform buffer. + bool wasMouseDown = false; + bool isMouseDown = false; + float lastMouseX = 0.0f; + float lastMouseY = 0.0f; + float clickMouseX = 0.0f; + float clickMouseY = 0.0f; - Uniforms uniforms = {}; + bool firstTime = true; + platform::TimePoint startTime; + + virtual void renderFrame(int frameIndex) override { - bool isMouseClick = isMouseDown && !wasMouseDown; - wasMouseDown = isMouseDown; + auto commandBuffer = gTransientHeaps[frameIndex]->createCommandBuffer(); + if (firstTime) + { + startTime = platform::PerformanceCounter::now(); + firstTime = false; + } + + // Update uniform buffer. - if( isMouseClick ) + Uniforms uniforms = {}; { - clickMouseX = lastMouseX; - clickMouseY = lastMouseY; + bool isMouseClick = isMouseDown && !wasMouseDown; + wasMouseDown = isMouseDown; + + if (isMouseClick) + { + clickMouseX = lastMouseX; + clickMouseY = lastMouseY; + } + + uniforms.iMouse[0] = lastMouseX; + uniforms.iMouse[1] = lastMouseY; + uniforms.iMouse[2] = isMouseDown ? clickMouseX : -clickMouseX; + uniforms.iMouse[3] = isMouseClick ? clickMouseY : -clickMouseY; + uniforms.iTime = platform::PerformanceCounter::getElapsedTimeInSeconds(startTime); + uniforms.iResolution[0] = float(windowWidth); + uniforms.iResolution[1] = float(windowHeight); } - uniforms.iMouse[0] = lastMouseX; - uniforms.iMouse[1] = lastMouseY; - uniforms.iMouse[2] = isMouseDown ? clickMouseX : -clickMouseX; - uniforms.iMouse[3] = isMouseClick ? clickMouseY : -clickMouseY; - uniforms.iTime = platform::PerformanceCounter::getElapsedTimeInSeconds(startTime); - uniforms.iResolution[0] = float(windowWidth); - uniforms.iResolution[1] = float(windowHeight); + // Encode render commands. + auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + encoder->setViewportAndScissor(viewport); + auto rootObject = encoder->bindPipeline(gPipelineState); + auto constantBuffer = rootObject->getObject(ShaderOffset()); + constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms)); + + encoder->setVertexBuffer(0, gVertexBuffer); + encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + encoder->draw(3); + encoder->endEncoding(); + commandBuffer->close(); + + gQueue->executeCommandBuffer(commandBuffer); + gSwapchain->present(); + } + void handleEvent(const platform::MouseEventArgs& event) + { + isMouseDown = ((int)event.buttons & (int)platform::ButtonState::Enum::LeftButton) != 0; + lastMouseX = (float)event.x; + lastMouseY = (float)event.y; } - - // Encode render commands. - auto encoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - encoder->setViewportAndScissor(viewport); - auto rootObject = encoder->bindPipeline(gPipelineState); - auto constantBuffer = rootObject->getObject(ShaderOffset()); - constantBuffer->setData(ShaderOffset(), &uniforms, sizeof(uniforms)); - - encoder->setVertexBuffer(0, gVertexBuffer); - encoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); - encoder->draw(3); - encoder->endEncoding(); - commandBuffer->close(); - - gQueue->executeCommandBuffer(commandBuffer); - gSwapchain->present(); -} - -void handleEvent(const platform::MouseEventArgs& event) -{ - isMouseDown = ((int)event.buttons & (int)platform::ButtonState::Enum::LeftButton) != 0; - lastMouseX = (float)event.x; - lastMouseY = (float)event.y; -} }; // This macro instantiates an appropriate main function to diff --git a/examples/triangle/main.cpp b/examples/triangle/main.cpp index 88c55c4163..e77f488cc8 100644 --- a/examples/triangle/main.cpp +++ b/examples/triangle/main.cpp @@ -32,12 +32,12 @@ // with Slang may depend on an application/engine making certain // design choices in their abstraction layer. // -#include "slang-gfx.h" +#include "core/slang-basic.h" +#include "examples/example-base/example-base.h" #include "gfx-util/shader-cursor.h" -#include "tools/platform/window.h" +#include "platform/window.h" #include "slang-com-ptr.h" -#include "source/core/slang-basic.h" -#include "examples/example-base/example-base.h" +#include "slang-gfx.h" using namespace gfx; using namespace Slang; @@ -55,11 +55,10 @@ struct Vertex }; static const int kVertexCount = 3; -static const Vertex kVertexData[kVertexCount] = -{ - { { 0, 0, 0.5 }, { 1, 0, 0 } }, - { { 0, 1, 0.5 }, { 0, 0, 1 } }, - { { 1, 0, 0.5 }, { 0, 1, 0 } }, +static const Vertex kVertexData[kVertexCount] = { + {{0, 0, 0.5}, {1, 0, 0}}, + {{0, 1, 0.5}, {0, 0, 1}}, + {{1, 0, 0.5}, {0, 1, 0}}, }; // The example application will be implemented as a `struct`, so that @@ -68,338 +67,340 @@ static const Vertex kVertexData[kVertexCount] = struct HelloWorld : public WindowedAppBase { -// Many Slang API functions return detailed diagnostic information -// (error messages, warnings, etc.) as a "blob" of data, or return -// a null blob pointer instead if there were no issues. -// -// For convenience, we define a subroutine that will dump the information -// in a diagnostic blob if one is produced, and skip it otherwise. -// -void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) -{ - if( diagnosticsBlob != nullptr ) - { - printf("%s", (const char*) diagnosticsBlob->getBufferPointer()); - } -} - -// The main task an application cares about is compiling shader code -// from souce (if needed) and loading it through the chosen graphics API. -// -// In addition, an application may want to receive reflection information -// about the program, which is what a `slang::ProgramLayout` provides. -// -gfx::Result loadShaderProgram( - gfx::IDevice* device, - gfx::IShaderProgram** outProgram) -{ - // We need to obatin a compilation session (`slang::ISession`) that will provide - // a scope to all the compilation and loading of code we do. + // Many Slang API functions return detailed diagnostic information + // (error messages, warnings, etc.) as a "blob" of data, or return + // a null blob pointer instead if there were no issues. // - // Our example application uses the `gfx` graphics API abstraction layer, which already - // creates a Slang compilation session for us, so we just grab and use it here. - ComPtr slangSession; - slangSession = device->getSlangSession(); - - // We can now start loading code into the slang session. - // - // The simplest way to load code is by calling `loadModule` with the name of a Slang - // module. A call to `loadModule("MyStuff")` will behave more or less as if you - // wrote: - // - // import MyStuff; - // - // In a Slang shader file. The compiler will use its search paths to try to locate - // `MyModule.slang`, then compile and load that file. If a matching module had - // already been loaded previously, that would be used directly. - // - ComPtr diagnosticsBlob; - Slang::String path = resourceBase.resolveResource("shaders.slang"); - slang::IModule* module = slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - if(!module) - return SLANG_FAIL; - - // Loading the `shaders` module will compile and check all the shader code in it, - // including the shader entry points we want to use. Now that the module is loaded - // we can look up those entry points by name. - // - // Note: If you are using this `loadModule` approach to load your shader code it is - // important to tag your entry point functions with the `[shader("...")]` attribute - // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there - // is no umambiguous way for the compiler to know which functions represent entry - // points when it parses your code via `loadModule()`. - // - ComPtr vertexEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef())); + // For convenience, we define a subroutine that will dump the information + // in a diagnostic blob if one is produced, and skip it otherwise. // - ComPtr fragmentEntryPoint; - SLANG_RETURN_ON_FAIL(module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef())); + void diagnoseIfNeeded(slang::IBlob* diagnosticsBlob) + { + if (diagnosticsBlob != nullptr) + { + printf("%s", (const char*)diagnosticsBlob->getBufferPointer()); + } + } - // At this point we have a few different Slang API objects that represent - // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. - // - // A single Slang module could contain many different entry points (e.g., - // four vertex entry points, three fragment entry points, and two compute - // shaders), and before we try to generate output code for our target API - // we need to identify which entry points we plan to use together. + // The main task an application cares about is compiling shader code + // from souce (if needed) and loading it through the chosen graphics API. // - // Modules and entry points are both examples of *component types* in the - // Slang API. The API also provides a way to build a *composite* out of - // other pieces, and that is what we are going to do with our module - // and entry points. + // In addition, an application may want to receive reflection information + // about the program, which is what a `slang::ProgramLayout` provides. // - Slang::List componentTypes; - componentTypes.add(module); - - // Later on when we go to extract compiled kernel code for our vertex - // and fragment shaders, we will need to make use of their order within - // the composition, so we will record the relative ordering of the entry - // points here as we add them. - int entryPointCount = 0; - int vertexEntryPointIndex = entryPointCount++; - componentTypes.add(vertexEntryPoint); - - int fragmentEntryPointIndex = entryPointCount++; - componentTypes.add(fragmentEntryPoint); - - // Actually creating the composite component type is a single operation - // on the Slang session, but the operation could potentially fail if - // something about the composite was invalid (e.g., you are trying to - // combine multiple copies of the same module), so we need to deal - // with the possibility of diagnostic output. - // - ComPtr linkedProgram; - SlangResult result = slangSession->createCompositeComponentType( - componentTypes.getBuffer(), - componentTypes.getCount(), - linkedProgram.writeRef(), - diagnosticsBlob.writeRef()); - diagnoseIfNeeded(diagnosticsBlob); - SLANG_RETURN_ON_FAIL(result); - - // Once we've described the particular composition of entry points - // that we want to compile, we defer to the graphics API layer - // to extract compiled kernel code and load it into the API-specific - // program representation. - // - gfx::IShaderProgram::Desc programDesc = {}; - programDesc.slangGlobalScope = linkedProgram; - SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); - - if (isTestMode()) + gfx::Result loadShaderProgram(gfx::IDevice* device, gfx::IShaderProgram** outProgram) { - printEntrypointHashes(entryPointCount, 1, linkedProgram); - } + // We need to obatin a compilation session (`slang::ISession`) that will provide + // a scope to all the compilation and loading of code we do. + // + // Our example application uses the `gfx` graphics API abstraction layer, which already + // creates a Slang compilation session for us, so we just grab and use it here. + ComPtr slangSession; + slangSession = device->getSlangSession(); - return SLANG_OK; -} + // We can now start loading code into the slang session. + // + // The simplest way to load code is by calling `loadModule` with the name of a Slang + // module. A call to `loadModule("MyStuff")` will behave more or less as if you + // wrote: + // + // import MyStuff; + // + // In a Slang shader file. The compiler will use its search paths to try to locate + // `MyModule.slang`, then compile and load that file. If a matching module had + // already been loaded previously, that would be used directly. + // + ComPtr diagnosticsBlob; + Slang::String path = resourceBase.resolveResource("shaders.slang"); + slang::IModule* module = + slangSession->loadModule(path.getBuffer(), diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + if (!module) + return SLANG_FAIL; + + // Loading the `shaders` module will compile and check all the shader code in it, + // including the shader entry points we want to use. Now that the module is loaded + // we can look up those entry points by name. + // + // Note: If you are using this `loadModule` approach to load your shader code it is + // important to tag your entry point functions with the `[shader("...")]` attribute + // (e.g., `[shader("vertex")] void vertexMain(...)`). Without that information there + // is no umambiguous way for the compiler to know which functions represent entry + // points when it parses your code via `loadModule()`. + // + ComPtr vertexEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("vertexMain", vertexEntryPoint.writeRef())); + // + ComPtr fragmentEntryPoint; + SLANG_RETURN_ON_FAIL( + module->findEntryPointByName("fragmentMain", fragmentEntryPoint.writeRef())); -// -// The above function shows the core of what is required to use the -// Slang API as a simple compiler (e.g., a drop-in replacement for -// fxc or dxc). -// -// The rest of this file implements an extremely simple rendering application -// that will execute the vertex/fragment shaders loaded with the function -// we have just defined. -// + // At this point we have a few different Slang API objects that represent + // pieces of our code: `module`, `vertexEntryPoint`, and `fragmentEntryPoint`. + // + // A single Slang module could contain many different entry points (e.g., + // four vertex entry points, three fragment entry points, and two compute + // shaders), and before we try to generate output code for our target API + // we need to identify which entry points we plan to use together. + // + // Modules and entry points are both examples of *component types* in the + // Slang API. The API also provides a way to build a *composite* out of + // other pieces, and that is what we are going to do with our module + // and entry points. + // + Slang::List componentTypes; + componentTypes.add(module); + + // Later on when we go to extract compiled kernel code for our vertex + // and fragment shaders, we will need to make use of their order within + // the composition, so we will record the relative ordering of the entry + // points here as we add them. + int entryPointCount = 0; + int vertexEntryPointIndex = entryPointCount++; + componentTypes.add(vertexEntryPoint); + + int fragmentEntryPointIndex = entryPointCount++; + componentTypes.add(fragmentEntryPoint); + + // Actually creating the composite component type is a single operation + // on the Slang session, but the operation could potentially fail if + // something about the composite was invalid (e.g., you are trying to + // combine multiple copies of the same module), so we need to deal + // with the possibility of diagnostic output. + // + ComPtr linkedProgram; + SlangResult result = slangSession->createCompositeComponentType( + componentTypes.getBuffer(), + componentTypes.getCount(), + linkedProgram.writeRef(), + diagnosticsBlob.writeRef()); + diagnoseIfNeeded(diagnosticsBlob); + SLANG_RETURN_ON_FAIL(result); + + // Once we've described the particular composition of entry points + // that we want to compile, we defer to the graphics API layer + // to extract compiled kernel code and load it into the API-specific + // program representation. + // + gfx::IShaderProgram::Desc programDesc = {}; + programDesc.slangGlobalScope = linkedProgram; + SLANG_RETURN_ON_FAIL(device->createProgram(programDesc, outProgram)); -// We will define global variables for the various platform and -// graphics API objects that our application needs: -// -// As a reminder, *none* of these are Slang API objects. All -// of them come from the utility library we are using to simplify -// building an example program. -// -ComPtr gPipelineState; -ComPtr gVertexBuffer; + if (isTestMode()) + { + printEntrypointHashes(entryPointCount, 1, linkedProgram); + } -// Now that we've covered the function that actually loads and -// compiles our Slang shade code, we can go through the rest -// of the application code without as much commentary. -// -Slang::Result initialize() -{ - // Create a window for our application to render into. - // - initializeBase("hello-world", 1024, 768); + return SLANG_OK; + } - // We will create objects needed to configur the "input assembler" - // (IA) stage of the D3D pipeline. - // - // First, we create an input layout: // - InputElementDesc inputElements[] = { - { "POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position) }, - { "COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color) }, - }; - auto inputLayout = gDevice->createInputLayout( - sizeof(Vertex), - &inputElements[0], - 2); - if(!inputLayout) return SLANG_FAIL; - - // Next we allocate a vertex buffer for our pre-initialized - // vertex data. + // The above function shows the core of what is required to use the + // Slang API as a simple compiler (e.g., a drop-in replacement for + // fxc or dxc). // - IBufferResource::Desc vertexBufferDesc; - vertexBufferDesc.type = IResource::Type::Buffer; - vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); - vertexBufferDesc.defaultState = ResourceState::VertexBuffer; - gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); - if(!gVertexBuffer) return SLANG_FAIL; - - // Now we will use our `loadShaderProgram` function to load - // the code from `shaders.slang` into the graphics API. + // The rest of this file implements an extremely simple rendering application + // that will execute the vertex/fragment shaders loaded with the function + // we have just defined. // - ComPtr shaderProgram; - SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, shaderProgram.writeRef())); - // Following the D3D12/Vulkan style of API, we need a pipeline state object - // (PSO) to encapsulate the configuration of the overall graphics pipeline. - // - GraphicsPipelineStateDesc desc; - desc.inputLayout = inputLayout; - desc.program = shaderProgram; - desc.framebufferLayout = gFramebufferLayout; - auto pipelineState = gDevice->createGraphicsPipelineState(desc); - if (!pipelineState) - return SLANG_FAIL; - - gPipelineState = pipelineState; - - return SLANG_OK; -} - -// With the initialization out of the way, we can now turn our attention -// to the per-frame rendering logic. As with the initialization, there is -// nothing really Slang-specific here, so the commentary doesn't need -// to be very detailed. -// -virtual void renderFrame(int frameBufferIndex) override -{ - ComPtr commandBuffer = gTransientHeaps[frameBufferIndex]->createCommandBuffer(); - auto renderEncoder = commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); - - gfx::Viewport viewport = {}; - viewport.maxZ = 1.0f; - viewport.extentX = (float)windowWidth; - viewport.extentY = (float)windowHeight; - renderEncoder->setViewportAndScissor(viewport); - - // In order to bind shader parameters to the pipeline, we need - // to know how those parameters were assigned to locations/bindings/registers - // for the target graphics API. + // We will define global variables for the various platform and + // graphics API objects that our application needs: // - // The Slang compiler assigns locations to parameters in a deterministic - // fashion, so it is possible for a programmer to hard-code locations - // into their application code that will match up with their shaders. + // As a reminder, *none* of these are Slang API objects. All + // of them come from the utility library we are using to simplify + // building an example program. // - // Hard-coding of locations can become intractable as an application needs - // to support more different target platforms and graphics APIs, as well - // as more shaders with different specialized variants. - // - // Rather than rely on hard-coded locations, our examples will make use of - // reflection information provided by the Slang compiler (see `programLayout` - // above), and our example graphics API layer will translate that reflection - // information into a layout for a "root shader object." - // - // The root object will store values/bindings for all of the parameters in - // the `IShaderProgram` used to create the pipeline state. At a conceptual - // level we can think of `rootObject` as representing the "global scope" of - // the shader program that was loaded; it has entries for each global shader - // parameter that was declared. - // - // Readers who are familiar with D3D12 or Vulkan might think of this root - // layout as being similar in spirit to a "root signature" or "pipeline layout." - // - // We start parameter binding by binding the pipeline state in command encoder. - // This method will return a transient root shader object for us to write our - // shader parameters into. - // - auto rootObject = renderEncoder->bindPipeline(gPipelineState); + ComPtr gPipelineState; + ComPtr gVertexBuffer; - // We will update the model-view-projection matrix that is passed - // into the shader code via the `Uniforms` buffer on a per-frame - // basis, even though the data that is loaded does not change - // per-frame (we always use an identity matrix). + // Now that we've covered the function that actually loads and + // compiles our Slang shade code, we can go through the rest + // of the application code without as much commentary. // - auto deviceInfo = gDevice->getDeviceInfo(); + Slang::Result initialize() + { + // Create a window for our application to render into. + // + initializeBase("hello-world", 1024, 768); - // We know that `rootObject` is a root shader object created - // from our program, and that it is set up to hold values for - // all the parameter of that program. In order to actually - // set values, we need to be able to look up the location - // of speciic parameter that we want to set. - // - // Our example graphics API layer supports this operation - // with the idea of a *shader cursor* which can be thought - // of as pointing "into" a particular shader object at - // some location/offset. This design choice abstracts over - // the many ways that different platforms and APIs represent - // the necessary offset information. - // - // We construct an initial shader cursor that points at the - // entire shader program. You can think of this as akin to - // a diretory path of `/` for the root directory in a file - // system. - // - ShaderCursor rootCursor(rootObject); - // - // Next, we use a convenience overload of `operator[]` to - // navigate from the root cursor down to the parameter we - // want to set. - // - // The operation `rootCursor["Uniforms"]` looks up the - // offset/location of the global shader parameter `Uniforms` - // (which is a uniform/constant buffer), and the subsequent - // `["modelViewProjection"]` step navigates from there down - // to the member named `modelViewProjection` in that buffer. - // - // Once we have formed a cursor that "points" at the - // model-view projection matrix, we can set its data directly. - // - rootCursor["Uniforms"]["modelViewProjection"].setData( - deviceInfo.identityProjectionMatrix, sizeof(float) * 16); - // - // Some readers might be concerned about the performance o - // the above operations because of the use of strings. For - // those readers, here are two things to note: - // - // * While these `operator[]` steps do need to perform string - // comparisons, they do *not* make copies of the strings or - // perform any heap allocation. - // - // * There are other overloads of `operator[]` that use the - // *index* of a parameter/field instead of its name, and those - // operations have fixed/constant overhead and perform no - // string comparisons. The indices used are independent of - // the target platform and graphics API, and can thus be - // hard-coded even in cross-platform code. - // + // We will create objects needed to configur the "input assembler" + // (IA) stage of the D3D pipeline. + // + // First, we create an input layout: + // + InputElementDesc inputElements[] = { + {"POSITION", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, position)}, + {"COLOR", 0, Format::R32G32B32_FLOAT, offsetof(Vertex, color)}, + }; + auto inputLayout = gDevice->createInputLayout(sizeof(Vertex), &inputElements[0], 2); + if (!inputLayout) + return SLANG_FAIL; + + // Next we allocate a vertex buffer for our pre-initialized + // vertex data. + // + IBufferResource::Desc vertexBufferDesc; + vertexBufferDesc.type = IResource::Type::Buffer; + vertexBufferDesc.sizeInBytes = kVertexCount * sizeof(Vertex); + vertexBufferDesc.defaultState = ResourceState::VertexBuffer; + gVertexBuffer = gDevice->createBufferResource(vertexBufferDesc, &kVertexData[0]); + if (!gVertexBuffer) + return SLANG_FAIL; + + // Now we will use our `loadShaderProgram` function to load + // the code from `shaders.slang` into the graphics API. + // + ComPtr shaderProgram; + SLANG_RETURN_ON_FAIL(loadShaderProgram(gDevice, shaderProgram.writeRef())); - // We also need to set up a few pieces of fixed-function pipeline - // state that are not bound by the pipeline state above. - // - renderEncoder->setVertexBuffer(0, gVertexBuffer); - renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + // Following the D3D12/Vulkan style of API, we need a pipeline state object + // (PSO) to encapsulate the configuration of the overall graphics pipeline. + // + GraphicsPipelineStateDesc desc; + desc.inputLayout = inputLayout; + desc.program = shaderProgram; + desc.framebufferLayout = gFramebufferLayout; + auto pipelineState = gDevice->createGraphicsPipelineState(desc); + if (!pipelineState) + return SLANG_FAIL; - // Finally, we are ready to issue a draw call for a single triangle. - // - renderEncoder->draw(3); - renderEncoder->endEncoding(); - commandBuffer->close(); - gQueue->executeCommandBuffer(commandBuffer); + gPipelineState = pipelineState; + + return SLANG_OK; + } - if (!isTestMode()) + // With the initialization out of the way, we can now turn our attention + // to the per-frame rendering logic. As with the initialization, there is + // nothing really Slang-specific here, so the commentary doesn't need + // to be very detailed. + // + virtual void renderFrame(int frameBufferIndex) override { - // With that, we are done drawing for one frame, and ready for the next. + ComPtr commandBuffer = + gTransientHeaps[frameBufferIndex]->createCommandBuffer(); + auto renderEncoder = + commandBuffer->encodeRenderCommands(gRenderPass, gFramebuffers[frameBufferIndex]); + + gfx::Viewport viewport = {}; + viewport.maxZ = 1.0f; + viewport.extentX = (float)windowWidth; + viewport.extentY = (float)windowHeight; + renderEncoder->setViewportAndScissor(viewport); + + // In order to bind shader parameters to the pipeline, we need + // to know how those parameters were assigned to locations/bindings/registers + // for the target graphics API. // - gSwapchain->present(); - } -} + // The Slang compiler assigns locations to parameters in a deterministic + // fashion, so it is possible for a programmer to hard-code locations + // into their application code that will match up with their shaders. + // + // Hard-coding of locations can become intractable as an application needs + // to support more different target platforms and graphics APIs, as well + // as more shaders with different specialized variants. + // + // Rather than rely on hard-coded locations, our examples will make use of + // reflection information provided by the Slang compiler (see `programLayout` + // above), and our example graphics API layer will translate that reflection + // information into a layout for a "root shader object." + // + // The root object will store values/bindings for all of the parameters in + // the `IShaderProgram` used to create the pipeline state. At a conceptual + // level we can think of `rootObject` as representing the "global scope" of + // the shader program that was loaded; it has entries for each global shader + // parameter that was declared. + // + // Readers who are familiar with D3D12 or Vulkan might think of this root + // layout as being similar in spirit to a "root signature" or "pipeline layout." + // + // We start parameter binding by binding the pipeline state in command encoder. + // This method will return a transient root shader object for us to write our + // shader parameters into. + // + auto rootObject = renderEncoder->bindPipeline(gPipelineState); + + // We will update the model-view-projection matrix that is passed + // into the shader code via the `Uniforms` buffer on a per-frame + // basis, even though the data that is loaded does not change + // per-frame (we always use an identity matrix). + // + auto deviceInfo = gDevice->getDeviceInfo(); + + // We know that `rootObject` is a root shader object created + // from our program, and that it is set up to hold values for + // all the parameter of that program. In order to actually + // set values, we need to be able to look up the location + // of speciic parameter that we want to set. + // + // Our example graphics API layer supports this operation + // with the idea of a *shader cursor* which can be thought + // of as pointing "into" a particular shader object at + // some location/offset. This design choice abstracts over + // the many ways that different platforms and APIs represent + // the necessary offset information. + // + // We construct an initial shader cursor that points at the + // entire shader program. You can think of this as akin to + // a diretory path of `/` for the root directory in a file + // system. + // + ShaderCursor rootCursor(rootObject); + // + // Next, we use a convenience overload of `operator[]` to + // navigate from the root cursor down to the parameter we + // want to set. + // + // The operation `rootCursor["Uniforms"]` looks up the + // offset/location of the global shader parameter `Uniforms` + // (which is a uniform/constant buffer), and the subsequent + // `["modelViewProjection"]` step navigates from there down + // to the member named `modelViewProjection` in that buffer. + // + // Once we have formed a cursor that "points" at the + // model-view projection matrix, we can set its data directly. + // + rootCursor["Uniforms"]["modelViewProjection"].setData( + deviceInfo.identityProjectionMatrix, + sizeof(float) * 16); + // + // Some readers might be concerned about the performance o + // the above operations because of the use of strings. For + // those readers, here are two things to note: + // + // * While these `operator[]` steps do need to perform string + // comparisons, they do *not* make copies of the strings or + // perform any heap allocation. + // + // * There are other overloads of `operator[]` that use the + // *index* of a parameter/field instead of its name, and those + // operations have fixed/constant overhead and perform no + // string comparisons. The indices used are independent of + // the target platform and graphics API, and can thus be + // hard-coded even in cross-platform code. + // + + // We also need to set up a few pieces of fixed-function pipeline + // state that are not bound by the pipeline state above. + // + renderEncoder->setVertexBuffer(0, gVertexBuffer); + renderEncoder->setPrimitiveTopology(PrimitiveTopology::TriangleList); + // Finally, we are ready to issue a draw call for a single triangle. + // + renderEncoder->draw(3); + renderEncoder->endEncoding(); + commandBuffer->close(); + gQueue->executeCommandBuffer(commandBuffer); + + if (!isTestMode()) + { + // With that, we are done drawing for one frame, and ready for the next. + // + gSwapchain->present(); + } + } }; // This macro instantiates an appropriate main function to diff --git a/examples/triangle/shaders.slang b/examples/triangle/shaders.slang index fe35db9c86..2d371ea393 100644 --- a/examples/triangle/shaders.slang +++ b/examples/triangle/shaders.slang @@ -57,10 +57,12 @@ VertexStageOutput vertexMain( // Fragment Shader [shader("fragment")] -float4 fragmentMain( +Fragment fragmentMain( CoarseVertex coarseVertex : CoarseVertex) : SV_Target { float3 color = coarseVertex.color; - return float4(color, 1.0); + Fragment output; + output.color = float4(color, 1.0); + return output; } diff --git a/external/.clang-format b/external/.clang-format new file mode 100644 index 0000000000..e3845288a2 --- /dev/null +++ b/external/.clang-format @@ -0,0 +1 @@ +DisableFormat: true diff --git a/external/CMakeLists.txt b/external/CMakeLists.txt index e72e416073..43105a5f05 100644 --- a/external/CMakeLists.txt +++ b/external/CMakeLists.txt @@ -8,6 +8,16 @@ if(NOT CMAKE_MESSAGE_LOG_LEVEL) set(CMAKE_MESSAGE_LOG_LEVEL NOTICE) endif() +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.25") + set(system SYSTEM) +else() + message( + STATUS + "CMake 3.25 is required to suppress warnings originating in headers in external/ but you are using ${CMAKE_VERSION}, be prepared for some warnings" + ) + set(system) +endif() + # Similarly, disable warnings for external projects if(NOT SLANG_ENABLE_EXTERNAL_COMPILER_WARNINGS) if(MSVC) @@ -17,35 +27,50 @@ if(NOT SLANG_ENABLE_EXTERNAL_COMPILER_WARNINGS) endif() endif() +if(NOT ${SLANG_USE_SYSTEM_UNORDERED_DENSE}) + add_subdirectory(unordered_dense EXCLUDE_FROM_ALL ${system}) +endif() + # Miniz -add_subdirectory(miniz EXCLUDE_FROM_ALL SYSTEM) -set_property(TARGET miniz PROPERTY POSITION_INDEPENDENT_CODE ON) -# Work around https://github.com/richgel999/miniz/pull/292 -get_target_property(miniz_c_launcher miniz C_COMPILER_LAUNCHER) -if(MSVC AND miniz_c_launcher MATCHES "ccache") - set_property(TARGET miniz PROPERTY C_COMPILER_LAUNCHER) - set_property(TARGET miniz PROPERTY MSVC_DEBUG_INFORMATION_FORMAT "") +if(NOT ${SLANG_USE_SYSTEM_MINIZ}) + add_subdirectory(miniz EXCLUDE_FROM_ALL ${system}) + set_property(TARGET miniz PROPERTY POSITION_INDEPENDENT_CODE ON) + # Work around https://github.com/richgel999/miniz/pull/292 + get_target_property(miniz_c_launcher miniz C_COMPILER_LAUNCHER) + if(MSVC AND miniz_c_launcher MATCHES "ccache") + set_property(TARGET miniz PROPERTY C_COMPILER_LAUNCHER) + set_property(TARGET miniz PROPERTY MSVC_DEBUG_INFORMATION_FORMAT "") + endif() endif() # LZ4 -set(LZ4_BUNDLED_MODE ON) -add_subdirectory(lz4/build/cmake EXCLUDE_FROM_ALL SYSTEM) -if(MSVC) - target_compile_options( - lz4_static - PRIVATE /wd5045 /wd4820 /wd4711 /wd6385 /wd6262 - ) +if(NOT ${SLANG_USE_SYSTEM_LZ4}) + set(LZ4_BUNDLED_MODE ON) + add_subdirectory(lz4/build/cmake EXCLUDE_FROM_ALL ${system}) + if(MSVC) + target_compile_options( + lz4_static + PRIVATE /wd5045 /wd4820 /wd4711 /wd6385 /wd6262 + ) + endif() endif() # Vulkan headers -add_subdirectory(vulkan EXCLUDE_FROM_ALL SYSTEM) +if(NOT ${SLANG_USE_SYSTEM_VULKAN_HEADERS}) + add_subdirectory(vulkan EXCLUDE_FROM_ALL ${system}) +endif() # metal-cpp headers add_library(metal-cpp INTERFACE) -target_include_directories(metal-cpp INTERFACE "${CMAKE_CURRENT_LIST_DIR}/metal-cpp") +target_include_directories( + metal-cpp + INTERFACE "${CMAKE_CURRENT_LIST_DIR}/metal-cpp" +) # SPIRV-Headers -add_subdirectory(spirv-headers EXCLUDE_FROM_ALL SYSTEM) +if(NOT ${SLANG_USE_SYSTEM_SPIRV_HEADERS}) + add_subdirectory(spirv-headers EXCLUDE_FROM_ALL ${system}) +endif() if(SLANG_ENABLE_SLANG_GLSLANG) # SPIRV-Tools @@ -53,24 +78,43 @@ if(SLANG_ENABLE_SLANG_GLSLANG) set(SPIRV_WERROR OFF) set(SPIRV_HEADER_DIR "${CMAKE_CURRENT_LIST_DIR}/spirv-headers/") set(SPIRV_SKIP_TESTS ON) - add_subdirectory(spirv-tools EXCLUDE_FROM_ALL SYSTEM) + add_subdirectory(spirv-tools EXCLUDE_FROM_ALL ${system}) # glslang set(SKIP_GLSLANG_INSTALL ON) set(ENABLE_OPT ON) set(ENABLE_PCH OFF) - add_subdirectory(glslang EXCLUDE_FROM_ALL SYSTEM) + add_subdirectory(glslang EXCLUDE_FROM_ALL ${system}) endif() # imgui add_library(imgui INTERFACE) target_include_directories(imgui INTERFACE "${CMAKE_CURRENT_LIST_DIR}/imgui") +# stb +add_library(stb INTERFACE) +target_include_directories(stb INTERFACE "${CMAKE_CURRENT_LIST_DIR}/stb") + # slang-rhi -set(SLANG_RHI_SLANG_INCLUDE_DIR ${CMAKE_SOURCE_DIR}/include) -set(SLANG_RHI_SLANG_BINARY_DIR ${CMAKE_BINARY_DIR}) -set(SLANG_RHI_BUILD_TESTS OFF) -add_subdirectory(slang-rhi) +if(SLANG_ENABLE_SLANG_RHI) + set(SLANG_RHI_BINARY_DIR ${CMAKE_BINARY_DIR}/$/bin) + set(SLANG_RHI_SLANG_INCLUDE_DIR ${slang_SOURCE_DIR}/include) + set(SLANG_RHI_SLANG_BINARY_DIR ${CMAKE_BINARY_DIR}) + set(SLANG_RHI_BUILD_TESTS OFF) + set(SLANG_RHI_BUILD_EXAMPLES OFF) + + # Not disabling these break tests (issue #5474) + set(SLANG_RHI_FETCH_DXC OFF) + set(SLANG_RHI_FETCH_AGILITY_SDK OFF) + + if(SLANG_ENABLE_DX_ON_VK) + set(SLANG_RHI_HAS_D3D12 ON) + endif() + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + set(SLANG_RHI_ENABLE_WGPU OFF) + endif() + add_subdirectory(slang-rhi) +endif() # Tidy things up: diff --git a/external/build-llvm.sh b/external/build-llvm.sh index 95302a742b..0575bf4bfb 100755 --- a/external/build-llvm.sh +++ b/external/build-llvm.sh @@ -20,7 +20,7 @@ EOF # # Some helper functions # -msg(){ +msg() { printf "%s\n" "$1" >&2 } @@ -62,13 +62,35 @@ extra_arguments=() while [[ "$#" -gt 0 ]]; do case $1 in - -h | --help) help; exit ;; - --repo) repo=$2; shift;; - --branch) branch=$2; shift;; - --source-dir) source_dir=$2; shift;; - --config) config=$2; shift;; - --install-prefix) install_prefix=$2; shift;; - --) shift; extra_arguments+=("$@"); break;; + -h | --help) + help + exit + ;; + --repo) + repo=$2 + shift + ;; + --branch) + branch=$2 + shift + ;; + --source-dir) + source_dir=$2 + shift + ;; + --config) + config=$2 + shift + ;; + --install-prefix) + install_prefix=$2 + shift + ;; + --) + shift + extra_arguments+=("$@") + break + ;; *) msg "Unknown parameter passed: $1" help >&2 diff --git a/external/bump-glslang.sh b/external/bump-glslang.sh index b7d30e3a07..d3923cf0e7 100755 --- a/external/bump-glslang.sh +++ b/external/bump-glslang.sh @@ -35,7 +35,7 @@ while [[ "$#" -gt 0 ]]; do shift done -if [ $help ]; then +if [ "$help" ]; then me=$(basename "$0") cat < /dev/null - then - echo "This script needs $1, but it isn't in \$PATH" - missing_bin=1 +require_bin() { + if ! command -v "$1" &>/dev/null; then + echo "This script needs $1, but it isn't in \$PATH" + missing_bin=1 fi } require_bin "jq" require_bin "git" require_bin "python" require_bin "cmake" -if [ $missing_bin ]; then +if [ "$missing_bin" ]; then exit 1 fi @@ -100,13 +97,13 @@ if ! test -f "$glslang/.git"; then exit 1 fi -known_good_commit(){ +known_good_commit() { jq <"$glslang/known_good.json" \ ".commits | .[] | select(.name == \"$1\") | .commit" \ --raw-output } -bump_dep(){ +bump_dep() { commit=$(known_good_commit "$2") big_msg "Fetching $commit from origin in $1" git -C "$1" fetch origin "$commit" @@ -116,7 +113,7 @@ bump_dep(){ declare -A old_ref declare -A new_ref -merge_dep(){ +merge_dep() { name=$1 dir=$2 up=$3 @@ -180,14 +177,15 @@ rm -f "$spirv_tools_generated/*.{inc,h}" cp --target-directory "$spirv_tools_generated" "$build"/*.{inc,h} set +x -if [ $do_commit ]; then +if [ "$do_commit" ]; then big_msg "Committing changes" - msg=$(cat < ${new_ref["glslang"]} external/spirv-tools: ${old_ref["spirv-tools"]} -> ${new_ref["spirv-tools"]}" EOF -) + ) git commit \ --message "$msg" \ diff --git a/external/slang-rhi b/external/slang-rhi index 54317882dd..6c495919b9 160000 --- a/external/slang-rhi +++ b/external/slang-rhi @@ -1 +1 @@ -Subproject commit 54317882dd20c131f8c9bcdbe844242763d58039 +Subproject commit 6c495919b92754f8489eb0085ad859344963dcd2 diff --git a/external/slang-tint-headers/slang-tint.h b/external/slang-tint-headers/slang-tint.h new file mode 100644 index 0000000000..ee70b56070 --- /dev/null +++ b/external/slang-tint-headers/slang-tint.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +struct tint_CompileRequest +{ + const char* wgslCode; + size_t wgslCodeLength; +}; + +struct tint_CompileResult +{ + const uint8_t* buffer; + size_t bufferSize; + const char* error; +}; + + +typedef int (*tint_CompileFunc)(tint_CompileRequest* request, tint_CompileResult* result); + +typedef void (*tint_FreeResultFunc)(tint_CompileResult* result); diff --git a/external/spirv-headers b/external/spirv-headers index 2acb319af3..2a9b6f951c 160000 --- a/external/spirv-headers +++ b/external/spirv-headers @@ -1 +1 @@ -Subproject commit 2acb319af38d43be3ea76bfabf3998e5281d8d12 +Subproject commit 2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801 diff --git a/external/spirv-tools b/external/spirv-tools index ce46482db7..db36df60af 160000 --- a/external/spirv-tools +++ b/external/spirv-tools @@ -1 +1 @@ -Subproject commit ce46482db7ab3ea9c52fce832d27ca40b14f8e87 +Subproject commit db36df60afcfe3ee8370c78d6c231c6f2f64c5b9 diff --git a/external/spirv-tools-generated/build-version.inc b/external/spirv-tools-generated/build-version.inc index afc77a6d49..a7f7126df2 100644 --- a/external/spirv-tools-generated/build-version.inc +++ b/external/spirv-tools-generated/build-version.inc @@ -1 +1 @@ -"v2024.2", "SPIRV-Tools v2024.2 v2024.2-24-gce46482d" +"v2024.3", "SPIRV-Tools v2024.3 v2022.2-674-ge8c2fbca" diff --git a/external/spirv-tools-generated/core.insts-unified1.inc b/external/spirv-tools-generated/core.insts-unified1.inc index 5550ea5c5c..522ac17812 100644 --- a/external/spirv-tools-generated/core.insts-unified1.inc +++ b/external/spirv-tools-generated/core.insts-unified1.inc @@ -1,5 +1,6 @@ static const spv::Capability pygen_variable_caps_Addresses[] = {spv::Capability::Addresses}; static const spv::Capability pygen_variable_caps_AddressesPhysicalStorageBufferAddresses[] = {spv::Capability::Addresses, spv::Capability::PhysicalStorageBufferAddresses}; +static const spv::Capability pygen_variable_caps_AddressesUntypedPointersKHR[] = {spv::Capability::Addresses, spv::Capability::UntypedPointersKHR}; static const spv::Capability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBuffer[] = {spv::Capability::Addresses, spv::Capability::VariablePointers, spv::Capability::VariablePointersStorageBuffer}; static const spv::Capability pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddresses[] = {spv::Capability::Addresses, spv::Capability::VariablePointers, spv::Capability::VariablePointersStorageBuffer, spv::Capability::PhysicalStorageBufferAddresses}; static const spv::Capability pygen_variable_caps_ArbitraryPrecisionFixedPointINTEL[] = {spv::Capability::ArbitraryPrecisionFixedPointINTEL}; @@ -76,6 +77,7 @@ static const spv::Capability pygen_variable_caps_SubgroupAvcMotionEstimationINTE static const spv::Capability pygen_variable_caps_SubgroupAvcMotionEstimationINTELSubgroupAvcMotionEstimationIntraINTEL[] = {spv::Capability::SubgroupAvcMotionEstimationINTEL, spv::Capability::SubgroupAvcMotionEstimationIntraINTEL}; static const spv::Capability pygen_variable_caps_SubgroupBallotKHR[] = {spv::Capability::SubgroupBallotKHR}; static const spv::Capability pygen_variable_caps_SubgroupBufferBlockIOINTEL[] = {spv::Capability::SubgroupBufferBlockIOINTEL}; +static const spv::Capability pygen_variable_caps_SubgroupBufferPrefetchINTEL[] = {spv::Capability::SubgroupBufferPrefetchINTEL}; static const spv::Capability pygen_variable_caps_SubgroupDispatch[] = {spv::Capability::SubgroupDispatch}; static const spv::Capability pygen_variable_caps_SubgroupImageBlockIOINTEL[] = {spv::Capability::SubgroupImageBlockIOINTEL}; static const spv::Capability pygen_variable_caps_SubgroupImageMediaBlockIOINTEL[] = {spv::Capability::SubgroupImageMediaBlockIOINTEL}; @@ -90,6 +92,7 @@ static const spv::Capability pygen_variable_caps_TileImageDepthReadAccessEXT[] = static const spv::Capability pygen_variable_caps_TileImageStencilReadAccessEXT[] = {spv::Capability::TileImageStencilReadAccessEXT}; static const spv::Capability pygen_variable_caps_USMStorageClassesINTEL[] = {spv::Capability::USMStorageClassesINTEL}; static const spv::Capability pygen_variable_caps_UnstructuredLoopControlsINTEL[] = {spv::Capability::UnstructuredLoopControlsINTEL}; +static const spv::Capability pygen_variable_caps_UntypedPointersKHR[] = {spv::Capability::UntypedPointersKHR}; static const spv::Capability pygen_variable_caps_VariableLengthArrayINTEL[] = {spv::Capability::VariableLengthArrayINTEL}; static const spv::Capability pygen_variable_caps_VectorComputeINTEL[] = {spv::Capability::VectorComputeINTEL}; @@ -143,7 +146,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"TypeVoid", spv::Op::OpTypeVoid, 0, nullptr, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"TypeBool", spv::Op::OpTypeBool, 0, nullptr, 1, {SPV_OPERAND_TYPE_RESULT_ID}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"TypeInt", spv::Op::OpTypeInt, 0, nullptr, 3, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, - {"TypeFloat", spv::Op::OpTypeFloat, 0, nullptr, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, + {"TypeFloat", spv::Op::OpTypeFloat, 0, nullptr, 3, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_OPTIONAL_FPENCODING}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"TypeVector", spv::Op::OpTypeVector, 0, nullptr, 3, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"TypeMatrix", spv::Op::OpTypeMatrix, 1, pygen_variable_caps_Matrix, 3, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"TypeImage", spv::Op::OpTypeImage, 0, nullptr, 9, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_DIMENSIONALITY, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_SAMPLER_IMAGE_FORMAT, SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER}, 1, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, @@ -181,7 +184,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"Load", spv::Op::OpLoad, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"Store", spv::Op::OpStore, 0, nullptr, 3, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"CopyMemory", spv::Op::OpCopyMemory, 0, nullptr, 4, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, - {"CopyMemorySized", spv::Op::OpCopyMemorySized, 1, pygen_variable_caps_Addresses, 5, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, + {"CopyMemorySized", spv::Op::OpCopyMemorySized, 2, pygen_variable_caps_AddressesUntypedPointersKHR, 5, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"AccessChain", spv::Op::OpAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"InBoundsAccessChain", spv::Op::OpInBoundsAccessChain, 0, nullptr, 4, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"PtrAccessChain", spv::Op::OpPtrAccessChain, 4, pygen_variable_caps_AddressesVariablePointersVariablePointersStorageBufferPhysicalStorageBufferAddresses, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, @@ -472,8 +475,16 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"DepthAttachmentReadEXT", spv::Op::OpDepthAttachmentReadEXT, 1, pygen_variable_caps_TileImageDepthReadAccessEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"StencilAttachmentReadEXT", spv::Op::OpStencilAttachmentReadEXT, 1, pygen_variable_caps_TileImageStencilReadAccessEXT, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"TerminateInvocation", spv::Op::OpTerminateInvocation, 1, pygen_variable_caps_Shader, 0, {}, 0, 0, 1, pygen_variable_exts_SPV_KHR_terminate_invocation, SPV_SPIRV_VERSION_WORD(1,6), 0xffffffffu}, + {"TypeUntypedPointerKHR", spv::Op::OpTypeUntypedPointerKHR, 1, pygen_variable_caps_UntypedPointersKHR, 2, {SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_STORAGE_CLASS}, 1, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedVariableKHR", spv::Op::OpUntypedVariableKHR, 1, pygen_variable_caps_UntypedPointersKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_STORAGE_CLASS, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedAccessChainKHR", spv::Op::OpUntypedAccessChainKHR, 1, pygen_variable_caps_UntypedPointersKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedInBoundsAccessChainKHR", spv::Op::OpUntypedInBoundsAccessChainKHR, 1, pygen_variable_caps_UntypedPointersKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"SubgroupBallotKHR", spv::Op::OpSubgroupBallotKHR, 1, pygen_variable_caps_SubgroupBallotKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_shader_ballot, 0xffffffffu, 0xffffffffu}, {"SubgroupFirstInvocationKHR", spv::Op::OpSubgroupFirstInvocationKHR, 1, pygen_variable_caps_SubgroupBallotKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_shader_ballot, 0xffffffffu, 0xffffffffu}, + {"UntypedPtrAccessChainKHR", spv::Op::OpUntypedPtrAccessChainKHR, 1, pygen_variable_caps_UntypedPointersKHR, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedInBoundsPtrAccessChainKHR", spv::Op::OpUntypedInBoundsPtrAccessChainKHR, 1, pygen_variable_caps_UntypedPointersKHR, 6, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_VARIABLE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedArrayLengthKHR", spv::Op::OpUntypedArrayLengthKHR, 1, pygen_variable_caps_UntypedPointersKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_LITERAL_INTEGER}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"UntypedPrefetchKHR", spv::Op::OpUntypedPrefetchKHR, 1, pygen_variable_caps_UntypedPointersKHR, 5, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID, SPV_OPERAND_TYPE_OPTIONAL_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"SubgroupAllKHR", spv::Op::OpSubgroupAllKHR, 1, pygen_variable_caps_SubgroupVoteKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_subgroup_vote, 0xffffffffu, 0xffffffffu}, {"SubgroupAnyKHR", spv::Op::OpSubgroupAnyKHR, 1, pygen_variable_caps_SubgroupVoteKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_subgroup_vote, 0xffffffffu, 0xffffffffu}, {"SubgroupAllEqualKHR", spv::Op::OpSubgroupAllEqualKHR, 1, pygen_variable_caps_SubgroupVoteKHR, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 1, pygen_variable_exts_SPV_KHR_subgroup_vote, 0xffffffffu, 0xffffffffu}, @@ -851,6 +862,7 @@ static const spv_opcode_desc_t kOpcodeTableEntries[] = { {"ConvertBF16ToFINTEL", spv::Op::OpConvertBF16ToFINTEL, 1, pygen_variable_caps_BFloat16ConversionINTEL, 3, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"ControlBarrierArriveINTEL", spv::Op::OpControlBarrierArriveINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"ControlBarrierWaitINTEL", spv::Op::OpControlBarrierWaitINTEL, 1, pygen_variable_caps_SplitBarrierINTEL, 3, {SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_MEMORY_SEMANTICS_ID}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, + {"SubgroupBlockPrefetchINTEL", spv::Op::OpSubgroupBlockPrefetchINTEL, 1, pygen_variable_caps_SubgroupBufferPrefetchINTEL, 3, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_OPTIONAL_MEMORY_ACCESS}, 0, 0, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"GroupIMulKHR", spv::Op::OpGroupIMulKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"GroupFMulKHR", spv::Op::OpGroupFMulKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, {"GroupBitwiseAndKHR", spv::Op::OpGroupBitwiseAndKHR, 1, pygen_variable_caps_GroupUniformArithmeticKHR, 5, {SPV_OPERAND_TYPE_TYPE_ID, SPV_OPERAND_TYPE_RESULT_ID, SPV_OPERAND_TYPE_SCOPE_ID, SPV_OPERAND_TYPE_GROUP_OPERATION, SPV_OPERAND_TYPE_ID}, 1, 1, 0, nullptr, 0xffffffffu, 0xffffffffu}, diff --git a/external/spirv-tools-generated/enum_string_mapping.inc b/external/spirv-tools-generated/enum_string_mapping.inc index a93c413975..7c97fe8553 100644 --- a/external/spirv-tools-generated/enum_string_mapping.inc +++ b/external/spirv-tools-generated/enum_string_mapping.inc @@ -44,6 +44,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_EXT_opacity_micromap"; case Extension::kSPV_EXT_physical_storage_buffer: return "SPV_EXT_physical_storage_buffer"; + case Extension::kSPV_EXT_relaxed_printf_string_address_space: + return "SPV_EXT_relaxed_printf_string_address_space"; case Extension::kSPV_EXT_replicated_composites: return "SPV_EXT_replicated_composites"; case Extension::kSPV_EXT_shader_atomic_float16_add: @@ -140,6 +142,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_INTEL_shader_integer_functions2"; case Extension::kSPV_INTEL_split_barrier: return "SPV_INTEL_split_barrier"; + case Extension::kSPV_INTEL_subgroup_buffer_prefetch: + return "SPV_INTEL_subgroup_buffer_prefetch"; case Extension::kSPV_INTEL_subgroups: return "SPV_INTEL_subgroups"; case Extension::kSPV_INTEL_unstructured_loop_controls: @@ -156,6 +160,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_KHR_8bit_storage"; case Extension::kSPV_KHR_bit_instructions: return "SPV_KHR_bit_instructions"; + case Extension::kSPV_KHR_compute_shader_derivatives: + return "SPV_KHR_compute_shader_derivatives"; case Extension::kSPV_KHR_cooperative_matrix: return "SPV_KHR_cooperative_matrix"; case Extension::kSPV_KHR_device_group: @@ -218,6 +224,8 @@ const char* ExtensionToString(Extension extension) { return "SPV_KHR_terminate_invocation"; case Extension::kSPV_KHR_uniform_group_instructions: return "SPV_KHR_uniform_group_instructions"; + case Extension::kSPV_KHR_untyped_pointers: + return "SPV_KHR_untyped_pointers"; case Extension::kSPV_KHR_variable_pointers: return "SPV_KHR_variable_pointers"; case Extension::kSPV_KHR_vulkan_memory_model: @@ -277,8 +285,8 @@ const char* ExtensionToString(Extension extension) { bool GetExtensionFromString(const char* str, Extension* extension) { - static const char* known_ext_strs[] = { "SPV_AMDX_shader_enqueue", "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_early_and_late_fragment_tests", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_ARM_cooperative_matrix_layouts", "SPV_ARM_core_builtins", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_mesh_shader", "SPV_EXT_opacity_micromap", "SPV_EXT_physical_storage_buffer", "SPV_EXT_replicated_composites", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_tile_image", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_bfloat16_conversion", "SPV_INTEL_blocking_pipes", "SPV_INTEL_cache_controls", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fp_max_error", "SPV_INTEL_fpga_argument_interfaces", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_dsp_control", "SPV_INTEL_fpga_invocation_pipelining_attributes", "SPV_INTEL_fpga_latency_control", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_global_variable_fpga_decorations", "SPV_INTEL_global_variable_host_access", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_composites", "SPV_INTEL_loop_fuse", "SPV_INTEL_masked_gather_scatter", "SPV_INTEL_maximum_registers", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_runtime_aligned", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_split_barrier", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_cooperative_matrix", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_float_controls2", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_maximal_reconvergence", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_quad_control", "SPV_KHR_ray_cull_mask", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_ray_tracing_position_fetch", "SPV_KHR_relaxed_extended_instruction", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_rotate", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_uniform_group_instructions", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_displacement_micromap", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_raw_access_chains", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_atomic_fp16_vector", "SPV_NV_shader_image_footprint", "SPV_NV_shader_invocation_reorder", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_QCOM_image_processing", "SPV_QCOM_image_processing2", "SPV_VALIDATOR_ignore_type_decl_unique" }; - static const Extension known_ext_ids[] = { Extension::kSPV_AMDX_shader_enqueue, Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_early_and_late_fragment_tests, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_ARM_cooperative_matrix_layouts, Extension::kSPV_ARM_core_builtins, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_mesh_shader, Extension::kSPV_EXT_opacity_micromap, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_replicated_composites, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_tile_image, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_bfloat16_conversion, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_cache_controls, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fp_max_error, Extension::kSPV_INTEL_fpga_argument_interfaces, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_dsp_control, Extension::kSPV_INTEL_fpga_invocation_pipelining_attributes, Extension::kSPV_INTEL_fpga_latency_control, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_global_variable_fpga_decorations, Extension::kSPV_INTEL_global_variable_host_access, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_composites, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_masked_gather_scatter, Extension::kSPV_INTEL_maximum_registers, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_runtime_aligned, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_split_barrier, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_cooperative_matrix, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_float_controls2, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_maximal_reconvergence, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_quad_control, Extension::kSPV_KHR_ray_cull_mask, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_ray_tracing_position_fetch, Extension::kSPV_KHR_relaxed_extended_instruction, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_rotate, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_uniform_group_instructions, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_displacement_micromap, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_raw_access_chains, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_atomic_fp16_vector, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_invocation_reorder, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_QCOM_image_processing, Extension::kSPV_QCOM_image_processing2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; + static const char* known_ext_strs[] = { "SPV_AMDX_shader_enqueue", "SPV_AMD_gcn_shader", "SPV_AMD_gpu_shader_half_float", "SPV_AMD_gpu_shader_half_float_fetch", "SPV_AMD_gpu_shader_int16", "SPV_AMD_shader_ballot", "SPV_AMD_shader_early_and_late_fragment_tests", "SPV_AMD_shader_explicit_vertex_parameter", "SPV_AMD_shader_fragment_mask", "SPV_AMD_shader_image_load_store_lod", "SPV_AMD_shader_trinary_minmax", "SPV_AMD_texture_gather_bias_lod", "SPV_ARM_cooperative_matrix_layouts", "SPV_ARM_core_builtins", "SPV_EXT_demote_to_helper_invocation", "SPV_EXT_descriptor_indexing", "SPV_EXT_fragment_fully_covered", "SPV_EXT_fragment_invocation_density", "SPV_EXT_fragment_shader_interlock", "SPV_EXT_mesh_shader", "SPV_EXT_opacity_micromap", "SPV_EXT_physical_storage_buffer", "SPV_EXT_relaxed_printf_string_address_space", "SPV_EXT_replicated_composites", "SPV_EXT_shader_atomic_float16_add", "SPV_EXT_shader_atomic_float_add", "SPV_EXT_shader_atomic_float_min_max", "SPV_EXT_shader_image_int64", "SPV_EXT_shader_stencil_export", "SPV_EXT_shader_tile_image", "SPV_EXT_shader_viewport_index_layer", "SPV_GOOGLE_decorate_string", "SPV_GOOGLE_hlsl_functionality1", "SPV_GOOGLE_user_type", "SPV_INTEL_arbitrary_precision_fixed_point", "SPV_INTEL_arbitrary_precision_floating_point", "SPV_INTEL_arbitrary_precision_integers", "SPV_INTEL_bfloat16_conversion", "SPV_INTEL_blocking_pipes", "SPV_INTEL_cache_controls", "SPV_INTEL_debug_module", "SPV_INTEL_device_side_avc_motion_estimation", "SPV_INTEL_float_controls2", "SPV_INTEL_fp_fast_math_mode", "SPV_INTEL_fp_max_error", "SPV_INTEL_fpga_argument_interfaces", "SPV_INTEL_fpga_buffer_location", "SPV_INTEL_fpga_cluster_attributes", "SPV_INTEL_fpga_dsp_control", "SPV_INTEL_fpga_invocation_pipelining_attributes", "SPV_INTEL_fpga_latency_control", "SPV_INTEL_fpga_loop_controls", "SPV_INTEL_fpga_memory_accesses", "SPV_INTEL_fpga_memory_attributes", "SPV_INTEL_fpga_reg", "SPV_INTEL_function_pointers", "SPV_INTEL_global_variable_fpga_decorations", "SPV_INTEL_global_variable_host_access", "SPV_INTEL_inline_assembly", "SPV_INTEL_io_pipes", "SPV_INTEL_kernel_attributes", "SPV_INTEL_long_composites", "SPV_INTEL_loop_fuse", "SPV_INTEL_masked_gather_scatter", "SPV_INTEL_maximum_registers", "SPV_INTEL_media_block_io", "SPV_INTEL_memory_access_aliasing", "SPV_INTEL_optnone", "SPV_INTEL_runtime_aligned", "SPV_INTEL_shader_integer_functions2", "SPV_INTEL_split_barrier", "SPV_INTEL_subgroup_buffer_prefetch", "SPV_INTEL_subgroups", "SPV_INTEL_unstructured_loop_controls", "SPV_INTEL_usm_storage_classes", "SPV_INTEL_variable_length_array", "SPV_INTEL_vector_compute", "SPV_KHR_16bit_storage", "SPV_KHR_8bit_storage", "SPV_KHR_bit_instructions", "SPV_KHR_compute_shader_derivatives", "SPV_KHR_cooperative_matrix", "SPV_KHR_device_group", "SPV_KHR_expect_assume", "SPV_KHR_float_controls", "SPV_KHR_float_controls2", "SPV_KHR_fragment_shader_barycentric", "SPV_KHR_fragment_shading_rate", "SPV_KHR_integer_dot_product", "SPV_KHR_linkonce_odr", "SPV_KHR_maximal_reconvergence", "SPV_KHR_multiview", "SPV_KHR_no_integer_wrap_decoration", "SPV_KHR_non_semantic_info", "SPV_KHR_physical_storage_buffer", "SPV_KHR_post_depth_coverage", "SPV_KHR_quad_control", "SPV_KHR_ray_cull_mask", "SPV_KHR_ray_query", "SPV_KHR_ray_tracing", "SPV_KHR_ray_tracing_position_fetch", "SPV_KHR_relaxed_extended_instruction", "SPV_KHR_shader_atomic_counter_ops", "SPV_KHR_shader_ballot", "SPV_KHR_shader_clock", "SPV_KHR_shader_draw_parameters", "SPV_KHR_storage_buffer_storage_class", "SPV_KHR_subgroup_rotate", "SPV_KHR_subgroup_uniform_control_flow", "SPV_KHR_subgroup_vote", "SPV_KHR_terminate_invocation", "SPV_KHR_uniform_group_instructions", "SPV_KHR_untyped_pointers", "SPV_KHR_variable_pointers", "SPV_KHR_vulkan_memory_model", "SPV_KHR_workgroup_memory_explicit_layout", "SPV_NVX_multiview_per_view_attributes", "SPV_NV_bindless_texture", "SPV_NV_compute_shader_derivatives", "SPV_NV_cooperative_matrix", "SPV_NV_displacement_micromap", "SPV_NV_fragment_shader_barycentric", "SPV_NV_geometry_shader_passthrough", "SPV_NV_mesh_shader", "SPV_NV_raw_access_chains", "SPV_NV_ray_tracing", "SPV_NV_ray_tracing_motion_blur", "SPV_NV_sample_mask_override_coverage", "SPV_NV_shader_atomic_fp16_vector", "SPV_NV_shader_image_footprint", "SPV_NV_shader_invocation_reorder", "SPV_NV_shader_sm_builtins", "SPV_NV_shader_subgroup_partitioned", "SPV_NV_shading_rate", "SPV_NV_stereo_view_rendering", "SPV_NV_viewport_array2", "SPV_QCOM_image_processing", "SPV_QCOM_image_processing2", "SPV_VALIDATOR_ignore_type_decl_unique" }; + static const Extension known_ext_ids[] = { Extension::kSPV_AMDX_shader_enqueue, Extension::kSPV_AMD_gcn_shader, Extension::kSPV_AMD_gpu_shader_half_float, Extension::kSPV_AMD_gpu_shader_half_float_fetch, Extension::kSPV_AMD_gpu_shader_int16, Extension::kSPV_AMD_shader_ballot, Extension::kSPV_AMD_shader_early_and_late_fragment_tests, Extension::kSPV_AMD_shader_explicit_vertex_parameter, Extension::kSPV_AMD_shader_fragment_mask, Extension::kSPV_AMD_shader_image_load_store_lod, Extension::kSPV_AMD_shader_trinary_minmax, Extension::kSPV_AMD_texture_gather_bias_lod, Extension::kSPV_ARM_cooperative_matrix_layouts, Extension::kSPV_ARM_core_builtins, Extension::kSPV_EXT_demote_to_helper_invocation, Extension::kSPV_EXT_descriptor_indexing, Extension::kSPV_EXT_fragment_fully_covered, Extension::kSPV_EXT_fragment_invocation_density, Extension::kSPV_EXT_fragment_shader_interlock, Extension::kSPV_EXT_mesh_shader, Extension::kSPV_EXT_opacity_micromap, Extension::kSPV_EXT_physical_storage_buffer, Extension::kSPV_EXT_relaxed_printf_string_address_space, Extension::kSPV_EXT_replicated_composites, Extension::kSPV_EXT_shader_atomic_float16_add, Extension::kSPV_EXT_shader_atomic_float_add, Extension::kSPV_EXT_shader_atomic_float_min_max, Extension::kSPV_EXT_shader_image_int64, Extension::kSPV_EXT_shader_stencil_export, Extension::kSPV_EXT_shader_tile_image, Extension::kSPV_EXT_shader_viewport_index_layer, Extension::kSPV_GOOGLE_decorate_string, Extension::kSPV_GOOGLE_hlsl_functionality1, Extension::kSPV_GOOGLE_user_type, Extension::kSPV_INTEL_arbitrary_precision_fixed_point, Extension::kSPV_INTEL_arbitrary_precision_floating_point, Extension::kSPV_INTEL_arbitrary_precision_integers, Extension::kSPV_INTEL_bfloat16_conversion, Extension::kSPV_INTEL_blocking_pipes, Extension::kSPV_INTEL_cache_controls, Extension::kSPV_INTEL_debug_module, Extension::kSPV_INTEL_device_side_avc_motion_estimation, Extension::kSPV_INTEL_float_controls2, Extension::kSPV_INTEL_fp_fast_math_mode, Extension::kSPV_INTEL_fp_max_error, Extension::kSPV_INTEL_fpga_argument_interfaces, Extension::kSPV_INTEL_fpga_buffer_location, Extension::kSPV_INTEL_fpga_cluster_attributes, Extension::kSPV_INTEL_fpga_dsp_control, Extension::kSPV_INTEL_fpga_invocation_pipelining_attributes, Extension::kSPV_INTEL_fpga_latency_control, Extension::kSPV_INTEL_fpga_loop_controls, Extension::kSPV_INTEL_fpga_memory_accesses, Extension::kSPV_INTEL_fpga_memory_attributes, Extension::kSPV_INTEL_fpga_reg, Extension::kSPV_INTEL_function_pointers, Extension::kSPV_INTEL_global_variable_fpga_decorations, Extension::kSPV_INTEL_global_variable_host_access, Extension::kSPV_INTEL_inline_assembly, Extension::kSPV_INTEL_io_pipes, Extension::kSPV_INTEL_kernel_attributes, Extension::kSPV_INTEL_long_composites, Extension::kSPV_INTEL_loop_fuse, Extension::kSPV_INTEL_masked_gather_scatter, Extension::kSPV_INTEL_maximum_registers, Extension::kSPV_INTEL_media_block_io, Extension::kSPV_INTEL_memory_access_aliasing, Extension::kSPV_INTEL_optnone, Extension::kSPV_INTEL_runtime_aligned, Extension::kSPV_INTEL_shader_integer_functions2, Extension::kSPV_INTEL_split_barrier, Extension::kSPV_INTEL_subgroup_buffer_prefetch, Extension::kSPV_INTEL_subgroups, Extension::kSPV_INTEL_unstructured_loop_controls, Extension::kSPV_INTEL_usm_storage_classes, Extension::kSPV_INTEL_variable_length_array, Extension::kSPV_INTEL_vector_compute, Extension::kSPV_KHR_16bit_storage, Extension::kSPV_KHR_8bit_storage, Extension::kSPV_KHR_bit_instructions, Extension::kSPV_KHR_compute_shader_derivatives, Extension::kSPV_KHR_cooperative_matrix, Extension::kSPV_KHR_device_group, Extension::kSPV_KHR_expect_assume, Extension::kSPV_KHR_float_controls, Extension::kSPV_KHR_float_controls2, Extension::kSPV_KHR_fragment_shader_barycentric, Extension::kSPV_KHR_fragment_shading_rate, Extension::kSPV_KHR_integer_dot_product, Extension::kSPV_KHR_linkonce_odr, Extension::kSPV_KHR_maximal_reconvergence, Extension::kSPV_KHR_multiview, Extension::kSPV_KHR_no_integer_wrap_decoration, Extension::kSPV_KHR_non_semantic_info, Extension::kSPV_KHR_physical_storage_buffer, Extension::kSPV_KHR_post_depth_coverage, Extension::kSPV_KHR_quad_control, Extension::kSPV_KHR_ray_cull_mask, Extension::kSPV_KHR_ray_query, Extension::kSPV_KHR_ray_tracing, Extension::kSPV_KHR_ray_tracing_position_fetch, Extension::kSPV_KHR_relaxed_extended_instruction, Extension::kSPV_KHR_shader_atomic_counter_ops, Extension::kSPV_KHR_shader_ballot, Extension::kSPV_KHR_shader_clock, Extension::kSPV_KHR_shader_draw_parameters, Extension::kSPV_KHR_storage_buffer_storage_class, Extension::kSPV_KHR_subgroup_rotate, Extension::kSPV_KHR_subgroup_uniform_control_flow, Extension::kSPV_KHR_subgroup_vote, Extension::kSPV_KHR_terminate_invocation, Extension::kSPV_KHR_uniform_group_instructions, Extension::kSPV_KHR_untyped_pointers, Extension::kSPV_KHR_variable_pointers, Extension::kSPV_KHR_vulkan_memory_model, Extension::kSPV_KHR_workgroup_memory_explicit_layout, Extension::kSPV_NVX_multiview_per_view_attributes, Extension::kSPV_NV_bindless_texture, Extension::kSPV_NV_compute_shader_derivatives, Extension::kSPV_NV_cooperative_matrix, Extension::kSPV_NV_displacement_micromap, Extension::kSPV_NV_fragment_shader_barycentric, Extension::kSPV_NV_geometry_shader_passthrough, Extension::kSPV_NV_mesh_shader, Extension::kSPV_NV_raw_access_chains, Extension::kSPV_NV_ray_tracing, Extension::kSPV_NV_ray_tracing_motion_blur, Extension::kSPV_NV_sample_mask_override_coverage, Extension::kSPV_NV_shader_atomic_fp16_vector, Extension::kSPV_NV_shader_image_footprint, Extension::kSPV_NV_shader_invocation_reorder, Extension::kSPV_NV_shader_sm_builtins, Extension::kSPV_NV_shader_subgroup_partitioned, Extension::kSPV_NV_shading_rate, Extension::kSPV_NV_stereo_view_rendering, Extension::kSPV_NV_viewport_array2, Extension::kSPV_QCOM_image_processing, Extension::kSPV_QCOM_image_processing2, Extension::kSPV_VALIDATOR_ignore_type_decl_unique }; const auto b = std::begin(known_ext_strs); const auto e = std::end(known_ext_strs); const auto found = std::equal_range( @@ -498,6 +506,8 @@ const char* CapabilityToString(spv::Capability capability) { return "RayQueryProvisionalKHR"; case spv::Capability::RayQueryKHR: return "RayQueryKHR"; + case spv::Capability::UntypedPointersKHR: + return "UntypedPointersKHR"; case spv::Capability::RayTraversalPrimitiveCullingKHR: return "RayTraversalPrimitiveCullingKHR"; case spv::Capability::RayTracingKHR: @@ -550,8 +560,8 @@ const char* CapabilityToString(spv::Capability capability) { return "MeshShadingEXT"; case spv::Capability::FragmentBarycentricKHR: return "FragmentBarycentricKHR"; - case spv::Capability::ComputeDerivativeGroupQuadsNV: - return "ComputeDerivativeGroupQuadsNV"; + case spv::Capability::ComputeDerivativeGroupQuadsKHR: + return "ComputeDerivativeGroupQuadsKHR"; case spv::Capability::FragmentDensityEXT: return "FragmentDensityEXT"; case spv::Capability::GroupNonUniformPartitionedNV: @@ -592,8 +602,8 @@ const char* CapabilityToString(spv::Capability capability) { return "VulkanMemoryModelDeviceScope"; case spv::Capability::PhysicalStorageBufferAddresses: return "PhysicalStorageBufferAddresses"; - case spv::Capability::ComputeDerivativeGroupLinearNV: - return "ComputeDerivativeGroupLinearNV"; + case spv::Capability::ComputeDerivativeGroupLinearKHR: + return "ComputeDerivativeGroupLinearKHR"; case spv::Capability::RayTracingProvisionalKHR: return "RayTracingProvisionalKHR"; case spv::Capability::CooperativeMatrixNV: @@ -758,6 +768,8 @@ const char* CapabilityToString(spv::Capability capability) { return "GlobalVariableHostAccessINTEL"; case spv::Capability::GlobalVariableFPGADecorationsINTEL: return "GlobalVariableFPGADecorationsINTEL"; + case spv::Capability::SubgroupBufferPrefetchINTEL: + return "SubgroupBufferPrefetchINTEL"; case spv::Capability::GroupUniformArithmeticKHR: return "GroupUniformArithmeticKHR"; case spv::Capability::MaskedGatherScatterINTEL: diff --git a/external/spirv-tools-generated/extension_enum.inc b/external/spirv-tools-generated/extension_enum.inc index ac42c58ee7..243af26ce7 100644 --- a/external/spirv-tools-generated/extension_enum.inc +++ b/external/spirv-tools-generated/extension_enum.inc @@ -20,6 +20,7 @@ kSPV_EXT_fragment_shader_interlock, kSPV_EXT_mesh_shader, kSPV_EXT_opacity_micromap, kSPV_EXT_physical_storage_buffer, +kSPV_EXT_relaxed_printf_string_address_space, kSPV_EXT_replicated_composites, kSPV_EXT_shader_atomic_float16_add, kSPV_EXT_shader_atomic_float_add, @@ -68,6 +69,7 @@ kSPV_INTEL_optnone, kSPV_INTEL_runtime_aligned, kSPV_INTEL_shader_integer_functions2, kSPV_INTEL_split_barrier, +kSPV_INTEL_subgroup_buffer_prefetch, kSPV_INTEL_subgroups, kSPV_INTEL_unstructured_loop_controls, kSPV_INTEL_usm_storage_classes, @@ -76,6 +78,7 @@ kSPV_INTEL_vector_compute, kSPV_KHR_16bit_storage, kSPV_KHR_8bit_storage, kSPV_KHR_bit_instructions, +kSPV_KHR_compute_shader_derivatives, kSPV_KHR_cooperative_matrix, kSPV_KHR_device_group, kSPV_KHR_expect_assume, @@ -107,6 +110,7 @@ kSPV_KHR_subgroup_uniform_control_flow, kSPV_KHR_subgroup_vote, kSPV_KHR_terminate_invocation, kSPV_KHR_uniform_group_instructions, +kSPV_KHR_untyped_pointers, kSPV_KHR_variable_pointers, kSPV_KHR_vulkan_memory_model, kSPV_KHR_workgroup_memory_explicit_layout, diff --git a/external/spirv-tools-generated/generators.inc b/external/spirv-tools-generated/generators.inc index e67e57560b..fe7580d0d2 100644 --- a/external/spirv-tools-generated/generators.inc +++ b/external/spirv-tools-generated/generators.inc @@ -20,7 +20,7 @@ {19, "Tellusim", "Clay Shader Compiler", "Tellusim Clay Shader Compiler"}, {20, "W3C WebGPU Group", "WHLSL Shader Translator", "W3C WebGPU Group WHLSL Shader Translator"}, {21, "Google", "Clspv", "Google Clspv"}, -{22, "Google", "MLIR SPIR-V Serializer", "Google MLIR SPIR-V Serializer"}, +{22, "LLVM", "MLIR SPIR-V Serializer", "LLVM MLIR SPIR-V Serializer"}, {23, "Google", "Tint Compiler", "Google Tint Compiler"}, {24, "Google", "ANGLE Shader Compiler", "Google ANGLE Shader Compiler"}, {25, "Netease Games", "Messiah Shader Compiler", "Netease Games Messiah Shader Compiler"}, @@ -41,4 +41,5 @@ {40, "NVIDIA", "Slang Compiler", "NVIDIA Slang Compiler"}, {41, "Zig Software Foundation", "Zig Compiler", "Zig Software Foundation Zig Compiler"}, {42, "Rendong Liang", "spq", "Rendong Liang spq"}, -{43, "LLVM", "LLVM SPIR-V Backend", "LLVM LLVM SPIR-V Backend"}, \ No newline at end of file +{43, "LLVM", "LLVM SPIR-V Backend", "LLVM LLVM SPIR-V Backend"}, +{44, "Robert Konrad", "Kongruent", "Robert Konrad Kongruent"}, \ No newline at end of file diff --git a/external/spirv-tools-generated/nonsemantic.vkspreflection.insts.inc b/external/spirv-tools-generated/nonsemantic.vkspreflection.insts.inc index 623b9cf235..2f14c059a1 100644 --- a/external/spirv-tools-generated/nonsemantic.vkspreflection.insts.inc +++ b/external/spirv-tools-generated/nonsemantic.vkspreflection.insts.inc @@ -6,7 +6,7 @@ static const spv_ext_inst_desc_t nonsemantic_vkspreflection_entries[] = { {"StopCounter", 3, 0, nullptr, {SPV_OPERAND_TYPE_ID, SPV_OPERAND_TYPE_NONE}}, {"PushConstants", 4, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_STRING, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, {"SpecializationMapEntry", 5, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, - {"DescriptorSetBuffer", 6, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, + {"DescriptorSetBuffer", 6, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, {"DescriptorSetImage", 7, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}}, {"DescriptorSetSampler", 8, 0, nullptr, {SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_FLOAT, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_FLOAT, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_FLOAT, SPV_OPERAND_TYPE_LITERAL_FLOAT, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_LITERAL_INTEGER, SPV_OPERAND_TYPE_NONE}} }; \ No newline at end of file diff --git a/external/spirv-tools-generated/operand.kinds-unified1.inc b/external/spirv-tools-generated/operand.kinds-unified1.inc index ccfd69aae8..3a3a8c55ed 100644 --- a/external/spirv-tools-generated/operand.kinds-unified1.inc +++ b/external/spirv-tools-generated/operand.kinds-unified1.inc @@ -5,8 +5,8 @@ static const spv::Capability pygen_variable_caps_AtomicStorage[] = {spv::Capabil static const spv::Capability pygen_variable_caps_BindlessTextureNV[] = {spv::Capability::BindlessTextureNV}; static const spv::Capability pygen_variable_caps_CacheControlsINTEL[] = {spv::Capability::CacheControlsINTEL}; static const spv::Capability pygen_variable_caps_ClipDistance[] = {spv::Capability::ClipDistance}; -static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupLinearNV[] = {spv::Capability::ComputeDerivativeGroupLinearNV}; -static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupQuadsNV[] = {spv::Capability::ComputeDerivativeGroupQuadsNV}; +static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupLinearNVComputeDerivativeGroupLinearKHR[] = {spv::Capability::ComputeDerivativeGroupLinearNV, spv::Capability::ComputeDerivativeGroupLinearKHR}; +static const spv::Capability pygen_variable_caps_ComputeDerivativeGroupQuadsNVComputeDerivativeGroupQuadsKHR[] = {spv::Capability::ComputeDerivativeGroupQuadsNV, spv::Capability::ComputeDerivativeGroupQuadsKHR}; static const spv::Capability pygen_variable_caps_CoreBuiltinsARM[] = {spv::Capability::CoreBuiltinsARM}; static const spv::Capability pygen_variable_caps_CullDistance[] = {spv::Capability::CullDistance}; static const spv::Capability pygen_variable_caps_DenormFlushToZero[] = {spv::Capability::DenormFlushToZero}; @@ -211,6 +211,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_optnone[] = {spvt static const spvtools::Extension pygen_variable_exts_SPV_INTEL_runtime_aligned[] = {spvtools::Extension::kSPV_INTEL_runtime_aligned}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_shader_integer_functions2[] = {spvtools::Extension::kSPV_INTEL_shader_integer_functions2}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_split_barrier[] = {spvtools::Extension::kSPV_INTEL_split_barrier}; +static const spvtools::Extension pygen_variable_exts_SPV_INTEL_subgroup_buffer_prefetch[] = {spvtools::Extension::kSPV_INTEL_subgroup_buffer_prefetch}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_subgroups[] = {spvtools::Extension::kSPV_INTEL_subgroups}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_unstructured_loop_controls[] = {spvtools::Extension::kSPV_INTEL_unstructured_loop_controls}; static const spvtools::Extension pygen_variable_exts_SPV_INTEL_usm_storage_classes[] = {spvtools::Extension::kSPV_INTEL_usm_storage_classes}; @@ -219,6 +220,7 @@ static const spvtools::Extension pygen_variable_exts_SPV_INTEL_vector_compute[] static const spvtools::Extension pygen_variable_exts_SPV_KHR_16bit_storage[] = {spvtools::Extension::kSPV_KHR_16bit_storage}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_8bit_storage[] = {spvtools::Extension::kSPV_KHR_8bit_storage}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_bit_instructions[] = {spvtools::Extension::kSPV_KHR_bit_instructions}; +static const spvtools::Extension pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives[] = {spvtools::Extension::kSPV_KHR_compute_shader_derivatives, spvtools::Extension::kSPV_NV_compute_shader_derivatives}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_cooperative_matrix[] = {spvtools::Extension::kSPV_KHR_cooperative_matrix}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_device_group[] = {spvtools::Extension::kSPV_KHR_device_group}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_expect_assume[] = {spvtools::Extension::kSPV_KHR_expect_assume}; @@ -248,13 +250,13 @@ static const spvtools::Extension pygen_variable_exts_SPV_KHR_subgroup_rotate[] = static const spvtools::Extension pygen_variable_exts_SPV_KHR_subgroup_uniform_control_flow[] = {spvtools::Extension::kSPV_KHR_subgroup_uniform_control_flow}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_subgroup_vote[] = {spvtools::Extension::kSPV_KHR_subgroup_vote}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_uniform_group_instructions[] = {spvtools::Extension::kSPV_KHR_uniform_group_instructions}; +static const spvtools::Extension pygen_variable_exts_SPV_KHR_untyped_pointers[] = {spvtools::Extension::kSPV_KHR_untyped_pointers}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_variable_pointers[] = {spvtools::Extension::kSPV_KHR_variable_pointers}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_vulkan_memory_model[] = {spvtools::Extension::kSPV_KHR_vulkan_memory_model}; static const spvtools::Extension pygen_variable_exts_SPV_KHR_workgroup_memory_explicit_layout[] = {spvtools::Extension::kSPV_KHR_workgroup_memory_explicit_layout}; static const spvtools::Extension pygen_variable_exts_SPV_NVX_multiview_per_view_attributes[] = {spvtools::Extension::kSPV_NVX_multiview_per_view_attributes}; static const spvtools::Extension pygen_variable_exts_SPV_NVX_multiview_per_view_attributesSPV_NV_mesh_shader[] = {spvtools::Extension::kSPV_NVX_multiview_per_view_attributes, spvtools::Extension::kSPV_NV_mesh_shader}; static const spvtools::Extension pygen_variable_exts_SPV_NV_bindless_texture[] = {spvtools::Extension::kSPV_NV_bindless_texture}; -static const spvtools::Extension pygen_variable_exts_SPV_NV_compute_shader_derivatives[] = {spvtools::Extension::kSPV_NV_compute_shader_derivatives}; static const spvtools::Extension pygen_variable_exts_SPV_NV_cooperative_matrix[] = {spvtools::Extension::kSPV_NV_cooperative_matrix}; static const spvtools::Extension pygen_variable_exts_SPV_NV_displacement_micromap[] = {spvtools::Extension::kSPV_NV_displacement_micromap}; static const spvtools::Extension pygen_variable_exts_SPV_NV_geometry_shader_passthrough[] = {spvtools::Extension::kSPV_NV_geometry_shader_passthrough}; @@ -546,8 +548,10 @@ static const spv_operand_desc_t pygen_variable_ExecutionModeEntries[] = { {"OutputLinesNV", 5269, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu}, {"OutputPrimitivesEXT", 5270, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}, {"OutputPrimitivesNV", 5270, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {SPV_OPERAND_TYPE_LITERAL_INTEGER}, 0xffffffffu, 0xffffffffu}, - {"DerivativeGroupQuadsNV", 5289, 1, pygen_variable_caps_ComputeDerivativeGroupQuadsNV, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, - {"DerivativeGroupLinearNV", 5290, 1, pygen_variable_caps_ComputeDerivativeGroupLinearNV, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"DerivativeGroupQuadsKHR", 5289, 2, pygen_variable_caps_ComputeDerivativeGroupQuadsNVComputeDerivativeGroupQuadsKHR, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"DerivativeGroupQuadsNV", 5289, 2, pygen_variable_caps_ComputeDerivativeGroupQuadsNVComputeDerivativeGroupQuadsKHR, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"DerivativeGroupLinearKHR", 5290, 2, pygen_variable_caps_ComputeDerivativeGroupLinearNVComputeDerivativeGroupLinearKHR, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"DerivativeGroupLinearNV", 5290, 2, pygen_variable_caps_ComputeDerivativeGroupLinearNVComputeDerivativeGroupLinearKHR, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, {"OutputTrianglesEXT", 5298, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu}, {"OutputTrianglesNV", 5298, 2, pygen_variable_caps_MeshShadingNVMeshShadingEXT, 2, pygen_variable_exts_SPV_EXT_mesh_shaderSPV_NV_mesh_shader, {}, 0xffffffffu, 0xffffffffu}, {"PixelInterlockOrderedEXT", 5366, 1, pygen_variable_caps_FragmentShaderPixelInterlockEXT, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, @@ -725,7 +729,8 @@ static const spv_operand_desc_t pygen_variable_ImageChannelDataTypeEntries[] = { {"UnormInt24", 15, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"UnormInt101010_2", 16, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, {"UnsignedIntRaw10EXT", 19, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, - {"UnsignedIntRaw12EXT", 20, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu} + {"UnsignedIntRaw12EXT", 20, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu}, + {"UnormInt2_101010EXT", 21, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1,0), 0xffffffffu} }; static const spv_operand_desc_t pygen_variable_FPRoundingModeEntries[] = { @@ -1215,6 +1220,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"RoundingModeRTZ", 4468, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_float_controls, {}, SPV_SPIRV_VERSION_WORD(1,4), 0xffffffffu}, {"RayQueryProvisionalKHR", 4471, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_ray_query, {}, 0xffffffffu, 0xffffffffu}, {"RayQueryKHR", 4472, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_ray_query, {}, 0xffffffffu, 0xffffffffu}, + {"UntypedPointersKHR", 4473, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_untyped_pointers, {}, 0xffffffffu, 0xffffffffu}, {"RayTraversalPrimitiveCullingKHR", 4478, 2, pygen_variable_caps_RayQueryKHRRayTracingKHR, 2, pygen_variable_exts_SPV_KHR_ray_querySPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"RayTracingKHR", 4479, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"TextureSampleWeightedQCOM", 4484, 0, nullptr, 1, pygen_variable_exts_SPV_QCOM_image_processing, {}, 0xffffffffu, 0xffffffffu}, @@ -1243,7 +1249,8 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"MeshShadingEXT", 5283, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_mesh_shader, {}, 0xffffffffu, 0xffffffffu}, {"FragmentBarycentricKHR", 5284, 0, nullptr, 2, pygen_variable_exts_SPV_KHR_fragment_shader_barycentricSPV_NV_fragment_shader_barycentric, {}, 0xffffffffu, 0xffffffffu}, {"FragmentBarycentricNV", 5284, 0, nullptr, 2, pygen_variable_exts_SPV_KHR_fragment_shader_barycentricSPV_NV_fragment_shader_barycentric, {}, 0xffffffffu, 0xffffffffu}, - {"ComputeDerivativeGroupQuadsNV", 5288, 0, nullptr, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"ComputeDerivativeGroupQuadsKHR", 5288, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"ComputeDerivativeGroupQuadsNV", 5288, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, {"FragmentDensityEXT", 5291, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"ShadingRateNV", 5291, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_EXT_fragment_invocation_densitySPV_NV_shading_rate, {}, 0xffffffffu, 0xffffffffu}, {"GroupNonUniformPartitionedNV", 5297, 0, nullptr, 1, pygen_variable_exts_SPV_NV_shader_subgroup_partitioned, {}, 0xffffffffu, 0xffffffffu}, @@ -1280,7 +1287,8 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"VulkanMemoryModelDeviceScopeKHR", 5346, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_vulkan_memory_model, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"PhysicalStorageBufferAddresses", 5347, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, {"PhysicalStorageBufferAddressesEXT", 5347, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_EXT_physical_storage_bufferSPV_KHR_physical_storage_buffer, {}, SPV_SPIRV_VERSION_WORD(1,5), 0xffffffffu}, - {"ComputeDerivativeGroupLinearNV", 5350, 0, nullptr, 1, pygen_variable_exts_SPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"ComputeDerivativeGroupLinearKHR", 5350, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, + {"ComputeDerivativeGroupLinearNV", 5350, 1, pygen_variable_caps_Shader, 2, pygen_variable_exts_SPV_KHR_compute_shader_derivativesSPV_NV_compute_shader_derivatives, {}, 0xffffffffu, 0xffffffffu}, {"RayTracingProvisionalKHR", 5353, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_KHR_ray_tracing, {}, 0xffffffffu, 0xffffffffu}, {"CooperativeMatrixNV", 5357, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_NV_cooperative_matrix, {}, 0xffffffffu, 0xffffffffu}, {"FragmentShaderSampleInterlockEXT", 5363, 1, pygen_variable_caps_Shader, 1, pygen_variable_exts_SPV_EXT_fragment_shader_interlock, {}, 0xffffffffu, 0xffffffffu}, @@ -1368,6 +1376,7 @@ static const spv_operand_desc_t pygen_variable_CapabilityEntries[] = { {"FPGAArgumentInterfacesINTEL", 6174, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_fpga_argument_interfaces, {}, 0xffffffffu, 0xffffffffu}, {"GlobalVariableHostAccessINTEL", 6187, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_host_access, {}, 0xffffffffu, 0xffffffffu}, {"GlobalVariableFPGADecorationsINTEL", 6189, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_global_variable_fpga_decorations, {}, 0xffffffffu, 0xffffffffu}, + {"SubgroupBufferPrefetchINTEL", 6220, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_subgroup_buffer_prefetch, {}, 0xffffffffu, 0xffffffffu}, {"GroupUniformArithmeticKHR", 6400, 0, nullptr, 1, pygen_variable_exts_SPV_KHR_uniform_group_instructions, {}, 0xffffffffu, 0xffffffffu}, {"MaskedGatherScatterINTEL", 6427, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_masked_gather_scatter, {}, 0xffffffffu, 0xffffffffu}, {"CacheControlsINTEL", 6441, 0, nullptr, 1, pygen_variable_exts_SPV_INTEL_cache_controls, {}, 0xffffffffu, 0xffffffffu}, @@ -1441,6 +1450,10 @@ static const spv_operand_desc_t pygen_variable_NamedMaximumNumberOfRegistersEntr {"AutoINTEL", 0, 1, pygen_variable_caps_RegisterLimitsINTEL, 0, nullptr, {}, 0xffffffffu, 0xffffffffu} }; +static const spv_operand_desc_t pygen_variable_FPEncodingEntries[] = { + {"place holder", 0, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(999,0), 0} +}; + static const spv_operand_desc_t pygen_variable_DebugInfoFlagsEntries[] = { {"None", 0x0000, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, {"FlagIsProtected", 0x01, 0, nullptr, 0, nullptr, {}, SPV_SPIRV_VERSION_WORD(1, 0), 0xffffffffu}, @@ -1609,6 +1622,7 @@ static const spv_operand_desc_group_t pygen_variable_OperandInfoTable[] = { {SPV_OPERAND_TYPE_LOAD_CACHE_CONTROL, ARRAY_SIZE(pygen_variable_LoadCacheControlEntries), pygen_variable_LoadCacheControlEntries}, {SPV_OPERAND_TYPE_STORE_CACHE_CONTROL, ARRAY_SIZE(pygen_variable_StoreCacheControlEntries), pygen_variable_StoreCacheControlEntries}, {SPV_OPERAND_TYPE_NAMED_MAXIMUM_NUMBER_OF_REGISTERS, ARRAY_SIZE(pygen_variable_NamedMaximumNumberOfRegistersEntries), pygen_variable_NamedMaximumNumberOfRegistersEntries}, + {SPV_OPERAND_TYPE_FPENCODING, ARRAY_SIZE(pygen_variable_FPEncodingEntries), pygen_variable_FPEncodingEntries}, {SPV_OPERAND_TYPE_DEBUG_INFO_FLAGS, ARRAY_SIZE(pygen_variable_DebugInfoFlagsEntries), pygen_variable_DebugInfoFlagsEntries}, {SPV_OPERAND_TYPE_DEBUG_BASE_TYPE_ATTRIBUTE_ENCODING, ARRAY_SIZE(pygen_variable_DebugBaseTypeAttributeEncodingEntries), pygen_variable_DebugBaseTypeAttributeEncodingEntries}, {SPV_OPERAND_TYPE_DEBUG_COMPOSITE_TYPE, ARRAY_SIZE(pygen_variable_DebugCompositeTypeEntries), pygen_variable_DebugCompositeTypeEntries}, @@ -1625,5 +1639,6 @@ static const spv_operand_desc_group_t pygen_variable_OperandInfoTable[] = { {SPV_OPERAND_TYPE_OPTIONAL_RAW_ACCESS_CHAIN_OPERANDS, ARRAY_SIZE(pygen_variable_RawAccessChainOperandsEntries), pygen_variable_RawAccessChainOperandsEntries}, {SPV_OPERAND_TYPE_OPTIONAL_ACCESS_QUALIFIER, ARRAY_SIZE(pygen_variable_AccessQualifierEntries), pygen_variable_AccessQualifierEntries}, {SPV_OPERAND_TYPE_OPTIONAL_PACKED_VECTOR_FORMAT, ARRAY_SIZE(pygen_variable_PackedVectorFormatEntries), pygen_variable_PackedVectorFormatEntries}, - {SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS, ARRAY_SIZE(pygen_variable_CooperativeMatrixOperandsEntries), pygen_variable_CooperativeMatrixOperandsEntries} + {SPV_OPERAND_TYPE_OPTIONAL_COOPERATIVE_MATRIX_OPERANDS, ARRAY_SIZE(pygen_variable_CooperativeMatrixOperandsEntries), pygen_variable_CooperativeMatrixOperandsEntries}, + {SPV_OPERAND_TYPE_OPTIONAL_FPENCODING, ARRAY_SIZE(pygen_variable_FPEncodingEntries), pygen_variable_FPEncodingEntries} }; \ No newline at end of file diff --git a/external/vulkan b/external/vulkan index 577baa0503..f864bc6dfe 160000 --- a/external/vulkan +++ b/external/vulkan @@ -1 +1 @@ -Subproject commit 577baa05033cf1d9236b3d078ca4b3269ed87a2b +Subproject commit f864bc6dfe6229a399566e979c16795386d0f308 diff --git a/extras/.clang-format b/extras/.clang-format deleted file mode 100644 index 81cacff351..0000000000 --- a/extras/.clang-format +++ /dev/null @@ -1,48 +0,0 @@ ---- -BasedOnStyle: LLVM -IndentWidth: 4 ---- -Language: Cpp -# Force pointers to the type for C++. -IndentPPDirectives: AfterHash -DerivePointerAlignment: false -PointerAlignment: Left -BinPackArguments: false -BinPackParameters: false -ExperimentalAutoDetectBinPacking: false -AllowAllParametersOfDeclarationOnNextLine: true -NamespaceIndentation: None -FixNamespaceComments: true -AccessModifierOffset: -4 -AlignTrailingComments: false -ConstructorInitializerIndentWidth: 4 -AlignEscapedNewlinesLeft: true -PenaltyReturnTypeOnItsOwnLine: 100 -ColumnLimit: 100 -IncludeBlocks: Preserve -AlignAfterOpenBracket: AlwaysBreak -IndentCaseBlocks: true -SortIncludes: true -SortUsingDeclarations: true -UseTab: Never -BreakConstructorInitializers: BeforeComma -BreakInheritanceList: BeforeComma -BreakBeforeBraces: Custom -BraceWrapping: - AfterCaseLabel: true - AfterClass: true - AfterEnum: true - AfterStruct: true - AfterUnion: true - SplitEmptyFunction: false - AfterControlStatement: Always - AfterFunction: true - AfterNamespace: true - AfterExternBlock: true - BeforeCatch: true - BeforeElse: true - # BeforeLambdaBody: true - # BeforeWhile: false - IndentBraces: false - SplitEmptyFunction: false - SplitEmptyRecord: false \ No newline at end of file diff --git a/extras/formatting.sh b/extras/formatting.sh new file mode 100755 index 0000000000..f6a3134aac --- /dev/null +++ b/extras/formatting.sh @@ -0,0 +1,250 @@ +#!/usr/bin/env bash + +set -e + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +source_dir="$(dirname "$script_dir")" + +check_only=0 +no_version_check=0 +run_cpp=0 +run_yaml=0 +run_markdown=0 +run_sh=0 +run_cmake=0 +run_all=1 + +show_help() { + me=$(basename "$0") + cat <] [--cpp] [--yaml] [--md] [--sh] [--cmake] + +Options: + --check-only Check formatting without modifying files + --no-version-check Skip version compatibility checks + --source Path to source directory to format (defaults to parent of script directory) + --cpp Format only C++ files + --yaml Format only YAML/JSON files + --md Format only markdown files + --sh Format only shell script files + --cmake Format only CMake files +EOF +} + +while [[ "$#" -gt 0 ]]; do + case $1 in + -h | --help) + show_help + exit 0 + ;; + --check-only) check_only=1 ;; + --no-version-check) no_version_check=1 ;; + --cpp) + run_cpp=1 + run_all=0 + ;; + --yaml) + run_yaml=1 + run_all=0 + ;; + --md) + run_markdown=1 + run_all=0 + ;; + --sh) + run_sh=1 + run_all=0 + ;; + --cmake) + run_cmake=1 + run_all=0 + ;; + --source) + source_dir="$2" + shift + ;; + *) + echo "unrecognized argument: $1" + show_help + exit 1 + ;; + esac + shift +done + +cd "$source_dir" || exit 1 + +require_bin() { + local name="$1" + local min_version="$2" + local max_version="${3:-}" + local version + + if ! command -v "$name" &>/dev/null; then + echo "This script needs $name, but it isn't in \$PATH" >&2 + missing_bin=1 + return + fi + + if [ "$no_version_check" -eq 0 ]; then + version=$("$name" --version | grep -oP "\d+\.\d+\.?\d*" | head -n1) + + if ! printf '%s\n%s\n' "$min_version" "$version" | sort -V -C; then + echo "$name version $version is too old. Version $min_version or newer is required." >&2 + missing_bin=1 + return + fi + + if [ -n "$max_version" ]; then + if ! printf '%s\n%s\n' "$version" "$max_version" | sort -V -C; then + echo "$name version $version is too new. Version less than $max_version is required." >&2 + missing_bin=1 + return + fi + fi + fi +} + +require_bin "git" "1.8" +require_bin "gersemi" "0.17" +require_bin "xargs" "3" +require_bin "diff" "2" +require_bin "clang-format" "17" "18" +require_bin "prettier" "3" +require_bin "shfmt" "3" + +if [ "$missing_bin" ]; then + exit 1 +fi + +exit_code=0 + +cmake_formatting() { + echo "Formatting CMake files..." >&2 + + readarray -t files < <(git ls-files '*.cmake' 'CMakeLists.txt' '**/CMakeLists.txt') + + common_args=( + # turn on warning when this is fixed https://github.com/BlankSpruce/gersemi/issues/39 + --no-warn-about-unknown-commands + --definitions "${files[@]}" + ) + + if [ "$check_only" -eq 1 ]; then + gersemi "${common_args[@]}" --diff --color "${files[@]}" + gersemi "${common_args[@]}" --check "${files[@]}" || exit_code=1 + else + gersemi "${common_args[@]}" --in-place "${files[@]}" + fi +} + +track_progress() { + # Don't output the progress bar if stderr isn't a terminal, just eat all the input + [ -t 2 ] || { + cat >/dev/null + return + } + + local total=$1 + local current=0 + + while IFS= read -r _; do + ((current++)) || : + percent=$((current * 100 / total)) + printf '\rProgress: [%-50s] %d%%' "$(printf '#%.0s' $(seq 1 $((percent / 2))))" "$percent" >&2 + done + echo >&2 +} + +cpp_formatting() { + echo "Formatting cpp files..." >&2 + + readarray -t files < <(git ls-files '*.cpp' '*.hpp' '*.c' '*.h' ':!external/**') + + # The progress reporting is a bit sneaky, we use `--verbose` with xargs which + # prints a line to stderr for each command, and we simply count these... + + if [ "$check_only" -eq 1 ]; then + local tmpdir + tmpdir=$(mktemp -d) + trap 'rm -rf "$tmpdir"' EXIT + + printf '%s\n' "${files[@]}" | xargs --verbose -P "$(nproc)" -I{} bash -c " + mkdir -p \"\$(dirname \"$tmpdir/{}\")\" + diff -u --color=always --label \"{}\" --label \"{}\" \"{}\" <(clang-format \"{}\") > \"$tmpdir/{}\" + : + " |& track_progress ${#files[@]} + + for file in "${files[@]}"; do + # Fail if any of the diffs have contents + if [ -s "$tmpdir/$file" ]; then + cat "$tmpdir/$file" + exit_code=1 + fi + done + else + printf '%s\n' "${files[@]}" | xargs --verbose -n1 -P "$(nproc)" clang-format -i |& + track_progress ${#files[@]} + fi +} + +# Format the 'files' array using the prettier tool (abstracted here because +# it's used by markdown and json +prettier_formatting() { + if [ "$check_only" -eq 1 ]; then + for file in "${files[@]}"; do + if ! output=$(prettier "$file" 2>/dev/null); then + continue + fi + if ! diff -q "$file" <(echo "$output") >/dev/null 2>&1; then + diff --color -u --label "$file" --label "$file" "$file" <(echo "$output") || : + exit_code=1 + fi + done + else + prettier --write "${files[@]}" | grep -v '(unchanged)' >&2 || : + fi +} + +yaml_json_formatting() { + echo "Formatting yaml and json files..." >&2 + + readarray -t files < <(git ls-files "*.yaml" "*.yml" "*.json" ':!external/**') + + prettier_formatting +} + +markdown_formatting() { + echo "Formatting markdown files..." >&2 + + readarray -t files < <(git ls-files "*.md" ':!external/**') + + prettier_formatting +} + +sh_formatting() { + echo "Formatting sh files..." >&2 + + readarray -t files < <(git ls-files "*.sh") + + common_args=( + # default 8 is way too wide + --indent 2 + ) + + if [ "$check_only" -eq 1 ]; then + shfmt "${common_args[@]}" --diff "${files[@]}" || exit_code=1 + else + shfmt "${common_args[@]}" --write "${files[@]}" + fi +} + +((run_all || run_sh)) && sh_formatting +((run_all || run_cmake)) && cmake_formatting +((run_all || run_yaml)) && yaml_json_formatting +((run_markdown)) && markdown_formatting +((run_all || run_cpp)) && cpp_formatting + +exit $exit_code diff --git a/extras/macos-notarize.json b/extras/macos-notarize.json index ee369a0ac5..517ea30f41 100644 --- a/extras/macos-notarize.json +++ b/extras/macos-notarize.json @@ -1,7 +1,7 @@ { - "notarize" :{ - "path": "slang-macos-dist.zip", - "bundle_id": "shader-slang.slang", - "staple": false - } -} \ No newline at end of file + "notarize": { + "path": "slang-macos-dist.zip", + "bundle_id": "shader-slang.slang", + "staple": false + } +} diff --git a/extras/macos-sign.json b/extras/macos-sign.json index fbe511bf3b..b374294987 100644 --- a/extras/macos-sign.json +++ b/extras/macos-sign.json @@ -1,11 +1,11 @@ { - "source" : [ - "./bin/macosx-*/release/libslang.dylib", - "./bin/macosx-*/release/slangc", - "./bin/macosx-*/release/slangd" - ], - "bundle_id" : "shader-slang.slang", - "sign" :{ - "application_identity" : "d6ada82a113e4204aaad914e1013e9548ffd30d0" - } -} \ No newline at end of file + "source": [ + "./bin/macosx-*/release/libslang.dylib", + "./bin/macosx-*/release/slangc", + "./bin/macosx-*/release/slangd" + ], + "bundle_id": "shader-slang.slang", + "sign": { + "application_identity": "d6ada82a113e4204aaad914e1013e9548ffd30d0" + } +} diff --git a/include/.clang-format b/include/.clang-format new file mode 100644 index 0000000000..12ac8862d1 --- /dev/null +++ b/include/.clang-format @@ -0,0 +1,2 @@ +BasedOnStyle: InheritParentConfig +IndentPPDirectives: BeforeHash diff --git a/include/slang-com-helper.h b/include/slang-com-helper.h index fc8b7de582..557b278df3 100644 --- a/include/slang-com-helper.h +++ b/include/slang-com-helper.h @@ -2,36 +2,90 @@ #define SLANG_COM_HELPER_H /** \file slang-com-helper.h -*/ + */ #include "slang.h" + #include /* !!!!!!!!!!!!!!!!!!!!! Macros to help checking SlangResult !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ -/*! Set SLANG_HANDLE_RESULT_FAIL(x) to code to be executed whenever an error occurs, and is detected by one of the macros */ +/*! Set SLANG_HANDLE_RESULT_FAIL(x) to code to be executed whenever an error occurs, and is detected + * by one of the macros */ #ifndef SLANG_HANDLE_RESULT_FAIL -# define SLANG_HANDLE_RESULT_FAIL(x) + #define SLANG_HANDLE_RESULT_FAIL(x) #endif -//! Helper macro, that makes it easy to add result checking to calls in functions/methods that themselves return Result. -#define SLANG_RETURN_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return _res; } } -//! Helper macro that can be used to test the return value from a call, and will return in a void method/function -#define SLANG_RETURN_VOID_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return; } } +//! Helper macro, that makes it easy to add result checking to calls in functions/methods that +//! themselves return Result. +#define SLANG_RETURN_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + SLANG_HANDLE_RESULT_FAIL(_res); \ + return _res; \ + } \ + } +//! Helper macro that can be used to test the return value from a call, and will return in a void +//! method/function +#define SLANG_RETURN_VOID_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + SLANG_HANDLE_RESULT_FAIL(_res); \ + return; \ + } \ + } //! Helper macro that will return false on failure. -#define SLANG_RETURN_FALSE_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return false; } } +#define SLANG_RETURN_FALSE_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + SLANG_HANDLE_RESULT_FAIL(_res); \ + return false; \ + } \ + } //! Helper macro that will return nullptr on failure. -#define SLANG_RETURN_NULL_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { SLANG_HANDLE_RESULT_FAIL(_res); return nullptr; } } - -//! Helper macro that will assert if the return code from a call is failure, also returns the failure. -#define SLANG_ASSERT_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { assert(false); return _res; } } -//! Helper macro that will assert if the result from a call is a failure, also returns. -#define SLANG_ASSERT_VOID_ON_FAIL(x) { SlangResult _res = (x); if (SLANG_FAILED(_res)) { assert(false); return; } } +#define SLANG_RETURN_NULL_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + SLANG_HANDLE_RESULT_FAIL(_res); \ + return nullptr; \ + } \ + } + +//! Helper macro that will assert if the return code from a call is failure, also returns the +//! failure. +#define SLANG_ASSERT_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + assert(false); \ + return _res; \ + } \ + } +//! Helper macro that will assert if the result from a call is a failure, also returns. +#define SLANG_ASSERT_VOID_ON_FAIL(x) \ + { \ + SlangResult _res = (x); \ + if (SLANG_FAILED(_res)) \ + { \ + assert(false); \ + return; \ + } \ + } /* !!!!!!!!!!!!!!!!!!!!!!! C++ helpers !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ #if defined(__cplusplus) -namespace Slang { +namespace Slang +{ // Alias SlangResult to Slang::Result typedef SlangResult Result; @@ -64,67 +118,79 @@ SLANG_FORCE_INLINE bool operator!=(const Slang::Guid& a, const Slang::Guid& b) return !(a == b); } -/* !!!!!!!! Macros to simplify implementing COM interfaces !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -/* Assumes underlying implementation has a member m_refCount that is initialized to 0 and can have ++ and -- operate on it. -For SLANG_IUNKNOWN_QUERY_INTERFACE to work - must have a method 'getInterface' that returns valid pointers for the Guid, or nullptr -if not found. */ - -#define SLANG_IUNKNOWN_QUERY_INTERFACE \ -SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE \ -{ \ - ISlangUnknown* intf = getInterface(uuid); \ - if (intf) \ - { \ - addRef(); \ - *outObject = intf; \ - return SLANG_OK;\ - } \ - return SLANG_E_NO_INTERFACE;\ -} - -#define SLANG_IUNKNOWN_ADD_REF \ -SLANG_NO_THROW uint32_t SLANG_MCALL addRef() \ -{ \ - return ++m_refCount; \ -} - -#define SLANG_IUNKNOWN_RELEASE \ -SLANG_NO_THROW uint32_t SLANG_MCALL release() \ -{ \ - --m_refCount; \ - if (m_refCount == 0) \ - { \ - delete this; \ - return 0; \ - } \ - return m_refCount; \ -} - -#define SLANG_IUNKNOWN_ALL \ - SLANG_IUNKNOWN_QUERY_INTERFACE \ - SLANG_IUNKNOWN_ADD_REF \ - SLANG_IUNKNOWN_RELEASE - -// ------------------------ RefObject IUnknown ----------------------------- - -#define SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE \ -SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE \ -{ \ - void* intf = getInterface(uuid); \ - if (intf) \ - { \ - addReference(); \ - *outObject = intf; \ - return SLANG_OK;\ - } \ - return SLANG_E_NO_INTERFACE;\ -} - -#define SLANG_REF_OBJECT_IUNKNOWN_ADD_REF SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return (uint32_t)addReference(); } -#define SLANG_REF_OBJECT_IUNKNOWN_RELEASE SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return (uint32_t)releaseReference(); } - -# define SLANG_REF_OBJECT_IUNKNOWN_ALL \ + /* !!!!!!!! Macros to simplify implementing COM interfaces !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + + /* Assumes underlying implementation has a member m_refCount that is initialized to 0 and can + have ++ and -- operate on it. For SLANG_IUNKNOWN_QUERY_INTERFACE to work - must have a method + 'getInterface' that returns valid pointers for the Guid, or nullptr if not found. */ + + #define SLANG_IUNKNOWN_QUERY_INTERFACE \ + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface( \ + SlangUUID const& uuid, \ + void** outObject) SLANG_OVERRIDE \ + { \ + ISlangUnknown* intf = getInterface(uuid); \ + if (intf) \ + { \ + addRef(); \ + *outObject = intf; \ + return SLANG_OK; \ + } \ + return SLANG_E_NO_INTERFACE; \ + } + + #define SLANG_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() \ + { \ + return ++m_refCount; \ + } + + #define SLANG_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() \ + { \ + --m_refCount; \ + if (m_refCount == 0) \ + { \ + delete this; \ + return 0; \ + } \ + return m_refCount; \ + } + + #define SLANG_IUNKNOWN_ALL \ + SLANG_IUNKNOWN_QUERY_INTERFACE \ + SLANG_IUNKNOWN_ADD_REF \ + SLANG_IUNKNOWN_RELEASE + + // ------------------------ RefObject IUnknown ----------------------------- + + #define SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE \ + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface( \ + SlangUUID const& uuid, \ + void** outObject) SLANG_OVERRIDE \ + { \ + void* intf = getInterface(uuid); \ + if (intf) \ + { \ + addReference(); \ + *outObject = intf; \ + return SLANG_OK; \ + } \ + return SLANG_E_NO_INTERFACE; \ + } + + #define SLANG_REF_OBJECT_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE \ + { \ + return (uint32_t)addReference(); \ + } + #define SLANG_REF_OBJECT_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE \ + { \ + return (uint32_t)releaseReference(); \ + } + + #define SLANG_REF_OBJECT_IUNKNOWN_ALL \ SLANG_REF_OBJECT_IUNKNOWN_QUERY_INTERFACE \ SLANG_REF_OBJECT_IUNKNOWN_ADD_REF \ SLANG_REF_OBJECT_IUNKNOWN_RELEASE diff --git a/include/slang-com-ptr.h b/include/slang-com-ptr.h index 00cc9dbb17..e9d211d929 100644 --- a/include/slang-com-ptr.h +++ b/include/slang-com-ptr.h @@ -6,20 +6,21 @@ #include #include -namespace Slang { +namespace Slang +{ /*! \brief ComPtr is a simple smart pointer that manages types which implement COM based interfaces. -\details A class that implements a COM, must derive from the IUnknown interface or a type that matches -it's layout exactly (such as ISlangUnknown). Trying to use this template with a class that doesn't follow -these rules, will lead to undefined behavior. -This is a 'strong' pointer type, and will AddRef when a non null pointer is set and Release when the pointer -leaves scope. -Using 'detach' allows a pointer to be removed from the management of the ComPtr. -To set the smart pointer to null, there is the method setNull, or alternatively just assign SLANG_NULL/nullptr. - -One edge case using the template is that sometimes you want access as a pointer to a pointer. Sometimes this -is to write into the smart pointer, other times to pass as an array. To handle these different behaviors -there are the methods readRef and writeRef, which are used instead of the & (ref) operator. For example +\details A class that implements a COM, must derive from the IUnknown interface or a type that +matches it's layout exactly (such as ISlangUnknown). Trying to use this template with a class that +doesn't follow these rules, will lead to undefined behavior. This is a 'strong' pointer type, and +will AddRef when a non null pointer is set and Release when the pointer leaves scope. Using 'detach' +allows a pointer to be removed from the management of the ComPtr. To set the smart pointer to null, +there is the method setNull, or alternatively just assign SLANG_NULL/nullptr. + +One edge case using the template is that sometimes you want access as a pointer to a pointer. +Sometimes this is to write into the smart pointer, other times to pass as an array. To handle these +different behaviors there are the methods readRef and writeRef, which are used instead of the & +(ref) operator. For example \code Void doSomething(ID3D12Resource** resources, IndexT numResources); @@ -44,115 +45,164 @@ enum InitAttach INIT_ATTACH }; -template +template class ComPtr { public: - typedef T Type; - typedef ComPtr ThisType; - typedef ISlangUnknown* Ptr; - - /// Constructors - /// Default Ctor. Sets to nullptr - SLANG_FORCE_INLINE ComPtr() :m_ptr(nullptr) {} - SLANG_FORCE_INLINE ComPtr(std::nullptr_t) : m_ptr(nullptr) {} - /// Sets, and ref counts. - SLANG_FORCE_INLINE explicit ComPtr(T* ptr) :m_ptr(ptr) { if (ptr) ((Ptr)ptr)->addRef(); } - /// The copy ctor - SLANG_FORCE_INLINE ComPtr(const ThisType& rhs) : m_ptr(rhs.m_ptr) { if (m_ptr) ((Ptr)m_ptr)->addRef(); } - - /// Ctor without adding to ref count. - SLANG_FORCE_INLINE explicit ComPtr(InitAttach, T* ptr) :m_ptr(ptr) { } - /// Ctor without adding to ref count - SLANG_FORCE_INLINE ComPtr(InitAttach, const ThisType& rhs) : m_ptr(rhs.m_ptr) { } + typedef T Type; + typedef ComPtr ThisType; + typedef ISlangUnknown* Ptr; + + /// Constructors + /// Default Ctor. Sets to nullptr + SLANG_FORCE_INLINE ComPtr() + : m_ptr(nullptr) + { + } + SLANG_FORCE_INLINE ComPtr(std::nullptr_t) + : m_ptr(nullptr) + { + } + /// Sets, and ref counts. + SLANG_FORCE_INLINE explicit ComPtr(T* ptr) + : m_ptr(ptr) + { + if (ptr) + ((Ptr)ptr)->addRef(); + } + /// The copy ctor + SLANG_FORCE_INLINE ComPtr(const ThisType& rhs) + : m_ptr(rhs.m_ptr) + { + if (m_ptr) + ((Ptr)m_ptr)->addRef(); + } + + /// Ctor without adding to ref count. + SLANG_FORCE_INLINE explicit ComPtr(InitAttach, T* ptr) + : m_ptr(ptr) + { + } + /// Ctor without adding to ref count + SLANG_FORCE_INLINE ComPtr(InitAttach, const ThisType& rhs) + : m_ptr(rhs.m_ptr) + { + } #ifdef SLANG_HAS_MOVE_SEMANTICS - /// Move Ctor - SLANG_FORCE_INLINE ComPtr(ThisType&& rhs) : m_ptr(rhs.m_ptr) { rhs.m_ptr = nullptr; } - /// Move assign - SLANG_FORCE_INLINE ComPtr& operator=(ThisType&& rhs) { T* swap = m_ptr; m_ptr = rhs.m_ptr; rhs.m_ptr = swap; return *this; } + /// Move Ctor + SLANG_FORCE_INLINE ComPtr(ThisType&& rhs) + : m_ptr(rhs.m_ptr) + { + rhs.m_ptr = nullptr; + } + /// Move assign + SLANG_FORCE_INLINE ComPtr& operator=(ThisType&& rhs) + { + T* swap = m_ptr; + m_ptr = rhs.m_ptr; + rhs.m_ptr = swap; + return *this; + } #endif - /// Destructor releases the pointer, assuming it is set - SLANG_FORCE_INLINE ~ComPtr() { if (m_ptr) ((Ptr)m_ptr)->release(); } - - // !!! Operators !!! - - /// Returns the dumb pointer - SLANG_FORCE_INLINE operator T *() const { return m_ptr; } - - SLANG_FORCE_INLINE T& operator*() { return *m_ptr; } - /// For making method invocations through the smart pointer work through the dumb pointer - SLANG_FORCE_INLINE T* operator->() const { return m_ptr; } - - /// Assign - SLANG_FORCE_INLINE const ThisType &operator=(const ThisType& rhs); - /// Assign from dumb ptr - SLANG_FORCE_INLINE T* operator=(T* in); - - /// Get the pointer and don't ref - SLANG_FORCE_INLINE T* get() const { return m_ptr; } - /// Release a contained nullptr pointer if set - SLANG_FORCE_INLINE void setNull(); - - /// Detach - SLANG_FORCE_INLINE T* detach() { T* ptr = m_ptr; m_ptr = nullptr; return ptr; } - /// Set to a pointer without changing the ref count - SLANG_FORCE_INLINE void attach(T* in) { m_ptr = in; } - - /// Get ready for writing (nulls contents) - SLANG_FORCE_INLINE T** writeRef() { setNull(); return &m_ptr; } - /// Get for read access - SLANG_FORCE_INLINE T*const* readRef() const { return &m_ptr; } - - /// Swap - void swap(ThisType& rhs); + /// Destructor releases the pointer, assuming it is set + SLANG_FORCE_INLINE ~ComPtr() + { + if (m_ptr) + ((Ptr)m_ptr)->release(); + } + + // !!! Operators !!! + + /// Returns the dumb pointer + SLANG_FORCE_INLINE operator T*() const { return m_ptr; } + + SLANG_FORCE_INLINE T& operator*() { return *m_ptr; } + /// For making method invocations through the smart pointer work through the dumb pointer + SLANG_FORCE_INLINE T* operator->() const { return m_ptr; } + + /// Assign + SLANG_FORCE_INLINE const ThisType& operator=(const ThisType& rhs); + /// Assign from dumb ptr + SLANG_FORCE_INLINE T* operator=(T* in); + + /// Get the pointer and don't ref + SLANG_FORCE_INLINE T* get() const { return m_ptr; } + /// Release a contained nullptr pointer if set + SLANG_FORCE_INLINE void setNull(); + + /// Detach + SLANG_FORCE_INLINE T* detach() + { + T* ptr = m_ptr; + m_ptr = nullptr; + return ptr; + } + /// Set to a pointer without changing the ref count + SLANG_FORCE_INLINE void attach(T* in) { m_ptr = in; } + + /// Get ready for writing (nulls contents) + SLANG_FORCE_INLINE T** writeRef() + { + setNull(); + return &m_ptr; + } + /// Get for read access + SLANG_FORCE_INLINE T* const* readRef() const { return &m_ptr; } + + /// Swap + void swap(ThisType& rhs); protected: - /// Gets the address of the dumb pointer. + /// Gets the address of the dumb pointer. // Disabled: use writeRef and readRef to get a reference based on usage. #ifndef SLANG_COM_PTR_ENABLE_REF_OPERATOR - SLANG_FORCE_INLINE T** operator&() = delete; + SLANG_FORCE_INLINE T** operator&() = delete; #endif - T* m_ptr; + T* m_ptr; }; //---------------------------------------------------------------------------- -template +template void ComPtr::setNull() { - if (m_ptr) - { - ((Ptr)m_ptr)->release(); - m_ptr = nullptr; - } + if (m_ptr) + { + ((Ptr)m_ptr)->release(); + m_ptr = nullptr; + } } //---------------------------------------------------------------------------- -template +template const ComPtr& ComPtr::operator=(const ThisType& rhs) { - if (rhs.m_ptr) ((Ptr)rhs.m_ptr)->addRef(); - if (m_ptr) ((Ptr)m_ptr)->release(); - m_ptr = rhs.m_ptr; - return *this; + if (rhs.m_ptr) + ((Ptr)rhs.m_ptr)->addRef(); + if (m_ptr) + ((Ptr)m_ptr)->release(); + m_ptr = rhs.m_ptr; + return *this; } //---------------------------------------------------------------------------- -template +template T* ComPtr::operator=(T* ptr) { - if (ptr) ((Ptr)ptr)->addRef(); - if (m_ptr) ((Ptr)m_ptr)->release(); - m_ptr = ptr; - return m_ptr; + if (ptr) + ((Ptr)ptr)->addRef(); + if (m_ptr) + ((Ptr)m_ptr)->release(); + m_ptr = ptr; + return m_ptr; } //---------------------------------------------------------------------------- -template +template void ComPtr::swap(ThisType& rhs) { - T* tmp = m_ptr; - m_ptr = rhs.m_ptr; - rhs.m_ptr = tmp; + T* tmp = m_ptr; + m_ptr = rhs.m_ptr; + rhs.m_ptr = tmp; } } // namespace Slang diff --git a/include/slang-deprecated.h b/include/slang-deprecated.h new file mode 100644 index 0000000000..82d81af75c --- /dev/null +++ b/include/slang-deprecated.h @@ -0,0 +1,1598 @@ +#pragma once + +#include "slang.h" + +/* DEPRECATED DEFINITIONS + +Everything in this file represents deprecated APIs/definition that are only +being kept around for source/binary compatibility with old client code. New +code should not use any of these declarations, and the Slang API will drop these +declarations over time. +*/ + +#ifdef __cplusplus +extern "C" +{ +#endif + + /*! + @brief Initialize an instance of the Slang library. + */ + SLANG_API SlangSession* spCreateSession(const char* deprecated = 0); + + /*! + @brief Clean up after an instance of the Slang library. + */ + SLANG_API void spDestroySession(SlangSession* session); + + /** @see slang::IGlobalSession::setSharedLibraryLoader + */ + SLANG_API void spSessionSetSharedLibraryLoader( + SlangSession* session, + ISlangSharedLibraryLoader* loader); + + /** @see slang::IGlobalSession::getSharedLibraryLoader + */ + SLANG_API ISlangSharedLibraryLoader* spSessionGetSharedLibraryLoader(SlangSession* session); + + /** @see slang::IGlobalSession::checkCompileTargetSupport + */ + SLANG_API SlangResult + spSessionCheckCompileTargetSupport(SlangSession* session, SlangCompileTarget target); + + /** @see slang::IGlobalSession::checkPassThroughSupport + */ + SLANG_API SlangResult + spSessionCheckPassThroughSupport(SlangSession* session, SlangPassThrough passThrough); + + /** @see slang::IGlobalSession::addBuiltins + */ + SLANG_API void spAddBuiltins( + SlangSession* session, + char const* sourcePath, + char const* sourceString); + + /* @see slang::IGlobalSession::createCompileRequest + */ + SLANG_API SlangCompileRequest* spCreateCompileRequest(SlangSession* session); + + /*! + @brief Destroy a compile request. + Note a request is a COM object and can be destroyed via 'Release'. + */ + SLANG_API void spDestroyCompileRequest(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::setFileSystem */ + SLANG_API void spSetFileSystem(SlangCompileRequest* request, ISlangFileSystem* fileSystem); + + /*! @see slang::ICompileRequest::setCompileFlags */ + SLANG_API void spSetCompileFlags(SlangCompileRequest* request, SlangCompileFlags flags); + + /*! @see slang::ICompileRequest::getCompileFlags */ + SLANG_API SlangCompileFlags spGetCompileFlags(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::setDumpIntermediates */ + SLANG_API void spSetDumpIntermediates(SlangCompileRequest* request, int enable); + + /*! @see slang::ICompileRequest::setDumpIntermediatePrefix */ + SLANG_API void spSetDumpIntermediatePrefix(SlangCompileRequest* request, const char* prefix); + + /*! DEPRECATED: use `spSetTargetLineDirectiveMode` instead. + @see slang::ICompileRequest::setLineDirectiveMode */ + SLANG_API void spSetLineDirectiveMode( + SlangCompileRequest* request, + SlangLineDirectiveMode mode); + + /*! @see slang::ICompileRequest::setTargetLineDirectiveMode */ + SLANG_API void spSetTargetLineDirectiveMode( + SlangCompileRequest* request, + int targetIndex, + SlangLineDirectiveMode mode); + + /*! @see slang::ICompileRequest::setTargetLineDirectiveMode */ + SLANG_API void spSetTargetForceGLSLScalarBufferLayout( + SlangCompileRequest* request, + int targetIndex, + bool forceScalarLayout); + + /*! @see slang::ICompileRequest::setTargetUseMinimumSlangOptimization */ + SLANG_API void spSetTargetUseMinimumSlangOptimization( + slang::ICompileRequest* request, + int targetIndex, + bool val); + + /*! @see slang::ICompileRequest::setIgnoreCapabilityCheck */ + SLANG_API void spSetIgnoreCapabilityCheck(slang::ICompileRequest* request, bool val); + + /*! @see slang::ICompileRequest::setCodeGenTarget */ + SLANG_API void spSetCodeGenTarget(SlangCompileRequest* request, SlangCompileTarget target); + + /*! @see slang::ICompileRequest::addCodeGenTarget */ + SLANG_API int spAddCodeGenTarget(SlangCompileRequest* request, SlangCompileTarget target); + + /*! @see slang::ICompileRequest::setTargetProfile */ + SLANG_API void spSetTargetProfile( + SlangCompileRequest* request, + int targetIndex, + SlangProfileID profile); + + /*! @see slang::ICompileRequest::setTargetFlags */ + SLANG_API void spSetTargetFlags( + SlangCompileRequest* request, + int targetIndex, + SlangTargetFlags flags); + + + /*! @see slang::ICompileRequest::setTargetFloatingPointMode */ + SLANG_API void spSetTargetFloatingPointMode( + SlangCompileRequest* request, + int targetIndex, + SlangFloatingPointMode mode); + + /*! @see slang::ICompileRequest::addTargetCapability */ + SLANG_API void spAddTargetCapability( + slang::ICompileRequest* request, + int targetIndex, + SlangCapabilityID capability); + + /* DEPRECATED: use `spSetMatrixLayoutMode` instead. */ + SLANG_API void spSetTargetMatrixLayoutMode( + SlangCompileRequest* request, + int targetIndex, + SlangMatrixLayoutMode mode); + + /*! @see slang::ICompileRequest::setMatrixLayoutMode */ + SLANG_API void spSetMatrixLayoutMode(SlangCompileRequest* request, SlangMatrixLayoutMode mode); + + /*! @see slang::ICompileRequest::setDebugInfoLevel */ + SLANG_API void spSetDebugInfoLevel(SlangCompileRequest* request, SlangDebugInfoLevel level); + + /*! @see slang::ICompileRequest::setDebugInfoFormat */ + SLANG_API void spSetDebugInfoFormat(SlangCompileRequest* request, SlangDebugInfoFormat format); + + /*! @see slang::ICompileRequest::setOptimizationLevel */ + SLANG_API void spSetOptimizationLevel( + SlangCompileRequest* request, + SlangOptimizationLevel level); + + + /*! @see slang::ICompileRequest::setOutputContainerFormat */ + SLANG_API void spSetOutputContainerFormat( + SlangCompileRequest* request, + SlangContainerFormat format); + + /*! @see slang::ICompileRequest::setPassThrough */ + SLANG_API void spSetPassThrough(SlangCompileRequest* request, SlangPassThrough passThrough); + + /*! @see slang::ICompileRequest::setDiagnosticCallback */ + SLANG_API void spSetDiagnosticCallback( + SlangCompileRequest* request, + SlangDiagnosticCallback callback, + void const* userData); + + /*! @see slang::ICompileRequest::setWriter */ + SLANG_API void spSetWriter( + SlangCompileRequest* request, + SlangWriterChannel channel, + ISlangWriter* writer); + + /*! @see slang::ICompileRequest::getWriter */ + SLANG_API ISlangWriter* spGetWriter(SlangCompileRequest* request, SlangWriterChannel channel); + + /*! @see slang::ICompileRequest::addSearchPath */ + SLANG_API void spAddSearchPath(SlangCompileRequest* request, const char* searchDir); + + /*! @see slang::ICompileRequest::addPreprocessorDefine */ + SLANG_API void spAddPreprocessorDefine( + SlangCompileRequest* request, + const char* key, + const char* value); + + /*! @see slang::ICompileRequest::processCommandLineArguments */ + SLANG_API SlangResult spProcessCommandLineArguments( + SlangCompileRequest* request, + char const* const* args, + int argCount); + + /*! @see slang::ICompileRequest::addTranslationUnit */ + SLANG_API int spAddTranslationUnit( + SlangCompileRequest* request, + SlangSourceLanguage language, + char const* name); + + + /*! @see slang::ICompileRequest::setDefaultModuleName */ + SLANG_API void spSetDefaultModuleName( + SlangCompileRequest* request, + const char* defaultModuleName); + + /*! @see slang::ICompileRequest::addPreprocessorDefine */ + SLANG_API void spTranslationUnit_addPreprocessorDefine( + SlangCompileRequest* request, + int translationUnitIndex, + const char* key, + const char* value); + + + /*! @see slang::ICompileRequest::addTranslationUnitSourceFile */ + SLANG_API void spAddTranslationUnitSourceFile( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path); + + /*! @see slang::ICompileRequest::addTranslationUnitSourceString */ + SLANG_API void spAddTranslationUnitSourceString( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + char const* source); + + + /*! @see slang::ICompileRequest::addLibraryReference */ + SLANG_API SlangResult spAddLibraryReference( + SlangCompileRequest* request, + const char* basePath, + const void* libData, + size_t libDataSize); + + /*! @see slang::ICompileRequest::addTranslationUnitSourceStringSpan */ + SLANG_API void spAddTranslationUnitSourceStringSpan( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + char const* sourceBegin, + char const* sourceEnd); + + /*! @see slang::ICompileRequest::addTranslationUnitSourceBlob */ + SLANG_API void spAddTranslationUnitSourceBlob( + SlangCompileRequest* request, + int translationUnitIndex, + char const* path, + ISlangBlob* sourceBlob); + + /*! @see slang::IGlobalSession::findProfile */ + SLANG_API SlangProfileID spFindProfile(SlangSession* session, char const* name); + + /*! @see slang::IGlobalSession::findCapability */ + SLANG_API SlangCapabilityID spFindCapability(SlangSession* session, char const* name); + + /*! @see slang::ICompileRequest::addEntryPoint */ + SLANG_API int spAddEntryPoint( + SlangCompileRequest* request, + int translationUnitIndex, + char const* name, + SlangStage stage); + + /*! @see slang::ICompileRequest::addEntryPointEx */ + SLANG_API int spAddEntryPointEx( + SlangCompileRequest* request, + int translationUnitIndex, + char const* name, + SlangStage stage, + int genericArgCount, + char const** genericArgs); + + /*! @see slang::ICompileRequest::setGlobalGenericArgs */ + SLANG_API SlangResult spSetGlobalGenericArgs( + SlangCompileRequest* request, + int genericArgCount, + char const** genericArgs); + + /*! @see slang::ICompileRequest::setTypeNameForGlobalExistentialTypeParam */ + SLANG_API SlangResult spSetTypeNameForGlobalExistentialTypeParam( + SlangCompileRequest* request, + int slotIndex, + char const* typeName); + + /*! @see slang::ICompileRequest::setTypeNameForEntryPointExistentialTypeParam */ + SLANG_API SlangResult spSetTypeNameForEntryPointExistentialTypeParam( + SlangCompileRequest* request, + int entryPointIndex, + int slotIndex, + char const* typeName); + + /*! @see slang::ICompileRequest::compile */ + SLANG_API SlangResult spCompile(SlangCompileRequest* request); + + + /*! @see slang::ICompileRequest::getDiagnosticOutput */ + SLANG_API char const* spGetDiagnosticOutput(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::getDiagnosticOutputBlob */ + SLANG_API SlangResult + spGetDiagnosticOutputBlob(SlangCompileRequest* request, ISlangBlob** outBlob); + + + /*! @see slang::ICompileRequest::getDependencyFileCount */ + SLANG_API int spGetDependencyFileCount(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::getDependencyFilePath */ + SLANG_API char const* spGetDependencyFilePath(SlangCompileRequest* request, int index); + + /*! @see slang::ICompileRequest::getTranslationUnitCount */ + SLANG_API int spGetTranslationUnitCount(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::getEntryPointSource */ + SLANG_API char const* spGetEntryPointSource(SlangCompileRequest* request, int entryPointIndex); + + /*! @see slang::ICompileRequest::getEntryPointCode */ + SLANG_API void const* spGetEntryPointCode( + SlangCompileRequest* request, + int entryPointIndex, + size_t* outSize); + + /*! @see slang::ICompileRequest::getEntryPointCodeBlob */ + SLANG_API SlangResult spGetEntryPointCodeBlob( + SlangCompileRequest* request, + int entryPointIndex, + int targetIndex, + ISlangBlob** outBlob); + + /*! @see slang::ICompileRequest::getEntryPointHostCallable */ + SLANG_API SlangResult spGetEntryPointHostCallable( + SlangCompileRequest* request, + int entryPointIndex, + int targetIndex, + ISlangSharedLibrary** outSharedLibrary); + + /*! @see slang::ICompileRequest::getTargetCodeBlob */ + SLANG_API SlangResult + spGetTargetCodeBlob(SlangCompileRequest* request, int targetIndex, ISlangBlob** outBlob); + + /*! @see slang::ICompileRequest::getTargetHostCallable */ + SLANG_API SlangResult spGetTargetHostCallable( + SlangCompileRequest* request, + int targetIndex, + ISlangSharedLibrary** outSharedLibrary); + + /*! @see slang::ICompileRequest::getCompileRequestCode */ + SLANG_API void const* spGetCompileRequestCode(SlangCompileRequest* request, size_t* outSize); + + /*! @see slang::ICompileRequest::getContainerCode */ + SLANG_API SlangResult spGetContainerCode(SlangCompileRequest* request, ISlangBlob** outBlob); + + /*! @see slang::ICompileRequest::loadRepro */ + SLANG_API SlangResult spLoadRepro( + SlangCompileRequest* request, + ISlangFileSystem* fileSystem, + const void* data, + size_t size); + + /*! @see slang::ICompileRequest::saveRepro */ + SLANG_API SlangResult spSaveRepro(SlangCompileRequest* request, ISlangBlob** outBlob); + + /*! @see slang::ICompileRequest::enableReproCapture */ + SLANG_API SlangResult spEnableReproCapture(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::getCompileTimeProfile */ + SLANG_API SlangResult spGetCompileTimeProfile( + SlangCompileRequest* request, + ISlangProfiler** compileTimeProfile, + bool shouldClear); + + + /** Extract contents of a repro. + + Writes the contained files and manifest with their 'unique' names into fileSystem. For more + details read the docs/repro.md documentation. + + @param session The slang session + @param reproData Holds the repro data + @param reproDataSize The size of the repro data + @param fileSystem File system that the contents of the repro will be written to + @returns A `SlangResult` to indicate success or failure. + */ + SLANG_API SlangResult spExtractRepro( + SlangSession* session, + const void* reproData, + size_t reproDataSize, + ISlangMutableFileSystem* fileSystem); + + /* Turns a repro into a file system. + + Makes the contents of the repro available as a file system - that is able to access the files + with the same paths as were used on the original repro file system. + + @param session The slang session + @param reproData The repro data + @param reproDataSize The size of the repro data + @param replaceFileSystem Will attempt to load by unique names from this file system before + using contents of the repro. Optional. + @param outFileSystem The file system that can be used to access contents + @returns A `SlangResult` to indicate success or failure. + */ + SLANG_API SlangResult spLoadReproAsFileSystem( + SlangSession* session, + const void* reproData, + size_t reproDataSize, + ISlangFileSystem* replaceFileSystem, + ISlangFileSystemExt** outFileSystem); + + /*! @see slang::ICompileRequest::overrideDiagnosticSeverity */ + SLANG_API void spOverrideDiagnosticSeverity( + SlangCompileRequest* request, + SlangInt messageID, + SlangSeverity overrideSeverity); + + /*! @see slang::ICompileRequest::getDiagnosticFlags */ + SLANG_API SlangDiagnosticFlags spGetDiagnosticFlags(SlangCompileRequest* request); + + /*! @see slang::ICompileRequest::setDiagnosticFlags */ + SLANG_API void spSetDiagnosticFlags(SlangCompileRequest* request, SlangDiagnosticFlags flags); + + + // get reflection data from a compilation request + SLANG_API SlangReflection* spGetReflection(SlangCompileRequest* request); + + // User Attribute + SLANG_API char const* spReflectionUserAttribute_GetName(SlangReflectionUserAttribute* attrib); + SLANG_API unsigned int spReflectionUserAttribute_GetArgumentCount( + SlangReflectionUserAttribute* attrib); + SLANG_API SlangReflectionType* spReflectionUserAttribute_GetArgumentType( + SlangReflectionUserAttribute* attrib, + unsigned int index); + SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueInt( + SlangReflectionUserAttribute* attrib, + unsigned int index, + int* rs); + SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueFloat( + SlangReflectionUserAttribute* attrib, + unsigned int index, + float* rs); + + /** Returns the string-typed value of a user attribute argument + The string returned is not null-terminated. The length of the string is returned via + `outSize`. If index of out of range, or if the specified argument is not a string, the + function will return nullptr. + */ + SLANG_API const char* spReflectionUserAttribute_GetArgumentValueString( + SlangReflectionUserAttribute* attrib, + unsigned int index, + size_t* outSize); + + // Type Reflection + + SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* type); + SLANG_API unsigned int spReflectionType_GetUserAttributeCount(SlangReflectionType* type); + SLANG_API SlangReflectionUserAttribute* spReflectionType_GetUserAttribute( + SlangReflectionType* type, + unsigned int index); + SLANG_API SlangReflectionUserAttribute* spReflectionType_FindUserAttributeByName( + SlangReflectionType* type, + char const* name); + SLANG_API SlangReflectionType* spReflectionType_applySpecializations( + SlangReflectionType* type, + SlangReflectionGeneric* generic); + + SLANG_API unsigned int spReflectionType_GetFieldCount(SlangReflectionType* type); + SLANG_API SlangReflectionVariable* spReflectionType_GetFieldByIndex( + SlangReflectionType* type, + unsigned index); + + /** Returns the number of elements in the given type. + + This operation is valid for vector and array types. For other types it returns zero. + + When invoked on an unbounded-size array it will return `SLANG_UNBOUNDED_SIZE`, + which is defined to be `~size_t(0)`. + + If the size of a type cannot be statically computed, perhaps because it depends on + a generic parameter that has not been bound to a specific value, this function returns zero. + */ + SLANG_API size_t spReflectionType_GetElementCount(SlangReflectionType* type); + + SLANG_API SlangReflectionType* spReflectionType_GetElementType(SlangReflectionType* type); + + SLANG_API unsigned int spReflectionType_GetRowCount(SlangReflectionType* type); + SLANG_API unsigned int spReflectionType_GetColumnCount(SlangReflectionType* type); + SLANG_API SlangScalarType spReflectionType_GetScalarType(SlangReflectionType* type); + + SLANG_API SlangResourceShape spReflectionType_GetResourceShape(SlangReflectionType* type); + SLANG_API SlangResourceAccess spReflectionType_GetResourceAccess(SlangReflectionType* type); + SLANG_API SlangReflectionType* spReflectionType_GetResourceResultType( + SlangReflectionType* type); + + SLANG_API char const* spReflectionType_GetName(SlangReflectionType* type); + SLANG_API SlangResult + spReflectionType_GetFullName(SlangReflectionType* type, ISlangBlob** outNameBlob); + SLANG_API SlangReflectionGeneric* spReflectionType_GetGenericContainer( + SlangReflectionType* type); + + // Type Layout Reflection + + SLANG_API SlangReflectionType* spReflectionTypeLayout_GetType(SlangReflectionTypeLayout* type); + SLANG_API SlangTypeKind spReflectionTypeLayout_getKind(SlangReflectionTypeLayout* type); + SLANG_API size_t spReflectionTypeLayout_GetSize( + SlangReflectionTypeLayout* type, + SlangParameterCategory category); + SLANG_API size_t spReflectionTypeLayout_GetStride( + SlangReflectionTypeLayout* type, + SlangParameterCategory category); + SLANG_API int32_t spReflectionTypeLayout_getAlignment( + SlangReflectionTypeLayout* type, + SlangParameterCategory category); + + SLANG_API uint32_t spReflectionTypeLayout_GetFieldCount(SlangReflectionTypeLayout* type); + SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetFieldByIndex( + SlangReflectionTypeLayout* type, + unsigned index); + + SLANG_API SlangInt spReflectionTypeLayout_findFieldIndexByName( + SlangReflectionTypeLayout* typeLayout, + const char* nameBegin, + const char* nameEnd); + + SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetExplicitCounter( + SlangReflectionTypeLayout* typeLayout); + + SLANG_API size_t spReflectionTypeLayout_GetElementStride( + SlangReflectionTypeLayout* type, + SlangParameterCategory category); + SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout( + SlangReflectionTypeLayout* type); + SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetElementVarLayout( + SlangReflectionTypeLayout* type); + SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getContainerVarLayout( + SlangReflectionTypeLayout* type); + + SLANG_API SlangParameterCategory + spReflectionTypeLayout_GetParameterCategory(SlangReflectionTypeLayout* type); + + SLANG_API unsigned spReflectionTypeLayout_GetCategoryCount(SlangReflectionTypeLayout* type); + SLANG_API SlangParameterCategory + spReflectionTypeLayout_GetCategoryByIndex(SlangReflectionTypeLayout* type, unsigned index); + + SLANG_API SlangMatrixLayoutMode + spReflectionTypeLayout_GetMatrixLayoutMode(SlangReflectionTypeLayout* type); + + SLANG_API int spReflectionTypeLayout_getGenericParamIndex(SlangReflectionTypeLayout* type); + + SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getPendingDataTypeLayout( + SlangReflectionTypeLayout* type); + + SLANG_API SlangReflectionVariableLayout* + spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(SlangReflectionTypeLayout* type); + SLANG_API SlangInt spReflectionType_getSpecializedTypeArgCount(SlangReflectionType* type); + SLANG_API SlangReflectionType* spReflectionType_getSpecializedTypeArgType( + SlangReflectionType* type, + SlangInt index); + + SLANG_API SlangInt + spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* typeLayout); + SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_isBindingRangeSpecializable( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangReflectionVariable* spReflectionTypeLayout_getBindingRangeLeafVariable( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangImageFormat spReflectionTypeLayout_getBindingRangeImageFormat( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset( + SlangReflectionTypeLayout* typeLayout, + SlangInt fieldIndex); + SLANG_API SlangInt spReflectionTypeLayout_getExplicitCounterBindingRangeOffset( + SlangReflectionTypeLayout* inTypeLayout); + + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount( + SlangReflectionTypeLayout* typeLayout, + SlangInt index); + + SLANG_API SlangInt + spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* typeLayout); + SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex); + SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex); + SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex, + SlangInt rangeIndex); + SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex, + SlangInt rangeIndex); + SLANG_API SlangBindingType spReflectionTypeLayout_getDescriptorSetDescriptorRangeType( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex, + SlangInt rangeIndex); + SLANG_API SlangParameterCategory spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory( + SlangReflectionTypeLayout* typeLayout, + SlangInt setIndex, + SlangInt rangeIndex); + + SLANG_API SlangInt + spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex( + SlangReflectionTypeLayout* typeLayout, + SlangInt subObjectRangeIndex); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeSpaceOffset( + SlangReflectionTypeLayout* typeLayout, + SlangInt subObjectRangeIndex); + SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSubObjectRangeOffset( + SlangReflectionTypeLayout* typeLayout, + SlangInt subObjectRangeIndex); + +#if 0 + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeObjectCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index); + SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getSubObjectRangeTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index); + + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex); + SLANG_API SlangBindingType spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingType(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeIndexOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); + SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); +#endif + + // Variable Reflection + + SLANG_API char const* spReflectionVariable_GetName(SlangReflectionVariable* var); + SLANG_API SlangReflectionType* spReflectionVariable_GetType(SlangReflectionVariable* var); + SLANG_API SlangReflectionModifier* spReflectionVariable_FindModifier( + SlangReflectionVariable* var, + SlangModifierID modifierID); + SLANG_API unsigned int spReflectionVariable_GetUserAttributeCount(SlangReflectionVariable* var); + SLANG_API SlangReflectionUserAttribute* spReflectionVariable_GetUserAttribute( + SlangReflectionVariable* var, + unsigned int index); + SLANG_API SlangReflectionUserAttribute* spReflectionVariable_FindUserAttributeByName( + SlangReflectionVariable* var, + SlangSession* globalSession, + char const* name); + SLANG_API bool spReflectionVariable_HasDefaultValue(SlangReflectionVariable* inVar); + SLANG_API SlangReflectionGeneric* spReflectionVariable_GetGenericContainer( + SlangReflectionVariable* var); + SLANG_API SlangReflectionVariable* spReflectionVariable_applySpecializations( + SlangReflectionVariable* var, + SlangReflectionGeneric* generic); + + // Variable Layout Reflection + + SLANG_API SlangReflectionVariable* spReflectionVariableLayout_GetVariable( + SlangReflectionVariableLayout* var); + + SLANG_API SlangReflectionTypeLayout* spReflectionVariableLayout_GetTypeLayout( + SlangReflectionVariableLayout* var); + + SLANG_API size_t spReflectionVariableLayout_GetOffset( + SlangReflectionVariableLayout* var, + SlangParameterCategory category); + SLANG_API size_t spReflectionVariableLayout_GetSpace( + SlangReflectionVariableLayout* var, + SlangParameterCategory category); + + SLANG_API char const* spReflectionVariableLayout_GetSemanticName( + SlangReflectionVariableLayout* var); + SLANG_API size_t + spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* var); + + + // Function Reflection + + SLANG_API SlangReflectionDecl* spReflectionFunction_asDecl(SlangReflectionFunction* func); + SLANG_API char const* spReflectionFunction_GetName(SlangReflectionFunction* func); + SLANG_API SlangReflectionModifier* spReflectionFunction_FindModifier( + SlangReflectionFunction* var, + SlangModifierID modifierID); + SLANG_API unsigned int spReflectionFunction_GetUserAttributeCount( + SlangReflectionFunction* func); + SLANG_API SlangReflectionUserAttribute* spReflectionFunction_GetUserAttribute( + SlangReflectionFunction* func, + unsigned int index); + SLANG_API SlangReflectionUserAttribute* spReflectionFunction_FindUserAttributeByName( + SlangReflectionFunction* func, + SlangSession* globalSession, + char const* name); + SLANG_API unsigned int spReflectionFunction_GetParameterCount(SlangReflectionFunction* func); + SLANG_API SlangReflectionVariable* spReflectionFunction_GetParameter( + SlangReflectionFunction* func, + unsigned index); + SLANG_API SlangReflectionType* spReflectionFunction_GetResultType( + SlangReflectionFunction* func); + SLANG_API SlangReflectionGeneric* spReflectionFunction_GetGenericContainer( + SlangReflectionFunction* func); + SLANG_API SlangReflectionFunction* spReflectionFunction_applySpecializations( + SlangReflectionFunction* func, + SlangReflectionGeneric* generic); + SLANG_API SlangReflectionFunction* spReflectionFunction_specializeWithArgTypes( + SlangReflectionFunction* func, + SlangInt argTypeCount, + SlangReflectionType* const* argTypes); + SLANG_API bool spReflectionFunction_isOverloaded(SlangReflectionFunction* func); + SLANG_API unsigned int spReflectionFunction_getOverloadCount(SlangReflectionFunction* func); + SLANG_API SlangReflectionFunction* spReflectionFunction_getOverload( + SlangReflectionFunction* func, + unsigned int index); + + // Abstract Decl Reflection + + SLANG_API unsigned int spReflectionDecl_getChildrenCount(SlangReflectionDecl* parentDecl); + SLANG_API SlangReflectionDecl* spReflectionDecl_getChild( + SlangReflectionDecl* parentDecl, + unsigned int index); + SLANG_API char const* spReflectionDecl_getName(SlangReflectionDecl* decl); + SLANG_API SlangDeclKind spReflectionDecl_getKind(SlangReflectionDecl* decl); + SLANG_API SlangReflectionFunction* spReflectionDecl_castToFunction(SlangReflectionDecl* decl); + SLANG_API SlangReflectionVariable* spReflectionDecl_castToVariable(SlangReflectionDecl* decl); + SLANG_API SlangReflectionGeneric* spReflectionDecl_castToGeneric(SlangReflectionDecl* decl); + SLANG_API SlangReflectionType* spReflection_getTypeFromDecl(SlangReflectionDecl* decl); + SLANG_API SlangReflectionDecl* spReflectionDecl_getParent(SlangReflectionDecl* decl); + + // Generic Reflection + + SLANG_API SlangReflectionDecl* spReflectionGeneric_asDecl(SlangReflectionGeneric* generic); + SLANG_API char const* spReflectionGeneric_GetName(SlangReflectionGeneric* generic); + SLANG_API unsigned int spReflectionGeneric_GetTypeParameterCount( + SlangReflectionGeneric* generic); + SLANG_API SlangReflectionVariable* spReflectionGeneric_GetTypeParameter( + SlangReflectionGeneric* generic, + unsigned index); + SLANG_API unsigned int spReflectionGeneric_GetValueParameterCount( + SlangReflectionGeneric* generic); + SLANG_API SlangReflectionVariable* spReflectionGeneric_GetValueParameter( + SlangReflectionGeneric* generic, + unsigned index); + SLANG_API unsigned int spReflectionGeneric_GetTypeParameterConstraintCount( + SlangReflectionGeneric* generic, + SlangReflectionVariable* typeParam); + SLANG_API SlangReflectionType* spReflectionGeneric_GetTypeParameterConstraintType( + SlangReflectionGeneric* generic, + SlangReflectionVariable* typeParam, + unsigned index); + SLANG_API SlangDeclKind spReflectionGeneric_GetInnerKind(SlangReflectionGeneric* generic); + SLANG_API SlangReflectionDecl* spReflectionGeneric_GetInnerDecl( + SlangReflectionGeneric* generic); + SLANG_API SlangReflectionGeneric* spReflectionGeneric_GetOuterGenericContainer( + SlangReflectionGeneric* generic); + SLANG_API SlangReflectionType* spReflectionGeneric_GetConcreteType( + SlangReflectionGeneric* generic, + SlangReflectionVariable* typeParam); + SLANG_API int64_t spReflectionGeneric_GetConcreteIntVal( + SlangReflectionGeneric* generic, + SlangReflectionVariable* valueParam); + SLANG_API SlangReflectionGeneric* spReflectionGeneric_applySpecializations( + SlangReflectionGeneric* currGeneric, + SlangReflectionGeneric* generic); + + + /** Get the stage that a variable belongs to (if any). + + A variable "belongs" to a specific stage when it is a varying input/output + parameter either defined as part of the parameter list for an entry + point *or* at the global scope of a stage-specific GLSL code file (e.g., + an `in` parameter in a GLSL `.vs` file belongs to the vertex stage). + */ + SLANG_API SlangStage spReflectionVariableLayout_getStage(SlangReflectionVariableLayout* var); + + + SLANG_API SlangReflectionVariableLayout* spReflectionVariableLayout_getPendingDataLayout( + SlangReflectionVariableLayout* var); + + // Shader Parameter Reflection + + SLANG_API unsigned spReflectionParameter_GetBindingIndex(SlangReflectionParameter* parameter); + SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParameter* parameter); + + SLANG_API SlangResult spIsParameterLocationUsed( + SlangCompileRequest* request, + SlangInt entryPointIndex, + SlangInt targetIndex, + SlangParameterCategory category, // is this a `t` register? `s` register? + SlangUInt spaceIndex, // `space` for D3D12, `set` for Vulkan + SlangUInt registerIndex, // `register` for D3D12, `binding` for Vulkan + bool& outUsed); + + // Entry Point Reflection + + SLANG_API char const* spReflectionEntryPoint_getName(SlangReflectionEntryPoint* entryPoint); + + SLANG_API char const* spReflectionEntryPoint_getNameOverride( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API SlangReflectionFunction* spReflectionEntryPoint_getFunction( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API unsigned spReflectionEntryPoint_getParameterCount( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getParameterByIndex( + SlangReflectionEntryPoint* entryPoint, + unsigned index); + + SLANG_API SlangStage spReflectionEntryPoint_getStage(SlangReflectionEntryPoint* entryPoint); + + SLANG_API void spReflectionEntryPoint_getComputeThreadGroupSize( + SlangReflectionEntryPoint* entryPoint, + SlangUInt axisCount, + SlangUInt* outSizeAlongAxis); + + SLANG_API void spReflectionEntryPoint_getComputeWaveSize( + SlangReflectionEntryPoint* entryPoint, + SlangUInt* outWaveSize); + + SLANG_API int spReflectionEntryPoint_usesAnySampleRateInput( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getVarLayout( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getResultVarLayout( + SlangReflectionEntryPoint* entryPoint); + + SLANG_API int spReflectionEntryPoint_hasDefaultConstantBuffer( + SlangReflectionEntryPoint* entryPoint); + + // SlangReflectionTypeParameter + SLANG_API char const* spReflectionTypeParameter_GetName( + SlangReflectionTypeParameter* typeParam); + SLANG_API unsigned spReflectionTypeParameter_GetIndex(SlangReflectionTypeParameter* typeParam); + SLANG_API unsigned spReflectionTypeParameter_GetConstraintCount( + SlangReflectionTypeParameter* typeParam); + SLANG_API SlangReflectionType* spReflectionTypeParameter_GetConstraintByIndex( + SlangReflectionTypeParameter* typeParam, + unsigned int index); + + // Shader Reflection + + SLANG_API SlangResult spReflection_ToJson( + SlangReflection* reflection, + SlangCompileRequest* request, + ISlangBlob** outBlob); + + SLANG_API unsigned spReflection_GetParameterCount(SlangReflection* reflection); + SLANG_API SlangReflectionParameter* spReflection_GetParameterByIndex( + SlangReflection* reflection, + unsigned index); + + SLANG_API unsigned int spReflection_GetTypeParameterCount(SlangReflection* reflection); + SLANG_API SlangReflectionTypeParameter* spReflection_GetTypeParameterByIndex( + SlangReflection* reflection, + unsigned int index); + SLANG_API SlangReflectionTypeParameter* spReflection_FindTypeParameter( + SlangReflection* reflection, + char const* name); + + SLANG_API SlangReflectionType* spReflection_FindTypeByName( + SlangReflection* reflection, + char const* name); + SLANG_API SlangReflectionTypeLayout* spReflection_GetTypeLayout( + SlangReflection* reflection, + SlangReflectionType* reflectionType, + SlangLayoutRules rules); + + SLANG_API SlangReflectionFunction* spReflection_FindFunctionByName( + SlangReflection* reflection, + char const* name); + SLANG_API SlangReflectionFunction* spReflection_FindFunctionByNameInType( + SlangReflection* reflection, + SlangReflectionType* reflType, + char const* name); + SLANG_API SlangReflectionVariable* spReflection_FindVarByNameInType( + SlangReflection* reflection, + SlangReflectionType* reflType, + char const* name); + + SLANG_API SlangUInt spReflection_getEntryPointCount(SlangReflection* reflection); + SLANG_API SlangReflectionEntryPoint* spReflection_getEntryPointByIndex( + SlangReflection* reflection, + SlangUInt index); + SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName( + SlangReflection* reflection, + char const* name); + + SLANG_API SlangUInt spReflection_getGlobalConstantBufferBinding(SlangReflection* reflection); + SLANG_API size_t spReflection_getGlobalConstantBufferSize(SlangReflection* reflection); + + SLANG_API SlangReflectionType* spReflection_specializeType( + SlangReflection* reflection, + SlangReflectionType* type, + SlangInt specializationArgCount, + SlangReflectionType* const* specializationArgs, + ISlangBlob** outDiagnostics); + + SLANG_API SlangReflectionGeneric* spReflection_specializeGeneric( + SlangReflection* inProgramLayout, + SlangReflectionGeneric* generic, + SlangInt argCount, + SlangReflectionGenericArgType const* argTypes, + SlangReflectionGenericArg const* args, + ISlangBlob** outDiagnostics); + + SLANG_API bool spReflection_isSubType( + SlangReflection* reflection, + SlangReflectionType* subType, + SlangReflectionType* superType); + + /// Get the number of hashed strings + SLANG_API SlangUInt spReflection_getHashedStringCount(SlangReflection* reflection); + + /// Get a hashed string. The number of chars is written in outCount. + /// The count does *NOT* including terminating 0. The returned string will be 0 terminated. + SLANG_API const char* spReflection_getHashedString( + SlangReflection* reflection, + SlangUInt index, + size_t* outCount); + + /// Compute a string hash. + /// Count should *NOT* include terminating zero. + SLANG_API SlangUInt32 spComputeStringHash(const char* chars, size_t count); + + /// Get a type layout representing reflection information for the global-scope parameters. + SLANG_API SlangReflectionTypeLayout* spReflection_getGlobalParamsTypeLayout( + SlangReflection* reflection); + + /// Get a variable layout representing reflection information for the global-scope parameters. + SLANG_API SlangReflectionVariableLayout* spReflection_getGlobalParamsVarLayout( + SlangReflection* reflection); + + SLANG_API char const* spGetTranslationUnitSource( + SlangCompileRequest* request, + int translationUnitIndex); +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +SLANG_API slang::ISession* spReflection_GetSession(SlangReflection* reflection); + +namespace slang +{ +struct IComponentType; +struct IModule; +} // namespace slang + +extern "C" +{ + /** @see slang::ICompileRequest::getProgram + */ + SLANG_API SlangResult + spCompileRequest_getProgram(SlangCompileRequest* request, slang::IComponentType** outProgram); + + /** @see slang::ICompileRequest::getProgramWithEntryPoints + */ + SLANG_API SlangResult spCompileRequest_getProgramWithEntryPoints( + SlangCompileRequest* request, + slang::IComponentType** outProgram); + + /** @see slang::ICompileRequest::getEntryPoint + */ + SLANG_API SlangResult spCompileRequest_getEntryPoint( + SlangCompileRequest* request, + SlangInt entryPointIndex, + slang::IComponentType** outEntryPoint); + + /** @see slang::ICompileRequest::getModule + */ + SLANG_API SlangResult spCompileRequest_getModule( + SlangCompileRequest* request, + SlangInt translationUnitIndex, + slang::IModule** outModule); + + /** @see slang::ICompileRequest::getSession + */ + SLANG_API SlangResult + spCompileRequest_getSession(SlangCompileRequest* request, slang::ISession** outSession); +} + +namespace slang +{ +/*! +@brief A request for one or more compilation actions to be performed. +*/ +struct ICompileRequest : public ISlangUnknown +{ + SLANG_COM_INTERFACE( + 0x96d33993, + 0x317c, + 0x4db5, + {0xaf, 0xd8, 0x66, 0x6e, 0xe7, 0x72, 0x48, 0xe2}) + + /** Set the filesystem hook to use for a compile request + + The provided `fileSystem` will be used to load any files that + need to be loaded during processing of the compile `request`. + This includes: + + - Source files loaded via `spAddTranslationUnitSourceFile` + - Files referenced via `#include` + - Files loaded to resolve `#import` operations + */ + virtual SLANG_NO_THROW void SLANG_MCALL setFileSystem(ISlangFileSystem* fileSystem) = 0; + + /*! + @brief Set flags to be used for compilation. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setCompileFlags(SlangCompileFlags flags) = 0; + + /*! + @brief Returns the compilation flags previously set with `setCompileFlags` + */ + virtual SLANG_NO_THROW SlangCompileFlags SLANG_MCALL getCompileFlags() = 0; + + /*! + @brief Set whether to dump intermediate results (for debugging) or not. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediates(int enable) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediatePrefix(const char* prefix) = 0; + + /*! + @brief Set whether (and how) `#line` directives should be output. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setLineDirectiveMode(SlangLineDirectiveMode mode) = 0; + + /*! + @brief Sets the target for code generation. + @param target The code generation target. Possible values are: + - SLANG_GLSL. Generates GLSL code. + - SLANG_HLSL. Generates HLSL code. + - SLANG_SPIRV. Generates SPIR-V code. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setCodeGenTarget(SlangCompileTarget target) = 0; + + /*! + @brief Add a code-generation target to be used. + */ + virtual SLANG_NO_THROW int SLANG_MCALL addCodeGenTarget(SlangCompileTarget target) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetProfile(int targetIndex, SlangProfileID profile) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetFlags(int targetIndex, SlangTargetFlags flags) = 0; + + /*! + @brief Set the floating point mode (e.g., precise or fast) to use a target. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetFloatingPointMode(int targetIndex, SlangFloatingPointMode mode) = 0; + + /* DEPRECATED: use `spSetMatrixLayoutMode` instead. */ + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetMatrixLayoutMode(int targetIndex, SlangMatrixLayoutMode mode) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setMatrixLayoutMode(SlangMatrixLayoutMode mode) = 0; + + /*! + @brief Set the level of debug information to produce. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setDebugInfoLevel(SlangDebugInfoLevel level) = 0; + + /*! + @brief Set the level of optimization to perform. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setOptimizationLevel(SlangOptimizationLevel level) = 0; + + + /*! + @brief Set the container format to be used for binary output. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setOutputContainerFormat(SlangContainerFormat format) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setPassThrough(SlangPassThrough passThrough) = 0; + + + virtual SLANG_NO_THROW void SLANG_MCALL + setDiagnosticCallback(SlangDiagnosticCallback callback, void const* userData) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setWriter(SlangWriterChannel channel, ISlangWriter* writer) = 0; + + virtual SLANG_NO_THROW ISlangWriter* SLANG_MCALL getWriter(SlangWriterChannel channel) = 0; + + /*! + @brief Add a path to use when searching for referenced files. + This will be used for both `#include` directives and also for explicit `__import` declarations. + @param ctx The compilation context. + @param searchDir The additional search directory. + */ + virtual SLANG_NO_THROW void SLANG_MCALL addSearchPath(const char* searchDir) = 0; + + /*! + @brief Add a macro definition to be used during preprocessing. + @param key The name of the macro to define. + @param value The value of the macro to define. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + addPreprocessorDefine(const char* key, const char* value) = 0; + + /*! + @brief Set options using arguments as if specified via command line. + @return Returns SlangResult. On success SLANG_SUCCEEDED(result) is true. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + processCommandLineArguments(char const* const* args, int argCount) = 0; + + /** Add a distinct translation unit to the compilation request + + `name` is optional. + Returns the zero-based index of the translation unit created. + */ + virtual SLANG_NO_THROW int SLANG_MCALL + addTranslationUnit(SlangSourceLanguage language, char const* name) = 0; + + + /** Set a default module name. Translation units will default to this module name if one is not + passed. If not set each translation unit will get a unique name. + */ + virtual SLANG_NO_THROW void SLANG_MCALL setDefaultModuleName(const char* defaultModuleName) = 0; + + /** Add a preprocessor definition that is scoped to a single translation unit. + + @param translationUnitIndex The index of the translation unit to get the definition. + @param key The name of the macro to define. + @param value The value of the macro to define. + */ + virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitPreprocessorDefine( + int translationUnitIndex, + const char* key, + const char* value) = 0; + + + /** Add a source file to the given translation unit. + + If a user-defined file system has been specified via + `spSetFileSystem`, then it will be used to load the + file at `path`. Otherwise, Slang will use the OS + file system. + + This function does *not* search for a file using + the registered search paths (`spAddSearchPath`), + and instead using the given `path` as-is. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + addTranslationUnitSourceFile(int translationUnitIndex, char const* path) = 0; + + /** Add a source string to the given translation unit. + + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param source A null-terminated UTF-8 encoded string of source code. + + The implementation will make a copy of the source code data. + An application may free the buffer immediately after this call returns. + + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. + */ + virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceString( + int translationUnitIndex, + char const* path, + char const* source) = 0; + + + /** Add a slang library - such that its contents can be referenced during linking. + This is equivalent to the -r command line option. + + @param basePath The base path used to lookup referenced modules. + @param libData The library data + @param libDataSize The size of the library data + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + addLibraryReference(const char* basePath, const void* libData, size_t libDataSize) = 0; + + /** Add a source string to the given translation unit. + + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param sourceBegin A pointer to a buffer of UTF-8 encoded source code. + @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` + + The implementation will make a copy of the source code data. + An application may free the buffer immediately after this call returns. + + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. + */ + virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceStringSpan( + int translationUnitIndex, + char const* path, + char const* sourceBegin, + char const* sourceEnd) = 0; + + /** Add a blob of source code to the given translation unit. + + @param translationUnitIndex The index of the translation unit to add source to. + @param path The file-system path that should be assumed for the source code. + @param sourceBlob A blob containing UTF-8 encoded source code. + @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` + + The compile request will retain a reference to the blob. + + The `path` will be used in any diagnostic output, as well + as to determine the base path when resolving relative + `#include`s. + */ + virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceBlob( + int translationUnitIndex, + char const* path, + ISlangBlob* sourceBlob) = 0; + + /** Add an entry point in a particular translation unit + */ + virtual SLANG_NO_THROW int SLANG_MCALL + addEntryPoint(int translationUnitIndex, char const* name, SlangStage stage) = 0; + + /** Add an entry point in a particular translation unit, + with additional arguments that specify the concrete + type names for entry-point generic type parameters. + */ + virtual SLANG_NO_THROW int SLANG_MCALL addEntryPointEx( + int translationUnitIndex, + char const* name, + SlangStage stage, + int genericArgCount, + char const** genericArgs) = 0; + + /** Specify the arguments to use for global generic parameters. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + setGlobalGenericArgs(int genericArgCount, char const** genericArgs) = 0; + + /** Specify the concrete type to be used for a global "existential slot." + + Every shader parameter (or leaf field of a `struct`-type shader parameter) + that has an interface or array-of-interface type introduces an existential + slot. The number of slots consumed by a shader parameter, and the starting + slot of each parameter can be queried via the reflection API using + `SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM`. + + In order to generate specialized code, a concrete type needs to be specified + for each existential slot. This function specifies the name of the type + (or in general a type *expression*) to use for a specific slot at the + global scope. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + setTypeNameForGlobalExistentialTypeParam(int slotIndex, char const* typeName) = 0; + + /** Specify the concrete type to be used for an entry-point "existential slot." + + Every shader parameter (or leaf field of a `struct`-type shader parameter) + that has an interface or array-of-interface type introduces an existential + slot. The number of slots consumed by a shader parameter, and the starting + slot of each parameter can be queried via the reflection API using + `SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM`. + + In order to generate specialized code, a concrete type needs to be specified + for each existential slot. This function specifies the name of the type + (or in general a type *expression*) to use for a specific slot at the + entry-point scope. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL setTypeNameForEntryPointExistentialTypeParam( + int entryPointIndex, + int slotIndex, + char const* typeName) = 0; + + /** Enable or disable an experimental, best-effort GLSL frontend + */ + virtual SLANG_NO_THROW void SLANG_MCALL setAllowGLSLInput(bool value) = 0; + + /** Execute the compilation request. + + @returns SlangResult, SLANG_OK on success. Use SLANG_SUCCEEDED() and SLANG_FAILED() to test + SlangResult. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile() = 0; + + + /** Get any diagnostic messages reported by the compiler. + + @returns A null-terminated UTF-8 encoded string of diagnostic messages. + + The returned pointer is only guaranteed to be valid + until `request` is destroyed. Applications that wish to + hold on to the diagnostic output for longer should use + `getDiagnosticOutputBlob`. + */ + virtual SLANG_NO_THROW char const* SLANG_MCALL getDiagnosticOutput() = 0; + + /** Get diagnostic messages reported by the compiler. + + @param outBlob A pointer to receive a blob holding a nul-terminated UTF-8 encoded string of + diagnostic messages. + @returns A `SlangResult` indicating success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getDiagnosticOutputBlob(ISlangBlob** outBlob) = 0; + + + /** Get the number of files that this compilation depended on. + + This includes both the explicit source files, as well as any + additional files that were transitively referenced (e.g., via + a `#include` directive). + */ + virtual SLANG_NO_THROW int SLANG_MCALL getDependencyFileCount() = 0; + + /** Get the path to a file this compilation depended on. + */ + virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(int index) = 0; + + /** Get the number of translation units associated with the compilation request + */ + virtual SLANG_NO_THROW int SLANG_MCALL getTranslationUnitCount() = 0; + + /** Get the output source code associated with a specific entry point. + + The lifetime of the output pointer is the same as `request`. + */ + virtual SLANG_NO_THROW char const* SLANG_MCALL getEntryPointSource(int entryPointIndex) = 0; + + /** Get the output bytecode associated with a specific entry point. + + The lifetime of the output pointer is the same as `request`. + */ + virtual SLANG_NO_THROW void const* SLANG_MCALL + getEntryPointCode(int entryPointIndex, size_t* outSize) = 0; + + /** Get the output code associated with a specific entry point. + + @param entryPointIndex The index of the entry point to get code for. + @param targetIndex The index of the target to get code for (default: zero). + @param outBlob A pointer that will receive the blob of code + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getEntryPointCodeBlob(int entryPointIndex, int targetIndex, ISlangBlob** outBlob) = 0; + + /** Get entry point 'callable' functions accessible through the ISlangSharedLibrary interface. + + That the functions remain in scope as long as the ISlangSharedLibrary interface is in scope. + + NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. + + @param entryPointIndex The index of the entry point to get code for. + @param targetIndex The index of the target to get code for (default: zero). + @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried + on. + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointHostCallable( + int entryPointIndex, + int targetIndex, + ISlangSharedLibrary** outSharedLibrary) = 0; + + /** Get the output code associated with a specific target. + + @param targetIndex The index of the target to get code for (default: zero). + @param outBlob A pointer that will receive the blob of code + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getTargetCodeBlob(int targetIndex, ISlangBlob** outBlob) = 0; + + /** Get 'callable' functions for a target accessible through the ISlangSharedLibrary interface. + + That the functions remain in scope as long as the ISlangSharedLibrary interface is in scope. + + NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. + + @param targetIndex The index of the target to get code for (default: zero). + @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried + on. + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getTargetHostCallable(int targetIndex, ISlangSharedLibrary** outSharedLibrary) = 0; + + /** Get the output bytecode associated with an entire compile request. + + The lifetime of the output pointer is the same as `request` and the last spCompile. + + @param outSize The size of the containers contents in bytes. Will be zero if there is + no code available. + @returns Pointer to start of the contained data, or nullptr if there is no code + available. + */ + virtual SLANG_NO_THROW void const* SLANG_MCALL getCompileRequestCode(size_t* outSize) = 0; + + /** Get the compilation result as a file system. + The result is not written to the actual OS file system, but is made available as an + in memory representation. + */ + virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL + getCompileRequestResultAsFileSystem() = 0; + + /** Return the container code as a blob. The container blob is created as part of a compilation + (with spCompile), and a container is produced with a suitable ContainerFormat. + + @param outSize The blob containing the container data. + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getContainerCode(ISlangBlob** outBlob) = 0; + + /** Load repro from memory specified. + + Should only be performed on a newly created request. + + NOTE! When using the fileSystem, files will be loaded via their `unique names` as if they are + part of the flat file system. This mechanism is described more fully in docs/repro.md. + + @param fileSystem An (optional) filesystem. Pass nullptr to just use contents of repro + held in data. + @param data The data to load from. + @param size The size of the data to load from. + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadRepro(ISlangFileSystem* fileSystem, const void* data, size_t size) = 0; + + /** Save repro state. Should *typically* be performed after spCompile, so that everything + that is needed for a compilation is available. + + @param outBlob Blob that will hold the serialized state + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveRepro(ISlangBlob** outBlob) = 0; + + /** Enable repro capture. + + Should be set after any ISlangFileSystem has been set, but before any compilation. It ensures + that everything that the ISlangFileSystem accesses will be correctly recorded. Note that if a + ISlangFileSystem/ISlangFileSystemExt isn't explicitly set (ie the default is used), then the + request will automatically be set up to record everything appropriate. + + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL enableReproCapture() = 0; + + /** Get the (linked) program for a compile request. + + The linked program will include all of the global-scope modules for the + translation units in the program, plus any modules that they `import` + (transitively), specialized to any global specialization arguments that + were provided via the API. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getProgram(slang::IComponentType** outProgram) = 0; + + /** Get the (partially linked) component type for an entry point. + + The returned component type will include the entry point at the + given index, and will be specialized using any specialization arguments + that were provided for it via the API. + + The returned component will *not* include the modules representing + the global scope and its dependencies/specialization, so a client + program will typically want to compose this component type with + the one returned by `spCompileRequest_getProgram` to get a complete + and usable component type from which kernel code can be requested. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getEntryPoint(SlangInt entryPointIndex, slang::IComponentType** outEntryPoint) = 0; + + /** Get the (un-linked) module for a translation unit. + + The returned module will not be linked against any dependencies, + nor against any entry points (even entry points declared inside + the module). Similarly, the module will not be specialized + to the arguments that might have been provided via the API. + + This function provides an atomic unit of loaded code that + is suitable for looking up types and entry points in the + given module, and for linking together to produce a composite + program that matches the needs of an application. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getModule(SlangInt translationUnitIndex, slang::IModule** outModule) = 0; + + /** Get the `ISession` handle behind the `SlangCompileRequest`. + TODO(JS): Arguably this should just return the session pointer. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSession(slang::ISession** outSession) = 0; + + /** get reflection data from a compilation request */ + virtual SLANG_NO_THROW SlangReflection* SLANG_MCALL getReflection() = 0; + + /** Make output specially handled for command line output */ + virtual SLANG_NO_THROW void SLANG_MCALL setCommandLineCompilerMode() = 0; + + /** Add a defined capability that should be assumed available on the target */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + addTargetCapability(SlangInt targetIndex, SlangCapabilityID capability) = 0; + + /** Get the (linked) program for a compile request, including all entry points. + + The resulting program will include all of the global-scope modules for the + translation units in the program, plus any modules that they `import` + (transitively), specialized to any global specialization arguments that + were provided via the API, as well as all entry points specified for compilation, + specialized to their entry-point specialization arguments. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getProgramWithEntryPoints(slang::IComponentType** outProgram) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL isParameterLocationUsed( + SlangInt entryPointIndex, + SlangInt targetIndex, + SlangParameterCategory category, + SlangUInt spaceIndex, + SlangUInt registerIndex, + bool& outUsed) = 0; + + /** Set the line directive mode for a target. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetLineDirectiveMode(SlangInt targetIndex, SlangLineDirectiveMode mode) = 0; + + /** Set whether to use scalar buffer layouts for GLSL/Vulkan targets. + If true, the generated GLSL/Vulkan code will use `scalar` layout for storage buffers. + If false, the resulting code will std430 for storage buffers. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetForceGLSLScalarBufferLayout(int targetIndex, bool forceScalarLayout) = 0; + + /** Overrides the severity of a specific diagnostic message. + + @param messageID Numeric identifier of the message to override, + as defined in the 1st parameter of the DIAGNOSTIC macro. + @param overrideSeverity New severity of the message. If the message is originally Error or + Fatal, the new severity cannot be lower than that. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + overrideDiagnosticSeverity(SlangInt messageID, SlangSeverity overrideSeverity) = 0; + + /** Returns the currently active flags of the request's diagnostic sink. */ + virtual SLANG_NO_THROW SlangDiagnosticFlags SLANG_MCALL getDiagnosticFlags() = 0; + + /** Sets the flags of the request's diagnostic sink. + The previously specified flags are discarded. */ + virtual SLANG_NO_THROW void SLANG_MCALL setDiagnosticFlags(SlangDiagnosticFlags flags) = 0; + + /** Set the debug format to be used for debugging information */ + virtual SLANG_NO_THROW void SLANG_MCALL + setDebugInfoFormat(SlangDebugInfoFormat debugFormat) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setEnableEffectAnnotations(bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setReportDownstreamTime(bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setReportPerfBenchmark(bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setSkipSPIRVValidation(bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetUseMinimumSlangOptimization(int targetIndex, bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setIgnoreCapabilityCheck(bool value) = 0; + + // return a copy of internal profiling results, and if `shouldClear` is true, clear the internal + // profiling results before returning. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getCompileTimeProfile(ISlangProfiler** compileTimeProfile, bool shouldClear) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetGenerateWholeProgram(int targetIndex, bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(int targetIndex, bool value) = 0; + + virtual SLANG_NO_THROW void SLANG_MCALL + setTargetEmbedDownstreamIR(int targetIndex, bool value) = 0; +}; + + #define SLANG_UUID_ICompileRequest ICompileRequest::getTypeGuid() + +} // namespace slang +#endif diff --git a/include/slang-gfx.h b/include/slang-gfx.h index d273ce4276..6f46fed339 100644 --- a/include/slang-gfx.h +++ b/include/slang-gfx.h @@ -1,30 +1,30 @@ // render.h #pragma once -#include -#include - -#include "slang.h" #include "slang-com-ptr.h" +#include "slang.h" + +#include +#include #if defined(SLANG_GFX_DYNAMIC) -# if defined(_MSC_VER) -# ifdef SLANG_GFX_DYNAMIC_EXPORT -# define SLANG_GFX_API SLANG_DLL_EXPORT -# else -# define SLANG_GFX_API __declspec(dllimport) -# endif -# else -// TODO: need to consider compiler capabilities -//# ifdef SLANG_DYNAMIC_EXPORT -# define SLANG_GFX_API SLANG_DLL_EXPORT -//# endif -# endif + #if defined(_MSC_VER) + #ifdef SLANG_GFX_DYNAMIC_EXPORT + #define SLANG_GFX_API SLANG_DLL_EXPORT + #else + #define SLANG_GFX_API __declspec(dllimport) + #endif + #else + // TODO: need to consider compiler capabilities + // # ifdef SLANG_DYNAMIC_EXPORT + #define SLANG_GFX_API SLANG_DLL_EXPORT + // # endif + #endif #endif #ifndef SLANG_GFX_API -# define SLANG_GFX_API + #define SLANG_GFX_API #endif // Needed for building on cygwin with gcc @@ -34,10 +34,13 @@ // GLOBAL TODO: doc comments // GLOBAL TODO: Rationalize integer types (not a smush of uint/int/Uint/Int/etc) // - need typedefs in gfx namespace for Count, Index, Size, Offset (ex. DeviceAddress) -// - Index and Count are for arrays, and indexing into array - like things(XY coordinates of pixels, etc.) -// - Count is also for anything where we need to measure how many of something there are. This includes things like extents. +// - Index and Count are for arrays, and indexing into array - like things(XY coordinates of +// pixels, etc.) +// - Count is also for anything where we need to measure how many of something there are. +// This includes things like extents. // - Offset and Size are almost always for bytes and things measured in bytes. -namespace gfx { +namespace gfx +{ using Slang::ComPtr; @@ -56,7 +59,10 @@ const uint64_t kTimeoutInfinite = 0xFFFFFFFFFFFFFFFF; enum class StructType { - D3D12DeviceExtendedDesc, D3D12ExperimentalFeaturesDesc, SlangSessionExtendedDesc, RayTracingValidationDesc + D3D12DeviceExtendedDesc, + D3D12ExperimentalFeaturesDesc, + SlangSessionExtendedDesc, + RayTracingValidationDesc }; // TODO: Rename to Stage @@ -92,6 +98,7 @@ enum class DeviceType Metal, CPU, CUDA, + WebGPU, CountOf, }; @@ -135,23 +142,24 @@ class ITransientResourceHeap; enum class ShaderModuleSourceType { - SlangSource, // a slang source string in memory. - SlangModuleBinary, // a slang module binary code in memory. - SlangSourceFile, // a slang source from file. + SlangSource, // a slang source string in memory. + SlangModuleBinary, // a slang module binary code in memory. + SlangSourceFile, // a slang source from file. SlangModuleBinaryFile, // a slang module binary code from file. }; -class IShaderProgram: public ISlangUnknown +class IShaderProgram : public ISlangUnknown { public: // Defines how linking should be performed for a shader program. enum class LinkingStyle { - // Compose all entry-points in a single program, then compile all entry-points together with the same - // set of root shader arguments. + // Compose all entry-points in a single program, then compile all entry-points together with + // the same set of root shader arguments. SingleProgram, - // Link and compile each entry-point individually, potentially with different specializations. + // Link and compile each entry-point individually, potentially with different + // specializations. SeparateEntryPointCompilation }; @@ -162,7 +170,7 @@ class IShaderProgram: public ISlangUnknown LinkingStyle linkingStyle = LinkingStyle::SingleProgram; // The global scope or a Slang composite component that represents the entire program. - slang::IComponentType* slangGlobalScope; + slang::IComponentType* slangGlobalScope; // Number of separate entry point components in the `slangEntryPoints` array to link in. // If set to 0, then `slangGlobalScope` must contain Slang EntryPoint components. @@ -190,14 +198,18 @@ class IShaderProgram: public ISlangUnknown virtual SLANG_NO_THROW slang::TypeReflection* SLANG_MCALL findTypeByName(const char* name) = 0; }; -#define SLANG_UUID_IShaderProgram \ - { \ - 0x9d32d0ad, 0x915c, 0x4ffd, { 0x91, 0xe2, 0x50, 0x85, 0x54, 0xa0, 0x4a, 0x76 } \ +#define SLANG_UUID_IShaderProgram \ + { \ + 0x9d32d0ad, 0x915c, 0x4ffd, \ + { \ + 0x91, 0xe2, 0x50, 0x85, 0x54, 0xa0, 0x4a, 0x76 \ + } \ } // TODO: Confirm with Yong that we really want this naming convention // TODO: Rename to what? // Dont' change without keeping in sync with Format +// clang-format off #define GFX_FORMAT(x) \ x( Unknown, 0, 0) \ \ @@ -303,17 +315,20 @@ class IShaderProgram: public ISlangUnknown \ x(R64_UINT, 8, 1) \ \ - x(R64_SINT, 8, 1) \ - \ + x(R64_SINT, 8, 1) +// clang-format on + // TODO: This should be generated from above // TODO: enum class should be explicitly uint32_t or whatever's appropriate /// Different formats of things like pixels or elements of vertices -/// NOTE! Any change to this type (adding, removing, changing order) - must also be reflected in changes GFX_FORMAT +/// NOTE! Any change to this type (adding, removing, changing order) - must also be reflected in +/// changes GFX_FORMAT enum class Format { // D3D formats omitted: 19-22, 44-47, 65-66, 68-70, 73, 76, 79, 82, 88-89, 92-94, 97, 100-114 - // These formats are omitted due to lack of a corresponding Vulkan format. D24_UNORM_S8_UINT (DXGI_FORMAT 45) - // has a matching Vulkan format but is also omitted as it is only supported by Nvidia. + // These formats are omitted due to lack of a corresponding Vulkan format. D24_UNORM_S8_UINT + // (DXGI_FORMAT 45) has a matching Vulkan format but is also omitted as it is only supported by + // Nvidia. Unknown, R32G32B32A32_TYPELESS, @@ -417,7 +432,7 @@ enum class Format BC7_UNORM_SRGB, R64_UINT, - + R64_SINT, _Count, @@ -430,27 +445,32 @@ enum class Format // TODO: Width/Height/Depth/whatever should not be used. We should use extentX, extentY, etc. struct FormatInfo { - GfxCount channelCount; ///< The amount of channels in the format. Only set if the channelType is set - uint8_t channelType; ///< One of SlangScalarType None if type isn't made up of elements of type. TODO: Change to uint32_t? + GfxCount + channelCount; ///< The amount of channels in the format. Only set if the channelType is set + uint8_t channelType; ///< One of SlangScalarType None if type isn't made up of elements of type. + ///< TODO: Change to uint32_t? - Size blockSizeInBytes; ///< The size of a block in bytes. - GfxCount pixelsPerBlock; ///< The number of pixels contained in a block. - GfxCount blockWidth; ///< The width of a block in pixels. - GfxCount blockHeight; ///< The height of a block in pixels. + Size blockSizeInBytes; ///< The size of a block in bytes. + GfxCount pixelsPerBlock; ///< The number of pixels contained in a block. + GfxCount blockWidth; ///< The width of a block in pixels. + GfxCount blockHeight; ///< The height of a block in pixels. }; enum class InputSlotClass { - PerVertex, PerInstance + PerVertex, + PerInstance }; struct InputElementDesc { - char const* semanticName; ///< The name of the corresponding parameter in shader code. - GfxIndex semanticIndex; ///< The index of the corresponding parameter in shader code. Only needed if multiple parameters share a semantic name. - Format format; ///< The format of the data being fetched for this element. - Offset offset; ///< The offset in bytes of this element from the start of the corresponding chunk of vertex stream data. - GfxIndex bufferSlotIndex; ///< The index of the vertex stream to fetch this element's data from. + char const* semanticName; ///< The name of the corresponding parameter in shader code. + GfxIndex semanticIndex; ///< The index of the corresponding parameter in shader code. Only + ///< needed if multiple parameters share a semantic name. + Format format; ///< The format of the data being fetched for this element. + Offset offset; ///< The offset in bytes of this element from the start of the corresponding + ///< chunk of vertex stream data. + GfxIndex bufferSlotIndex; ///< The index of the vertex stream to fetch this element's data from. }; struct VertexStreamDesc @@ -462,12 +482,19 @@ struct VertexStreamDesc enum class PrimitiveType { - Point, Line, Triangle, Patch + Point, + Line, + Triangle, + Patch }; enum class PrimitiveTopology { - TriangleList, TriangleStrip, PointList, LineList, LineStrip + TriangleList, + TriangleStrip, + PointList, + LineList, + LineStrip }; enum class ResourceState @@ -501,18 +528,24 @@ struct ResourceStateSet { public: void add(ResourceState state) { m_bitFields |= (1LL << (uint32_t)state); } - template void add(ResourceState s, TResourceState... states) + template + void add(ResourceState s, TResourceState... states) { add(s); add(states...); } - bool contains(ResourceState state) const { return (m_bitFields & (1LL << (uint32_t)state)) != 0; } + bool contains(ResourceState state) const + { + return (m_bitFields & (1LL << (uint32_t)state)) != 0; + } ResourceStateSet() : m_bitFields(0) - {} + { + } ResourceStateSet(const ResourceStateSet& other) = default; ResourceStateSet(ResourceState state) { add(state); } - template ResourceStateSet(TResourceState... states) + template + ResourceStateSet(TResourceState... states) { add(states...); } @@ -541,14 +574,14 @@ enum class MemoryType enum class InteropHandleAPI { Unknown, - D3D12, // A D3D12 object pointer. - Vulkan, // A general Vulkan object handle. - CUDA, // A general CUDA object handle. - Win32, // A general Win32 HANDLE. - FileDescriptor, // A file descriptor. - DeviceAddress, // A device address. + D3D12, // A D3D12 object pointer. + Vulkan, // A general Vulkan object handle. + CUDA, // A general CUDA object handle. + Win32, // A general Win32 HANDLE. + FileDescriptor, // A file descriptor. + DeviceAddress, // A device address. D3D12CpuDescriptorHandle, // A D3D12_CPU_DESCRIPTOR_HANDLE value. - Metal, // A general Metal object handle. + Metal, // A general Metal object handle. }; struct InteropHandle @@ -569,28 +602,32 @@ class IInputLayout : public ISlangUnknown GfxCount vertexStreamCount = 0; }; }; -#define SLANG_UUID_IInputLayout \ - { \ - 0x45223711, 0xa84b, 0x455c, { 0xbe, 0xfa, 0x49, 0x37, 0x42, 0x1e, 0x8e, 0x2e } \ +#define SLANG_UUID_IInputLayout \ + { \ + 0x45223711, 0xa84b, 0x455c, \ + { \ + 0xbe, 0xfa, 0x49, 0x37, 0x42, 0x1e, 0x8e, 0x2e \ + } \ } -class IResource: public ISlangUnknown +class IResource : public ISlangUnknown { public: - /// The type of resource. - /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise isTexture won't work correctly) + /// The type of resource. + /// NOTE! The order needs to be such that all texture types are at or after Texture1D (otherwise + /// isTexture won't work correctly) enum class Type { - Unknown, ///< Unknown - Buffer, ///< A buffer (like a constant/index/vertex buffer) - Texture1D, ///< A 1d texture - Texture2D, ///< A 2d texture - Texture3D, ///< A 3d texture - TextureCube, ///< A cubemap consists of 6 Texture2D like faces + Unknown, ///< Unknown + Buffer, ///< A buffer (like a constant/index/vertex buffer) + Texture1D, ///< A 1d texture + Texture2D, ///< A 2d texture + Texture3D, ///< A 3d texture + TextureCube, ///< A cubemap consists of 6 Texture2D like faces _Count, }; - /// Base class for Descs + /// Base class for Descs struct DescBase { Type type = Type::Unknown; @@ -607,11 +644,13 @@ class IResource: public ISlangUnknown virtual SLANG_NO_THROW Result SLANG_MCALL setDebugName(const char* name) = 0; virtual SLANG_NO_THROW const char* SLANG_MCALL getDebugName() = 0; - }; -#define SLANG_UUID_IResource \ - { \ - 0xa0e39f34, 0x8398, 0x4522, { 0x95, 0xc2, 0xeb, 0xc0, 0xf9, 0x84, 0xef, 0x3f } \ +#define SLANG_UUID_IResource \ + { \ + 0xa0e39f34, 0x8398, 0x4522, \ + { \ + 0x95, 0xc2, 0xeb, 0xc0, 0xf9, 0x84, 0xef, 0x3f \ + } \ } struct MemoryRange @@ -621,13 +660,13 @@ struct MemoryRange uint64_t size; }; -class IBufferResource: public IResource +class IBufferResource : public IResource { public: - struct Desc: public DescBase + struct Desc : public DescBase { - Size sizeInBytes = 0; ///< Total size in bytes - Size elementSize = 0; ///< Get the element stride. If > 0, this is a structured buffer + Size sizeInBytes = 0; ///< Total size in bytes + Size elementSize = 0; ///< Get the element stride. If > 0, this is a structured buffer Format format = Format::Unknown; }; @@ -636,9 +675,12 @@ class IBufferResource: public IResource virtual SLANG_NO_THROW Result SLANG_MCALL map(MemoryRange* rangeToRead, void** outPointer) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL unmap(MemoryRange* writtenRange) = 0; }; -#define SLANG_UUID_IBufferResource \ - { \ - 0x1b274efe, 0x5e37, 0x492b, { 0x82, 0x6e, 0x7e, 0xe7, 0xe8, 0xf5, 0xa4, 0x9b } \ +#define SLANG_UUID_IBufferResource \ + { \ + 0x1b274efe, 0x5e37, 0x492b, \ + { \ + 0x82, 0x6e, 0x7e, 0xe7, 0xe8, 0xf5, 0xa4, 0x9b \ + } \ } struct DepthStencilClearValue @@ -659,8 +701,8 @@ struct ClearValue struct BufferRange { - Offset offset; ///< Offset in bytes. - Size size; ///< Size in bytes. + Offset offset; ///< Offset in bytes. + Size size; ///< Size in bytes. }; enum class TextureAspect : uint32_t @@ -683,10 +725,10 @@ struct SubresourceRange GfxIndex mipLevel; GfxCount mipLevelCount; GfxIndex baseArrayLayer; // For Texture3D, this is WSlice. - GfxCount layerCount; // For cube maps, this is a multiple of 6. + GfxCount layerCount; // For cube maps, this is a multiple of 6. }; -class ITextureResource: public IResource +class ITextureResource : public IResource { public: static const GfxCount kRemainingTextureSize = 0xffffffff; @@ -696,97 +738,103 @@ class ITextureResource: public IResource GfxIndex y = 0; GfxIndex z = 0; Offset3D() = default; - Offset3D(GfxIndex _x, GfxIndex _y, GfxIndex _z) :x(_x), y(_y), z(_z) {} + Offset3D(GfxIndex _x, GfxIndex _y, GfxIndex _z) + : x(_x), y(_y), z(_z) + { + } }; struct SampleDesc { - GfxCount numSamples = 1; ///< Number of samples per pixel - int quality = 0; ///< The quality measure for the samples + GfxCount numSamples = 1; ///< Number of samples per pixel + int quality = 0; ///< The quality measure for the samples }; struct Extents { - GfxCount width = 0; ///< Width in pixels - GfxCount height = 0; ///< Height in pixels (if 2d or 3d) - GfxCount depth = 0; ///< Depth (if 3d) + GfxCount width = 0; ///< Width in pixels + GfxCount height = 0; ///< Height in pixels (if 2d or 3d) + GfxCount depth = 0; ///< Depth (if 3d) }; - struct Desc: public DescBase + struct Desc : public DescBase { Extents size; - GfxCount arraySize = 0; ///< Array size + GfxCount arraySize = 0; ///< Array size - GfxCount numMipLevels = 0; ///< Number of mip levels - if 0 will create all mip levels - Format format; ///< The resources format - SampleDesc sampleDesc; ///< How the resource is sampled + GfxCount numMipLevels = 0; ///< Number of mip levels - if 0 will create all mip levels + Format format; ///< The resources format + SampleDesc sampleDesc; ///< How the resource is sampled ClearValue* optimalClearValue = nullptr; }; - /// Data for a single subresource of a texture. - /// - /// Each subresource is a tensor with `1 <= rank <= 3`, - /// where the rank is deterined by the base shape of the - /// texture (Buffer, 1D, 2D, 3D, or Cube). For the common - /// case of a 2D texture, `rank == 2` and each subresource - /// is a 2D image. - /// - /// Subresource tensors must be stored in a row-major layout, - /// so that the X axis strides over texels, the Y axis strides - /// over 1D rows of texels, and the Z axis strides over 2D - /// "layers" of texels. - /// - /// For a texture with multiple mip levels or array elements, - /// each mip level and array element is stores as a distinct - /// subresource. When indexing into an array of subresources, - /// the index of a subresoruce for mip level `m` and array - /// index `a` is `m + a*mipLevelCount`. - /// + /// Data for a single subresource of a texture. + /// + /// Each subresource is a tensor with `1 <= rank <= 3`, + /// where the rank is deterined by the base shape of the + /// texture (Buffer, 1D, 2D, 3D, or Cube). For the common + /// case of a 2D texture, `rank == 2` and each subresource + /// is a 2D image. + /// + /// Subresource tensors must be stored in a row-major layout, + /// so that the X axis strides over texels, the Y axis strides + /// over 1D rows of texels, and the Z axis strides over 2D + /// "layers" of texels. + /// + /// For a texture with multiple mip levels or array elements, + /// each mip level and array element is stores as a distinct + /// subresource. When indexing into an array of subresources, + /// the index of a subresoruce for mip level `m` and array + /// index `a` is `m + a*mipLevelCount`. + /// struct SubresourceData { - /// Pointer to texel data for the subresource tensor. + /// Pointer to texel data for the subresource tensor. void const* data; - /// Stride in bytes between rows of the subresource tensor. - /// - /// This is the number of bytes to add to a pointer to a texel - /// at (X,Y,Z) to get to a texel at (X,Y+1,Z). - /// - /// Devices may not support all possible values for `strideY`. - /// In particular, they may only support strictly positive strides. - /// + /// Stride in bytes between rows of the subresource tensor. + /// + /// This is the number of bytes to add to a pointer to a texel + /// at (X,Y,Z) to get to a texel at (X,Y+1,Z). + /// + /// Devices may not support all possible values for `strideY`. + /// In particular, they may only support strictly positive strides. + /// gfx::Size strideY; - /// Stride in bytes between layers of the subresource tensor. - /// - /// This is the number of bytes to add to a pointer to a texel - /// at (X,Y,Z) to get to a texel at (X,Y,Z+1). - /// - /// Devices may not support all possible values for `strideZ`. - /// In particular, they may only support strictly positive strides. - /// + /// Stride in bytes between layers of the subresource tensor. + /// + /// This is the number of bytes to add to a pointer to a texel + /// at (X,Y,Z) to get to a texel at (X,Y,Z+1). + /// + /// Devices may not support all possible values for `strideZ`. + /// In particular, they may only support strictly positive strides. + /// gfx::Size strideZ; }; virtual SLANG_NO_THROW Desc* SLANG_MCALL getDesc() = 0; }; -#define SLANG_UUID_ITextureResource \ - { \ - 0xcf88a31c, 0x6187, 0x46c5, { 0xa4, 0xb7, 0xeb, 0x58, 0xc7, 0x33, 0x40, 0x17 } \ +#define SLANG_UUID_ITextureResource \ + { \ + 0xcf88a31c, 0x6187, 0x46c5, \ + { \ + 0xa4, 0xb7, 0xeb, 0x58, 0xc7, 0x33, 0x40, 0x17 \ + } \ } enum class ComparisonFunc : uint8_t { - Never = 0x0, - Less = 0x1, - Equal = 0x2, - LessEqual = 0x3, - Greater = 0x4, - NotEqual = 0x5, - GreaterEqual = 0x6, - Always = 0x7, + Never = 0x0, + Less = 0x1, + Equal = 0x2, + LessEqual = 0x3, + Greater = 0x4, + NotEqual = 0x5, + GreaterEqual = 0x6, + Always = 0x7, }; enum class TextureFilteringMode @@ -817,19 +865,19 @@ class ISamplerState : public ISlangUnknown public: struct Desc { - TextureFilteringMode minFilter = TextureFilteringMode::Linear; - TextureFilteringMode magFilter = TextureFilteringMode::Linear; - TextureFilteringMode mipFilter = TextureFilteringMode::Linear; - TextureReductionOp reductionOp = TextureReductionOp::Average; - TextureAddressingMode addressU = TextureAddressingMode::Wrap; - TextureAddressingMode addressV = TextureAddressingMode::Wrap; - TextureAddressingMode addressW = TextureAddressingMode::Wrap; - float mipLODBias = 0.0f; - uint32_t maxAnisotropy = 1; - ComparisonFunc comparisonFunc = ComparisonFunc::Never; - float borderColor[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - float minLOD = -FLT_MAX; - float maxLOD = FLT_MAX; + TextureFilteringMode minFilter = TextureFilteringMode::Linear; + TextureFilteringMode magFilter = TextureFilteringMode::Linear; + TextureFilteringMode mipFilter = TextureFilteringMode::Linear; + TextureReductionOp reductionOp = TextureReductionOp::Average; + TextureAddressingMode addressU = TextureAddressingMode::Wrap; + TextureAddressingMode addressV = TextureAddressingMode::Wrap; + TextureAddressingMode addressW = TextureAddressingMode::Wrap; + float mipLODBias = 0.0f; + uint32_t maxAnisotropy = 1; + ComparisonFunc comparisonFunc = ComparisonFunc::Never; + float borderColor[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + float minLOD = -FLT_MAX; + float maxLOD = FLT_MAX; }; /// Returns a native API handle representing this sampler state object. @@ -837,9 +885,12 @@ class ISamplerState : public ISlangUnknown /// When using Vulkan, this will be a VkSampler. virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outNativeHandle) = 0; }; -#define SLANG_UUID_ISamplerState \ - { \ - 0x8b8055df, 0x9377, 0x401d, { 0x91, 0xff, 0x3f, 0xa3, 0xbf, 0x66, 0x64, 0xf4 } \ +#define SLANG_UUID_ISamplerState \ + { \ + 0x8b8055df, 0x9377, 0x401d, \ + { \ + 0x91, 0xff, 0x3f, 0xa3, 0xbf, 0x66, 0x64, 0xf4 \ + } \ } class IResourceView : public ISlangUnknown @@ -866,12 +917,13 @@ class IResourceView : public ISlangUnknown struct Desc { - Type type; - Format format; + Type type; + Format format; // Required fields for `RenderTarget` and `DepthStencil` views. RenderTargetDesc renderTarget; - // Specifies the range of a texture resource for a ShaderRsource/UnorderedAccess/RenderTarget/DepthStencil view. + // Specifies the range of a texture resource for a + // ShaderRsource/UnorderedAccess/RenderTarget/DepthStencil view. SubresourceRange subresourceRange; // Specifies the range of a buffer resource for a ShaderResource/UnorderedAccess view. BufferRange bufferRange; @@ -879,15 +931,18 @@ class IResourceView : public ISlangUnknown virtual SLANG_NO_THROW Desc* SLANG_MCALL getViewDesc() = 0; /// Returns a native API handle representing this resource view object. - /// When using D3D12, this will be a D3D12_CPU_DESCRIPTOR_HANDLE or a buffer device address depending - /// on the type of the resource view. - /// When using Vulkan, this will be a VkImageView, VkBufferView, VkAccelerationStructure or a VkBuffer - /// depending on the type of the resource view. + /// When using D3D12, this will be a D3D12_CPU_DESCRIPTOR_HANDLE or a buffer device address + /// depending on the type of the resource view. When using Vulkan, this will be a VkImageView, + /// VkBufferView, VkAccelerationStructure or a VkBuffer depending on the type of the resource + /// view. virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outNativeHandle) = 0; }; -#define SLANG_UUID_IResourceView \ - { \ - 0x7b6c4926, 0x884, 0x408c, { 0xad, 0x8a, 0x50, 0x3a, 0x8e, 0x23, 0x98, 0xa4 } \ +#define SLANG_UUID_IResourceView \ + { \ + 0x7b6c4926, 0x884, 0x408c, \ + { \ + 0xad, 0x8a, 0x50, 0x3a, 0x8e, 0x23, 0x98, 0xa4 \ + } \ } class IAccelerationStructure : public IResourceView @@ -917,7 +972,8 @@ class IAccelerationStructure : public IResourceView enum class GeometryType { - Triangles, ProcedurePrimitives + Triangles, + ProcedurePrimitives }; struct GeometryFlags @@ -1046,9 +1102,12 @@ class IAccelerationStructure : public IResourceView virtual SLANG_NO_THROW DeviceAddress SLANG_MCALL getDeviceAddress() = 0; }; -#define SLANG_UUID_IAccelerationStructure \ - { \ - 0xa5cdda3c, 0x1d4e, 0x4df7, { 0x8e, 0xf2, 0xb7, 0x3f, 0xce, 0x4, 0xde, 0x3b } \ +#define SLANG_UUID_IAccelerationStructure \ + { \ + 0xa5cdda3c, 0x1d4e, 0x4df7, \ + { \ + 0x8e, 0xf2, 0xb7, 0x3f, 0xce, 0x4, 0xde, 0x3b \ + } \ } class IFence : public ISlangUnknown @@ -1069,9 +1128,12 @@ class IFence : public ISlangUnknown virtual SLANG_NO_THROW Result SLANG_MCALL getSharedHandle(InteropHandle* outHandle) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outNativeHandle) = 0; }; -#define SLANG_UUID_IFence \ - { \ - 0x7fe1c283, 0xd3f4, 0x48ed, { 0xaa, 0xf3, 0x1, 0x51, 0x96, 0x4e, 0x7c, 0xb5 } \ +#define SLANG_UUID_IFence \ + { \ + 0x7fe1c283, 0xd3f4, 0x48ed, \ + { \ + 0xaa, 0xf3, 0x1, 0x51, 0x96, 0x4e, 0x7c, 0xb5 \ + } \ } struct ShaderOffset @@ -1085,14 +1147,11 @@ struct ShaderOffset } bool operator==(const ShaderOffset& other) const { - return uniformOffset == other.uniformOffset - && bindingRangeIndex == other.bindingRangeIndex - && bindingArrayIndex == other.bindingArrayIndex; - } - bool operator!=(const ShaderOffset& other) const - { - return !this->operator==(other); + return uniformOffset == other.uniformOffset && + bindingRangeIndex == other.bindingRangeIndex && + bindingArrayIndex == other.bindingArrayIndex; } + bool operator!=(const ShaderOffset& other) const { return !this->operator==(other); } bool operator<(const ShaderOffset& other) const { if (bindingRangeIndex < other.bindingRangeIndex) @@ -1112,7 +1171,9 @@ struct ShaderOffset enum class ShaderObjectContainerType { - None, Array, StructuredBuffer + None, + Array, + StructuredBuffer }; class IShaderObject : public ISlangUnknown @@ -1122,38 +1183,40 @@ class IShaderObject : public ISlangUnknown virtual SLANG_NO_THROW ShaderObjectContainerType SLANG_MCALL getContainerType() = 0; virtual SLANG_NO_THROW GfxCount SLANG_MCALL getEntryPointCount() = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - getEntryPoint(GfxIndex index, IShaderObject** entryPoint) = 0; + getEntryPoint(GfxIndex index, IShaderObject** entryPoint) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - setData(ShaderOffset const& offset, void const* data, Size size) = 0; + setData(ShaderOffset const& offset, void const* data, Size size) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - getObject(ShaderOffset const& offset, IShaderObject** object) = 0; + getObject(ShaderOffset const& offset, IShaderObject** object) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - setObject(ShaderOffset const& offset, IShaderObject* object) = 0; + setObject(ShaderOffset const& offset, IShaderObject* object) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - setResource(ShaderOffset const& offset, IResourceView* resourceView) = 0; + setResource(ShaderOffset const& offset, IResourceView* resourceView) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - setSampler(ShaderOffset const& offset, ISamplerState* sampler) = 0; + setSampler(ShaderOffset const& offset, ISamplerState* sampler) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL setCombinedTextureSampler( - ShaderOffset const& offset, IResourceView* textureView, ISamplerState* sampler) = 0; + ShaderOffset const& offset, + IResourceView* textureView, + ISamplerState* sampler) = 0; - /// Manually overrides the specialization argument for the sub-object binding at `offset`. - /// Specialization arguments are passed to the shader compiler to specialize the type - /// of interface-typed shader parameters. + /// Manually overrides the specialization argument for the sub-object binding at `offset`. + /// Specialization arguments are passed to the shader compiler to specialize the type + /// of interface-typed shader parameters. virtual SLANG_NO_THROW Result SLANG_MCALL setSpecializationArgs( ShaderOffset const& offset, const slang::SpecializationArg* args, GfxCount count) = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL getCurrentVersion( - ITransientResourceHeap* transientHeap, - IShaderObject** outObject) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + getCurrentVersion(ITransientResourceHeap* transientHeap, IShaderObject** outObject) = 0; virtual SLANG_NO_THROW const void* SLANG_MCALL getRawData() = 0; virtual SLANG_NO_THROW Size SLANG_MCALL getSize() = 0; - /// Use the provided constant buffer instead of the internally created one. - virtual SLANG_NO_THROW Result SLANG_MCALL setConstantBufferOverride(IBufferResource* constantBuffer) = 0; + /// Use the provided constant buffer instead of the internally created one. + virtual SLANG_NO_THROW Result SLANG_MCALL + setConstantBufferOverride(IBufferResource* constantBuffer) = 0; inline ComPtr getObject(ShaderOffset const& offset) @@ -1169,9 +1232,12 @@ class IShaderObject : public ISlangUnknown return entryPoint; } }; -#define SLANG_UUID_IShaderObject \ - { \ - 0xc1fa997e, 0x5ca2, 0x45ae, { 0x9b, 0xcb, 0xc4, 0x35, 0x9e, 0x85, 0x5, 0x85 } \ +#define SLANG_UUID_IShaderObject \ + { \ + 0xc1fa997e, 0x5ca2, 0x45ae, \ + { \ + 0x9b, 0xcb, 0xc4, 0x35, 0x9e, 0x85, 0x5, 0x85 \ + } \ } enum class StencilOp : uint8_t @@ -1207,23 +1273,23 @@ enum class FrontFaceMode : uint8_t struct DepthStencilOpDesc { - StencilOp stencilFailOp = StencilOp::Keep; - StencilOp stencilDepthFailOp = StencilOp::Keep; - StencilOp stencilPassOp = StencilOp::Keep; - ComparisonFunc stencilFunc = ComparisonFunc::Always; + StencilOp stencilFailOp = StencilOp::Keep; + StencilOp stencilDepthFailOp = StencilOp::Keep; + StencilOp stencilPassOp = StencilOp::Keep; + ComparisonFunc stencilFunc = ComparisonFunc::Always; }; struct DepthStencilDesc { - bool depthTestEnable = false; - bool depthWriteEnable = true; - ComparisonFunc depthFunc = ComparisonFunc::Less; + bool depthTestEnable = false; + bool depthWriteEnable = true; + ComparisonFunc depthFunc = ComparisonFunc::Less; - bool stencilEnable = false; - uint32_t stencilReadMask = 0xFFFFFFFF; - uint32_t stencilWriteMask = 0xFFFFFFFF; - DepthStencilOpDesc frontFace; - DepthStencilOpDesc backFace; + bool stencilEnable = false; + uint32_t stencilReadMask = 0xFFFFFFFF; + uint32_t stencilWriteMask = 0xFFFFFFFF; + DepthStencilOpDesc frontFace; + DepthStencilOpDesc backFace; uint32_t stencilRef = 0; // TODO: this should be removed }; @@ -1281,24 +1347,24 @@ enum class BlendFactor namespace RenderTargetWriteMask { - typedef uint8_t Type; - enum - { - EnableNone = 0, - EnableRed = 0x01, - EnableGreen = 0x02, - EnableBlue = 0x04, - EnableAlpha = 0x08, - EnableAll = 0x0F, - }; +typedef uint8_t Type; +enum +{ + EnableNone = 0, + EnableRed = 0x01, + EnableGreen = 0x02, + EnableBlue = 0x04, + EnableAlpha = 0x08, + EnableAll = 0x0F, }; +}; // namespace RenderTargetWriteMask typedef RenderTargetWriteMask::Type RenderTargetWriteMaskT; struct AspectBlendDesc { - BlendFactor srcFactor = BlendFactor::One; - BlendFactor dstFactor = BlendFactor::Zero; - BlendOp op = BlendOp::Add; + BlendFactor srcFactor = BlendFactor::One; + BlendFactor dstFactor = BlendFactor::Zero; + BlendOp op = BlendOp::Add; }; struct TargetBlendDesc @@ -1306,16 +1372,16 @@ struct TargetBlendDesc AspectBlendDesc color; AspectBlendDesc alpha; bool enableBlend = false; - LogicOp logicOp = LogicOp::NoOp; - RenderTargetWriteMaskT writeMask = RenderTargetWriteMask::EnableAll; + LogicOp logicOp = LogicOp::NoOp; + RenderTargetWriteMaskT writeMask = RenderTargetWriteMask::EnableAll; }; struct BlendDesc { - TargetBlendDesc targets[kMaxRenderTargetCount]; - GfxCount targetCount = 0; + TargetBlendDesc targets[kMaxRenderTargetCount]; + GfxCount targetCount = 0; - bool alphaToCoverageEnable = false; + bool alphaToCoverageEnable = false; }; class IFramebufferLayout : public ISlangUnknown @@ -1333,26 +1399,29 @@ class IFramebufferLayout : public ISlangUnknown TargetLayout* depthStencil = nullptr; }; }; -#define SLANG_UUID_IFramebufferLayout \ - { \ - 0xa838785, 0xc13a, 0x4832, { 0xad, 0x88, 0x64, 0x6, 0xb5, 0x4b, 0x5e, 0xba } \ +#define SLANG_UUID_IFramebufferLayout \ + { \ + 0xa838785, 0xc13a, 0x4832, \ + { \ + 0xad, 0x88, 0x64, 0x6, 0xb5, 0x4b, 0x5e, 0xba \ + } \ } struct GraphicsPipelineStateDesc { - IShaderProgram* program = nullptr; + IShaderProgram* program = nullptr; - IInputLayout* inputLayout = nullptr; + IInputLayout* inputLayout = nullptr; IFramebufferLayout* framebufferLayout = nullptr; - PrimitiveType primitiveType = PrimitiveType::Triangle; - DepthStencilDesc depthStencil; - RasterizerDesc rasterizer; - BlendDesc blend; + PrimitiveType primitiveType = PrimitiveType::Triangle; + DepthStencilDesc depthStencil; + RasterizerDesc rasterizer; + BlendDesc blend; }; struct ComputePipelineStateDesc { - IShaderProgram* program = nullptr; + IShaderProgram* program = nullptr; void* d3d12RootSignatureOverride = nullptr; }; @@ -1391,8 +1460,8 @@ class IShaderTable : public ISlangUnknown // Specifies the bytes to overwrite into a record in the shader table. struct ShaderRecordOverwrite { - Offset offset; // Offset within the shader record. - Size size; // Number of bytes to overwrite. + Offset offset; // Offset within the shader record. + Size size; // Number of bytes to overwrite. uint8_t data[8]; // Content to overwrite. }; @@ -1417,9 +1486,12 @@ class IShaderTable : public ISlangUnknown IShaderProgram* program; }; }; -#define SLANG_UUID_IShaderTable \ - { \ - 0xa721522c, 0xdf31, 0x4c2f, { 0xa5, 0xe7, 0x3b, 0xe0, 0x12, 0x4b, 0x31, 0x78 } \ +#define SLANG_UUID_IShaderTable \ + { \ + 0xa721522c, 0xdf31, 0x4c2f, \ + { \ + 0xa5, 0xe7, 0x3b, 0xe0, 0x12, 0x4b, 0x31, 0x78 \ + } \ } class IPipelineState : public ISlangUnknown @@ -1427,9 +1499,12 @@ class IPipelineState : public ISlangUnknown public: virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outHandle) = 0; }; -#define SLANG_UUID_IPipelineState \ - { \ - 0xca7e57d, 0x8a90, 0x44f3, { 0xbd, 0xb1, 0xfe, 0x9b, 0x35, 0x3f, 0x5a, 0x72 } \ +#define SLANG_UUID_IPipelineState \ + { \ + 0xca7e57d, 0x8a90, 0x44f3, \ + { \ + 0xbd, 0xb1, 0xfe, 0x9b, 0x35, 0x3f, 0x5a, 0x72 \ + } \ } @@ -1447,8 +1522,8 @@ struct Viewport float originY = 0.0f; float extentX = 0.0f; float extentY = 0.0f; - float minZ = 0.0f; - float maxZ = 1.0f; + float minZ = 0.0f; + float maxZ = 1.0f; }; class IFramebuffer : public ISlangUnknown @@ -1462,9 +1537,12 @@ class IFramebuffer : public ISlangUnknown IFramebufferLayout* layout; }; }; -#define SLANG_UUID_IFrameBuffer \ - { \ - 0xf0c0d9a, 0x4ef3, 0x4e18, { 0x9b, 0xa9, 0x34, 0x60, 0xea, 0x69, 0x87, 0x95 } \ +#define SLANG_UUID_IFrameBuffer \ + { \ + 0xf0c0d9a, 0x4ef3, 0x4e18, \ + { \ + 0x9b, 0xa9, 0x34, 0x60, 0xea, 0x69, 0x87, 0x95 \ + } \ } struct WindowHandle @@ -1506,7 +1584,8 @@ struct FaceMask { enum Enum { - Front = 1, Back = 2 + Front = 1, + Back = 2 }; }; @@ -1515,11 +1594,14 @@ class IRenderPassLayout : public ISlangUnknown public: enum class TargetLoadOp { - Load, Clear, DontCare + Load, + Clear, + DontCare }; enum class TargetStoreOp { - Store, DontCare + Store, + DontCare }; struct TargetAccessDesc { @@ -1538,9 +1620,12 @@ class IRenderPassLayout : public ISlangUnknown TargetAccessDesc* depthStencilAccess = nullptr; }; }; -#define SLANG_UUID_IRenderPassLayout \ - { \ - 0xdaab0b1a, 0xf45d, 0x4ae9, { 0xbf, 0x2c, 0xe0, 0xbb, 0x76, 0x7d, 0xfa, 0xd1 } \ +#define SLANG_UUID_IRenderPassLayout \ + { \ + 0xdaab0b1a, 0xf45d, 0x4ae9, \ + { \ + 0xbf, 0x2c, 0xe0, 0xbb, 0x76, 0x7d, 0xfa, 0xd1 \ + } \ } enum class QueryType @@ -1559,20 +1644,33 @@ class IQueryPool : public ISlangUnknown QueryType type; GfxCount count; }; + public: - virtual SLANG_NO_THROW Result SLANG_MCALL getResult(GfxIndex queryIndex, GfxCount count, uint64_t* data) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + getResult(GfxIndex queryIndex, GfxCount count, uint64_t* data) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL reset() = 0; }; -#define SLANG_UUID_IQueryPool \ - { 0xc2cc3784, 0x12da, 0x480a, { 0xa8, 0x74, 0x8b, 0x31, 0x96, 0x1c, 0xa4, 0x36 } } +#define SLANG_UUID_IQueryPool \ + { \ + 0xc2cc3784, 0x12da, 0x480a, \ + { \ + 0xa8, 0x74, 0x8b, 0x31, 0x96, 0x1c, 0xa4, 0x36 \ + } \ + } class ICommandEncoder : public ISlangUnknown { - SLANG_COM_INTERFACE( 0x77ea6383, 0xbe3d, 0x40aa, { 0x8b, 0x45, 0xfd, 0xf0, 0xd7, 0x5b, 0xfa, 0x34 }); + SLANG_COM_INTERFACE( + 0x77ea6383, + 0xbe3d, + 0x40aa, + {0x8b, 0x45, 0xfd, 0xf0, 0xd7, 0x5b, 0xfa, 0x34}); + public: virtual SLANG_NO_THROW void SLANG_MCALL endEncoding() = 0; - virtual SLANG_NO_THROW void SLANG_MCALL writeTimestamp(IQueryPool* queryPool, GfxIndex queryIndex) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL + writeTimestamp(IQueryPool* queryPool, GfxIndex queryIndex) = 0; }; struct IndirectDispatchArguments @@ -1619,7 +1717,11 @@ struct ClearResourceViewFlags class IResourceCommandEncoder : public ICommandEncoder { // {F99A00E9-ED50-4088-8A0E-3B26755031EA} - SLANG_COM_INTERFACE(0xf99a00e9, 0xed50, 0x4088, { 0x8a, 0xe, 0x3b, 0x26, 0x75, 0x50, 0x31, 0xea }); + SLANG_COM_INTERFACE( + 0xf99a00e9, + 0xed50, + 0x4088, + {0x8a, 0xe, 0x3b, 0x26, 0x75, 0x50, 0x31, 0xea}); public: virtual SLANG_NO_THROW void SLANG_MCALL copyBuffer( @@ -1662,18 +1764,26 @@ class IResourceCommandEncoder : public ICommandEncoder ITextureResource::SubresourceData* subResourceData, GfxCount subResourceDataCount) = 0; virtual SLANG_NO_THROW void SLANG_MCALL - uploadBufferData(IBufferResource* dst, Offset offset, Size size, void* data) = 0; + uploadBufferData(IBufferResource* dst, Offset offset, Size size, void* data) = 0; virtual SLANG_NO_THROW void SLANG_MCALL textureBarrier( - GfxCount count, ITextureResource* const* textures, ResourceState src, ResourceState dst) = 0; + GfxCount count, + ITextureResource* const* textures, + ResourceState src, + ResourceState dst) = 0; virtual SLANG_NO_THROW void SLANG_MCALL textureSubresourceBarrier( ITextureResource* texture, SubresourceRange subresourceRange, ResourceState src, ResourceState dst) = 0; virtual SLANG_NO_THROW void SLANG_MCALL bufferBarrier( - GfxCount count, IBufferResource* const* buffers, ResourceState src, ResourceState dst) = 0; + GfxCount count, + IBufferResource* const* buffers, + ResourceState src, + ResourceState dst) = 0; virtual SLANG_NO_THROW void SLANG_MCALL clearResourceView( - IResourceView* view, ClearValue* clearValue, ClearResourceViewFlags::Enum flags) = 0; + IResourceView* view, + ClearValue* clearValue, + ClearResourceViewFlags::Enum flags) = 0; virtual SLANG_NO_THROW void SLANG_MCALL resolveResource( ITextureResource* source, ResourceState sourceState, @@ -1687,7 +1797,8 @@ class IResourceCommandEncoder : public ICommandEncoder GfxCount count, IBufferResource* buffer, Offset offset) = 0; - virtual SLANG_NO_THROW void SLANG_MCALL beginDebugEvent(const char* name, float rgbColor[3]) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL + beginDebugEvent(const char* name, float rgbColor[3]) = 0; virtual SLANG_NO_THROW void SLANG_MCALL endDebugEvent() = 0; inline void textureBarrier(ITextureResource* texture, ResourceState src, ResourceState dst) { @@ -1702,7 +1813,11 @@ class IResourceCommandEncoder : public ICommandEncoder class IRenderCommandEncoder : public IResourceCommandEncoder { // {7A8D56D0-53E6-4AD6-85F7-D14DC110FDCE} - SLANG_COM_INTERFACE(0x7a8d56d0, 0x53e6, 0x4ad6, { 0x85, 0xf7, 0xd1, 0x4d, 0xc1, 0x10, 0xfd, 0xce }) + SLANG_COM_INTERFACE( + 0x7a8d56d0, + 0x53e6, + 0x4ad6, + {0x85, 0xf7, 0xd1, 0x4d, 0xc1, 0x10, 0xfd, 0xce}) public: // Sets the current pipeline state. This method returns a transient shader object for // writing shader parameters. This shader object will not retain any resources or @@ -1710,7 +1825,7 @@ class IRenderCommandEncoder : public IResourceCommandEncoder // resources or shader objects that is set into `outRootShaderObject` stays alive during // the execution of the command buffer. virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) = 0; + bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) = 0; inline IShaderObject* bindPipeline(IPipelineState* state) { IShaderObject* rootObject = nullptr; @@ -1720,12 +1835,12 @@ class IRenderCommandEncoder : public IResourceCommandEncoder // Sets the current pipeline state along with a pre-created mutable root shader object. virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; + bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; - virtual SLANG_NO_THROW void - SLANG_MCALL setViewports(GfxCount count, const Viewport* viewports) = 0; - virtual SLANG_NO_THROW void - SLANG_MCALL setScissorRects(GfxCount count, const ScissorRect* scissors) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL + setViewports(GfxCount count, const Viewport* viewports) = 0; + virtual SLANG_NO_THROW void SLANG_MCALL + setScissorRects(GfxCount count, const ScissorRect* scissors) = 0; /// Sets the viewport, and sets the scissor rect to match the viewport. inline void setViewportAndScissor(Viewport const& viewport) @@ -1743,18 +1858,17 @@ class IRenderCommandEncoder : public IResourceCommandEncoder GfxCount slotCount, IBufferResource* const* buffers, const Offset* offsets) = 0; - inline void setVertexBuffer( - GfxIndex slot, IBufferResource* buffer, Offset offset = 0) + inline void setVertexBuffer(GfxIndex slot, IBufferResource* buffer, Offset offset = 0) { setVertexBuffers(slot, 1, &buffer, &offset); } virtual SLANG_NO_THROW void SLANG_MCALL - setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset = 0) = 0; + setIndexBuffer(IBufferResource* buffer, Format indexFormat, Offset offset = 0) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - draw(GfxCount vertexCount, GfxIndex startVertex = 0) = 0; + draw(GfxCount vertexCount, GfxIndex startVertex = 0) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - drawIndexed(GfxCount indexCount, GfxIndex startIndex = 0, GfxIndex baseVertex = 0) = 0; + drawIndexed(GfxCount indexCount, GfxIndex startIndex = 0, GfxIndex baseVertex = 0) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL drawIndirect( GfxCount maxDrawCount, IBufferResource* argBuffer, @@ -1769,7 +1883,9 @@ class IRenderCommandEncoder : public IResourceCommandEncoder Offset countOffset = 0) = 0; virtual SLANG_NO_THROW void SLANG_MCALL setStencilReference(uint32_t referenceValue) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL setSamplePositions( - GfxCount samplesPerPixel, GfxCount pixelCount, const SamplePosition* samplePositions) = 0; + GfxCount samplesPerPixel, + GfxCount pixelCount, + const SamplePosition* samplePositions) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL drawInstanced( GfxCount vertexCount, GfxCount instanceCount, @@ -1781,14 +1897,17 @@ class IRenderCommandEncoder : public IResourceCommandEncoder GfxIndex startIndexLocation, GfxIndex baseVertexLocation, GfxIndex startInstanceLocation) = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL - drawMeshTasks(int x, int y, int z) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL drawMeshTasks(int x, int y, int z) = 0; }; class IComputeCommandEncoder : public IResourceCommandEncoder { // {88AA9322-82F7-4FE6-A68A-29C7FE798737} - SLANG_COM_INTERFACE(0x88aa9322, 0x82f7, 0x4fe6, { 0xa6, 0x8a, 0x29, 0xc7, 0xfe, 0x79, 0x87, 0x37 }) + SLANG_COM_INTERFACE( + 0x88aa9322, + 0x82f7, + 0x4fe6, + {0xa6, 0x8a, 0x29, 0xc7, 0xfe, 0x79, 0x87, 0x37}) public: // Sets the current pipeline state. This method returns a transient shader object for @@ -1797,7 +1916,7 @@ class IComputeCommandEncoder : public IResourceCommandEncoder // resources or shader objects that is set into `outRooShaderObject` stays alive during // the execution of the command buffer. virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) = 0; + bindPipeline(IPipelineState* state, IShaderObject** outRootShaderObject) = 0; inline IShaderObject* bindPipeline(IPipelineState* state) { IShaderObject* rootObject = nullptr; @@ -1806,14 +1925,16 @@ class IComputeCommandEncoder : public IResourceCommandEncoder } // Sets the current pipeline state along with a pre-created mutable root shader object. virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; + bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL dispatchCompute(int x, int y, int z) = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL dispatchComputeIndirect(IBufferResource* cmdBuffer, Offset offset) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + dispatchComputeIndirect(IBufferResource* cmdBuffer, Offset offset) = 0; }; enum class AccelerationStructureCopyMode { - Clone, Compact + Clone, + Compact }; struct AccelerationStructureQueryDesc @@ -1827,7 +1948,11 @@ struct AccelerationStructureQueryDesc class IRayTracingCommandEncoder : public IResourceCommandEncoder { - SLANG_COM_INTERFACE(0x9a672b87, 0x5035, 0x45e3, { 0x96, 0x7c, 0x1f, 0x85, 0xcd, 0xb3, 0x63, 0x4f }) + SLANG_COM_INTERFACE( + 0x9a672b87, + 0x5035, + 0x45e3, + {0x96, 0x7c, 0x1f, 0x85, 0xcd, 0xb3, 0x63, 0x4f}) public: virtual SLANG_NO_THROW void SLANG_MCALL buildAccelerationStructure( const IAccelerationStructure::BuildDesc& desc, @@ -1843,18 +1968,19 @@ class IRayTracingCommandEncoder : public IResourceCommandEncoder GfxCount queryCount, AccelerationStructureQueryDesc* queryDescs) = 0; virtual SLANG_NO_THROW void SLANG_MCALL - serializeAccelerationStructure(DeviceAddress dest, IAccelerationStructure* source) = 0; + serializeAccelerationStructure(DeviceAddress dest, IAccelerationStructure* source) = 0; virtual SLANG_NO_THROW void SLANG_MCALL - deserializeAccelerationStructure(IAccelerationStructure* dest, DeviceAddress source) = 0; + deserializeAccelerationStructure(IAccelerationStructure* dest, DeviceAddress source) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipeline(IPipelineState* state, IShaderObject** outRootObject) = 0; + bindPipeline(IPipelineState* state, IShaderObject** outRootObject) = 0; // Sets the current pipeline state along with a pre-created mutable root shader object. virtual SLANG_NO_THROW Result SLANG_MCALL - bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; + bindPipelineWithRootObject(IPipelineState* state, IShaderObject* rootObject) = 0; /// Issues a dispatch command to start ray tracing workload with a ray tracing pipeline. - /// `rayGenShaderIndex` specifies the index into the shader table that identifies the ray generation shader. + /// `rayGenShaderIndex` specifies the index into the shader table that identifies the ray + /// generation shader. virtual SLANG_NO_THROW Result SLANG_MCALL dispatchRays( GfxIndex rayGenShaderIndex, IShaderTable* shaderTable, @@ -1875,8 +2001,9 @@ class ICommandBuffer : public ISlangUnknown IRenderPassLayout* renderPass, IFramebuffer* framebuffer, IRenderCommandEncoder** outEncoder) = 0; - inline IRenderCommandEncoder* - encodeRenderCommands(IRenderPassLayout* renderPass, IFramebuffer* framebuffer) + inline IRenderCommandEncoder* encodeRenderCommands( + IRenderPassLayout* renderPass, + IFramebuffer* framebuffer) { IRenderCommandEncoder* result; encodeRenderCommands(renderPass, framebuffer, &result); @@ -1884,7 +2011,7 @@ class ICommandBuffer : public ISlangUnknown } virtual SLANG_NO_THROW void SLANG_MCALL - encodeComputeCommands(IComputeCommandEncoder** outEncoder) = 0; + encodeComputeCommands(IComputeCommandEncoder** outEncoder) = 0; inline IComputeCommandEncoder* encodeComputeCommands() { IComputeCommandEncoder* result; @@ -1893,7 +2020,7 @@ class ICommandBuffer : public ISlangUnknown } virtual SLANG_NO_THROW void SLANG_MCALL - encodeResourceCommands(IResourceCommandEncoder** outEncoder) = 0; + encodeResourceCommands(IResourceCommandEncoder** outEncoder) = 0; inline IResourceCommandEncoder* encodeResourceCommands() { IResourceCommandEncoder* result; @@ -1902,7 +2029,7 @@ class ICommandBuffer : public ISlangUnknown } virtual SLANG_NO_THROW void SLANG_MCALL - encodeRayTracingCommands(IRayTracingCommandEncoder** outEncoder) = 0; + encodeRayTracingCommands(IRayTracingCommandEncoder** outEncoder) = 0; inline IRayTracingCommandEncoder* encodeRayTracingCommands() { IRayTracingCommandEncoder* result; @@ -1914,9 +2041,12 @@ class ICommandBuffer : public ISlangUnknown virtual SLANG_NO_THROW Result SLANG_MCALL getNativeHandle(InteropHandle* outHandle) = 0; }; -#define SLANG_UUID_ICommandBuffer \ - { \ - 0x5d56063f, 0x91d4, 0x4723, { 0xa7, 0xa7, 0x7a, 0x15, 0xaf, 0x93, 0xeb, 0x48 } \ +#define SLANG_UUID_ICommandBuffer \ + { \ + 0x5d56063f, 0x91d4, 0x4723, \ + { \ + 0xa7, 0xa7, 0x7a, 0x15, 0xaf, 0x93, 0xeb, 0x48 \ + } \ } class ICommandBufferD3D12 : public ICommandBuffer @@ -1925,9 +2055,12 @@ class ICommandBufferD3D12 : public ICommandBuffer virtual SLANG_NO_THROW void SLANG_MCALL invalidateDescriptorHeapBinding() = 0; virtual SLANG_NO_THROW void SLANG_MCALL ensureInternalDescriptorHeapsBound() = 0; }; -#define SLANG_UUID_ICommandBufferD3D12 \ - { \ - 0xd56b7616, 0x6c14, 0x4841, { 0x9d, 0x9c, 0x7b, 0x7f, 0xdb, 0x9f, 0xd9, 0xb8 } \ +#define SLANG_UUID_ICommandBufferD3D12 \ + { \ + 0xd56b7616, 0x6c14, 0x4841, \ + { \ + 0x9d, 0x9c, 0x7b, 0x7f, 0xdb, 0x9f, 0xd9, 0xb8 \ + } \ } class ICommandQueue : public ISlangUnknown @@ -1953,7 +2086,9 @@ class ICommandQueue : public ISlangUnknown IFence* fenceToSignal, uint64_t newFenceValue) = 0; inline void executeCommandBuffer( - ICommandBuffer* commandBuffer, IFence* fenceToSignal = nullptr, uint64_t newFenceValue = 0) + ICommandBuffer* commandBuffer, + IFence* fenceToSignal = nullptr, + uint64_t newFenceValue = 0) { executeCommandBuffers(1, &commandBuffer, fenceToSignal, newFenceValue); } @@ -1964,11 +2099,14 @@ class ICommandQueue : public ISlangUnknown /// Queues a device side wait for the given fences. virtual SLANG_NO_THROW Result SLANG_MCALL - waitForFenceValuesOnDevice(GfxCount fenceCount, IFence** fences, uint64_t* waitValues) = 0; + waitForFenceValuesOnDevice(GfxCount fenceCount, IFence** fences, uint64_t* waitValues) = 0; }; -#define SLANG_UUID_ICommandQueue \ - { \ - 0x14e2bed0, 0xad0, 0x4dc8, { 0xb3, 0x41, 0x6, 0x3f, 0xe7, 0x2d, 0xbf, 0xe } \ +#define SLANG_UUID_ICommandQueue \ + { \ + 0x14e2bed0, 0xad0, 0x4dc8, \ + { \ + 0xb3, 0x41, 0x6, 0x3f, 0xe7, 0x2d, 0xbf, 0xe \ + } \ } class ITransientResourceHeap : public ISlangUnknown @@ -1999,8 +2137,8 @@ class ITransientResourceHeap : public ISlangUnknown // In most situations this method should be called at the beginning of each frame. virtual SLANG_NO_THROW Result SLANG_MCALL synchronizeAndReset() = 0; - // Must be called when the application has done using this heap to issue commands. In most situations - // this method should be called at the end of each frame. + // Must be called when the application has done using this heap to issue commands. In most + // situations this method should be called at the end of each frame. virtual SLANG_NO_THROW Result SLANG_MCALL finish() = 0; // Command buffers are one-time use. Once it is submitted to the queue via @@ -2009,7 +2147,7 @@ class ITransientResourceHeap : public ISlangUnknown // that only one command buffer maybe recorded at a time. User must finish recording a command // buffer before creating another command buffer. virtual SLANG_NO_THROW Result SLANG_MCALL - createCommandBuffer(ICommandBuffer** outCommandBuffer) = 0; + createCommandBuffer(ICommandBuffer** outCommandBuffer) = 0; inline ComPtr createCommandBuffer() { ComPtr result; @@ -2017,9 +2155,12 @@ class ITransientResourceHeap : public ISlangUnknown return result; } }; -#define SLANG_UUID_ITransientResourceHeap \ - { \ - 0xcd48bd29, 0xee72, 0x41b8, { 0xbc, 0xff, 0xa, 0x2b, 0x3a, 0xaa, 0x6d, 0xeb } \ +#define SLANG_UUID_ITransientResourceHeap \ + { \ + 0xcd48bd29, 0xee72, 0x41b8, \ + { \ + 0xbc, 0xff, 0xa, 0x2b, 0x3a, 0xaa, 0x6d, 0xeb \ + } \ } class ITransientResourceHeapD3D12 : public ISlangUnknown @@ -2027,7 +2168,8 @@ class ITransientResourceHeapD3D12 : public ISlangUnknown public: enum class DescriptorType { - ResourceView, Sampler + ResourceView, + Sampler }; virtual SLANG_NO_THROW Result SLANG_MCALL allocateTransientDescriptorTable( DescriptorType type, @@ -2035,9 +2177,12 @@ class ITransientResourceHeapD3D12 : public ISlangUnknown Offset& outDescriptorOffset, void** outD3DDescriptorHeapHandle) = 0; }; -#define SLANG_UUID_ITransientResourceHeapD3D12 \ - { \ - 0x9bc6a8bc, 0x5f7a, 0x454a, { 0x93, 0xef, 0x3b, 0x10, 0x5b, 0xb7, 0x63, 0x7e } \ +#define SLANG_UUID_ITransientResourceHeapD3D12 \ + { \ + 0x9bc6a8bc, 0x5f7a, 0x454a, \ + { \ + 0x93, 0xef, 0x3b, 0x10, 0x5b, 0xb7, 0x63, 0x7e \ + } \ } class ISwapchain : public ISlangUnknown @@ -2055,7 +2200,7 @@ class ISwapchain : public ISlangUnknown /// Returns the back buffer image at `index`. virtual SLANG_NO_THROW Result SLANG_MCALL - getImage(GfxIndex index, ITextureResource** outResource) = 0; + getImage(GfxIndex index, ITextureResource** outResource) = 0; /// Present the next image in the swapchain. virtual SLANG_NO_THROW Result SLANG_MCALL present() = 0; @@ -2074,9 +2219,12 @@ class ISwapchain : public ISlangUnknown // Toggle full screen mode. virtual SLANG_NO_THROW Result SLANG_MCALL setFullScreenMode(bool mode) = 0; }; -#define SLANG_UUID_ISwapchain \ - { \ - 0xbe91ba6c, 0x784, 0x4308, { 0xa1, 0x0, 0x19, 0xc3, 0x66, 0x83, 0x44, 0xb2 } \ +#define SLANG_UUID_ISwapchain \ + { \ + 0xbe91ba6c, 0x784, 0x4308, \ + { \ + 0xa1, 0x0, 0x19, 0xc3, 0x66, 0x83, 0x44, 0xb2 \ + } \ } struct AdapterLUID @@ -2090,10 +2238,7 @@ struct AdapterLUID return false; return true; } - bool operator!=(const AdapterLUID& other) const - { - return !this->operator==(other); - } + bool operator!=(const AdapterLUID& other) const { return !this->operator==(other); } }; struct AdapterInfo @@ -2104,7 +2249,8 @@ struct AdapterInfo // Unique identifier for the vendor (only available for D3D and Vulkan). uint32_t vendorID; - // Unique identifier for the physical device among devices from the vendor (only available for D3D and Vulkan) + // Unique identifier for the physical device among devices from the vendor (only available for + // D3D and Vulkan) uint32_t deviceID; // Logically unique identifier of the adapter. @@ -2114,7 +2260,10 @@ struct AdapterInfo class AdapterList { public: - AdapterList(ISlangBlob* blob) : m_blob(blob) {} + AdapterList(ISlangBlob* blob) + : m_blob(blob) + { + } const AdapterInfo* getAdapters() const { @@ -2196,17 +2345,21 @@ struct DeviceInfo enum class DebugMessageType { - Info, Warning, Error + Info, + Warning, + Error }; enum class DebugMessageSource { - Layer, Driver, Slang + Layer, + Driver, + Slang }; class IDebugCallback { public: virtual SLANG_NO_THROW void SLANG_MCALL - handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) = 0; + handleMessage(DebugMessageType type, DebugMessageSource source, const char* message) = 0; }; class IDevice : public ISlangUnknown @@ -2214,21 +2367,23 @@ class IDevice : public ISlangUnknown public: struct SlangDesc { - slang::IGlobalSession* slangGlobalSession = nullptr; // (optional) A slang global session object. If null will create automatically. + slang::IGlobalSession* slangGlobalSession = + nullptr; // (optional) A slang global session object. If null will create automatically. SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR; char const* const* searchPaths = nullptr; - GfxCount searchPathCount = 0; + GfxCount searchPathCount = 0; slang::PreprocessorMacroDesc const* preprocessorMacros = nullptr; - GfxCount preprocessorMacroCount = 0; + GfxCount preprocessorMacroCount = 0; - const char* targetProfile = nullptr; // (optional) Target shader profile. If null this will be set to platform dependent default. + const char* targetProfile = nullptr; // (optional) Target shader profile. If null this will + // be set to platform dependent default. SlangFloatingPointMode floatingPointMode = SLANG_FLOATING_POINT_MODE_DEFAULT; SlangOptimizationLevel optimizationLevel = SLANG_OPTIMIZATION_LEVEL_DEFAULT; SlangTargetFlags targetFlags = kDefaultTargetFlags; - SlangLineDirectiveMode lineDirectiveMode = SLANG_LINE_DIRECTIVE_MODE_DEFAULT;\ + SlangLineDirectiveMode lineDirectiveMode = SLANG_LINE_DIRECTIVE_MODE_DEFAULT; }; struct ShaderCacheDesc @@ -2248,9 +2403,10 @@ class IDevice : public ISlangUnknown { // The underlying API/Platform of the device. DeviceType deviceType = DeviceType::Default; - // The device's handles (if they exist) and their associated API. For D3D12, this contains a single InteropHandle - // for the ID3D12Device. For Vulkan, the first InteropHandle is the VkInstance, the second is the VkPhysicalDevice, - // and the third is the VkDevice. For CUDA, this only contains a single value for the CUDADevice. + // The device's handles (if they exist) and their associated API. For D3D12, this contains a + // single InteropHandle for the ID3D12Device. For Vulkan, the first InteropHandle is the + // VkInstance, the second is the VkPhysicalDevice, and the third is the VkDevice. For CUDA, + // this only contains a single value for the CUDADevice. InteropHandles existingDeviceHandles; // LUID of the adapter to use. Use getGfxAdapters() to get a list of available adapters. const AdapterLUID* adapterLUID = nullptr; @@ -2271,16 +2427,20 @@ class IDevice : public ISlangUnknown void** extendedDescs = nullptr; }; - virtual SLANG_NO_THROW Result SLANG_MCALL getNativeDeviceHandles(InteropHandles* outHandles) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + getNativeDeviceHandles(InteropHandles* outHandles) = 0; virtual SLANG_NO_THROW bool SLANG_MCALL hasFeature(const char* feature) = 0; - /// Returns a list of features supported by the renderer. - virtual SLANG_NO_THROW Result SLANG_MCALL getFeatures(const char** outFeatures, Size bufferSize, GfxCount* outFeatureCount) = 0; + /// Returns a list of features supported by the renderer. + virtual SLANG_NO_THROW Result SLANG_MCALL + getFeatures(const char** outFeatures, Size bufferSize, GfxCount* outFeatureCount) = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + getFormatSupportedResourceStates(Format format, ResourceStateSet* outStates) = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL getSlangSession(slang::ISession** outSlangSession) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + getSlangSession(slang::ISession** outSlangSession) = 0; inline ComPtr getSlangSession() { @@ -2300,26 +2460,27 @@ class IDevice : public ISlangUnknown return result; } - /// Create a texture resource. - /// - /// If `initData` is non-null, then it must point to an array of - /// `ITextureResource::SubresourceData` with one element for each - /// subresource of the texture being created. - /// - /// The number of subresources in a texture is: - /// - /// effectiveElementCount * mipLevelCount - /// - /// where the effective element count is computed as: - /// - /// effectiveElementCount = (isArray ? arrayElementCount : 1) * (isCube ? 6 : 1); - /// + /// Create a texture resource. + /// + /// If `initData` is non-null, then it must point to an array of + /// `ITextureResource::SubresourceData` with one element for each + /// subresource of the texture being created. + /// + /// The number of subresources in a texture is: + /// + /// effectiveElementCount * mipLevelCount + /// + /// where the effective element count is computed as: + /// + /// effectiveElementCount = (isArray ? arrayElementCount : 1) * (isCube ? 6 : 1); + /// virtual SLANG_NO_THROW Result SLANG_MCALL createTextureResource( const ITextureResource::Desc& desc, const ITextureResource::SubresourceData* initData, ITextureResource** outResource) = 0; - /// Create a texture resource. initData holds the initialize data to set the contents of the texture when constructed. + /// Create a texture resource. initData holds the initialize data to set the contents of the + /// texture when constructed. inline SLANG_NO_THROW ComPtr createTextureResource( const ITextureResource::Desc& desc, const ITextureResource::SubresourceData* initData = nullptr) @@ -2340,7 +2501,7 @@ class IDevice : public ISlangUnknown const Size size, ITextureResource** outResource) = 0; - /// Create a buffer resource + /// Create a buffer resource virtual SLANG_NO_THROW Result SLANG_MCALL createBufferResource( const IBufferResource::Desc& desc, const void* initData, @@ -2366,7 +2527,7 @@ class IDevice : public ISlangUnknown IBufferResource** outResource) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) = 0; + createSamplerState(ISamplerState::Desc const& desc, ISamplerState** outSampler) = 0; inline ComPtr createSamplerState(ISamplerState::Desc const& desc) { @@ -2376,9 +2537,13 @@ class IDevice : public ISlangUnknown } virtual SLANG_NO_THROW Result SLANG_MCALL createTextureView( - ITextureResource* texture, IResourceView::Desc const& desc, IResourceView** outView) = 0; + ITextureResource* texture, + IResourceView::Desc const& desc, + IResourceView** outView) = 0; - inline ComPtr createTextureView(ITextureResource* texture, IResourceView::Desc const& desc) + inline ComPtr createTextureView( + ITextureResource* texture, + IResourceView::Desc const& desc) { ComPtr view; SLANG_RETURN_NULL_ON_FAIL(createTextureView(texture, desc, view.writeRef())); @@ -2392,15 +2557,18 @@ class IDevice : public ISlangUnknown IResourceView** outView) = 0; inline ComPtr createBufferView( - IBufferResource* buffer, IBufferResource* counterBuffer, IResourceView::Desc const& desc) + IBufferResource* buffer, + IBufferResource* counterBuffer, + IResourceView::Desc const& desc) { ComPtr view; SLANG_RETURN_NULL_ON_FAIL(createBufferView(buffer, counterBuffer, desc, view.writeRef())); return view; } - virtual SLANG_NO_THROW Result SLANG_MCALL - createFramebufferLayout(IFramebufferLayout::Desc const& desc, IFramebufferLayout** outFrameBuffer) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL createFramebufferLayout( + IFramebufferLayout::Desc const& desc, + IFramebufferLayout** outFrameBuffer) = 0; inline ComPtr createFramebufferLayout(IFramebufferLayout::Desc const& desc) { ComPtr fb; @@ -2409,7 +2577,7 @@ class IDevice : public ISlangUnknown } virtual SLANG_NO_THROW Result SLANG_MCALL - createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) = 0; + createFramebuffer(IFramebuffer::Desc const& desc, IFramebuffer** outFrameBuffer) = 0; inline ComPtr createFramebuffer(IFramebuffer::Desc const& desc) { ComPtr fb; @@ -2428,7 +2596,9 @@ class IDevice : public ISlangUnknown } virtual SLANG_NO_THROW Result SLANG_MCALL createSwapchain( - ISwapchain::Desc const& desc, WindowHandle window, ISwapchain** outSwapchain) = 0; + ISwapchain::Desc const& desc, + WindowHandle window, + ISwapchain** outSwapchain) = 0; inline ComPtr createSwapchain(ISwapchain::Desc const& desc, WindowHandle window) { ComPtr swapchain; @@ -2436,8 +2606,8 @@ class IDevice : public ISlangUnknown return swapchain; } - virtual SLANG_NO_THROW Result SLANG_MCALL createInputLayout( - IInputLayout::Desc const& desc, IInputLayout** outLayout) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + createInputLayout(IInputLayout::Desc const& desc, IInputLayout** outLayout) = 0; inline ComPtr createInputLayout(IInputLayout::Desc const& desc) { @@ -2446,9 +2616,13 @@ class IDevice : public ISlangUnknown return layout; } - inline Result createInputLayout(Size vertexSize, InputElementDesc const* inputElements, GfxCount inputElementCount, IInputLayout** outLayout) + inline Result createInputLayout( + Size vertexSize, + InputElementDesc const* inputElements, + GfxCount inputElementCount, + IInputLayout** outLayout) { - VertexStreamDesc streamDesc = { vertexSize, InputSlotClass::PerVertex, 0 }; + VertexStreamDesc streamDesc = {vertexSize, InputSlotClass::PerVertex, 0}; IInputLayout::Desc inputLayoutDesc = {}; inputLayoutDesc.inputElementCount = inputElementCount; @@ -2458,15 +2632,19 @@ class IDevice : public ISlangUnknown return createInputLayout(inputLayoutDesc, outLayout); } - inline ComPtr createInputLayout(Size vertexSize, InputElementDesc const* inputElements, GfxCount inputElementCount) + inline ComPtr createInputLayout( + Size vertexSize, + InputElementDesc const* inputElements, + GfxCount inputElementCount) { ComPtr layout; - SLANG_RETURN_NULL_ON_FAIL(createInputLayout(vertexSize, inputElements, inputElementCount, layout.writeRef())); + SLANG_RETURN_NULL_ON_FAIL( + createInputLayout(vertexSize, inputElements, inputElementCount, layout.writeRef())); return layout; } virtual SLANG_NO_THROW Result SLANG_MCALL - createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue) = 0; + createCommandQueue(const ICommandQueue::Desc& desc, ICommandQueue** outQueue) = 0; inline ComPtr createCommandQueue(const ICommandQueue::Desc& desc) { ComPtr queue; @@ -2482,7 +2660,8 @@ class IDevice : public ISlangUnknown inline ComPtr createShaderObject(slang::TypeReflection* type) { ComPtr object; - SLANG_RETURN_NULL_ON_FAIL(createShaderObject(type, ShaderObjectContainerType::None, object.writeRef())); + SLANG_RETURN_NULL_ON_FAIL( + createShaderObject(type, ShaderObjectContainerType::None, object.writeRef())); return object; } @@ -2492,17 +2671,18 @@ class IDevice : public ISlangUnknown IShaderObject** outObject) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL createShaderObjectFromTypeLayout( - slang::TypeLayoutReflection* typeLayout, IShaderObject** outObject) = 0; + slang::TypeLayoutReflection* typeLayout, + IShaderObject** outObject) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL createMutableShaderObjectFromTypeLayout( - slang::TypeLayoutReflection* typeLayout, IShaderObject** outObject) = 0; - - virtual SLANG_NO_THROW Result SLANG_MCALL createMutableRootShaderObject( - IShaderProgram* program, + slang::TypeLayoutReflection* typeLayout, IShaderObject** outObject) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outTable) = 0; + createMutableRootShaderObject(IShaderProgram* program, IShaderObject** outObject) = 0; + + virtual SLANG_NO_THROW Result SLANG_MCALL + createShaderTable(const IShaderTable::Desc& desc, IShaderTable** outTable) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL createProgram( const IShaderProgram::Desc& desc, @@ -2522,23 +2702,20 @@ class IDevice : public ISlangUnknown ISlangBlob** outDiagnosticBlob = nullptr) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL createGraphicsPipelineState( - const GraphicsPipelineStateDesc& desc, - IPipelineState** outState) = 0; + const GraphicsPipelineStateDesc& desc, + IPipelineState** outState) = 0; - inline ComPtr createGraphicsPipelineState( - const GraphicsPipelineStateDesc& desc) + inline ComPtr createGraphicsPipelineState(const GraphicsPipelineStateDesc& desc) { ComPtr state; SLANG_RETURN_NULL_ON_FAIL(createGraphicsPipelineState(desc, state.writeRef())); return state; } - virtual SLANG_NO_THROW Result SLANG_MCALL createComputePipelineState( - const ComputePipelineStateDesc& desc, - IPipelineState** outState) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + createComputePipelineState(const ComputePipelineStateDesc& desc, IPipelineState** outState) = 0; - inline ComPtr createComputePipelineState( - const ComputePipelineStateDesc& desc) + inline ComPtr createComputePipelineState(const ComputePipelineStateDesc& desc) { ComPtr state; SLANG_RETURN_NULL_ON_FAIL(createComputePipelineState(desc, state.writeRef())); @@ -2546,9 +2723,10 @@ class IDevice : public ISlangUnknown } virtual SLANG_NO_THROW Result SLANG_MCALL createRayTracingPipelineState( - const RayTracingPipelineStateDesc& desc, IPipelineState** outState) = 0; + const RayTracingPipelineStateDesc& desc, + IPipelineState** outState) = 0; - /// Read back texture resource and stores the result in `outBlob`. + /// Read back texture resource and stores the result in `outBlob`. virtual SLANG_NO_THROW SlangResult SLANG_MCALL readTextureResource( ITextureResource* resource, ResourceState state, @@ -2556,17 +2734,14 @@ class IDevice : public ISlangUnknown Size* outRowPitch, Size* outPixelSize) = 0; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL readBufferResource( - IBufferResource* buffer, - Offset offset, - Size size, - ISlangBlob** outBlob) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + readBufferResource(IBufferResource* buffer, Offset offset, Size size, ISlangBlob** outBlob) = 0; - /// Get the type of this renderer + /// Get the type of this renderer virtual SLANG_NO_THROW const DeviceInfo& SLANG_MCALL getDeviceInfo() const = 0; - virtual SLANG_NO_THROW Result SLANG_MCALL createQueryPool( - const IQueryPool::Desc& desc, IQueryPool** outPool) = 0; + virtual SLANG_NO_THROW Result SLANG_MCALL + createQueryPool(const IQueryPool::Desc& desc, IQueryPool** outPool) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL getAccelerationStructurePrebuildInfo( @@ -2578,7 +2753,7 @@ class IDevice : public ISlangUnknown IAccelerationStructure** outView) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - createFence(const IFence::Desc& desc, IFence** outFence) = 0; + createFence(const IFence::Desc& desc, IFence** outFence) = 0; /// Wait on the host for the fences to signals. /// `timeout` is in nanoseconds, can be set to `kTimeoutInfinite`. @@ -2590,7 +2765,9 @@ class IDevice : public ISlangUnknown uint64_t timeout) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL getTextureAllocationInfo( - const ITextureResource::Desc& desc, Size* outSize, Size* outAlignment) = 0; + const ITextureResource::Desc& desc, + Size* outSize, + Size* outAlignment) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL getTextureRowAlignment(Size* outAlignment) = 0; @@ -2607,9 +2784,12 @@ class IDevice : public ISlangUnknown IShaderObject** outObject) = 0; }; -#define SLANG_UUID_IDevice \ - { \ - 0x715bdf26, 0x5135, 0x11eb, { 0xAE, 0x93, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x02 } \ +#define SLANG_UUID_IDevice \ + { \ + 0x715bdf26, 0x5135, 0x11eb, \ + { \ + 0xAE, 0x93, 0x02, 0x42, 0xAC, 0x13, 0x00, 0x02 \ + } \ } struct ShaderCacheStats @@ -2631,9 +2811,12 @@ class IShaderCache : public ISlangUnknown virtual SLANG_NO_THROW Result SLANG_MCALL resetShaderCacheStats() = 0; }; -#define SLANG_UUID_IShaderCache \ - { \ - 0x8eccc8ec, 0x5c04, 0x4a51, { 0x99, 0x75, 0x13, 0xf8, 0xfe, 0xa1, 0x59, 0xf3 } \ +#define SLANG_UUID_IShaderCache \ + { \ + 0x8eccc8ec, 0x5c04, 0x4a51, \ + { \ + 0x99, 0x75, 0x13, 0xf8, 0xfe, 0xa1, 0x59, 0xf3 \ + } \ } class IPipelineCreationAPIDispatcher : public ISlangUnknown @@ -2655,18 +2838,24 @@ class IPipelineCreationAPIDispatcher : public ISlangUnknown void* pipelineDesc, void** outPipelineState) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - beforeCreateRayTracingState(IDevice* device, slang::IComponentType* program) = 0; + beforeCreateRayTracingState(IDevice* device, slang::IComponentType* program) = 0; virtual SLANG_NO_THROW Result SLANG_MCALL - afterCreateRayTracingState(IDevice* device, slang::IComponentType* program) = 0; + afterCreateRayTracingState(IDevice* device, slang::IComponentType* program) = 0; }; -#define SLANG_UUID_IPipelineCreationAPIDispatcher \ - { \ - 0xc3d5f782, 0xeae1, 0x4da6, { 0xab, 0x40, 0x75, 0x32, 0x31, 0x2, 0xb7, 0xdc } \ +#define SLANG_UUID_IPipelineCreationAPIDispatcher \ + { \ + 0xc3d5f782, 0xeae1, 0x4da6, \ + { \ + 0xab, 0x40, 0x75, 0x32, 0x31, 0x2, 0xb7, 0xdc \ + } \ } -#define SLANG_UUID_IVulkanPipelineCreationAPIDispatcher \ - { \ - 0x4fcf1274, 0x8752, 0x4743, { 0xb3, 0x51, 0x47, 0xcb, 0x83, 0x71, 0xef, 0x99 } \ +#define SLANG_UUID_IVulkanPipelineCreationAPIDispatcher \ + { \ + 0x4fcf1274, 0x8752, 0x4743, \ + { \ + 0xb3, 0x51, 0x47, 0xcb, 0x83, 0x71, 0xef, 0x99 \ + } \ } // Global public functions @@ -2683,11 +2872,12 @@ extern "C" SLANG_GFX_API SlangResult SLANG_MCALL gfxGetFormatInfo(Format format, FormatInfo* outInfo); /// Gets a list of available adapters for a given device type - SLANG_GFX_API SlangResult SLANG_MCALL gfxGetAdapters(DeviceType type, ISlangBlob** outAdaptersBlob); + SLANG_GFX_API SlangResult SLANG_MCALL + gfxGetAdapters(DeviceType type, ISlangBlob** outAdaptersBlob); /// Given a type returns a function that can construct it, or nullptr if there isn't one SLANG_GFX_API SlangResult SLANG_MCALL - gfxCreateDevice(const IDevice::Desc* desc, IDevice** outDevice); + gfxCreateDevice(const IDevice::Desc* desc, IDevice** outDevice); /// Reports current set of live objects in gfx. /// Currently this only calls D3D's ReportLiveObjects. @@ -2696,10 +2886,10 @@ extern "C" /// Sets a callback for receiving debug messages. /// The layer does not hold a strong reference to the callback object. /// The user is responsible for holding the callback object alive. - SLANG_GFX_API SlangResult SLANG_MCALL - gfxSetDebugCallback(IDebugCallback* callback); + SLANG_GFX_API SlangResult SLANG_MCALL gfxSetDebugCallback(IDebugCallback* callback); - /// Enables debug layer. The debug layer will check all `gfx` calls and verify that uses are valid. + /// Enables debug layer. The debug layer will check all `gfx` calls and verify that uses are + /// valid. SLANG_GFX_API void SLANG_MCALL gfxEnableDebugLayer(); SLANG_GFX_API const char* SLANG_MCALL gfxGetDeviceTypeName(DeviceType type); @@ -2738,11 +2928,12 @@ struct SlangSessionExtendedDesc slang::CompilerOptionEntry* compilerOptionEntries = nullptr; }; -/// Whether to enable ray tracing validation (currently only Vulkan - D3D requires app layer to use NVAPI) +/// Whether to enable ray tracing validation (currently only Vulkan - D3D requires app layer to use +/// NVAPI) struct RayTracingValidationDesc { StructType structType = StructType::RayTracingValidationDesc; bool enableRaytracingValidation = false; }; -} +} // namespace gfx diff --git a/include/slang-image-format-defs.h b/include/slang-image-format-defs.h new file mode 100644 index 0000000000..0f7c7cec3f --- /dev/null +++ b/include/slang-image-format-defs.h @@ -0,0 +1,49 @@ +// slang-image-format-defs.h +#ifndef SLANG_FORMAT + #error Must define SLANG_FORMAT macro before including image-format-defs.h +#endif + +SLANG_FORMAT(unknown, (NONE, 0, 0)) +SLANG_FORMAT(rgba32f, (FLOAT32, 4, sizeof(float) * 4)) +SLANG_FORMAT(rgba16f, (FLOAT16, 4, sizeof(uint16_t) * 4)) +SLANG_FORMAT(rg32f, (FLOAT32, 2, sizeof(float) * 2)) +SLANG_FORMAT(rg16f, (FLOAT16, 2, sizeof(uint16_t) * 2)) +SLANG_FORMAT(r11f_g11f_b10f, (NONE, 3, sizeof(uint32_t))) +SLANG_FORMAT(r32f, (FLOAT32, 1, sizeof(float))) +SLANG_FORMAT(r16f, (FLOAT16, 1, sizeof(uint16_t))) +SLANG_FORMAT(rgba16, (UINT16, 4, sizeof(uint16_t) * 4)) +SLANG_FORMAT(rgb10_a2, (NONE, 4, sizeof(uint32_t))) +SLANG_FORMAT(rgba8, (UINT8, 4, sizeof(uint32_t))) +SLANG_FORMAT(rg16, (UINT16, 2, sizeof(uint16_t) * 2)) +SLANG_FORMAT(rg8, (UINT8, 2, sizeof(char) * 2)) +SLANG_FORMAT(r16, (UINT16, 1, sizeof(uint16_t))) +SLANG_FORMAT(r8, (UINT8, 1, sizeof(uint8_t))) +SLANG_FORMAT(rgba16_snorm, (UINT16, 4, sizeof(uint16_t) * 4)) +SLANG_FORMAT(rgba8_snorm, (UINT8, 4, sizeof(uint8_t) * 4)) +SLANG_FORMAT(rg16_snorm, (UINT16, 2, sizeof(uint16_t) * 2)) +SLANG_FORMAT(rg8_snorm, (UINT8, 2, sizeof(uint8_t) * 2)) +SLANG_FORMAT(r16_snorm, (UINT16, 1, sizeof(uint16_t))) +SLANG_FORMAT(r8_snorm, (UINT8, 1, sizeof(uint8_t))) +SLANG_FORMAT(rgba32i, (INT32, 4, sizeof(int32_t) * 4)) +SLANG_FORMAT(rgba16i, (INT16, 4, sizeof(int16_t) * 4)) +SLANG_FORMAT(rgba8i, (INT8, 4, sizeof(int8_t) * 4)) +SLANG_FORMAT(rg32i, (INT32, 2, sizeof(int32_t) * 2)) +SLANG_FORMAT(rg16i, (INT16, 2, sizeof(int16_t) * 2)) +SLANG_FORMAT(rg8i, (INT8, 2, sizeof(int8_t) * 2)) +SLANG_FORMAT(r32i, (INT32, 1, sizeof(int32_t))) +SLANG_FORMAT(r16i, (INT16, 1, sizeof(int16_t))) +SLANG_FORMAT(r8i, (INT8, 1, sizeof(int8_t))) +SLANG_FORMAT(rgba32ui, (UINT32, 4, sizeof(uint32_t) * 4)) +SLANG_FORMAT(rgba16ui, (UINT16, 4, sizeof(uint16_t) * 4)) +SLANG_FORMAT(rgb10_a2ui, (NONE, 4, sizeof(uint32_t))) +SLANG_FORMAT(rgba8ui, (UINT8, 4, sizeof(uint8_t) * 4)) +SLANG_FORMAT(rg32ui, (UINT32, 2, sizeof(uint32_t) * 2)) +SLANG_FORMAT(rg16ui, (UINT16, 2, sizeof(uint16_t) * 2)) +SLANG_FORMAT(rg8ui, (UINT8, 2, sizeof(uint8_t) * 2)) +SLANG_FORMAT(r32ui, (UINT32, 1, sizeof(uint32_t))) +SLANG_FORMAT(r16ui, (UINT16, 1, sizeof(uint16_t))) +SLANG_FORMAT(r8ui, (UINT8, 1, sizeof(uint8_t))) +SLANG_FORMAT(r64ui, (UINT64, 1, sizeof(uint64_t))) +SLANG_FORMAT(r64i, (INT64, 1, sizeof(int64_t))) + +#undef SLANG_FORMAT diff --git a/include/slang.h b/include/slang.h index 777cd406b3..2dfee6b281 100644 --- a/include/slang.h +++ b/include/slang.h @@ -17,55 +17,55 @@ used later in the file. Most applications should not need to touch this section. */ #ifndef SLANG_COMPILER -# define SLANG_COMPILER + #define SLANG_COMPILER -/* -Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/ -NOTE that SLANG_VC holds the compiler version - not just 1 or 0 -*/ -# if defined(_MSC_VER) -# if _MSC_VER >= 1900 -# define SLANG_VC 14 -# elif _MSC_VER >= 1800 -# define SLANG_VC 12 -# elif _MSC_VER >= 1700 -# define SLANG_VC 11 -# elif _MSC_VER >= 1600 -# define SLANG_VC 10 -# elif _MSC_VER >= 1500 -# define SLANG_VC 9 -# else -# error "unknown version of Visual C++ compiler" -# endif -# elif defined(__clang__) -# define SLANG_CLANG 1 -# elif defined(__SNC__) -# define SLANG_SNC 1 -# elif defined(__ghs__) -# define SLANG_GHS 1 -# elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */ -# define SLANG_GCC 1 -# else -# error "unknown compiler" -# endif -/* -Any compilers not detected by the above logic are now now explicitly zeroed out. -*/ -# ifndef SLANG_VC -# define SLANG_VC 0 -# endif -# ifndef SLANG_CLANG -# define SLANG_CLANG 0 -# endif -# ifndef SLANG_SNC -# define SLANG_SNC 0 -# endif -# ifndef SLANG_GHS -# define SLANG_GHS 0 -# endif -# ifndef SLANG_GCC -# define SLANG_GCC 0 -# endif + /* + Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/ + NOTE that SLANG_VC holds the compiler version - not just 1 or 0 + */ + #if defined(_MSC_VER) + #if _MSC_VER >= 1900 + #define SLANG_VC 14 + #elif _MSC_VER >= 1800 + #define SLANG_VC 12 + #elif _MSC_VER >= 1700 + #define SLANG_VC 11 + #elif _MSC_VER >= 1600 + #define SLANG_VC 10 + #elif _MSC_VER >= 1500 + #define SLANG_VC 9 + #else + #error "unknown version of Visual C++ compiler" + #endif + #elif defined(__clang__) + #define SLANG_CLANG 1 + #elif defined(__SNC__) + #define SLANG_SNC 1 + #elif defined(__ghs__) + #define SLANG_GHS 1 + #elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */ + #define SLANG_GCC 1 + #else + #error "unknown compiler" + #endif + /* + Any compilers not detected by the above logic are now now explicitly zeroed out. + */ + #ifndef SLANG_VC + #define SLANG_VC 0 + #endif + #ifndef SLANG_CLANG + #define SLANG_CLANG 0 + #endif + #ifndef SLANG_SNC + #define SLANG_SNC 0 + #endif + #ifndef SLANG_GHS + #define SLANG_GHS 0 + #endif + #ifndef SLANG_GCC + #define SLANG_GCC 0 + #endif #endif /* SLANG_COMPILER */ /* @@ -78,84 +78,86 @@ used later in the file. Most applications should not need to touch this section. */ #ifndef SLANG_PLATFORM -# define SLANG_PLATFORM -/** -Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/ -*/ -# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP -# define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */ -# elif defined(XBOXONE) -# define SLANG_XBOXONE 1 -# elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */ -# define SLANG_WIN64 1 -# elif defined(_M_PPC) -# define SLANG_X360 1 -# elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */ -# define SLANG_WIN32 1 -# elif defined(__ANDROID__) -# define SLANG_ANDROID 1 -# elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */ -# define SLANG_LINUX 1 -# elif defined(__APPLE__) -# include "TargetConditionals.h" -# if TARGET_OS_MAC -# define SLANG_OSX 1 -# else -# define SLANG_IOS 1 -# endif -# elif defined(__CELLOS_LV2__) -# define SLANG_PS3 1 -# elif defined(__ORBIS__) -# define SLANG_PS4 1 -# elif defined(__SNC__) && defined(__arm__) -# define SLANG_PSP2 1 -# elif defined(__ghs__) -# define SLANG_WIIU 1 -# else -# error "unknown target platform" -# endif -/* -Any platforms not detected by the above logic are now now explicitly zeroed out. -*/ -# ifndef SLANG_WINRT -# define SLANG_WINRT 0 -# endif -# ifndef SLANG_XBOXONE -# define SLANG_XBOXONE 0 -# endif -# ifndef SLANG_WIN64 -# define SLANG_WIN64 0 -# endif -# ifndef SLANG_X360 -# define SLANG_X360 0 -# endif -# ifndef SLANG_WIN32 -# define SLANG_WIN32 0 -# endif -# ifndef SLANG_ANDROID -# define SLANG_ANDROID 0 -# endif -# ifndef SLANG_LINUX -# define SLANG_LINUX 0 -# endif -# ifndef SLANG_IOS -# define SLANG_IOS 0 -# endif -# ifndef SLANG_OSX -# define SLANG_OSX 0 -# endif -# ifndef SLANG_PS3 -# define SLANG_PS3 0 -# endif -# ifndef SLANG_PS4 -# define SLANG_PS4 0 -# endif -# ifndef SLANG_PSP2 -# define SLANG_PSP2 0 -# endif -# ifndef SLANG_WIIU -# define SLANG_WIIU 0 -# endif + #define SLANG_PLATFORM + /** + Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/ + */ + #if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP + #define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */ + #elif defined(XBOXONE) + #define SLANG_XBOXONE 1 + #elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */ + #define SLANG_WIN64 1 + #elif defined(_M_PPC) + #define SLANG_X360 1 + #elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */ + #define SLANG_WIN32 1 + #elif defined(__ANDROID__) + #define SLANG_ANDROID 1 + #elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */ + #define SLANG_LINUX 1 + #elif defined(__APPLE__) + #include "TargetConditionals.h" + #if TARGET_OS_MAC + #define SLANG_OSX 1 + #else + #define SLANG_IOS 1 + #endif + #elif defined(__CELLOS_LV2__) + #define SLANG_PS3 1 + #elif defined(__ORBIS__) + #define SLANG_PS4 1 + #elif defined(__SNC__) && defined(__arm__) + #define SLANG_PSP2 1 + #elif defined(__ghs__) + #define SLANG_WIIU 1 + #elif defined(__EMSCRIPTEN__) + #define SLANG_WASM 1 + #else + #error "unknown target platform" + #endif + /* + Any platforms not detected by the above logic are now now explicitly zeroed out. + */ + #ifndef SLANG_WINRT + #define SLANG_WINRT 0 + #endif + #ifndef SLANG_XBOXONE + #define SLANG_XBOXONE 0 + #endif + #ifndef SLANG_WIN64 + #define SLANG_WIN64 0 + #endif + #ifndef SLANG_X360 + #define SLANG_X360 0 + #endif + #ifndef SLANG_WIN32 + #define SLANG_WIN32 0 + #endif + #ifndef SLANG_ANDROID + #define SLANG_ANDROID 0 + #endif + #ifndef SLANG_LINUX + #define SLANG_LINUX 0 + #endif + #ifndef SLANG_IOS + #define SLANG_IOS 0 + #endif + #ifndef SLANG_OSX + #define SLANG_OSX 0 + #endif + #ifndef SLANG_PS3 + #define SLANG_PS3 0 + #endif + #ifndef SLANG_PS4 + #define SLANG_PS4 0 + #endif + #ifndef SLANG_PSP2 + #define SLANG_PSP2 0 + #endif + #ifndef SLANG_WIIU + #define SLANG_WIIU 0 + #endif #endif /* SLANG_PLATFORM */ /* Shorthands for "families" of compilers/platforms */ @@ -163,57 +165,58 @@ Any platforms not detected by the above logic are now now explicitly zeroed out. #define SLANG_WINDOWS_FAMILY (SLANG_WINRT || SLANG_WIN32 || SLANG_WIN64) #define SLANG_MICROSOFT_FAMILY (SLANG_XBOXONE || SLANG_X360 || SLANG_WINDOWS_FAMILY) #define SLANG_LINUX_FAMILY (SLANG_LINUX || SLANG_ANDROID) -#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */ -#define SLANG_UNIX_FAMILY (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */ +#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */ +#define SLANG_UNIX_FAMILY \ + (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */ /* Macros concerning DirectX */ #if !defined(SLANG_CONFIG_DX_ON_VK) || !SLANG_CONFIG_DX_ON_VK -# define SLANG_ENABLE_DXVK 0 -# define SLANG_ENABLE_VKD3D 0 + #define SLANG_ENABLE_DXVK 0 + #define SLANG_ENABLE_VKD3D 0 #else -# define SLANG_ENABLE_DXVK 1 -# define SLANG_ENABLE_VKD3D 1 + #define SLANG_ENABLE_DXVK 1 + #define SLANG_ENABLE_VKD3D 1 #endif #if SLANG_WINDOWS_FAMILY -# define SLANG_ENABLE_DIRECTX 1 -# define SLANG_ENABLE_DXGI_DEBUG 1 -# define SLANG_ENABLE_DXBC_SUPPORT 1 -# define SLANG_ENABLE_PIX 1 + #define SLANG_ENABLE_DIRECTX 1 + #define SLANG_ENABLE_DXGI_DEBUG 1 + #define SLANG_ENABLE_DXBC_SUPPORT 1 + #define SLANG_ENABLE_PIX 1 #elif SLANG_LINUX_FAMILY -# define SLANG_ENABLE_DIRECTX (SLANG_ENABLE_DXVK || SLANG_ENABLE_VKD3D) -# define SLANG_ENABLE_DXGI_DEBUG 0 -# define SLANG_ENABLE_DXBC_SUPPORT 0 -# define SLANG_ENABLE_PIX 0 + #define SLANG_ENABLE_DIRECTX (SLANG_ENABLE_DXVK || SLANG_ENABLE_VKD3D) + #define SLANG_ENABLE_DXGI_DEBUG 0 + #define SLANG_ENABLE_DXBC_SUPPORT 0 + #define SLANG_ENABLE_PIX 0 #else -# define SLANG_ENABLE_DIRECTX 0 -# define SLANG_ENABLE_DXGI_DEBUG 0 -# define SLANG_ENABLE_DXBC_SUPPORT 0 -# define SLANG_ENABLE_PIX 0 + #define SLANG_ENABLE_DIRECTX 0 + #define SLANG_ENABLE_DXGI_DEBUG 0 + #define SLANG_ENABLE_DXBC_SUPPORT 0 + #define SLANG_ENABLE_PIX 0 #endif /* Macro for declaring if a method is no throw. Should be set before the return parameter. */ #ifndef SLANG_NO_THROW -# if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) -# define SLANG_NO_THROW __declspec(nothrow) -# endif + #if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) + #define SLANG_NO_THROW __declspec(nothrow) + #endif #endif #ifndef SLANG_NO_THROW -# define SLANG_NO_THROW + #define SLANG_NO_THROW #endif /* The `SLANG_STDCALL` and `SLANG_MCALL` defines are used to set the calling convention for interface methods. */ #ifndef SLANG_STDCALL -# if SLANG_MICROSOFT_FAMILY -# define SLANG_STDCALL __stdcall -# else -# define SLANG_STDCALL -# endif + #if SLANG_MICROSOFT_FAMILY + #define SLANG_STDCALL __stdcall + #else + #define SLANG_STDCALL + #endif #endif #ifndef SLANG_MCALL -# define SLANG_MCALL SLANG_STDCALL + #define SLANG_MCALL SLANG_STDCALL #endif @@ -222,94 +225,94 @@ convention for interface methods. #endif #if defined(_MSC_VER) -# define SLANG_DLL_EXPORT __declspec(dllexport) + #define SLANG_DLL_EXPORT __declspec(dllexport) #else -# if 0 && __GNUC__ >= 4 + #if 0 && __GNUC__ >= 4 // Didn't work on latest gcc on linux.. so disable for now // https://gcc.gnu.org/wiki/Visibility -# define SLANG_DLL_EXPORT __attribute__ ((dllexport)) -# else -# define SLANG_DLL_EXPORT __attribute__((__visibility__("default"))) -# endif + #define SLANG_DLL_EXPORT __attribute__((dllexport)) + #else + #define SLANG_DLL_EXPORT __attribute__((__visibility__("default"))) + #endif #endif #if defined(SLANG_DYNAMIC) -# if defined(_MSC_VER) -# ifdef SLANG_DYNAMIC_EXPORT -# define SLANG_API SLANG_DLL_EXPORT -# else -# define SLANG_API __declspec(dllimport) -# endif -# else + #if defined(_MSC_VER) + #ifdef SLANG_DYNAMIC_EXPORT + #define SLANG_API SLANG_DLL_EXPORT + #else + #define SLANG_API __declspec(dllimport) + #endif + #else // TODO: need to consider compiler capabilities -//# ifdef SLANG_DYNAMIC_EXPORT -# define SLANG_API SLANG_DLL_EXPORT -//# endif -# endif + // # ifdef SLANG_DYNAMIC_EXPORT + #define SLANG_API SLANG_DLL_EXPORT + // # endif + #endif #endif #ifndef SLANG_API -# define SLANG_API + #define SLANG_API #endif // GCC Specific #if SLANG_GCC_FAMILY -# define SLANG_NO_INLINE __attribute__((noinline)) -# define SLANG_FORCE_INLINE inline __attribute__((always_inline)) -# define SLANG_BREAKPOINT(id) __builtin_trap(); -# define SLANG_ALIGN_OF(T) __alignof__(T) + #define SLANG_NO_INLINE __attribute__((noinline)) + #define SLANG_FORCE_INLINE inline __attribute__((always_inline)) + #define SLANG_BREAKPOINT(id) __builtin_trap(); + #define SLANG_ALIGN_OF(T) __alignof__(T) #endif // SLANG_GCC_FAMILY #if SLANG_GCC_FAMILY || defined(__clang__) -// Use the builtin directly so we don't need to have an include of stddef.h -# define SLANG_OFFSET_OF(T, ELEMENT) __builtin_offsetof(T, ELEMENT) + // Use the builtin directly so we don't need to have an include of stddef.h + #define SLANG_OFFSET_OF(T, ELEMENT) __builtin_offsetof(T, ELEMENT) #endif #ifndef SLANG_OFFSET_OF -# define SLANG_OFFSET_OF(T, ELEMENT) (size_t(&((T*)1)->ELEMENT) - 1) + #define SLANG_OFFSET_OF(T, ELEMENT) (size_t(&((T*)1)->ELEMENT) - 1) #endif // Microsoft VC specific -#if SLANG_MICROSOFT_FAMILY -# define SLANG_NO_INLINE __declspec(noinline) -# define SLANG_FORCE_INLINE __forceinline -# define SLANG_BREAKPOINT(id) __debugbreak(); -# define SLANG_ALIGN_OF(T) __alignof(T) - -# define SLANG_INT64(x) (x##i64) -# define SLANG_UINT64(x) (x##ui64) +#if SLANG_VC + #define SLANG_NO_INLINE __declspec(noinline) + #define SLANG_FORCE_INLINE __forceinline + #define SLANG_BREAKPOINT(id) __debugbreak(); + #define SLANG_ALIGN_OF(T) __alignof(T) + + #define SLANG_INT64(x) (x##i64) + #define SLANG_UINT64(x) (x##ui64) #endif // SLANG_MICROSOFT_FAMILY #ifndef SLANG_FORCE_INLINE -# define SLANG_FORCE_INLINE inline + #define SLANG_FORCE_INLINE inline #endif #ifndef SLANG_NO_INLINE -# define SLANG_NO_INLINE + #define SLANG_NO_INLINE #endif #ifndef SLANG_COMPILE_TIME_ASSERT -# define SLANG_COMPILE_TIME_ASSERT(x) static_assert(x) + #define SLANG_COMPILE_TIME_ASSERT(x) static_assert(x) #endif #ifndef SLANG_BREAKPOINT -// Make it crash with a write to 0! -# define SLANG_BREAKPOINT(id) (*((int*)0) = int(id)); + // Make it crash with a write to 0! + #define SLANG_BREAKPOINT(id) (*((int*)0) = int(id)); #endif // Use for getting the amount of members of a standard C array. // Use 0[x] here to catch the case where x has an overloaded subscript operator -#define SLANG_COUNT_OF(x) (SlangSSizeT(sizeof(x)/sizeof(0[x]))) +#define SLANG_COUNT_OF(x) (SlangSSizeT(sizeof(x) / sizeof(0 [x]))) /// SLANG_INLINE exists to have a way to inline consistent with SLANG_ALWAYS_INLINE #define SLANG_INLINE inline -// If explicilty disabled and not set, set to not available +// If explicitly disabled and not set, set to not available #if !defined(SLANG_HAS_EXCEPTIONS) && defined(SLANG_DISABLE_EXCEPTIONS) -# define SLANG_HAS_EXCEPTIONS 0 + #define SLANG_HAS_EXCEPTIONS 0 #endif // If not set, the default is exceptions are available #ifndef SLANG_HAS_EXCEPTIONS -# define SLANG_HAS_EXCEPTIONS 1 + #define SLANG_HAS_EXCEPTIONS 1 #endif // Other defines @@ -320,127 +323,130 @@ convention for interface methods. #define SLANG_CONCAT(X, Y) SLANG_CONCAT_HELPER(X, Y) #ifndef SLANG_UNUSED -# define SLANG_UNUSED(v) (void)v; + #define SLANG_UNUSED(v) (void)v; #endif #if defined(__llvm__) -# define SLANG_MAYBE_UNUSED [[maybe_unused]] + #define SLANG_MAYBE_UNUSED [[maybe_unused]] #else -# define SLANG_MAYBE_UNUSED + #define SLANG_MAYBE_UNUSED #endif // Used for doing constant literals #ifndef SLANG_INT64 -# define SLANG_INT64(x) (x##ll) + #define SLANG_INT64(x) (x##ll) #endif #ifndef SLANG_UINT64 -# define SLANG_UINT64(x) (x##ull) + #define SLANG_UINT64(x) (x##ull) #endif #ifdef __cplusplus -# define SLANG_EXTERN_C extern "C" + #define SLANG_EXTERN_C extern "C" #else -# define SLANG_EXTERN_C + #define SLANG_EXTERN_C #endif #ifdef __cplusplus -// C++ specific macros -// Clang -#if SLANG_CLANG -# if (__clang_major__*10 + __clang_minor__) >= 33 -# define SLANG_HAS_MOVE_SEMANTICS 1 -# define SLANG_HAS_ENUM_CLASS 1 -# define SLANG_OVERRIDE override -# endif - -// Gcc -#elif SLANG_GCC_FAMILY -// Check for C++11 -# if (__cplusplus >= 201103L) -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 -# define SLANG_HAS_MOVE_SEMANTICS 1 -# endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 -# define SLANG_HAS_ENUM_CLASS 1 -# endif -# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 -# define SLANG_OVERRIDE override -# endif -# endif -# endif // SLANG_GCC_FAMILY - -// Visual Studio - -# if SLANG_VC -// C4481: nonstandard extension used: override specifier 'override' -# if _MSC_VER < 1700 -# pragma warning(disable : 4481) -# endif -# define SLANG_OVERRIDE override -# if _MSC_VER >= 1600 -# define SLANG_HAS_MOVE_SEMANTICS 1 -# endif -# if _MSC_VER >= 1700 -# define SLANG_HAS_ENUM_CLASS 1 -# endif -# endif // SLANG_VC - -// Set non set -# ifndef SLANG_OVERRIDE -# define SLANG_OVERRIDE -# endif -# ifndef SLANG_HAS_ENUM_CLASS -# define SLANG_HAS_ENUM_CLASS 0 -# endif -# ifndef SLANG_HAS_MOVE_SEMANTICS -# define SLANG_HAS_MOVE_SEMANTICS 0 -# endif + // C++ specific macros + // Clang + #if SLANG_CLANG + #if (__clang_major__ * 10 + __clang_minor__) >= 33 + #define SLANG_HAS_MOVE_SEMANTICS 1 + #define SLANG_HAS_ENUM_CLASS 1 + #define SLANG_OVERRIDE override + #endif + + // Gcc + #elif SLANG_GCC_FAMILY + // Check for C++11 + #if (__cplusplus >= 201103L) + #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 405 + #define SLANG_HAS_MOVE_SEMANTICS 1 + #endif + #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 + #define SLANG_HAS_ENUM_CLASS 1 + #endif + #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407 + #define SLANG_OVERRIDE override + #endif + #endif + #endif // SLANG_GCC_FAMILY + + // Visual Studio + + #if SLANG_VC + // C4481: nonstandard extension used: override specifier 'override' + #if _MSC_VER < 1700 + #pragma warning(disable : 4481) + #endif + #define SLANG_OVERRIDE override + #if _MSC_VER >= 1600 + #define SLANG_HAS_MOVE_SEMANTICS 1 + #endif + #if _MSC_VER >= 1700 + #define SLANG_HAS_ENUM_CLASS 1 + #endif + #endif // SLANG_VC + + // Set non set + #ifndef SLANG_OVERRIDE + #define SLANG_OVERRIDE + #endif + #ifndef SLANG_HAS_ENUM_CLASS + #define SLANG_HAS_ENUM_CLASS 0 + #endif + #ifndef SLANG_HAS_MOVE_SEMANTICS + #define SLANG_HAS_MOVE_SEMANTICS 0 + #endif #endif // __cplusplus /* Macros for detecting processor */ #if defined(_M_ARM) || defined(__ARM_EABI__) -// This is special case for nVidia tegra -# define SLANG_PROCESSOR_ARM 1 + // This is special case for nVidia tegra + #define SLANG_PROCESSOR_ARM 1 #elif defined(__i386__) || defined(_M_IX86) -# define SLANG_PROCESSOR_X86 1 + #define SLANG_PROCESSOR_X86 1 #elif defined(_M_AMD64) || defined(_M_X64) || defined(__amd64) || defined(__x86_64) -# define SLANG_PROCESSOR_X86_64 1 + #define SLANG_PROCESSOR_X86_64 1 #elif defined(_PPC_) || defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) -# if defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) -# define SLANG_PROCESSOR_POWER_PC_64 1 -# else -# define SLANG_PROCESSOR_POWER_PC 1 -# endif + #if defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) || \ + defined(__64BIT__) || defined(_LP64) || defined(__LP64__) + #define SLANG_PROCESSOR_POWER_PC_64 1 + #else + #define SLANG_PROCESSOR_POWER_PC 1 + #endif #elif defined(__arm__) -# define SLANG_PROCESSOR_ARM 1 + #define SLANG_PROCESSOR_ARM 1 #elif defined(_M_ARM64) || defined(__aarch64__) -# define SLANG_PROCESSOR_ARM_64 1 -#endif + #define SLANG_PROCESSOR_ARM_64 1 +#elif defined(__EMSCRIPTEN__) + #define SLANG_PROCESSOR_WASM 1 +#endif #ifndef SLANG_PROCESSOR_ARM -# define SLANG_PROCESSOR_ARM 0 + #define SLANG_PROCESSOR_ARM 0 #endif #ifndef SLANG_PROCESSOR_ARM_64 -# define SLANG_PROCESSOR_ARM_64 0 + #define SLANG_PROCESSOR_ARM_64 0 #endif #ifndef SLANG_PROCESSOR_X86 -# define SLANG_PROCESSOR_X86 0 + #define SLANG_PROCESSOR_X86 0 #endif #ifndef SLANG_PROCESSOR_X86_64 -# define SLANG_PROCESSOR_X86_64 0 + #define SLANG_PROCESSOR_X86_64 0 #endif #ifndef SLANG_PROCESSOR_POWER_PC -# define SLANG_PROCESSOR_POWER_PC 0 + #define SLANG_PROCESSOR_POWER_PC 0 #endif #ifndef SLANG_PROCESSOR_POWER_PC_64 -# define SLANG_PROCESSOR_POWER_PC_64 0 + #define SLANG_PROCESSOR_POWER_PC_64 0 #endif // Processor families @@ -450,46 +456,49 @@ convention for interface methods. #define SLANG_PROCESSOR_FAMILY_POWER_PC (SLANG_PROCESSOR_POWER_PC_64 | SLANG_PROCESSOR_POWER_PC) // Pointer size -#define SLANG_PTR_IS_64 (SLANG_PROCESSOR_ARM_64 | SLANG_PROCESSOR_X86_64 | SLANG_PROCESSOR_POWER_PC_64) +#define SLANG_PTR_IS_64 \ + (SLANG_PROCESSOR_ARM_64 | SLANG_PROCESSOR_X86_64 | SLANG_PROCESSOR_POWER_PC_64) #define SLANG_PTR_IS_32 (SLANG_PTR_IS_64 ^ 1) // Processor features #if SLANG_PROCESSOR_FAMILY_X86 -# define SLANG_LITTLE_ENDIAN 1 -# define SLANG_UNALIGNED_ACCESS 1 + #define SLANG_LITTLE_ENDIAN 1 + #define SLANG_UNALIGNED_ACCESS 1 #elif SLANG_PROCESSOR_FAMILY_ARM -# if defined(__ARMEB__) -# define SLANG_BIG_ENDIAN 1 -# else -# define SLANG_LITTLE_ENDIAN 1 -# endif + #if defined(__ARMEB__) + #define SLANG_BIG_ENDIAN 1 + #else + #define SLANG_LITTLE_ENDIAN 1 + #endif #elif SLANG_PROCESSOR_FAMILY_POWER_PC -# define SLANG_BIG_ENDIAN 1 + #define SLANG_BIG_ENDIAN 1 +#elif SLANG_WASM + #define SLANG_LITTLE_ENDIAN 1 #endif #ifndef SLANG_LITTLE_ENDIAN -# define SLANG_LITTLE_ENDIAN 0 + #define SLANG_LITTLE_ENDIAN 0 #endif #ifndef SLANG_BIG_ENDIAN -# define SLANG_BIG_ENDIAN 0 + #define SLANG_BIG_ENDIAN 0 #endif #ifndef SLANG_UNALIGNED_ACCESS -# define SLANG_UNALIGNED_ACCESS 0 + #define SLANG_UNALIGNED_ACCESS 0 #endif -// One endianess must be set +// One endianness must be set #if ((SLANG_BIG_ENDIAN | SLANG_LITTLE_ENDIAN) == 0) -# error "Couldn't determine endianess" + #error "Couldn't determine endianness" #endif -#ifndef SLANG_NO_INTTYPES -#include +#ifndef SLANG_NO_INTTYPES + #include #endif // ! SLANG_NO_INTTYPES -#ifndef SLANG_NO_STDDEF -#include +#ifndef SLANG_NO_STDDEF + #include #endif // ! SLANG_NO_STDDEF #ifdef __cplusplus @@ -504,32 +513,33 @@ extern "C" @file slang.h */ - typedef uint32_t SlangUInt32; - typedef int32_t SlangInt32; + typedef uint32_t SlangUInt32; + typedef int32_t SlangInt32; // Use SLANG_PTR_ macros to determine SlangInt/SlangUInt types. - // This is used over say using size_t/ptrdiff_t/intptr_t/uintptr_t, because on some targets, these types are distinct from - // their uint_t/int_t equivalents and so produce ambiguity with function overloading. + // This is used over say using size_t/ptrdiff_t/intptr_t/uintptr_t, because on some targets, + // these types are distinct from their uint_t/int_t equivalents and so produce ambiguity with + // function overloading. // - // SlangSizeT is helpful as on some compilers size_t is distinct from a regular integer type and so overloading doesn't work. - // Casting to SlangSizeT works around this. + // SlangSizeT is helpful as on some compilers size_t is distinct from a regular integer type and + // so overloading doesn't work. Casting to SlangSizeT works around this. #if SLANG_PTR_IS_64 - typedef int64_t SlangInt; - typedef uint64_t SlangUInt; + typedef int64_t SlangInt; + typedef uint64_t SlangUInt; - typedef int64_t SlangSSizeT; - typedef uint64_t SlangSizeT; + typedef int64_t SlangSSizeT; + typedef uint64_t SlangSizeT; #else - typedef int32_t SlangInt; - typedef uint32_t SlangUInt; +typedef int32_t SlangInt; +typedef uint32_t SlangUInt; - typedef int32_t SlangSSizeT; - typedef uint32_t SlangSizeT; +typedef int32_t SlangSSizeT; +typedef uint32_t SlangSizeT; #endif typedef bool SlangBool; - + /*! @brief Severity of a diagnostic generated by the compiler. Values come from the enum below, with higher values representing more severe @@ -541,10 +551,11 @@ extern "C" { SLANG_SEVERITY_DISABLED = 0, /**< A message that is disabled, filtered out. */ SLANG_SEVERITY_NOTE, /**< An informative message. */ - SLANG_SEVERITY_WARNING, /**< A warning, which indicates a possible proble. */ + SLANG_SEVERITY_WARNING, /**< A warning, which indicates a possible problem. */ SLANG_SEVERITY_ERROR, /**< An error, indicating that compilation failed. */ - SLANG_SEVERITY_FATAL, /**< An unrecoverable error, which forced compilation to abort. */ - SLANG_SEVERITY_INTERNAL, /**< An internal error, indicating a logic error in the compiler. */ + SLANG_SEVERITY_FATAL, /**< An unrecoverable error, which forced compilation to abort. */ + SLANG_SEVERITY_INTERNAL, /**< An internal error, indicating a logic error in the compiler. + */ }; typedef int SlangDiagnosticFlags; @@ -566,11 +577,11 @@ extern "C" /* NOTE! To keep binary compatibility care is needed with this enum! - * To add value, only add at the bottom (before COUNT_OF) + * To add value, only add at the bottom (before COUNT_OF) * To remove a value, add _DEPRECATED as a suffix, but leave in the list - - This will make the enum values stable, and compatible with libraries that might not use the latest - enum values. + + This will make the enum values stable, and compatible with libraries that might not use the + latest enum values. */ typedef int SlangCompileTargetIntegral; enum SlangCompileTarget : SlangCompileTargetIntegral @@ -578,8 +589,8 @@ extern "C" SLANG_TARGET_UNKNOWN, SLANG_TARGET_NONE, SLANG_GLSL, - SLANG_GLSL_VULKAN_DEPRECATED, //< deprecated and removed: just use `SLANG_GLSL`. - SLANG_GLSL_VULKAN_ONE_DESC_DEPRECATED, //< deprecated and removed. + SLANG_GLSL_VULKAN_DEPRECATED, //< deprecated and removed: just use `SLANG_GLSL`. + SLANG_GLSL_VULKAN_ONE_DESC_DEPRECATED, //< deprecated and removed. SLANG_HLSL, SLANG_SPIRV, SLANG_SPIRV_ASM, @@ -587,23 +598,27 @@ extern "C" SLANG_DXBC_ASM, SLANG_DXIL, SLANG_DXIL_ASM, - SLANG_C_SOURCE, ///< The C language - SLANG_CPP_SOURCE, ///< C++ code for shader kernels. - SLANG_HOST_EXECUTABLE, ///< Standalone binary executable (for hosting CPU/OS) - SLANG_SHADER_SHARED_LIBRARY, ///< A shared library/Dll for shader kernels (for hosting CPU/OS) - SLANG_SHADER_HOST_CALLABLE, ///< A CPU target that makes the compiled shader code available to be run immediately - SLANG_CUDA_SOURCE, ///< Cuda source - SLANG_PTX, ///< PTX - SLANG_CUDA_OBJECT_CODE, ///< Object code that contains CUDA functions. - SLANG_OBJECT_CODE, ///< Object code that can be used for later linking - SLANG_HOST_CPP_SOURCE, ///< C++ code for host library or executable. - SLANG_HOST_HOST_CALLABLE, ///< Host callable host code (ie non kernel/shader) - SLANG_CPP_PYTORCH_BINDING, ///< C++ PyTorch binding code. - SLANG_METAL, ///< Metal shading language - SLANG_METAL_LIB, ///< Metal library - SLANG_METAL_LIB_ASM, ///< Metal library assembly - SLANG_HOST_SHARED_LIBRARY, ///< A shared library/Dll for host code (for hosting CPU/OS) - SLANG_WGSL, ///< WebGPU shading language + SLANG_C_SOURCE, ///< The C language + SLANG_CPP_SOURCE, ///< C++ code for shader kernels. + SLANG_HOST_EXECUTABLE, ///< Standalone binary executable (for hosting CPU/OS) + SLANG_SHADER_SHARED_LIBRARY, ///< A shared library/Dll for shader kernels (for hosting + ///< CPU/OS) + SLANG_SHADER_HOST_CALLABLE, ///< A CPU target that makes the compiled shader code available + ///< to be run immediately + SLANG_CUDA_SOURCE, ///< Cuda source + SLANG_PTX, ///< PTX + SLANG_CUDA_OBJECT_CODE, ///< Object code that contains CUDA functions. + SLANG_OBJECT_CODE, ///< Object code that can be used for later linking + SLANG_HOST_CPP_SOURCE, ///< C++ code for host library or executable. + SLANG_HOST_HOST_CALLABLE, ///< Host callable host code (ie non kernel/shader) + SLANG_CPP_PYTORCH_BINDING, ///< C++ PyTorch binding code. + SLANG_METAL, ///< Metal shading language + SLANG_METAL_LIB, ///< Metal library + SLANG_METAL_LIB_ASM, ///< Metal library assembly + SLANG_HOST_SHARED_LIBRARY, ///< A shared library/Dll for host code (for hosting CPU/OS) + SLANG_WGSL, ///< WebGPU shading language + SLANG_WGSL_SPIRV_ASM, ///< SPIR-V assembly via WebGPU shading language + SLANG_WGSL_SPIRV, ///< SPIR-V via WebGPU shading language SLANG_TARGET_COUNT_OF, }; @@ -629,14 +644,16 @@ extern "C" SLANG_PASS_THROUGH_DXC, SLANG_PASS_THROUGH_GLSLANG, SLANG_PASS_THROUGH_SPIRV_DIS, - SLANG_PASS_THROUGH_CLANG, ///< Clang C/C++ compiler - SLANG_PASS_THROUGH_VISUAL_STUDIO, ///< Visual studio C/C++ compiler - SLANG_PASS_THROUGH_GCC, ///< GCC C/C++ compiler - SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C or C++ compiler, which is decided by the source type - SLANG_PASS_THROUGH_NVRTC, ///< NVRTC Cuda compiler - SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' - includes LLVM and Clang - SLANG_PASS_THROUGH_SPIRV_OPT, ///< SPIRV-opt - SLANG_PASS_THROUGH_METAL, ///< Metal compiler + SLANG_PASS_THROUGH_CLANG, ///< Clang C/C++ compiler + SLANG_PASS_THROUGH_VISUAL_STUDIO, ///< Visual studio C/C++ compiler + SLANG_PASS_THROUGH_GCC, ///< GCC C/C++ compiler + SLANG_PASS_THROUGH_GENERIC_C_CPP, ///< Generic C or C++ compiler, which is decided by the + ///< source type + SLANG_PASS_THROUGH_NVRTC, ///< NVRTC Cuda compiler + SLANG_PASS_THROUGH_LLVM, ///< LLVM 'compiler' - includes LLVM and Clang + SLANG_PASS_THROUGH_SPIRV_OPT, ///< SPIRV-opt + SLANG_PASS_THROUGH_METAL, ///< Metal compiler + SLANG_PASS_THROUGH_TINT, ///< Tint WGSL compiler SLANG_PASS_THROUGH_COUNT_OF, }; @@ -646,7 +663,7 @@ extern "C" { SLANG_ARCHIVE_TYPE_UNDEFINED, SLANG_ARCHIVE_TYPE_ZIP, - SLANG_ARCHIVE_TYPE_RIFF, ///< Riff container with no compression + SLANG_ARCHIVE_TYPE_RIFF, ///< Riff container with no compression SLANG_ARCHIVE_TYPE_RIFF_DEFLATE, SLANG_ARCHIVE_TYPE_RIFF_LZ4, SLANG_ARCHIVE_TYPE_COUNT_OF, @@ -659,10 +676,10 @@ extern "C" enum { /* Do as little mangling of names as possible, to try to preserve original names */ - SLANG_COMPILE_FLAG_NO_MANGLING = 1 << 3, + SLANG_COMPILE_FLAG_NO_MANGLING = 1 << 3, /* Skip code generation step, just check the code and generate layout */ - SLANG_COMPILE_FLAG_NO_CODEGEN = 1 << 4, + SLANG_COMPILE_FLAG_NO_CODEGEN = 1 << 4, /* Obfuscate shader names on release products */ SLANG_COMPILE_FLAG_OBFUSCATE = 1 << 5, @@ -670,14 +687,14 @@ extern "C" /* Deprecated flags: kept around to allow existing applications to compile. Note that the relevant features will still be left in their default state. */ - SLANG_COMPILE_FLAG_NO_CHECKING = 0, - SLANG_COMPILE_FLAG_SPLIT_MIXED_TYPES = 0, + SLANG_COMPILE_FLAG_NO_CHECKING = 0, + SLANG_COMPILE_FLAG_SPLIT_MIXED_TYPES = 0, }; /*! @brief Flags to control code generation behavior of a compilation target */ typedef unsigned int SlangTargetFlags; - enum + enum { /* When compiling for a D3D Shader Model 5.1 or higher target, allocate distinct register spaces for parameter blocks. @@ -696,9 +713,11 @@ extern "C" SLANG_TARGET_FLAG_DUMP_IR = 1 << 9, /* When set, will generate SPIRV directly rather than via glslang. */ + // This flag will be deprecated, use CompilerOption instead. SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY = 1 << 10, }; - constexpr static SlangTargetFlags kDefaultTargetFlags = SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY; + constexpr static SlangTargetFlags kDefaultTargetFlags = + SLANG_TARGET_FLAG_GENERATE_SPIRV_DIRECTLY; /*! @brief Options to control floating-point precision guarantees for a target. @@ -717,11 +736,14 @@ extern "C" typedef unsigned int SlangLineDirectiveModeIntegral; enum SlangLineDirectiveMode : SlangLineDirectiveModeIntegral { - SLANG_LINE_DIRECTIVE_MODE_DEFAULT = 0, /**< Default behavior: pick behavior base on target. */ - SLANG_LINE_DIRECTIVE_MODE_NONE, /**< Don't emit line directives at all. */ - SLANG_LINE_DIRECTIVE_MODE_STANDARD, /**< Emit standard C-style `#line` directives. */ - SLANG_LINE_DIRECTIVE_MODE_GLSL, /**< Emit GLSL-style directives with file *number* instead of name */ - SLANG_LINE_DIRECTIVE_MODE_SOURCE_MAP, /**< Use a source map to track line mappings (ie no #line will appear in emitting source) */ + SLANG_LINE_DIRECTIVE_MODE_DEFAULT = + 0, /**< Default behavior: pick behavior base on target. */ + SLANG_LINE_DIRECTIVE_MODE_NONE, /**< Don't emit line directives at all. */ + SLANG_LINE_DIRECTIVE_MODE_STANDARD, /**< Emit standard C-style `#line` directives. */ + SLANG_LINE_DIRECTIVE_MODE_GLSL, /**< Emit GLSL-style directives with file *number* instead + of name */ + SLANG_LINE_DIRECTIVE_MODE_SOURCE_MAP, /**< Use a source map to track line mappings (ie no + #line will appear in emitting source) */ }; typedef int SlangSourceLanguageIntegral; @@ -787,24 +809,28 @@ extern "C" typedef SlangUInt32 SlangDebugInfoLevelIntegral; enum SlangDebugInfoLevel : SlangDebugInfoLevelIntegral { - SLANG_DEBUG_INFO_LEVEL_NONE = 0, /**< Don't emit debug information at all. */ - SLANG_DEBUG_INFO_LEVEL_MINIMAL, /**< Emit as little debug information as possible, while still supporting stack trackes. */ - SLANG_DEBUG_INFO_LEVEL_STANDARD, /**< Emit whatever is the standard level of debug information for each target. */ - SLANG_DEBUG_INFO_LEVEL_MAXIMAL, /**< Emit as much debug infromation as possible for each target. */ - + SLANG_DEBUG_INFO_LEVEL_NONE = 0, /**< Don't emit debug information at all. */ + SLANG_DEBUG_INFO_LEVEL_MINIMAL, /**< Emit as little debug information as possible, while + still supporting stack trackers. */ + SLANG_DEBUG_INFO_LEVEL_STANDARD, /**< Emit whatever is the standard level of debug + information for each target. */ + SLANG_DEBUG_INFO_LEVEL_MAXIMAL, /**< Emit as much debug information as possible for each + target. */ }; /* Describes the debugging information format produced during a compilation. */ typedef SlangUInt32 SlangDebugInfoFormatIntegral; enum SlangDebugInfoFormat : SlangDebugInfoFormatIntegral { - SLANG_DEBUG_INFO_FORMAT_DEFAULT, ///< Use the default debugging format for the target - SLANG_DEBUG_INFO_FORMAT_C7, ///< CodeView C7 format (typically means debugging infomation is embedded in the binary) - SLANG_DEBUG_INFO_FORMAT_PDB, ///< Program database - - SLANG_DEBUG_INFO_FORMAT_STABS, ///< Stabs - SLANG_DEBUG_INFO_FORMAT_COFF, ///< COFF debug info - SLANG_DEBUG_INFO_FORMAT_DWARF, ///< DWARF debug info (we may want to support specifying the version) + SLANG_DEBUG_INFO_FORMAT_DEFAULT, ///< Use the default debugging format for the target + SLANG_DEBUG_INFO_FORMAT_C7, ///< CodeView C7 format (typically means debugging information + ///< is embedded in the binary) + SLANG_DEBUG_INFO_FORMAT_PDB, ///< Program database + + SLANG_DEBUG_INFO_FORMAT_STABS, ///< Stabs + SLANG_DEBUG_INFO_FORMAT_COFF, ///< COFF debug info + SLANG_DEBUG_INFO_FORMAT_DWARF, ///< DWARF debug info (we may want to support specifying the + ///< version) SLANG_DEBUG_INFO_FORMAT_COUNT_OF, }; @@ -812,191 +838,210 @@ extern "C" typedef SlangUInt32 SlangOptimizationLevelIntegral; enum SlangOptimizationLevel : SlangOptimizationLevelIntegral { - SLANG_OPTIMIZATION_LEVEL_NONE = 0, /**< Don't optimize at all. */ - SLANG_OPTIMIZATION_LEVEL_DEFAULT, /**< Default optimization level: balance code quality and compilation time. */ - SLANG_OPTIMIZATION_LEVEL_HIGH, /**< Optimize aggressively. */ - SLANG_OPTIMIZATION_LEVEL_MAXIMAL, /**< Include optimizations that may take a very long time, or may involve severe space-vs-speed tradeoffs */ + SLANG_OPTIMIZATION_LEVEL_NONE = 0, /**< Don't optimize at all. */ + SLANG_OPTIMIZATION_LEVEL_DEFAULT, /**< Default optimization level: balance code quality and + compilation time. */ + SLANG_OPTIMIZATION_LEVEL_HIGH, /**< Optimize aggressively. */ + SLANG_OPTIMIZATION_LEVEL_MAXIMAL, /**< Include optimizations that may take a very long time, + or may involve severe space-vs-speed tradeoffs */ + }; + + enum SlangEmitSpirvMethod + { + SLANG_EMIT_SPIRV_DEFAULT = 0, + SLANG_EMIT_SPIRV_VIA_GLSL, + SLANG_EMIT_SPIRV_DIRECTLY, }; // All compiler option names supported by Slang. namespace slang { - enum class CompilerOptionName - { - MacroDefine, // stringValue0: macro name; stringValue1: macro value - DepFile, - EntryPointName, - Specialize, - Help, - HelpStyle, - Include, // stringValue: additional include path. - Language, - MatrixLayoutColumn, // bool - MatrixLayoutRow, // bool - ZeroInitialize, // bool - IgnoreCapabilities, // bool - RestrictiveCapabilityCheck, // bool - ModuleName, // stringValue0: module name. - Output, - Profile, // intValue0: profile - Stage, // intValue0: stage - Target, // intValue0: CodeGenTarget - Version, - WarningsAsErrors, // stringValue0: "all" or comma separated list of warning codes or names. - DisableWarnings, // stringValue0: comma separated list of warning codes or names. - EnableWarning, // stringValue0: warning code or name. - DisableWarning, // stringValue0: warning code or name. - DumpWarningDiagnostics, - InputFilesRemain, - EmitIr, // bool - ReportDownstreamTime, // bool - ReportPerfBenchmark, // bool - SkipSPIRVValidation, // bool - SourceEmbedStyle, - SourceEmbedName, - SourceEmbedLanguage, - DisableShortCircuit, // bool - MinimumSlangOptimization, // bool - DisableNonEssentialValidations, // bool - DisableSourceMap, // bool - UnscopedEnum, // bool - PreserveParameters, // bool: preserve all resource parameters in the output code. - - // Target - - Capability, // intValue0: CapabilityName - DefaultImageFormatUnknown, // bool - DisableDynamicDispatch, // bool - DisableSpecialization, // bool - FloatingPointMode, // intValue0: FloatingPointMode - DebugInformation, // intValue0: DebugInfoLevel - LineDirectiveMode, - Optimization, // intValue0: OptimizationLevel - Obfuscate, // bool - - VulkanBindShift, // intValue0 (higher 8 bits): kind; intValue0(lower bits): set; intValue1: shift - VulkanBindGlobals, // intValue0: index; intValue1: set - VulkanInvertY, // bool - VulkanUseDxPositionW, // bool - VulkanUseEntryPointName, // bool - VulkanUseGLLayout, // bool - VulkanEmitReflection, // bool - - GLSLForceScalarLayout, // bool - EnableEffectAnnotations, // bool - - EmitSpirvViaGLSL, // bool - EmitSpirvDirectly, // bool - SPIRVCoreGrammarJSON, // stringValue0: json path - IncompleteLibrary, // bool, when set, will not issue an error when the linked program has unresolved extern function symbols. - - // Downstream - - CompilerPath, - DefaultDownstreamCompiler, - DownstreamArgs, // stringValue0: downstream compiler name. stringValue1: argument list, one per line. - PassThrough, - - // Repro - - DumpRepro, - DumpReproOnError, - ExtractRepro, - LoadRepro, - LoadReproDirectory, - ReproFallbackDirectory, - - // Debugging - - DumpAst, - DumpIntermediatePrefix, - DumpIntermediates, // bool - DumpIr, // bool - DumpIrIds, - PreprocessorOutput, - OutputIncludes, - ReproFileSystem, - SerialIr, // bool - SkipCodeGen, // bool - ValidateIr, // bool - VerbosePaths, - VerifyDebugSerialIr, - NoCodeGen, // Not used. - - // Experimental - - FileSystem, - Heterogeneous, - NoMangle, - NoHLSLBinding, - NoHLSLPackConstantBufferElements, - ValidateUniformity, - AllowGLSL, - EnableExperimentalPasses, - - // Internal - - ArchiveType, - CompileStdLib, - Doc, - IrCompression, - LoadStdLib, - ReferenceModule, - SaveStdLib, - SaveStdLibBinSource, - TrackLiveness, - LoopInversion, // bool, enable loop inversion optimization - - // Deprecated - ParameterBlocksUseRegisterSpaces, - - CountOfParsableOptions, - - // Used in parsed options only. - DebugInformationFormat, // intValue0: DebugInfoFormat - VulkanBindShiftAll, // intValue0: kind; intValue1: shift - GenerateWholeProgram, // bool - UseUpToDateBinaryModule, // bool, when set, will only load - // precompiled modules if it is up-to-date with its source. - EmbedDownstreamIR, // bool - ForceDXLayout, // bool - CountOf, - }; + enum class CompilerOptionName + { + MacroDefine, // stringValue0: macro name; stringValue1: macro value + DepFile, + EntryPointName, + Specialize, + Help, + HelpStyle, + Include, // stringValue: additional include path. + Language, + MatrixLayoutColumn, // bool + MatrixLayoutRow, // bool + ZeroInitialize, // bool + IgnoreCapabilities, // bool + RestrictiveCapabilityCheck, // bool + ModuleName, // stringValue0: module name. + Output, + Profile, // intValue0: profile + Stage, // intValue0: stage + Target, // intValue0: CodeGenTarget + Version, + WarningsAsErrors, // stringValue0: "all" or comma separated list of warning codes or names. + DisableWarnings, // stringValue0: comma separated list of warning codes or names. + EnableWarning, // stringValue0: warning code or name. + DisableWarning, // stringValue0: warning code or name. + DumpWarningDiagnostics, + InputFilesRemain, + EmitIr, // bool + ReportDownstreamTime, // bool + ReportPerfBenchmark, // bool + ReportCheckpointIntermediates, // bool + SkipSPIRVValidation, // bool + SourceEmbedStyle, + SourceEmbedName, + SourceEmbedLanguage, + DisableShortCircuit, // bool + MinimumSlangOptimization, // bool + DisableNonEssentialValidations, // bool + DisableSourceMap, // bool + UnscopedEnum, // bool + PreserveParameters, // bool: preserve all resource parameters in the output code. + + // Target + + Capability, // intValue0: CapabilityName + DefaultImageFormatUnknown, // bool + DisableDynamicDispatch, // bool + DisableSpecialization, // bool + FloatingPointMode, // intValue0: FloatingPointMode + DebugInformation, // intValue0: DebugInfoLevel + LineDirectiveMode, + Optimization, // intValue0: OptimizationLevel + Obfuscate, // bool + + VulkanBindShift, // intValue0 (higher 8 bits): kind; intValue0(lower bits): set; intValue1: + // shift + VulkanBindGlobals, // intValue0: index; intValue1: set + VulkanInvertY, // bool + VulkanUseDxPositionW, // bool + VulkanUseEntryPointName, // bool + VulkanUseGLLayout, // bool + VulkanEmitReflection, // bool + + GLSLForceScalarLayout, // bool + EnableEffectAnnotations, // bool + + EmitSpirvViaGLSL, // bool (will be deprecated) + EmitSpirvDirectly, // bool (will be deprecated) + SPIRVCoreGrammarJSON, // stringValue0: json path + IncompleteLibrary, // bool, when set, will not issue an error when the linked program has + // unresolved extern function symbols. + + // Downstream + + CompilerPath, + DefaultDownstreamCompiler, + DownstreamArgs, // stringValue0: downstream compiler name. stringValue1: argument list, one + // per line. + PassThrough, + + // Repro + + DumpRepro, + DumpReproOnError, + ExtractRepro, + LoadRepro, + LoadReproDirectory, + ReproFallbackDirectory, + + // Debugging + + DumpAst, + DumpIntermediatePrefix, + DumpIntermediates, // bool + DumpIr, // bool + DumpIrIds, + PreprocessorOutput, + OutputIncludes, + ReproFileSystem, + SerialIr, // bool + SkipCodeGen, // bool + ValidateIr, // bool + VerbosePaths, + VerifyDebugSerialIr, + NoCodeGen, // Not used. + + // Experimental + + FileSystem, + Heterogeneous, + NoMangle, + NoHLSLBinding, + NoHLSLPackConstantBufferElements, + ValidateUniformity, + AllowGLSL, + EnableExperimentalPasses, + + // Internal + + ArchiveType, + CompileCoreModule, + Doc, + IrCompression, + LoadCoreModule, + ReferenceModule, + SaveCoreModule, + SaveCoreModuleBinSource, + TrackLiveness, + LoopInversion, // bool, enable loop inversion optimization + + // Deprecated + ParameterBlocksUseRegisterSpaces, + + CountOfParsableOptions, + + // Used in parsed options only. + DebugInformationFormat, // intValue0: DebugInfoFormat + VulkanBindShiftAll, // intValue0: kind; intValue1: shift + GenerateWholeProgram, // bool + UseUpToDateBinaryModule, // bool, when set, will only load + // precompiled modules if it is up-to-date with its source. + EmbedDownstreamIR, // bool + ForceDXLayout, // bool + + // Add this new option to the end of the list to avoid breaking ABI as much as possible. + // Setting of EmitSpirvDirectly or EmitSpirvViaGLSL will turn into this option internally. + EmitSpirvMethod, // enum SlangEmitSpirvMethod + + EmitReflectionJSON, // bool + CountOf, + }; - enum class CompilerOptionValueKind - { - Int, - String - }; + enum class CompilerOptionValueKind + { + Int, + String + }; - struct CompilerOptionValue - { - CompilerOptionValueKind kind = CompilerOptionValueKind::Int; - int32_t intValue0 = 0; - int32_t intValue1 = 0; - const char* stringValue0 = nullptr; - const char* stringValue1 = nullptr; - }; + struct CompilerOptionValue + { + CompilerOptionValueKind kind = CompilerOptionValueKind::Int; + int32_t intValue0 = 0; + int32_t intValue1 = 0; + const char* stringValue0 = nullptr; + const char* stringValue1 = nullptr; + }; - struct CompilerOptionEntry - { - CompilerOptionName name; - CompilerOptionValue value; - }; - } + struct CompilerOptionEntry + { + CompilerOptionName name; + CompilerOptionValue value; + }; + } // namespace slang /** A result code for a Slang API operation. - This type is generally compatible with the Windows API `HRESULT` type. In particular, negative values indicate - failure results, while zero or positive results indicate success. + This type is generally compatible with the Windows API `HRESULT` type. In particular, negative + values indicate failure results, while zero or positive results indicate success. - In general, Slang APIs always return a zero result on success, unless documented otherwise. Strictly speaking - a negative value indicates an error, a positive (or 0) value indicates success. This can be tested for with the macros - SLANG_SUCCEEDED(x) or SLANG_FAILED(x). + In general, Slang APIs always return a zero result on success, unless documented otherwise. + Strictly speaking a negative value indicates an error, a positive (or 0) value indicates + success. This can be tested for with the macros SLANG_SUCCEEDED(x) or SLANG_FAILED(x). - It can represent if the call was successful or not. It can also specify in an extensible manner what facility - produced the result (as the integral 'facility') as well as what caused it (as an integral 'code'). - Under the covers SlangResult is represented as a int32_t. + It can represent if the call was successful or not. It can also specify in an extensible manner + what facility produced the result (as the integral 'facility') as well as what caused it (as an + integral 'code'). Under the covers SlangResult is represented as a int32_t. SlangResult is designed to be compatible with COM HRESULT. @@ -1006,8 +1051,9 @@ extern "C" ---------|----------|----- 31 | 30-16 | 15-0 - Severity - 1 fail, 0 is success - as SlangResult is signed 32 bits, means negative number indicates failure. - Facility is where the error originated from. Code is the code specific to the facility. + Severity - 1 fail, 0 is success - as SlangResult is signed 32 bits, means negative number + indicates failure. Facility is where the error originated from. Code is the code specific to the + facility. Result codes have the following styles, 1) SLANG_name @@ -1019,41 +1065,48 @@ extern "C" Style 1 is reserved for SLANG_OK and SLANG_FAIL as they are so commonly used. - It is acceptable to expand 'f' to a longer name to differentiate a name or drop if unique without it. - ie for a facility 'DRIVER' it might make sense to have an error of the form SLANG_E_DRIVER_OUT_OF_MEMORY + It is acceptable to expand 'f' to a longer name to differentiate a name or drop if unique + without it. ie for a facility 'DRIVER' it might make sense to have an error of the form + SLANG_E_DRIVER_OUT_OF_MEMORY */ typedef int32_t SlangResult; - //! Use to test if a result was failure. Never use result != SLANG_OK to test for failure, as there may be successful codes != SLANG_OK. + //! Use to test if a result was failure. Never use result != SLANG_OK to test for failure, as + //! there may be successful codes != SLANG_OK. #define SLANG_FAILED(status) ((status) < 0) - //! Use to test if a result succeeded. Never use result == SLANG_OK to test for success, as will detect other successful codes as a failure. + //! Use to test if a result succeeded. Never use result == SLANG_OK to test for success, as will + //! detect other successful codes as a failure. #define SLANG_SUCCEEDED(status) ((status) >= 0) //! Get the facility the result is associated with -#define SLANG_GET_RESULT_FACILITY(r) ((int32_t)(((r) >> 16) & 0x7fff)) +#define SLANG_GET_RESULT_FACILITY(r) ((int32_t)(((r) >> 16) & 0x7fff)) //! Get the result code for the facility -#define SLANG_GET_RESULT_CODE(r) ((int32_t)((r) & 0xffff)) +#define SLANG_GET_RESULT_CODE(r) ((int32_t)((r) & 0xffff)) -#define SLANG_MAKE_ERROR(fac, code) ((((int32_t)(fac)) << 16) | ((int32_t)(code)) | int32_t(0x80000000)) -#define SLANG_MAKE_SUCCESS(fac, code) ((((int32_t)(fac)) << 16) | ((int32_t)(code))) +#define SLANG_MAKE_ERROR(fac, code) \ + ((((int32_t)(fac)) << 16) | ((int32_t)(code)) | int32_t(0x80000000)) +#define SLANG_MAKE_SUCCESS(fac, code) ((((int32_t)(fac)) << 16) | ((int32_t)(code))) /*************************** Facilities ************************************/ //! Facilities compatible with windows COM - only use if known code is compatible -#define SLANG_FACILITY_WIN_GENERAL 0 -#define SLANG_FACILITY_WIN_INTERFACE 4 -#define SLANG_FACILITY_WIN_API 7 - - //! Base facility -> so as to not clash with HRESULT values (values in 0x200 range do not appear used) -#define SLANG_FACILITY_BASE 0x200 - - /*! Facilities numbers must be unique across a project to make the resulting result a unique number. - It can be useful to have a consistent short name for a facility, as used in the name prefix */ -#define SLANG_FACILITY_CORE SLANG_FACILITY_BASE - /* Facility for codes, that are not uniquely defined/protected. Can be used to pass back a specific error without requiring system wide facility uniqueness. Codes - should never be part of a public API. */ -#define SLANG_FACILITY_INTERNAL SLANG_FACILITY_BASE + 1 +#define SLANG_FACILITY_WIN_GENERAL 0 +#define SLANG_FACILITY_WIN_INTERFACE 4 +#define SLANG_FACILITY_WIN_API 7 + + //! Base facility -> so as to not clash with HRESULT values (values in 0x200 range do not appear + //! used) +#define SLANG_FACILITY_BASE 0x200 + + /*! Facilities numbers must be unique across a project to make the resulting result a unique + number. It can be useful to have a consistent short name for a facility, as used in the name + prefix */ +#define SLANG_FACILITY_CORE SLANG_FACILITY_BASE + /* Facility for codes, that are not uniquely defined/protected. Can be used to pass back a + specific error without requiring system wide facility uniqueness. Codes should never be part of + a public API. */ +#define SLANG_FACILITY_INTERNAL SLANG_FACILITY_BASE + 1 /// Base for external facilities. Facilities should be unique across modules. #define SLANG_FACILITY_EXTERNAL_BASE 0x210 @@ -1061,48 +1114,52 @@ extern "C" /* ************************ Win COM compatible Results ******************************/ // https://msdn.microsoft.com/en-us/library/windows/desktop/aa378137(v=vs.85).aspx - //! SLANG_OK indicates success, and is equivalent to SLANG_MAKE_SUCCESS(SLANG_FACILITY_WIN_GENERAL, 0) -#define SLANG_OK 0 - //! SLANG_FAIL is the generic failure code - meaning a serious error occurred and the call couldn't complete -#define SLANG_FAIL SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_GENERAL, 0x4005) + //! SLANG_OK indicates success, and is equivalent to + //! SLANG_MAKE_SUCCESS(SLANG_FACILITY_WIN_GENERAL, 0) +#define SLANG_OK 0 + //! SLANG_FAIL is the generic failure code - meaning a serious error occurred and the call + //! couldn't complete +#define SLANG_FAIL SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_GENERAL, 0x4005) -#define SLANG_MAKE_WIN_GENERAL_ERROR(code) SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_GENERAL, code) +#define SLANG_MAKE_WIN_GENERAL_ERROR(code) SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_GENERAL, code) //! Functionality is not implemented -#define SLANG_E_NOT_IMPLEMENTED SLANG_MAKE_WIN_GENERAL_ERROR(0x4001) +#define SLANG_E_NOT_IMPLEMENTED SLANG_MAKE_WIN_GENERAL_ERROR(0x4001) //! Interface not be found -#define SLANG_E_NO_INTERFACE SLANG_MAKE_WIN_GENERAL_ERROR(0x4002) +#define SLANG_E_NO_INTERFACE SLANG_MAKE_WIN_GENERAL_ERROR(0x4002) //! Operation was aborted (did not correctly complete) -#define SLANG_E_ABORT SLANG_MAKE_WIN_GENERAL_ERROR(0x4004) +#define SLANG_E_ABORT SLANG_MAKE_WIN_GENERAL_ERROR(0x4004) //! Indicates that a handle passed in as parameter to a method is invalid. -#define SLANG_E_INVALID_HANDLE SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 6) +#define SLANG_E_INVALID_HANDLE SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 6) //! Indicates that an argument passed in as parameter to a method is invalid. -#define SLANG_E_INVALID_ARG SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 0x57) +#define SLANG_E_INVALID_ARG SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 0x57) //! Operation could not complete - ran out of memory -#define SLANG_E_OUT_OF_MEMORY SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 0xe) +#define SLANG_E_OUT_OF_MEMORY SLANG_MAKE_ERROR(SLANG_FACILITY_WIN_API, 0xe) /* *************************** other Results **************************************/ -#define SLANG_MAKE_CORE_ERROR(code) SLANG_MAKE_ERROR(SLANG_FACILITY_CORE, code) +#define SLANG_MAKE_CORE_ERROR(code) SLANG_MAKE_ERROR(SLANG_FACILITY_CORE, code) // Supplied buffer is too small to be able to complete -#define SLANG_E_BUFFER_TOO_SMALL SLANG_MAKE_CORE_ERROR(1) +#define SLANG_E_BUFFER_TOO_SMALL SLANG_MAKE_CORE_ERROR(1) //! Used to identify a Result that has yet to be initialized. - //! It defaults to failure such that if used incorrectly will fail, as similar in concept to using an uninitialized variable. -#define SLANG_E_UNINITIALIZED SLANG_MAKE_CORE_ERROR(2) - //! Returned from an async method meaning the output is invalid (thus an error), but a result for the request is pending, and will be returned on a subsequent call with the async handle. -#define SLANG_E_PENDING SLANG_MAKE_CORE_ERROR(3) + //! It defaults to failure such that if used incorrectly will fail, as similar in concept to + //! using an uninitialized variable. +#define SLANG_E_UNINITIALIZED SLANG_MAKE_CORE_ERROR(2) + //! Returned from an async method meaning the output is invalid (thus an error), but a result + //! for the request is pending, and will be returned on a subsequent call with the async handle. +#define SLANG_E_PENDING SLANG_MAKE_CORE_ERROR(3) //! Indicates a file/resource could not be opened -#define SLANG_E_CANNOT_OPEN SLANG_MAKE_CORE_ERROR(4) +#define SLANG_E_CANNOT_OPEN SLANG_MAKE_CORE_ERROR(4) //! Indicates a file/resource could not be found -#define SLANG_E_NOT_FOUND SLANG_MAKE_CORE_ERROR(5) +#define SLANG_E_NOT_FOUND SLANG_MAKE_CORE_ERROR(5) //! An unhandled internal failure (typically from unhandled exception) -#define SLANG_E_INTERNAL_FAIL SLANG_MAKE_CORE_ERROR(6) - //! Could not complete because some underlying feature (hardware or software) was not available -#define SLANG_E_NOT_AVAILABLE SLANG_MAKE_CORE_ERROR(7) - //! Could not complete because the operation times out. -#define SLANG_E_TIME_OUT SLANG_MAKE_CORE_ERROR(8) +#define SLANG_E_INTERNAL_FAIL SLANG_MAKE_CORE_ERROR(6) + //! Could not complete because some underlying feature (hardware or software) was not available +#define SLANG_E_NOT_AVAILABLE SLANG_MAKE_CORE_ERROR(7) + //! Could not complete because the operation times out. +#define SLANG_E_TIME_OUT SLANG_MAKE_CORE_ERROR(8) /** A "Universally Unique Identifier" (UUID) @@ -1118,40 +1175,47 @@ extern "C" uint32_t data1; uint16_t data2; uint16_t data3; - uint8_t data4[8]; + uint8_t data4[8]; }; // Place at the start of an interface with the guid. -// Guid should be specified as SLANG_COM_INTERFACE(0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }) -// NOTE: it's the typical guid struct definition, without the surrounding {} -// It is not necessary to use the multiple parameters (we can wrap in parens), but this is simple. +// Guid should be specified as SLANG_COM_INTERFACE(0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, +// 0x00, 0x00, 0x00, 0x00, 0x46 }) NOTE: it's the typical guid struct definition, without the +// surrounding {} It is not necessary to use the multiple parameters (we can wrap in parens), but +// this is simple. #define SLANG_COM_INTERFACE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - public: \ - SLANG_FORCE_INLINE constexpr static SlangUUID getTypeGuid() \ - { \ - return { a, b, c, d0, d1, d2, d3, d4, d5, d6, d7 }; \ +public: \ + SLANG_FORCE_INLINE constexpr static SlangUUID getTypeGuid() \ + { \ + return {a, b, c, d0, d1, d2, d3, d4, d5, d6, d7}; \ } -// Sometimes it's useful to associate a guid with a class to identify it. This macro can used for this, -// and the guid extracted via the getTypeGuid() function defined in the type +// Sometimes it's useful to associate a guid with a class to identify it. This macro can used for +// this, and the guid extracted via the getTypeGuid() function defined in the type #define SLANG_CLASS_GUID(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - SLANG_FORCE_INLINE constexpr static SlangUUID getTypeGuid() \ - { \ - return { a, b, c, d0, d1, d2, d3, d4, d5, d6, d7 }; \ + SLANG_FORCE_INLINE constexpr static SlangUUID getTypeGuid() \ + { \ + return {a, b, c, d0, d1, d2, d3, d4, d5, d6, d7}; \ } // Helper to fill in pairs of GUIDs and return pointers. This ensures that the // type of the GUID passed matches the pointer type, and that it is derived // from ISlangUnknown, -// TODO(c++20): would is_derived_from be more appropriate here for private inheritance of ISlangUnknown? +// TODO(c++20): would is_derived_from be more appropriate here for private inheritance of +// ISlangUnknown? // // with : void createFoo(SlangUUID, void**); // Slang::ComPtr myBar; // call with: createFoo(SLANG_IID_PPV_ARGS(myBar.writeRef())) // to call : createFoo(Bar::getTypeGuid(), (void**)(myBar.writeRef())) -#define SLANG_IID_PPV_ARGS(ppType) \ - std::decay_t::getTypeGuid(), \ - ((void)[]{static_assert(std::is_base_of_v>);}, reinterpret_cast(ppType)) +#define SLANG_IID_PPV_ARGS(ppType) \ + std::decay_t::getTypeGuid(), \ + ( \ + (void)[] { \ + static_assert( \ + std::is_base_of_v>); \ + }, \ + reinterpret_cast(ppType)) /** Base interface for components exchanged through the API. @@ -1162,9 +1226,14 @@ extern "C" */ struct ISlangUnknown { - SLANG_COM_INTERFACE(0x00000000, 0x0000, 0x0000, { 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 }) + SLANG_COM_INTERFACE( + 0x00000000, + 0x0000, + 0x0000, + {0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46}) - virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + queryInterface(SlangUUID const& uuid, void** outObject) = 0; virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() = 0; virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() = 0; @@ -1172,33 +1241,44 @@ extern "C" Inline methods are provided to allow the above operations to be called using their traditional COM names/signatures: */ - SlangResult QueryInterface(struct _GUID const& uuid, void** outObject) { return queryInterface(*(SlangUUID const*)&uuid, outObject); } + SlangResult QueryInterface(struct _GUID const& uuid, void** outObject) + { + return queryInterface(*(SlangUUID const*)&uuid, outObject); + } uint32_t AddRef() { return addRef(); } uint32_t Release() { return release(); } }; - #define SLANG_UUID_ISlangUnknown ISlangUnknown::getTypeGuid() +#define SLANG_UUID_ISlangUnknown ISlangUnknown::getTypeGuid() /* An interface to provide a mechanism to cast, that doesn't require ref counting and doesn't have to return a pointer to a ISlangUnknown derived class */ class ISlangCastable : public ISlangUnknown { - SLANG_COM_INTERFACE(0x87ede0e1, 0x4852, 0x44b0, { 0x8b, 0xf2, 0xcb, 0x31, 0x87, 0x4d, 0xe2, 0x39 }); - - /// Can be used to cast to interfaces without reference counting. - /// Also provides access to internal implementations, when they provide a guid - /// Can simulate a 'generated' interface as long as kept in scope by cast from. + SLANG_COM_INTERFACE( + 0x87ede0e1, + 0x4852, + 0x44b0, + {0x8b, 0xf2, 0xcb, 0x31, 0x87, 0x4d, 0xe2, 0x39}); + + /// Can be used to cast to interfaces without reference counting. + /// Also provides access to internal implementations, when they provide a guid + /// Can simulate a 'generated' interface as long as kept in scope by cast from. virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) = 0; }; class ISlangClonable : public ISlangCastable { - SLANG_COM_INTERFACE(0x1ec36168, 0xe9f4, 0x430d, { 0xbb, 0x17, 0x4, 0x8a, 0x80, 0x46, 0xb3, 0x1f }); - - /// Note the use of guid is for the desired interface/object. - /// The object is returned *not* ref counted. Any type that can implements the interface, - /// derives from ICastable, and so (not withstanding some other issue) will always return - /// an ICastable interface which other interfaces/types are accessible from via castAs + SLANG_COM_INTERFACE( + 0x1ec36168, + 0xe9f4, + 0x430d, + {0xbb, 0x17, 0x4, 0x8a, 0x80, 0x46, 0xb3, 0x1f}); + + /// Note the use of guid is for the desired interface/object. + /// The object is returned *not* ref counted. Any type that can implements the interface, + /// derives from ICastable, and so (not withstanding some other issue) will always return + /// an ICastable interface which other interfaces/types are accessible from via castAs SLANG_NO_THROW virtual void* SLANG_MCALL clone(const SlangUUID& guid) = 0; }; @@ -1208,18 +1288,27 @@ extern "C" */ struct ISlangBlob : public ISlangUnknown { - SLANG_COM_INTERFACE(0x8BA5FB08, 0x5195, 0x40e2, { 0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02 }) + SLANG_COM_INTERFACE( + 0x8BA5FB08, + 0x5195, + 0x40e2, + {0xAC, 0x58, 0x0D, 0x98, 0x9C, 0x3A, 0x01, 0x02}) virtual SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() = 0; virtual SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() = 0; }; - #define SLANG_UUID_ISlangBlob ISlangBlob::getTypeGuid() +#define SLANG_UUID_ISlangBlob ISlangBlob::getTypeGuid() - /* Can be requested from ISlangCastable cast to indicate the contained chars are null terminated. - */ + /* Can be requested from ISlangCastable cast to indicate the contained chars are null + * terminated. + */ struct SlangTerminatedChars { - SLANG_CLASS_GUID(0xbe0db1a8, 0x3594, 0x4603, { 0xa7, 0x8b, 0xc4, 0x86, 0x84, 0x30, 0xdf, 0xbb }); + SLANG_CLASS_GUID( + 0xbe0db1a8, + 0x3594, + 0x4603, + {0xa7, 0x8b, 0xc4, 0x86, 0x84, 0x30, 0xdf, 0xbb}); operator const char*() const { return chars; } char chars[1]; }; @@ -1230,14 +1319,18 @@ extern "C" from disk, allowing applications to hook and/or override filesystem access from the compiler. - It is the responsibility of - the caller of any method that returns a ISlangBlob to release the blob when it is no + It is the responsibility of + the caller of any method that returns a ISlangBlob to release the blob when it is no longer used (using 'release'). */ struct ISlangFileSystem : public ISlangCastable { - SLANG_COM_INTERFACE(0x003A09FC, 0x3A4D, 0x4BA0, { 0xAD, 0x60, 0x1F, 0xD8, 0x63, 0xA9, 0x15, 0xAB }) + SLANG_COM_INTERFACE( + 0x003A09FC, + 0x3A4D, + 0x4BA0, + {0xAD, 0x60, 0x1F, 0xD8, 0x63, 0xA9, 0x15, 0xAB}) /** Load a file from `path` and return a blob of its contents @param path The path to load from, as a null-terminated UTF-8 string. @@ -1245,45 +1338,55 @@ extern "C" @returns A `SlangResult` to indicate success or failure in loading the file. NOTE! This is a *binary* load - the blob should contain the exact same bytes - as are found in the backing file. + as are found in the backing file. If load is successful, the implementation should create a blob to hold the file's content, store it to `outBlob`, and return 0. If the load fails, the implementation should return a failure status (any negative value will do). */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadFile( - char const* path, - ISlangBlob** outBlob) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadFile(char const* path, ISlangBlob** outBlob) = 0; }; - #define SLANG_UUID_ISlangFileSystem ISlangFileSystem::getTypeGuid() +#define SLANG_UUID_ISlangFileSystem ISlangFileSystem::getTypeGuid() - typedef void(*SlangFuncPtr)(void); + typedef void (*SlangFuncPtr)(void); - /** + /** (DEPRECATED) ISlangSharedLibrary */ - struct ISlangSharedLibrary_Dep1: public ISlangUnknown + struct ISlangSharedLibrary_Dep1 : public ISlangUnknown { - SLANG_COM_INTERFACE( 0x9c9d5bc5, 0xeb61, 0x496f,{ 0x80, 0xd7, 0xd1, 0x47, 0xc4, 0xa2, 0x37, 0x30 }) + SLANG_COM_INTERFACE( + 0x9c9d5bc5, + 0xeb61, + 0x496f, + {0x80, 0xd7, 0xd1, 0x47, 0xc4, 0xa2, 0x37, 0x30}) virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) = 0; }; - #define SLANG_UUID_ISlangSharedLibrary_Dep1 ISlangSharedLibrary_Dep1::getTypeGuid() +#define SLANG_UUID_ISlangSharedLibrary_Dep1 ISlangSharedLibrary_Dep1::getTypeGuid() /** An interface that can be used to encapsulate access to a shared library. An implementation does not have to implement the library as a shared library */ struct ISlangSharedLibrary : public ISlangCastable { - SLANG_COM_INTERFACE(0x70dbc7c4, 0xdc3b, 0x4a07, { 0xae, 0x7e, 0x75, 0x2a, 0xf6, 0xa8, 0x15, 0x55 }) + SLANG_COM_INTERFACE( + 0x70dbc7c4, + 0xdc3b, + 0x4a07, + {0xae, 0x7e, 0x75, 0x2a, 0xf6, 0xa8, 0x15, 0x55}) /** Get a function by name. If the library is unloaded will only return nullptr. @param name The name of the function @return The function pointer related to the name or nullptr if not found */ - SLANG_FORCE_INLINE SlangFuncPtr findFuncByName(char const* name) { return (SlangFuncPtr)findSymbolAddressByName(name); } + SLANG_FORCE_INLINE SlangFuncPtr findFuncByName(char const* name) + { + return (SlangFuncPtr)findSymbolAddressByName(name); + } /** Get a symbol by name. If the library is unloaded will only return nullptr. @param name The name of the symbol @@ -1291,166 +1394,183 @@ extern "C" */ virtual SLANG_NO_THROW void* SLANG_MCALL findSymbolAddressByName(char const* name) = 0; }; - #define SLANG_UUID_ISlangSharedLibrary ISlangSharedLibrary::getTypeGuid() +#define SLANG_UUID_ISlangSharedLibrary ISlangSharedLibrary::getTypeGuid() - struct ISlangSharedLibraryLoader: public ISlangUnknown + struct ISlangSharedLibraryLoader : public ISlangUnknown { - SLANG_COM_INTERFACE(0x6264ab2b, 0xa3e8, 0x4a06, { 0x97, 0xf1, 0x49, 0xbc, 0x2d, 0x2a, 0xb1, 0x4d }) - - /** Load a shared library. In typical usage the library name should *not* contain any platform - specific elements. For example on windows a dll name should *not* be passed with a '.dll' extension, - and similarly on linux a shared library should *not* be passed with the 'lib' prefix and '.so' extension - @path path The unadorned filename and/or path for the shared library - @ param sharedLibraryOut Holds the shared library if successfully loaded */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadSharedLibrary( - const char* path, - ISlangSharedLibrary** sharedLibraryOut) = 0; + SLANG_COM_INTERFACE( + 0x6264ab2b, + 0xa3e8, + 0x4a06, + {0x97, 0xf1, 0x49, 0xbc, 0x2d, 0x2a, 0xb1, 0x4d}) + + /** Load a shared library. In typical usage the library name should *not* contain any + platform specific elements. For example on windows a dll name should *not* be passed with a + '.dll' extension, and similarly on linux a shared library should *not* be passed with the + 'lib' prefix and '.so' extension + @path path The unadorned filename and/or path for the shared library + @ param sharedLibraryOut Holds the shared library if successfully loaded */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadSharedLibrary(const char* path, ISlangSharedLibrary** sharedLibraryOut) = 0; }; - #define SLANG_UUID_ISlangSharedLibraryLoader ISlangSharedLibraryLoader::getTypeGuid() - +#define SLANG_UUID_ISlangSharedLibraryLoader ISlangSharedLibraryLoader::getTypeGuid() + /* Type that identifies how a path should be interpreted */ typedef unsigned int SlangPathTypeIntegral; enum SlangPathType : SlangPathTypeIntegral { - SLANG_PATH_TYPE_DIRECTORY, /**< Path specified specifies a directory. */ - SLANG_PATH_TYPE_FILE, /**< Path specified is to a file. */ + SLANG_PATH_TYPE_DIRECTORY, /**< Path specified specifies a directory. */ + SLANG_PATH_TYPE_FILE, /**< Path specified is to a file. */ }; /* Callback to enumerate the contents of of a directory in a ISlangFileSystemExt. - The name is the name of a file system object (directory/file) in the specified path (ie it is without a path) */ - typedef void (*FileSystemContentsCallBack)(SlangPathType pathType, const char* name, void* userData); + The name is the name of a file system object (directory/file) in the specified path (ie it is + without a path) */ + typedef void ( + *FileSystemContentsCallBack)(SlangPathType pathType, const char* name, void* userData); /* Determines how paths map to files on the OS file system */ enum class OSPathKind : uint8_t { - None, ///< Paths do not map to the file system - Direct, ///< Paths map directly to the file system - OperatingSystem, ///< Only paths gained via PathKind::OperatingSystem map to the operating system file system + None, ///< Paths do not map to the file system + Direct, ///< Paths map directly to the file system + OperatingSystem, ///< Only paths gained via PathKind::OperatingSystem map to the operating + ///< system file system }; /* Used to determine what kind of path is required from an input path */ enum class PathKind { - /// Given a path, returns a simplified version of that path. - /// This typically means removing '..' and/or '.' from the path. - /// A simplified path must point to the same object as the original. - Simplified, - - /// Given a path, returns a 'canonical path' to the item. - /// This may be the operating system 'canonical path' that is the unique path to the item. - /// - /// If the item exists the returned canonical path should always be usable to access the item. - /// - /// If the item the path specifies doesn't exist, the canonical path may not be returnable - /// or be a path simplification. - /// Not all file systems support canonical paths. + /// Given a path, returns a simplified version of that path. + /// This typically means removing '..' and/or '.' from the path. + /// A simplified path must point to the same object as the original. + Simplified, + + /// Given a path, returns a 'canonical path' to the item. + /// This may be the operating system 'canonical path' that is the unique path to the item. + /// + /// If the item exists the returned canonical path should always be usable to access the + /// item. + /// + /// If the item the path specifies doesn't exist, the canonical path may not be returnable + /// or be a path simplification. + /// Not all file systems support canonical paths. Canonical, - /// Given a path returns a path such that it is suitable to be displayed to the user. - /// - /// For example if the file system is a zip file - it might include the path to the zip - /// container as well as the path to the specific file. - /// - /// NOTE! The display path won't necessarily work on the file system to access the item + /// Given a path returns a path such that it is suitable to be displayed to the user. + /// + /// For example if the file system is a zip file - it might include the path to the zip + /// container as well as the path to the specific file. + /// + /// NOTE! The display path won't necessarily work on the file system to access the item Display, - /// Get the path to the item on the *operating system* file system, if available. + /// Get the path to the item on the *operating system* file system, if available. OperatingSystem, CountOf, }; /** An extended file system abstraction. - - Implementing and using this interface over ISlangFileSystem gives much more control over how paths - are managed, as well as how it is determined if two files 'are the same'. + + Implementing and using this interface over ISlangFileSystem gives much more control over how + paths are managed, as well as how it is determined if two files 'are the same'. All paths as input char*, or output as ISlangBlobs are always encoded as UTF-8 strings. Blobs that contain strings are always zero terminated. */ struct ISlangFileSystemExt : public ISlangFileSystem { - SLANG_COM_INTERFACE(0x5fb632d2, 0x979d, 0x4481, { 0x9f, 0xee, 0x66, 0x3c, 0x3f, 0x14, 0x49, 0xe1 }) + SLANG_COM_INTERFACE( + 0x5fb632d2, + 0x979d, + 0x4481, + {0x9f, 0xee, 0x66, 0x3c, 0x3f, 0x14, 0x49, 0xe1}) /** Get a uniqueIdentity which uniquely identifies an object of the file system. - - Given a path, returns a 'uniqueIdentity' which ideally is the same value for the same object on the file system. - - The uniqueIdentity is used to compare if two paths are the same - which amongst other things allows Slang to - cache source contents internally. It is also used for #pragma once functionality. - - A *requirement* is for any implementation is that two paths can only return the same uniqueIdentity if the - contents of the two files are *identical*. If an implementation breaks this constraint it can produce incorrect compilation. - If an implementation cannot *strictly* identify *the same* files, this will only have an effect on #pragma once behavior. - - The string for the uniqueIdentity is held zero terminated in the ISlangBlob of outUniqueIdentity. - - Note that there are many ways a uniqueIdentity may be generated for a file. For example it could be the - 'canonical path' - assuming it is available and unambiguous for a file system. Another possible mechanism - could be to store the filename combined with the file date time to uniquely identify it. - + + Given a path, returns a 'uniqueIdentity' which ideally is the same value for the same object + on the file system. + + The uniqueIdentity is used to compare if two paths are the same - which amongst other things + allows Slang to cache source contents internally. It is also used for #pragma once + functionality. + + A *requirement* is for any implementation is that two paths can only return the same + uniqueIdentity if the contents of the two files are *identical*. If an implementation breaks + this constraint it can produce incorrect compilation. If an implementation cannot *strictly* + identify *the same* files, this will only have an effect on #pragma once behavior. + + The string for the uniqueIdentity is held zero terminated in the ISlangBlob of + outUniqueIdentity. + + Note that there are many ways a uniqueIdentity may be generated for a file. For example it + could be the 'canonical path' - assuming it is available and unambiguous for a file system. + Another possible mechanism could be to store the filename combined with the file date time + to uniquely identify it. + The client must ensure the blob be released when no longer used, otherwise memory will leak. - NOTE! Ideally this method would be called 'getPathUniqueIdentity' but for historical reasons and - backward compatibility it's name remains with 'File' even though an implementation should be made to work - with directories too. + NOTE! Ideally this method would be called 'getPathUniqueIdentity' but for historical reasons + and backward compatibility it's name remains with 'File' even though an implementation + should be made to work with directories too. @param path @param outUniqueIdentity @returns A `SlangResult` to indicate success or failure getting the uniqueIdentity. */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getFileUniqueIdentity( - const char* path, - ISlangBlob** outUniqueIdentity) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getFileUniqueIdentity(const char* path, ISlangBlob** outUniqueIdentity) = 0; /** Calculate a path combining the 'fromPath' with 'path' The client must ensure the blob be released when no longer used, otherwise memory will leak. @param fromPathType How to interpret the from path - as a file or a directory. - @param fromPath The from path. + @param fromPath The from path. @param path Path to be determined relative to the fromPath - @param pathOut Holds the string which is the relative path. The string is held in the blob zero terminated. + @param pathOut Holds the string which is the relative path. The string is held in the blob + zero terminated. @returns A `SlangResult` to indicate success or failure in loading the file. */ virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcCombinedPath( SlangPathType fromPathType, const char* fromPath, const char* path, - ISlangBlob** pathOut) = 0; - - /** Gets the type of path that path is on the file system. + ISlangBlob** pathOut) = 0; + + /** Gets the type of path that path is on the file system. @param path @param pathTypeOut - @returns SLANG_OK if located and type is known, else an error. SLANG_E_NOT_FOUND if not found. + @returns SLANG_OK if located and type is known, else an error. SLANG_E_NOT_FOUND if not + found. */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPathType( - const char* path, - SlangPathType* pathTypeOut) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPathType(const char* path, SlangPathType* pathTypeOut) = 0; /** Get a path based on the kind. @param kind The kind of path wanted @param path The input path @param outPath The output path held in a blob - @returns SLANG_OK if successfully simplified the path (SLANG_E_NOT_IMPLEMENTED if not implemented, or some other error code) + @returns SLANG_OK if successfully simplified the path (SLANG_E_NOT_IMPLEMENTED if not + implemented, or some other error code) */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPath( - PathKind kind, - const char* path, - ISlangBlob** outPath) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getPath(PathKind kind, const char* path, ISlangBlob** outPath) = 0; /** Clears any cached information */ virtual SLANG_NO_THROW void SLANG_MCALL clearCache() = 0; /** Enumerate the contents of the path - - Note that for normal Slang operation it isn't necessary to enumerate contents this can return SLANG_E_NOT_IMPLEMENTED. - + + Note that for normal Slang operation it isn't necessary to enumerate contents this can + return SLANG_E_NOT_IMPLEMENTED. + @param The path to enumerate - @param callback This callback is called for each entry in the path. + @param callback This callback is called for each entry in the path. @param userData This is passed to the callback - @returns SLANG_OK if successful + @returns SLANG_OK if successful */ virtual SLANG_NO_THROW SlangResult SLANG_MCALL enumeratePathContents( const char* path, @@ -1458,67 +1578,69 @@ extern "C" void* userData) = 0; /** Returns how paths map to the OS file system - + @returns OSPathKind that describes how paths map to the Operating System file system */ virtual SLANG_NO_THROW OSPathKind SLANG_MCALL getOSPathKind() = 0; }; - #define SLANG_UUID_ISlangFileSystemExt ISlangFileSystemExt::getTypeGuid() +#define SLANG_UUID_ISlangFileSystemExt ISlangFileSystemExt::getTypeGuid() struct ISlangMutableFileSystem : public ISlangFileSystemExt { - SLANG_COM_INTERFACE(0xa058675c, 0x1d65, 0x452a, { 0x84, 0x58, 0xcc, 0xde, 0xd1, 0x42, 0x71, 0x5 }) + SLANG_COM_INTERFACE( + 0xa058675c, + 0x1d65, + 0x452a, + {0x84, 0x58, 0xcc, 0xde, 0xd1, 0x42, 0x71, 0x5}) /** Write data to the specified path. @param path The path for data to be saved to @param data The data to be saved @param size The size of the data in bytes - @returns SLANG_OK if successful (SLANG_E_NOT_IMPLEMENTED if not implemented, or some other error code) + @returns SLANG_OK if successful (SLANG_E_NOT_IMPLEMENTED if not implemented, or some other + error code) */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFile( - const char* path, - const void* data, - size_t size) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFile(const char* path, const void* data, size_t size) = 0; /** Write data in the form of a blob to the specified path. - Depending on the implementation writing a blob might be faster/use less memory. It is assumed the - blob is *immutable* and that an implementation can reference count it. + Depending on the implementation writing a blob might be faster/use less memory. It is + assumed the blob is *immutable* and that an implementation can reference count it. - It is not guaranteed loading the same file will return the *same* blob - just a blob with same - contents. + It is not guaranteed loading the same file will return the *same* blob - just a blob with + same contents. @param path The path for data to be saved to @param dataBlob The data to be saved - @returns SLANG_OK if successful (SLANG_E_NOT_IMPLEMENTED if not implemented, or some other error code) + @returns SLANG_OK if successful (SLANG_E_NOT_IMPLEMENTED if not implemented, or some other + error code) */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveFileBlob( - const char* path, - ISlangBlob* dataBlob) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveFileBlob(const char* path, ISlangBlob* dataBlob) = 0; - /** Remove the entry in the path (directory of file). Will only delete an empty directory, if not empty - will return an error. + /** Remove the entry in the path (directory of file). Will only delete an empty directory, + if not empty will return an error. - @param path The path to remove - @returns SLANG_OK if successful + @param path The path to remove + @returns SLANG_OK if successful */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove( - const char* path) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL remove(const char* path) = 0; /** Create a directory. The path to the directory must exist - @param path To the directory to create. The parent path *must* exist otherwise will return an error. - @returns SLANG_OK if successful + @param path To the directory to create. The parent path *must* exist otherwise will return + an error. + @returns SLANG_OK if successful */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory( - const char* path) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createDirectory(const char* path) = 0; }; - #define SLANG_UUID_ISlangMutableFileSystem ISlangMutableFileSystem::getTypeGuid() +#define SLANG_UUID_ISlangMutableFileSystem ISlangMutableFileSystem::getTypeGuid() /* Identifies different types of writer target*/ typedef unsigned int SlangWriterChannelIntegral; @@ -1538,51 +1660,64 @@ extern "C" }; /** A stream typically of text, used for outputting diagnostic as well as other information. - */ + */ struct ISlangWriter : public ISlangUnknown { - SLANG_COM_INTERFACE(0xec457f0e, 0x9add, 0x4e6b,{ 0x85, 0x1c, 0xd7, 0xfa, 0x71, 0x6d, 0x15, 0xfd }) - - /** Begin an append buffer. - NOTE! Only one append buffer can be active at any time. - @param maxNumChars The maximum of chars that will be appended - @returns The start of the buffer for appending to. */ + SLANG_COM_INTERFACE( + 0xec457f0e, + 0x9add, + 0x4e6b, + {0x85, 0x1c, 0xd7, 0xfa, 0x71, 0x6d, 0x15, 0xfd}) + + /** Begin an append buffer. + NOTE! Only one append buffer can be active at any time. + @param maxNumChars The maximum of chars that will be appended + @returns The start of the buffer for appending to. */ virtual SLANG_NO_THROW char* SLANG_MCALL beginAppendBuffer(size_t maxNumChars) = 0; - /** Ends the append buffer, and is equivalent to a write of the append buffer. - NOTE! That an endAppendBuffer is not necessary if there are no characters to write. - @param buffer is the start of the data to append and must be identical to last value returned from beginAppendBuffer - @param numChars must be a value less than or equal to what was returned from last call to beginAppendBuffer - @returns Result, will be SLANG_OK on success */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL endAppendBuffer(char* buffer, size_t numChars) = 0; - /** Write text to the writer - @param chars The characters to write out - @param numChars The amount of characters - @returns SLANG_OK on success */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL write(const char* chars, size_t numChars) = 0; - /** Flushes any content to the output */ + /** Ends the append buffer, and is equivalent to a write of the append buffer. + NOTE! That an endAppendBuffer is not necessary if there are no characters to write. + @param buffer is the start of the data to append and must be identical to last value + returned from beginAppendBuffer + @param numChars must be a value less than or equal to what was returned from last call to + beginAppendBuffer + @returns Result, will be SLANG_OK on success */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + endAppendBuffer(char* buffer, size_t numChars) = 0; + /** Write text to the writer + @param chars The characters to write out + @param numChars The amount of characters + @returns SLANG_OK on success */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + write(const char* chars, size_t numChars) = 0; + /** Flushes any content to the output */ virtual SLANG_NO_THROW void SLANG_MCALL flush() = 0; - /** Determines if the writer stream is to the console, and can be used to alter the output - @returns Returns true if is a console writer */ + /** Determines if the writer stream is to the console, and can be used to alter the output + @returns Returns true if is a console writer */ virtual SLANG_NO_THROW SlangBool SLANG_MCALL isConsole() = 0; - /** Set the mode for the writer to use - @param mode The mode to use - @returns SLANG_OK on success */ + /** Set the mode for the writer to use + @param mode The mode to use + @returns SLANG_OK on success */ virtual SLANG_NO_THROW SlangResult SLANG_MCALL setMode(SlangWriterMode mode) = 0; }; - - #define SLANG_UUID_ISlangWriter ISlangWriter::getTypeGuid() + +#define SLANG_UUID_ISlangWriter ISlangWriter::getTypeGuid() struct ISlangProfiler : public ISlangUnknown { - SLANG_COM_INTERFACE(0x197772c7, 0x0155, 0x4b91, { 0x84, 0xe8, 0x66, 0x68, 0xba, 0xff, 0x06, 0x19 }) + SLANG_COM_INTERFACE( + 0x197772c7, + 0x0155, + 0x4b91, + {0x84, 0xe8, 0x66, 0x68, 0xba, 0xff, 0x06, 0x19}) virtual SLANG_NO_THROW size_t SLANG_MCALL getEntryCount() = 0; virtual SLANG_NO_THROW const char* SLANG_MCALL getEntryName(uint32_t index) = 0; virtual SLANG_NO_THROW long SLANG_MCALL getEntryTimeMS(uint32_t index) = 0; virtual SLANG_NO_THROW uint32_t SLANG_MCALL getEntryInvocationTimes(uint32_t index) = 0; }; - #define SLANG_UUID_ISlangProfiler ISlangProfiler::getTypeGuid() +#define SLANG_UUID_ISlangProfiler ISlangProfiler::getTypeGuid() - namespace slang { + namespace slang + { struct IGlobalSession; struct ICompileRequest; @@ -1592,7 +1727,7 @@ extern "C" @brief An instance of the Slang library. */ typedef slang::IGlobalSession SlangSession; - + typedef struct SlangProgramLayout SlangProgramLayout; @@ -1603,53 +1738,9 @@ extern "C" /*! - @brief Initialize an instance of the Slang library. - */ - SLANG_API SlangSession* spCreateSession(const char* deprecated = 0); - - /*! - @brief Clean up after an instance of the Slang library. - */ - SLANG_API void spDestroySession( - SlangSession* session); - - /** @see slang::IGlobalSession::setSharedLibraryLoader - */ - SLANG_API void spSessionSetSharedLibraryLoader( - SlangSession* session, - ISlangSharedLibraryLoader* loader); - - /** @see slang::IGlobalSession::getSharedLibraryLoader - */ - SLANG_API ISlangSharedLibraryLoader* spSessionGetSharedLibraryLoader( - SlangSession* session); - - /** @see slang::IGlobalSession::checkCompileTargetSupport - */ - SLANG_API SlangResult spSessionCheckCompileTargetSupport( - SlangSession* session, - SlangCompileTarget target); - - /** @see slang::IGlobalSession::checkPassThroughSupport - */ - SLANG_API SlangResult spSessionCheckPassThroughSupport( - SlangSession* session, - SlangPassThrough passThrough - ); - - /** @see slang::IGlobalSession::addBuiltins - */ - SLANG_API void spAddBuiltins( - SlangSession* session, - char const* sourcePath, - char const* sourceString); - - /*! - @brief Callback type used for diagnostic output. - */ - typedef void(*SlangDiagnosticCallback)( - char const* message, - void* userData); +@brief Callback type used for diagnostic output. +*/ + typedef void (*SlangDiagnosticCallback)(char const* message, void* userData); /*! @brief Get the build version 'tag' string. The string is the same as @@ -1669,430 +1760,6 @@ extern "C" */ SLANG_API const char* spGetBuildTagString(); - /* @see slang::IGlobalSession::createCompileRequest - */ - SLANG_API SlangCompileRequest* spCreateCompileRequest( - SlangSession* session); - - /*! - @brief Destroy a compile request. - Note a request is a COM object and can be destroyed via 'Release'. - */ - SLANG_API void spDestroyCompileRequest( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::setFileSystem */ - SLANG_API void spSetFileSystem( - SlangCompileRequest* request, - ISlangFileSystem* fileSystem); - - /*! @see slang::ICompileRequest::setCompileFlags */ - SLANG_API void spSetCompileFlags( - SlangCompileRequest* request, - SlangCompileFlags flags); - - /*! @see slang::ICompileRequest::getCompileFlags */ - SLANG_API SlangCompileFlags spGetCompileFlags( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::setDumpIntermediates */ - SLANG_API void spSetDumpIntermediates( - SlangCompileRequest* request, - int enable); - - /*! @see slang::ICompileRequest::setDumpIntermediatePrefix */ - SLANG_API void spSetDumpIntermediatePrefix( - SlangCompileRequest* request, - const char* prefix); - - /*! DEPRECATED: use `spSetTargetLineDirectiveMode` instead. - @see slang::ICompileRequest::setLineDirectiveMode */ - SLANG_API void spSetLineDirectiveMode( - SlangCompileRequest* request, - SlangLineDirectiveMode mode); - - /*! @see slang::ICompileRequest::setTargetLineDirectiveMode */ - SLANG_API void spSetTargetLineDirectiveMode( - SlangCompileRequest* request, - int targetIndex, - SlangLineDirectiveMode mode); - - /*! @see slang::ICompileRequest::setTargetLineDirectiveMode */ - SLANG_API void spSetTargetForceGLSLScalarBufferLayout( - SlangCompileRequest* request, - int targetIndex, - bool forceScalarLayout); - - /*! @see slang::ICompileRequest::setTargetUseMinimumSlangOptimization */ - SLANG_API void spSetTargetUseMinimumSlangOptimization( - slang::ICompileRequest* request, - int targetIndex, - bool val); - - /*! @see slang::ICompileRequest::setIngoreCapabilityCheck */ - SLANG_API void spSetIgnoreCapabilityCheck( - slang::ICompileRequest* request, - bool val); - - /*! @see slang::ICompileRequest::setCodeGenTarget */ - SLANG_API void spSetCodeGenTarget( - SlangCompileRequest* request, - SlangCompileTarget target); - - /*! @see slang::ICompileRequest::addCodeGenTarget */ - SLANG_API int spAddCodeGenTarget( - SlangCompileRequest* request, - SlangCompileTarget target); - - /*! @see slang::ICompileRequest::setTargetProfile */ - SLANG_API void spSetTargetProfile( - SlangCompileRequest* request, - int targetIndex, - SlangProfileID profile); - - /*! @see slang::ICompileRequest::setTargetFlags */ - SLANG_API void spSetTargetFlags( - SlangCompileRequest* request, - int targetIndex, - SlangTargetFlags flags); - - - - /*! @see slang::ICompileRequest::setTargetFloatingPointMode */ - SLANG_API void spSetTargetFloatingPointMode( - SlangCompileRequest* request, - int targetIndex, - SlangFloatingPointMode mode); - - /*! @see slang::ICompileRequest::addTargetCapability */ - SLANG_API void spAddTargetCapability( - slang::ICompileRequest* request, - int targetIndex, - SlangCapabilityID capability); - - /* DEPRECATED: use `spSetMatrixLayoutMode` instead. */ - SLANG_API void spSetTargetMatrixLayoutMode( - SlangCompileRequest* request, - int targetIndex, - SlangMatrixLayoutMode mode); - - /*! @see slang::ICompileRequest::setMatrixLayoutMode */ - SLANG_API void spSetMatrixLayoutMode( - SlangCompileRequest* request, - SlangMatrixLayoutMode mode); - - /*! @see slang::ICompileRequest::setDebugInfoLevel */ - SLANG_API void spSetDebugInfoLevel( - SlangCompileRequest* request, - SlangDebugInfoLevel level); - - /*! @see slang::ICompileRequest::setDebugInfoFormat */ - SLANG_API void spSetDebugInfoFormat( - SlangCompileRequest* request, - SlangDebugInfoFormat format); - - /*! @see slang::ICompileRequest::setOptimizationLevel */ - SLANG_API void spSetOptimizationLevel( - SlangCompileRequest* request, - SlangOptimizationLevel level); - - - - /*! @see slang::ICompileRequest::setOutputContainerFormat */ - SLANG_API void spSetOutputContainerFormat( - SlangCompileRequest* request, - SlangContainerFormat format); - - /*! @see slang::ICompileRequest::setPassThrough */ - SLANG_API void spSetPassThrough( - SlangCompileRequest* request, - SlangPassThrough passThrough); - - /*! @see slang::ICompileRequest::setDiagnosticCallback */ - SLANG_API void spSetDiagnosticCallback( - SlangCompileRequest* request, - SlangDiagnosticCallback callback, - void const* userData); - - /*! @see slang::ICompileRequest::setWriter */ - SLANG_API void spSetWriter( - SlangCompileRequest* request, - SlangWriterChannel channel, - ISlangWriter* writer); - - /*! @see slang::ICompileRequest::getWriter */ - SLANG_API ISlangWriter* spGetWriter( - SlangCompileRequest* request, - SlangWriterChannel channel); - - /*! @see slang::ICompileRequest::addSearchPath */ - SLANG_API void spAddSearchPath( - SlangCompileRequest* request, - const char* searchDir); - - /*! @see slang::ICompileRequest::addPreprocessorDefine */ - SLANG_API void spAddPreprocessorDefine( - SlangCompileRequest* request, - const char* key, - const char* value); - - /*! @see slang::ICompileRequest::processCommandLineArguments */ - SLANG_API SlangResult spProcessCommandLineArguments( - SlangCompileRequest* request, - char const* const* args, - int argCount); - - /*! @see slang::ICompileRequest::addTranslationUnit */ - SLANG_API int spAddTranslationUnit( - SlangCompileRequest* request, - SlangSourceLanguage language, - char const* name); - - - /*! @see slang::ICompileRequest::setDefaultModuleName */ - SLANG_API void spSetDefaultModuleName( - SlangCompileRequest* request, - const char* defaultModuleName); - - /*! @see slang::ICompileRequest::addPreprocessorDefine */ - SLANG_API void spTranslationUnit_addPreprocessorDefine( - SlangCompileRequest* request, - int translationUnitIndex, - const char* key, - const char* value); - - - /*! @see slang::ICompileRequest::addTranslationUnitSourceFile */ - SLANG_API void spAddTranslationUnitSourceFile( - SlangCompileRequest* request, - int translationUnitIndex, - char const* path); - - /*! @see slang::ICompileRequest::addTranslationUnitSourceString */ - SLANG_API void spAddTranslationUnitSourceString( - SlangCompileRequest* request, - int translationUnitIndex, - char const* path, - char const* source); - - - /*! @see slang::ICompileRequest::addLibraryReference */ - SLANG_API SlangResult spAddLibraryReference( - SlangCompileRequest* request, - const char* basePath, - const void* libData, - size_t libDataSize); - - /*! @see slang::ICompileRequest::addTranslationUnitSourceStringSpan */ - SLANG_API void spAddTranslationUnitSourceStringSpan( - SlangCompileRequest* request, - int translationUnitIndex, - char const* path, - char const* sourceBegin, - char const* sourceEnd); - - /*! @see slang::ICompileRequest::addTranslationUnitSourceBlob */ - SLANG_API void spAddTranslationUnitSourceBlob( - SlangCompileRequest* request, - int translationUnitIndex, - char const* path, - ISlangBlob* sourceBlob); - - /*! @see slang::IGlobalSession::findProfile */ - SLANG_API SlangProfileID spFindProfile( - SlangSession* session, - char const* name); - - /*! @see slang::IGlobalSession::findCapability */ - SLANG_API SlangCapabilityID spFindCapability( - SlangSession* session, - char const* name); - - /*! @see slang::ICompileRequest::addEntryPoint */ - SLANG_API int spAddEntryPoint( - SlangCompileRequest* request, - int translationUnitIndex, - char const* name, - SlangStage stage); - - /*! @see slang::ICompileRequest::addEntryPointEx */ - SLANG_API int spAddEntryPointEx( - SlangCompileRequest* request, - int translationUnitIndex, - char const* name, - SlangStage stage, - int genericArgCount, - char const** genericArgs); - - /*! @see slang::ICompileRequest::setGlobalGenericArgs */ - SLANG_API SlangResult spSetGlobalGenericArgs( - SlangCompileRequest* request, - int genericArgCount, - char const** genericArgs); - - /*! @see slang::ICompileRequest::setTypeNameForGlobalExistentialTypeParam */ - SLANG_API SlangResult spSetTypeNameForGlobalExistentialTypeParam( - SlangCompileRequest* request, - int slotIndex, - char const* typeName); - - /*! @see slang::ICompileRequest::setTypeNameForEntryPointExistentialTypeParam */ - SLANG_API SlangResult spSetTypeNameForEntryPointExistentialTypeParam( - SlangCompileRequest* request, - int entryPointIndex, - int slotIndex, - char const* typeName); - - /*! @see slang::ICompileRequest::compile */ - SLANG_API SlangResult spCompile( - SlangCompileRequest* request); - - - /*! @see slang::ICompileRequest::getDiagnosticOutput */ - SLANG_API char const* spGetDiagnosticOutput( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::getDiagnosticOutputBlob */ - SLANG_API SlangResult spGetDiagnosticOutputBlob( - SlangCompileRequest* request, - ISlangBlob** outBlob); - - - /*! @see slang::ICompileRequest::getDependencyFileCount */ - SLANG_API int - spGetDependencyFileCount( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::getDependencyFilePath */ - SLANG_API char const* - spGetDependencyFilePath( - SlangCompileRequest* request, - int index); - - /*! @see slang::ICompileRequest::getTranslationUnitCount */ - SLANG_API int - spGetTranslationUnitCount( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::getEntryPointSource */ - SLANG_API char const* spGetEntryPointSource( - SlangCompileRequest* request, - int entryPointIndex); - - /*! @see slang::ICompileRequest::getEntryPointCode */ - SLANG_API void const* spGetEntryPointCode( - SlangCompileRequest* request, - int entryPointIndex, - size_t* outSize); - - /*! @see slang::ICompileRequest::getEntryPointCodeBlob */ - SLANG_API SlangResult spGetEntryPointCodeBlob( - SlangCompileRequest* request, - int entryPointIndex, - int targetIndex, - ISlangBlob** outBlob); - - /*! @see slang::ICompileRequest::getEntryPointHostCallable */ - SLANG_API SlangResult spGetEntryPointHostCallable( - SlangCompileRequest* request, - int entryPointIndex, - int targetIndex, - ISlangSharedLibrary** outSharedLibrary); - - /*! @see slang::ICompileRequest::getTargetCodeBlob */ - SLANG_API SlangResult spGetTargetCodeBlob( - SlangCompileRequest* request, - int targetIndex, - ISlangBlob** outBlob); - - /*! @see slang::ICompileRequest::getTargetHostCallable */ - SLANG_API SlangResult spGetTargetHostCallable( - SlangCompileRequest* request, - int targetIndex, - ISlangSharedLibrary** outSharedLibrary); - - /*! @see slang::ICompileRequest::getCompileRequestCode */ - SLANG_API void const* spGetCompileRequestCode( - SlangCompileRequest* request, - size_t* outSize); - - /*! @see slang::ICompileRequest::getContainerCode */ - SLANG_API SlangResult spGetContainerCode( - SlangCompileRequest* request, - ISlangBlob** outBlob); - - /*! @see slang::ICompileRequest::loadRepro */ - SLANG_API SlangResult spLoadRepro( - SlangCompileRequest* request, - ISlangFileSystem* fileSystem, - const void* data, - size_t size); - - /*! @see slang::ICompileRequest::saveRepro */ - SLANG_API SlangResult spSaveRepro( - SlangCompileRequest* request, - ISlangBlob** outBlob - ); - - /*! @see slang::ICompileRequest::enableReproCapture */ - SLANG_API SlangResult spEnableReproCapture( - SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::getCompileTimeProfile */ - SLANG_API SlangResult spGetCompileTimeProfile( - SlangCompileRequest* request, - ISlangProfiler** compileTimeProfile, - bool shouldClear); - - - /** Extract contents of a repro. - - Writes the contained files and manifest with their 'unique' names into fileSystem. For more details read the - docs/repro.md documentation. - - @param session The slang session - @param reproData Holds the repro data - @param reproDataSize The size of the repro data - @param fileSystem File system that the contents of the repro will be written to - @returns A `SlangResult` to indicate success or failure. - */ - SLANG_API SlangResult spExtractRepro( - SlangSession* session, - const void* reproData, - size_t reproDataSize, - ISlangMutableFileSystem* fileSystem); - - /* Turns a repro into a file system. - - Makes the contents of the repro available as a file system - that is able to access the files with the same - paths as were used on the original repro file system. - - @param session The slang session - @param reproData The repro data - @param reproDataSize The size of the repro data - @param replaceFileSystem Will attempt to load by unique names from this file system before using contents of the repro. Optional. - @param outFileSystem The file system that can be used to access contents - @returns A `SlangResult` to indicate success or failure. - */ - SLANG_API SlangResult spLoadReproAsFileSystem( - SlangSession* session, - const void* reproData, - size_t reproDataSize, - ISlangFileSystem* replaceFileSystem, - ISlangFileSystemExt** outFileSystem); - - /*! @see slang::ICompileRequest::overrideDiagnosticSeverity */ - SLANG_API void spOverrideDiagnosticSeverity( - SlangCompileRequest* request, - SlangInt messageID, - SlangSeverity overrideSeverity); - - /*! @see slang::ICompileRequest::getDiagnosticFlags */ - SLANG_API SlangDiagnosticFlags spGetDiagnosticFlags(SlangCompileRequest* request); - - /*! @see slang::ICompileRequest::setDiagnosticFlags */ - SLANG_API void spSetDiagnosticFlags(SlangCompileRequest* request, SlangDiagnosticFlags flags); - /* Forward declarations of types used in the reflection interface; */ @@ -2101,17 +1768,17 @@ extern "C" typedef struct SlangEntryPoint SlangEntryPoint; typedef struct SlangEntryPointLayout SlangEntryPointLayout; - typedef struct SlangReflectionDecl SlangReflectionDecl; - typedef struct SlangReflectionModifier SlangReflectionModifier; - typedef struct SlangReflectionType SlangReflectionType; - typedef struct SlangReflectionTypeLayout SlangReflectionTypeLayout; - typedef struct SlangReflectionVariable SlangReflectionVariable; - typedef struct SlangReflectionVariableLayout SlangReflectionVariableLayout; - typedef struct SlangReflectionTypeParameter SlangReflectionTypeParameter; - typedef struct SlangReflectionUserAttribute SlangReflectionUserAttribute; - typedef struct SlangReflectionFunction SlangReflectionFunction; - typedef struct SlangReflectionGeneric SlangReflectionGeneric; - + typedef struct SlangReflectionDecl SlangReflectionDecl; + typedef struct SlangReflectionModifier SlangReflectionModifier; + typedef struct SlangReflectionType SlangReflectionType; + typedef struct SlangReflectionTypeLayout SlangReflectionTypeLayout; + typedef struct SlangReflectionVariable SlangReflectionVariable; + typedef struct SlangReflectionVariableLayout SlangReflectionVariableLayout; + typedef struct SlangReflectionTypeParameter SlangReflectionTypeParameter; + typedef struct SlangReflectionUserAttribute SlangReflectionUserAttribute; + typedef struct SlangReflectionFunction SlangReflectionFunction; + typedef struct SlangReflectionGeneric SlangReflectionGeneric; + union SlangReflectionGenericArg { SlangReflectionType* typeVal; @@ -2132,10 +1799,6 @@ extern "C" typedef SlangProgramLayout SlangReflection; typedef SlangEntryPointLayout SlangReflectionEntryPoint; - // get reflection data from a compilation request - SLANG_API SlangReflection* spGetReflection( - SlangCompileRequest* request); - // type reflection typedef unsigned int SlangTypeKindIntegral; @@ -2199,40 +1862,41 @@ extern "C" }; #ifndef SLANG_RESOURCE_SHAPE -# define SLANG_RESOURCE_SHAPE + #define SLANG_RESOURCE_SHAPE typedef unsigned int SlangResourceShapeIntegral; enum SlangResourceShape : SlangResourceShapeIntegral { - SLANG_RESOURCE_BASE_SHAPE_MASK = 0x0F, + SLANG_RESOURCE_BASE_SHAPE_MASK = 0x0F, - SLANG_RESOURCE_NONE = 0x00, + SLANG_RESOURCE_NONE = 0x00, - SLANG_TEXTURE_1D = 0x01, - SLANG_TEXTURE_2D = 0x02, - SLANG_TEXTURE_3D = 0x03, - SLANG_TEXTURE_CUBE = 0x04, - SLANG_TEXTURE_BUFFER = 0x05, + SLANG_TEXTURE_1D = 0x01, + SLANG_TEXTURE_2D = 0x02, + SLANG_TEXTURE_3D = 0x03, + SLANG_TEXTURE_CUBE = 0x04, + SLANG_TEXTURE_BUFFER = 0x05, - SLANG_STRUCTURED_BUFFER = 0x06, - SLANG_BYTE_ADDRESS_BUFFER = 0x07, - SLANG_RESOURCE_UNKNOWN = 0x08, - SLANG_ACCELERATION_STRUCTURE = 0x09, - SLANG_TEXTURE_SUBPASS = 0x0A, + SLANG_STRUCTURED_BUFFER = 0x06, + SLANG_BYTE_ADDRESS_BUFFER = 0x07, + SLANG_RESOURCE_UNKNOWN = 0x08, + SLANG_ACCELERATION_STRUCTURE = 0x09, + SLANG_TEXTURE_SUBPASS = 0x0A, - SLANG_RESOURCE_EXT_SHAPE_MASK = 0xF0, + SLANG_RESOURCE_EXT_SHAPE_MASK = 0xF0, - SLANG_TEXTURE_FEEDBACK_FLAG = 0x10, - SLANG_TEXTURE_SHADOW_FLAG = 0x20, - SLANG_TEXTURE_ARRAY_FLAG = 0x40, - SLANG_TEXTURE_MULTISAMPLE_FLAG = 0x80, + SLANG_TEXTURE_FEEDBACK_FLAG = 0x10, + SLANG_TEXTURE_SHADOW_FLAG = 0x20, + SLANG_TEXTURE_ARRAY_FLAG = 0x40, + SLANG_TEXTURE_MULTISAMPLE_FLAG = 0x80, - SLANG_TEXTURE_1D_ARRAY = SLANG_TEXTURE_1D | SLANG_TEXTURE_ARRAY_FLAG, - SLANG_TEXTURE_2D_ARRAY = SLANG_TEXTURE_2D | SLANG_TEXTURE_ARRAY_FLAG, - SLANG_TEXTURE_CUBE_ARRAY = SLANG_TEXTURE_CUBE | SLANG_TEXTURE_ARRAY_FLAG, + SLANG_TEXTURE_1D_ARRAY = SLANG_TEXTURE_1D | SLANG_TEXTURE_ARRAY_FLAG, + SLANG_TEXTURE_2D_ARRAY = SLANG_TEXTURE_2D | SLANG_TEXTURE_ARRAY_FLAG, + SLANG_TEXTURE_CUBE_ARRAY = SLANG_TEXTURE_CUBE | SLANG_TEXTURE_ARRAY_FLAG, - SLANG_TEXTURE_2D_MULTISAMPLE = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG, - SLANG_TEXTURE_2D_MULTISAMPLE_ARRAY = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG | SLANG_TEXTURE_ARRAY_FLAG, - SLANG_TEXTURE_SUBPASS_MULTISAMPLE = SLANG_TEXTURE_SUBPASS | SLANG_TEXTURE_MULTISAMPLE_FLAG, + SLANG_TEXTURE_2D_MULTISAMPLE = SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG, + SLANG_TEXTURE_2D_MULTISAMPLE_ARRAY = + SLANG_TEXTURE_2D | SLANG_TEXTURE_MULTISAMPLE_FLAG | SLANG_TEXTURE_ARRAY_FLAG, + SLANG_TEXTURE_SUBPASS_MULTISAMPLE = SLANG_TEXTURE_SUBPASS | SLANG_TEXTURE_MULTISAMPLE_FLAG, }; #endif typedef unsigned int SlangResourceAccessIntegral; @@ -2294,14 +1958,14 @@ extern "C" // This `MyParams` type introduces two existential type parameters: // one for `material` and one for `lights`. Even though `lights` // is an array, it only introduces one type parameter, because - // we need to hae a *single* concrete type for all the array + // we need to have a *single* concrete type for all the array // elements to be able to generate specialized code. // SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM, // An existential object parameter represents a value // that needs to be passed in to provide data for some - // interface-type shader paameter. + // interface-type shader parameter. // // Consider this example: // @@ -2348,7 +2012,7 @@ extern "C" }; /** Types of API-managed bindings that a parameter might use. - + `SlangBindingType` represents the distinct types of binding ranges that might be understood by an underlying graphics API or cross-API abstraction layer. Several of the enumeration cases here correspond to cases of `VkDescriptorType` @@ -2361,13 +2025,13 @@ extern "C" parameters of different types as occupying the same binding space for layout (e.g., in SPIR-V both a `Texture2D` and `SamplerState` use the same space of `binding` indices, and are not allowed to overlap), while those same types - map to different types of bindingsin the API (e.g., both textures and samplers + map to different types of bindings in the API (e.g., both textures and samplers use different `VkDescriptorType` values). When you want to answer "what register/binding did this parameter use?" you should use `SlangParameterCategory`. - When you wnat to answer "what type of descriptor range should this parameter use?" + When you want to answer "what type of descriptor range should this parameter use?" you should use `SlangBindingType`. */ typedef SlangUInt32 SlangBindingTypeIntegral; @@ -2394,12 +2058,15 @@ extern "C" SLANG_BINDING_TYPE_MUTABLE_FLAG = 0x100, - SLANG_BINDING_TYPE_MUTABLE_TETURE = SLANG_BINDING_TYPE_TEXTURE | SLANG_BINDING_TYPE_MUTABLE_FLAG, - SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER = SLANG_BINDING_TYPE_TYPED_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG, - SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER = SLANG_BINDING_TYPE_RAW_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG, + SLANG_BINDING_TYPE_MUTABLE_TETURE = + SLANG_BINDING_TYPE_TEXTURE | SLANG_BINDING_TYPE_MUTABLE_FLAG, + SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER = + SLANG_BINDING_TYPE_TYPED_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG, + SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER = + SLANG_BINDING_TYPE_RAW_BUFFER | SLANG_BINDING_TYPE_MUTABLE_FLAG, SLANG_BINDING_TYPE_BASE_MASK = 0x00FF, - SLANG_BINDING_TYPE_EXT_MASK = 0xFF00, + SLANG_BINDING_TYPE_EXT_MASK = 0xFF00, }; typedef SlangUInt32 SlangLayoutRulesIntegral; @@ -2425,3173 +2092,2320 @@ extern "C" SLANG_MODIFIER_INOUT }; - // User Attribute - SLANG_API char const* spReflectionUserAttribute_GetName(SlangReflectionUserAttribute* attrib); - SLANG_API unsigned int spReflectionUserAttribute_GetArgumentCount(SlangReflectionUserAttribute* attrib); - SLANG_API SlangReflectionType* spReflectionUserAttribute_GetArgumentType(SlangReflectionUserAttribute* attrib, unsigned int index); - SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueInt(SlangReflectionUserAttribute* attrib, unsigned int index, int * rs); - SLANG_API SlangResult spReflectionUserAttribute_GetArgumentValueFloat(SlangReflectionUserAttribute* attrib, unsigned int index, float * rs); - - /** Returns the string-typed value of a user attribute argument - The string returned is not null-terminated. The length of the string is returned via `outSize`. - If index of out of range, or if the specified argument is not a string, the function will return nullptr. - */ - SLANG_API const char* spReflectionUserAttribute_GetArgumentValueString(SlangReflectionUserAttribute* attrib, unsigned int index, size_t * outSize); + typedef SlangUInt32 SlangImageFormatIntegral; + enum SlangImageFormat : SlangImageFormatIntegral + { +#define SLANG_FORMAT(NAME, DESC) SLANG_IMAGE_FORMAT_##NAME, +#include "slang-image-format-defs.h" +#undef SLANG_FORMAT + }; - // Type Reflection +#define SLANG_UNBOUNDED_SIZE (~size_t(0)) - SLANG_API SlangTypeKind spReflectionType_GetKind(SlangReflectionType* type); - SLANG_API unsigned int spReflectionType_GetUserAttributeCount(SlangReflectionType* type); - SLANG_API SlangReflectionUserAttribute* spReflectionType_GetUserAttribute(SlangReflectionType* type, unsigned int index); - SLANG_API SlangReflectionUserAttribute* spReflectionType_FindUserAttributeByName(SlangReflectionType* type, char const* name); - SLANG_API SlangReflectionType* spReflectionType_applySpecializations(SlangReflectionType* type, SlangReflectionGeneric* generic); + // Shader Parameter Reflection - SLANG_API unsigned int spReflectionType_GetFieldCount(SlangReflectionType* type); - SLANG_API SlangReflectionVariable* spReflectionType_GetFieldByIndex(SlangReflectionType* type, unsigned index); + typedef SlangReflectionVariableLayout SlangReflectionParameter; - /** Returns the number of elements in the given type. +#ifdef __cplusplus +} +#endif - This operation is valid for vector and array types. For other types it returns zero. +#ifdef __cplusplus +namespace slang +{ +struct ISession; +} +#endif - When invoked on an unbounded-size array it will return `SLANG_UNBOUNDED_SIZE`, - which is defined to be `~size_t(0)`. +#include "slang-deprecated.h" - If the size of a type cannot be statically computed, perhaps because it depends on - a generic parameter that has not been bound to a specific value, this function returns zero. - */ - SLANG_API size_t spReflectionType_GetElementCount(SlangReflectionType* type); +#ifdef __cplusplus - #define SLANG_UNBOUNDED_SIZE (~size_t(0)) +/* Helper interfaces for C++ users */ +namespace slang +{ +struct BufferReflection; +struct DeclReflection; +struct TypeLayoutReflection; +struct TypeReflection; +struct VariableLayoutReflection; +struct VariableReflection; +struct FunctionReflection; +struct GenericReflection; + +union GenericArgReflection +{ + TypeReflection* typeVal; + int64_t intVal; + bool boolVal; +}; - SLANG_API SlangReflectionType* spReflectionType_GetElementType(SlangReflectionType* type); +struct UserAttribute +{ + char const* getName() + { + return spReflectionUserAttribute_GetName((SlangReflectionUserAttribute*)this); + } + uint32_t getArgumentCount() + { + return (uint32_t)spReflectionUserAttribute_GetArgumentCount( + (SlangReflectionUserAttribute*)this); + } + TypeReflection* getArgumentType(uint32_t index) + { + return (TypeReflection*)spReflectionUserAttribute_GetArgumentType( + (SlangReflectionUserAttribute*)this, + index); + } + SlangResult getArgumentValueInt(uint32_t index, int* value) + { + return spReflectionUserAttribute_GetArgumentValueInt( + (SlangReflectionUserAttribute*)this, + index, + value); + } + SlangResult getArgumentValueFloat(uint32_t index, float* value) + { + return spReflectionUserAttribute_GetArgumentValueFloat( + (SlangReflectionUserAttribute*)this, + index, + value); + } + const char* getArgumentValueString(uint32_t index, size_t* outSize) + { + return spReflectionUserAttribute_GetArgumentValueString( + (SlangReflectionUserAttribute*)this, + index, + outSize); + } +}; - SLANG_API unsigned int spReflectionType_GetRowCount(SlangReflectionType* type); - SLANG_API unsigned int spReflectionType_GetColumnCount(SlangReflectionType* type); - SLANG_API SlangScalarType spReflectionType_GetScalarType(SlangReflectionType* type); +struct TypeReflection +{ + enum class Kind + { + None = SLANG_TYPE_KIND_NONE, + Struct = SLANG_TYPE_KIND_STRUCT, + Array = SLANG_TYPE_KIND_ARRAY, + Matrix = SLANG_TYPE_KIND_MATRIX, + Vector = SLANG_TYPE_KIND_VECTOR, + Scalar = SLANG_TYPE_KIND_SCALAR, + ConstantBuffer = SLANG_TYPE_KIND_CONSTANT_BUFFER, + Resource = SLANG_TYPE_KIND_RESOURCE, + SamplerState = SLANG_TYPE_KIND_SAMPLER_STATE, + TextureBuffer = SLANG_TYPE_KIND_TEXTURE_BUFFER, + ShaderStorageBuffer = SLANG_TYPE_KIND_SHADER_STORAGE_BUFFER, + ParameterBlock = SLANG_TYPE_KIND_PARAMETER_BLOCK, + GenericTypeParameter = SLANG_TYPE_KIND_GENERIC_TYPE_PARAMETER, + Interface = SLANG_TYPE_KIND_INTERFACE, + OutputStream = SLANG_TYPE_KIND_OUTPUT_STREAM, + Specialized = SLANG_TYPE_KIND_SPECIALIZED, + Feedback = SLANG_TYPE_KIND_FEEDBACK, + Pointer = SLANG_TYPE_KIND_POINTER, + DynamicResource = SLANG_TYPE_KIND_DYNAMIC_RESOURCE, + }; - SLANG_API SlangResourceShape spReflectionType_GetResourceShape(SlangReflectionType* type); - SLANG_API SlangResourceAccess spReflectionType_GetResourceAccess(SlangReflectionType* type); - SLANG_API SlangReflectionType* spReflectionType_GetResourceResultType(SlangReflectionType* type); + enum ScalarType : SlangScalarTypeIntegral + { + None = SLANG_SCALAR_TYPE_NONE, + Void = SLANG_SCALAR_TYPE_VOID, + Bool = SLANG_SCALAR_TYPE_BOOL, + Int32 = SLANG_SCALAR_TYPE_INT32, + UInt32 = SLANG_SCALAR_TYPE_UINT32, + Int64 = SLANG_SCALAR_TYPE_INT64, + UInt64 = SLANG_SCALAR_TYPE_UINT64, + Float16 = SLANG_SCALAR_TYPE_FLOAT16, + Float32 = SLANG_SCALAR_TYPE_FLOAT32, + Float64 = SLANG_SCALAR_TYPE_FLOAT64, + Int8 = SLANG_SCALAR_TYPE_INT8, + UInt8 = SLANG_SCALAR_TYPE_UINT8, + Int16 = SLANG_SCALAR_TYPE_INT16, + UInt16 = SLANG_SCALAR_TYPE_UINT16, + }; - SLANG_API char const* spReflectionType_GetName(SlangReflectionType* type); - SLANG_API SlangResult spReflectionType_GetFullName(SlangReflectionType* type, ISlangBlob** outNameBlob); - SLANG_API SlangReflectionGeneric* spReflectionType_GetGenericContainer(SlangReflectionType* type); + Kind getKind() { return (Kind)spReflectionType_GetKind((SlangReflectionType*)this); } - // Type Layout Reflection + // only useful if `getKind() == Kind::Struct` + unsigned int getFieldCount() + { + return spReflectionType_GetFieldCount((SlangReflectionType*)this); + } - SLANG_API SlangReflectionType* spReflectionTypeLayout_GetType(SlangReflectionTypeLayout* type); - SLANG_API SlangTypeKind spReflectionTypeLayout_getKind(SlangReflectionTypeLayout* type); - SLANG_API size_t spReflectionTypeLayout_GetSize(SlangReflectionTypeLayout* type, SlangParameterCategory category); - SLANG_API size_t spReflectionTypeLayout_GetStride(SlangReflectionTypeLayout* type, SlangParameterCategory category); - SLANG_API int32_t spReflectionTypeLayout_getAlignment(SlangReflectionTypeLayout* type, SlangParameterCategory category); + VariableReflection* getFieldByIndex(unsigned int index) + { + return ( + VariableReflection*)spReflectionType_GetFieldByIndex((SlangReflectionType*)this, index); + } - SLANG_API uint32_t spReflectionTypeLayout_GetFieldCount(SlangReflectionTypeLayout* type); - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetFieldByIndex(SlangReflectionTypeLayout* type, unsigned index); + bool isArray() { return getKind() == TypeReflection::Kind::Array; } - SLANG_API SlangInt spReflectionTypeLayout_findFieldIndexByName(SlangReflectionTypeLayout* typeLayout, const char* nameBegin, const char* nameEnd); + TypeReflection* unwrapArray() + { + TypeReflection* type = this; + while (type->isArray()) + { + type = type->getElementType(); + } + return type; + } - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetExplicitCounter(SlangReflectionTypeLayout* typeLayout); + // only useful if `getKind() == Kind::Array` + size_t getElementCount() + { + return spReflectionType_GetElementCount((SlangReflectionType*)this); + } - SLANG_API size_t spReflectionTypeLayout_GetElementStride(SlangReflectionTypeLayout* type, SlangParameterCategory category); - SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_GetElementTypeLayout(SlangReflectionTypeLayout* type); - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_GetElementVarLayout(SlangReflectionTypeLayout* type); - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getContainerVarLayout(SlangReflectionTypeLayout* type); + size_t getTotalArrayElementCount() + { + if (!isArray()) + return 0; + size_t result = 1; + TypeReflection* type = this; + for (;;) + { + if (!type->isArray()) + return result; - SLANG_API SlangParameterCategory spReflectionTypeLayout_GetParameterCategory(SlangReflectionTypeLayout* type); + result *= type->getElementCount(); + type = type->getElementType(); + } + } - SLANG_API unsigned spReflectionTypeLayout_GetCategoryCount(SlangReflectionTypeLayout* type); - SLANG_API SlangParameterCategory spReflectionTypeLayout_GetCategoryByIndex(SlangReflectionTypeLayout* type, unsigned index); + TypeReflection* getElementType() + { + return (TypeReflection*)spReflectionType_GetElementType((SlangReflectionType*)this); + } - SLANG_API SlangMatrixLayoutMode spReflectionTypeLayout_GetMatrixLayoutMode(SlangReflectionTypeLayout* type); + unsigned getRowCount() { return spReflectionType_GetRowCount((SlangReflectionType*)this); } - SLANG_API int spReflectionTypeLayout_getGenericParamIndex(SlangReflectionTypeLayout* type); + unsigned getColumnCount() + { + return spReflectionType_GetColumnCount((SlangReflectionType*)this); + } - SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getPendingDataTypeLayout(SlangReflectionTypeLayout* type); + ScalarType getScalarType() + { + return (ScalarType)spReflectionType_GetScalarType((SlangReflectionType*)this); + } - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout(SlangReflectionTypeLayout* type); - SLANG_API SlangInt spReflectionType_getSpecializedTypeArgCount(SlangReflectionType* type); - SLANG_API SlangReflectionType* spReflectionType_getSpecializedTypeArgType(SlangReflectionType* type, SlangInt index); + TypeReflection* getResourceResultType() + { + return (TypeReflection*)spReflectionType_GetResourceResultType((SlangReflectionType*)this); + } - SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeCount(SlangReflectionTypeLayout* typeLayout); - SLANG_API SlangBindingType spReflectionTypeLayout_getBindingRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_isBindingRangeSpecializable(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getBindingRangeLeafTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangReflectionVariable* spReflectionTypeLayout_getBindingRangeLeafVariable(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_getFieldBindingRangeOffset(SlangReflectionTypeLayout* typeLayout, SlangInt fieldIndex); - SLANG_API SlangInt spReflectionTypeLayout_getExplicitCounterBindingRangeOffset(SlangReflectionTypeLayout* inTypeLayout); + SlangResourceShape getResourceShape() + { + return spReflectionType_GetResourceShape((SlangReflectionType*)this); + } - SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorSetIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_getBindingRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); + SlangResourceAccess getResourceAccess() + { + return spReflectionType_GetResourceAccess((SlangReflectionType*)this); + } - SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetCount(SlangReflectionTypeLayout* typeLayout); - SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex); - SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex); - SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex); - SLANG_API SlangInt spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex); - SLANG_API SlangBindingType spReflectionTypeLayout_getDescriptorSetDescriptorRangeType(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex); - SLANG_API SlangParameterCategory spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory(SlangReflectionTypeLayout* typeLayout, SlangInt setIndex, SlangInt rangeIndex); + char const* getName() { return spReflectionType_GetName((SlangReflectionType*)this); } - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex); - SLANG_API SlangReflectionVariableLayout* spReflectionTypeLayout_getSubObjectRangeOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex); + SlangResult getFullName(ISlangBlob** outNameBlob) + { + return spReflectionType_GetFullName((SlangReflectionType*)this, outNameBlob); + } -#if 0 - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeCount(SlangReflectionTypeLayout* typeLayout); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeObjectCount(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex(SlangReflectionTypeLayout* typeLayout, SlangInt index); - SLANG_API SlangReflectionTypeLayout* spReflectionTypeLayout_getSubObjectRangeTypeLayout(SlangReflectionTypeLayout* typeLayout, SlangInt index); + unsigned int getUserAttributeCount() + { + return spReflectionType_GetUserAttributeCount((SlangReflectionType*)this); + } - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex); - SLANG_API SlangBindingType spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingType(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeBindingCount(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeIndexOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); - SLANG_API SlangInt spReflectionTypeLayout_getSubObjectRangeDescriptorRangeSpaceOffset(SlangReflectionTypeLayout* typeLayout, SlangInt subObjectRangeIndex, SlangInt bindingRangeIndexInSubObject); -#endif + UserAttribute* getUserAttributeByIndex(unsigned int index) + { + return (UserAttribute*)spReflectionType_GetUserAttribute((SlangReflectionType*)this, index); + } - // Variable Reflection - - SLANG_API char const* spReflectionVariable_GetName(SlangReflectionVariable* var); - SLANG_API SlangReflectionType* spReflectionVariable_GetType(SlangReflectionVariable* var); - SLANG_API SlangReflectionModifier* spReflectionVariable_FindModifier(SlangReflectionVariable* var, SlangModifierID modifierID); - SLANG_API unsigned int spReflectionVariable_GetUserAttributeCount(SlangReflectionVariable* var); - SLANG_API SlangReflectionUserAttribute* spReflectionVariable_GetUserAttribute(SlangReflectionVariable* var, unsigned int index); - SLANG_API SlangReflectionUserAttribute* spReflectionVariable_FindUserAttributeByName(SlangReflectionVariable* var, SlangSession * globalSession, char const* name); - SLANG_API bool spReflectionVariable_HasDefaultValue(SlangReflectionVariable* inVar); - SLANG_API SlangReflectionGeneric* spReflectionVariable_GetGenericContainer(SlangReflectionVariable* var); - SLANG_API SlangReflectionVariable* spReflectionVariable_applySpecializations(SlangReflectionVariable* var, SlangReflectionGeneric* generic); - - // Variable Layout Reflection - - SLANG_API SlangReflectionVariable* spReflectionVariableLayout_GetVariable(SlangReflectionVariableLayout* var); - - SLANG_API SlangReflectionTypeLayout* spReflectionVariableLayout_GetTypeLayout(SlangReflectionVariableLayout* var); - - SLANG_API size_t spReflectionVariableLayout_GetOffset(SlangReflectionVariableLayout* var, SlangParameterCategory category); - SLANG_API size_t spReflectionVariableLayout_GetSpace(SlangReflectionVariableLayout* var, SlangParameterCategory category); - - SLANG_API char const* spReflectionVariableLayout_GetSemanticName(SlangReflectionVariableLayout* var); - SLANG_API size_t spReflectionVariableLayout_GetSemanticIndex(SlangReflectionVariableLayout* var); - - - // Function Reflection - - SLANG_API SlangReflectionDecl* spReflectionFunction_asDecl(SlangReflectionFunction* func); - SLANG_API char const* spReflectionFunction_GetName(SlangReflectionFunction* func); - SLANG_API SlangReflectionModifier* spReflectionFunction_FindModifier(SlangReflectionFunction* var, SlangModifierID modifierID); - SLANG_API unsigned int spReflectionFunction_GetUserAttributeCount(SlangReflectionFunction* func); - SLANG_API SlangReflectionUserAttribute* spReflectionFunction_GetUserAttribute(SlangReflectionFunction* func, unsigned int index); - SLANG_API SlangReflectionUserAttribute* spReflectionFunction_FindUserAttributeByName(SlangReflectionFunction* func, SlangSession* globalSession, char const* name); - SLANG_API unsigned int spReflectionFunction_GetParameterCount(SlangReflectionFunction* func); - SLANG_API SlangReflectionVariable* spReflectionFunction_GetParameter(SlangReflectionFunction* func, unsigned index); - SLANG_API SlangReflectionType* spReflectionFunction_GetResultType(SlangReflectionFunction* func); - SLANG_API SlangReflectionGeneric* spReflectionFunction_GetGenericContainer(SlangReflectionFunction* func); - SLANG_API SlangReflectionFunction* spReflectionFunction_applySpecializations(SlangReflectionFunction* func, SlangReflectionGeneric* generic); - - // Abstract Decl Reflection - - SLANG_API unsigned int spReflectionDecl_getChildrenCount(SlangReflectionDecl* parentDecl); - SLANG_API SlangReflectionDecl* spReflectionDecl_getChild(SlangReflectionDecl* parentDecl, unsigned int index); - SLANG_API char const* spReflectionDecl_getName(SlangReflectionDecl* decl); - SLANG_API SlangDeclKind spReflectionDecl_getKind(SlangReflectionDecl* decl); - SLANG_API SlangReflectionFunction* spReflectionDecl_castToFunction(SlangReflectionDecl* decl); - SLANG_API SlangReflectionVariable* spReflectionDecl_castToVariable(SlangReflectionDecl* decl); - SLANG_API SlangReflectionGeneric* spReflectionDecl_castToGeneric(SlangReflectionDecl* decl); - SLANG_API SlangReflectionType* spReflection_getTypeFromDecl(SlangReflectionDecl* decl); - SLANG_API SlangReflectionDecl* spReflectionDecl_getParent(SlangReflectionDecl* decl); - - // Generic Reflection - - SLANG_API SlangReflectionDecl* spReflectionGeneric_asDecl(SlangReflectionGeneric* generic); - SLANG_API char const* spReflectionGeneric_GetName(SlangReflectionGeneric* generic); - SLANG_API unsigned int spReflectionGeneric_GetTypeParameterCount(SlangReflectionGeneric* generic); - SLANG_API SlangReflectionVariable* spReflectionGeneric_GetTypeParameter(SlangReflectionGeneric* generic, unsigned index); - SLANG_API unsigned int spReflectionGeneric_GetValueParameterCount(SlangReflectionGeneric* generic); - SLANG_API SlangReflectionVariable* spReflectionGeneric_GetValueParameter(SlangReflectionGeneric* generic, unsigned index); - SLANG_API unsigned int spReflectionGeneric_GetTypeParameterConstraintCount(SlangReflectionGeneric* generic, SlangReflectionVariable* typeParam); - SLANG_API SlangReflectionType* spReflectionGeneric_GetTypeParameterConstraintType(SlangReflectionGeneric* generic, SlangReflectionVariable* typeParam, unsigned index); - SLANG_API SlangDeclKind spReflectionGeneric_GetInnerKind(SlangReflectionGeneric* generic); - SLANG_API SlangReflectionDecl* spReflectionGeneric_GetInnerDecl(SlangReflectionGeneric* generic); - SLANG_API SlangReflectionGeneric* spReflectionGeneric_GetOuterGenericContainer(SlangReflectionGeneric* generic); - SLANG_API SlangReflectionType* spReflectionGeneric_GetConcreteType(SlangReflectionGeneric* generic, SlangReflectionVariable* typeParam); - SLANG_API int64_t spReflectionGeneric_GetConcreteIntVal(SlangReflectionGeneric* generic, SlangReflectionVariable* valueParam); - SLANG_API SlangReflectionGeneric* spReflectionGeneric_applySpecializations(SlangReflectionGeneric* currGeneric, SlangReflectionGeneric* generic); - - - /** Get the stage that a variable belongs to (if any). - - A variable "belongs" to a specific stage when it is a varying input/output - parameter either defined as part of the parameter list for an entry - point *or* at the global scope of a stage-specific GLSL code file (e.g., - an `in` parameter in a GLSL `.vs` file belongs to the vertex stage). - */ - SLANG_API SlangStage spReflectionVariableLayout_getStage( - SlangReflectionVariableLayout* var); + UserAttribute* findUserAttributeByName(char const* name) + { + return (UserAttribute*)spReflectionType_FindUserAttributeByName( + (SlangReflectionType*)this, + name); + } + TypeReflection* applySpecializations(GenericReflection* generic) + { + return (TypeReflection*)spReflectionType_applySpecializations( + (SlangReflectionType*)this, + (SlangReflectionGeneric*)generic); + } - SLANG_API SlangReflectionVariableLayout* spReflectionVariableLayout_getPendingDataLayout(SlangReflectionVariableLayout* var); + GenericReflection* getGenericContainer() + { + return (GenericReflection*)spReflectionType_GetGenericContainer((SlangReflectionType*)this); + } +}; - // Shader Parameter Reflection +enum ParameterCategory : SlangParameterCategoryIntegral +{ + // TODO: these aren't scoped... + None = SLANG_PARAMETER_CATEGORY_NONE, + Mixed = SLANG_PARAMETER_CATEGORY_MIXED, + ConstantBuffer = SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER, + ShaderResource = SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE, + UnorderedAccess = SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS, + VaryingInput = SLANG_PARAMETER_CATEGORY_VARYING_INPUT, + VaryingOutput = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT, + SamplerState = SLANG_PARAMETER_CATEGORY_SAMPLER_STATE, + Uniform = SLANG_PARAMETER_CATEGORY_UNIFORM, + DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT, + SpecializationConstant = SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT, + PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER, + RegisterSpace = SLANG_PARAMETER_CATEGORY_REGISTER_SPACE, + GenericResource = SLANG_PARAMETER_CATEGORY_GENERIC, + + RayPayload = SLANG_PARAMETER_CATEGORY_RAY_PAYLOAD, + HitAttributes = SLANG_PARAMETER_CATEGORY_HIT_ATTRIBUTES, + CallablePayload = SLANG_PARAMETER_CATEGORY_CALLABLE_PAYLOAD, + + ShaderRecord = SLANG_PARAMETER_CATEGORY_SHADER_RECORD, + + ExistentialTypeParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM, + ExistentialObjectParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_OBJECT_PARAM, + + SubElementRegisterSpace = SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE, + + InputAttachmentIndex = SLANG_PARAMETER_CATEGORY_SUBPASS, + + MetalBuffer = SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER, + MetalTexture = SLANG_PARAMETER_CATEGORY_METAL_TEXTURE, + MetalArgumentBufferElement = SLANG_PARAMETER_CATEGORY_METAL_ARGUMENT_BUFFER_ELEMENT, + MetalAttribute = SLANG_PARAMETER_CATEGORY_METAL_ATTRIBUTE, + MetalPayload = SLANG_PARAMETER_CATEGORY_METAL_PAYLOAD, + + // DEPRECATED: + VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT, + FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT, +}; + +enum class BindingType : SlangBindingTypeIntegral +{ + Unknown = SLANG_BINDING_TYPE_UNKNOWN, + + Sampler = SLANG_BINDING_TYPE_SAMPLER, + Texture = SLANG_BINDING_TYPE_TEXTURE, + ConstantBuffer = SLANG_BINDING_TYPE_CONSTANT_BUFFER, + ParameterBlock = SLANG_BINDING_TYPE_PARAMETER_BLOCK, + TypedBuffer = SLANG_BINDING_TYPE_TYPED_BUFFER, + RawBuffer = SLANG_BINDING_TYPE_RAW_BUFFER, + CombinedTextureSampler = SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER, + InputRenderTarget = SLANG_BINDING_TYPE_INPUT_RENDER_TARGET, + InlineUniformData = SLANG_BINDING_TYPE_INLINE_UNIFORM_DATA, + RayTracingAccelerationStructure = SLANG_BINDING_TYPE_RAY_TRACING_ACCELERATION_STRUCTURE, + VaryingInput = SLANG_BINDING_TYPE_VARYING_INPUT, + VaryingOutput = SLANG_BINDING_TYPE_VARYING_OUTPUT, + ExistentialValue = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE, + PushConstant = SLANG_BINDING_TYPE_PUSH_CONSTANT, + + MutableFlag = SLANG_BINDING_TYPE_MUTABLE_FLAG, + + MutableTexture = SLANG_BINDING_TYPE_MUTABLE_TETURE, + MutableTypedBuffer = SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER, + MutableRawBuffer = SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER, + + BaseMask = SLANG_BINDING_TYPE_BASE_MASK, + ExtMask = SLANG_BINDING_TYPE_EXT_MASK, +}; + +struct TypeLayoutReflection +{ + TypeReflection* getType() + { + return (TypeReflection*)spReflectionTypeLayout_GetType((SlangReflectionTypeLayout*)this); + } - typedef SlangReflectionVariableLayout SlangReflectionParameter; + TypeReflection::Kind getKind() + { + return (TypeReflection::Kind)spReflectionTypeLayout_getKind( + (SlangReflectionTypeLayout*)this); + } - SLANG_API unsigned spReflectionParameter_GetBindingIndex(SlangReflectionParameter* parameter); - SLANG_API unsigned spReflectionParameter_GetBindingSpace(SlangReflectionParameter* parameter); + size_t getSize(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) + { + return spReflectionTypeLayout_GetSize((SlangReflectionTypeLayout*)this, category); + } - SLANG_API SlangResult spIsParameterLocationUsed( - SlangCompileRequest* request, - SlangInt entryPointIndex, - SlangInt targetIndex, - SlangParameterCategory category, // is this a `t` register? `s` register? - SlangUInt spaceIndex, // `space` for D3D12, `set` for Vulkan - SlangUInt registerIndex, // `register` for D3D12, `binding` for Vulkan - bool& outUsed); - - // Entry Point Reflection - - SLANG_API char const* spReflectionEntryPoint_getName( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API char const* spReflectionEntryPoint_getNameOverride( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API SlangReflectionFunction* spReflectionEntryPoint_getFunction( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API unsigned spReflectionEntryPoint_getParameterCount( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getParameterByIndex( - SlangReflectionEntryPoint* entryPoint, - unsigned index); - - SLANG_API SlangStage spReflectionEntryPoint_getStage(SlangReflectionEntryPoint* entryPoint); - - SLANG_API void spReflectionEntryPoint_getComputeThreadGroupSize( - SlangReflectionEntryPoint* entryPoint, - SlangUInt axisCount, - SlangUInt* outSizeAlongAxis); - - SLANG_API void spReflectionEntryPoint_getComputeWaveSize( - SlangReflectionEntryPoint* entryPoint, - SlangUInt* outWaveSize); - - SLANG_API int spReflectionEntryPoint_usesAnySampleRateInput( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getVarLayout( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API SlangReflectionVariableLayout* spReflectionEntryPoint_getResultVarLayout( - SlangReflectionEntryPoint* entryPoint); - - SLANG_API int spReflectionEntryPoint_hasDefaultConstantBuffer( - SlangReflectionEntryPoint* entryPoint); - - // SlangReflectionTypeParameter - SLANG_API char const* spReflectionTypeParameter_GetName(SlangReflectionTypeParameter* typeParam); - SLANG_API unsigned spReflectionTypeParameter_GetIndex(SlangReflectionTypeParameter* typeParam); - SLANG_API unsigned spReflectionTypeParameter_GetConstraintCount(SlangReflectionTypeParameter* typeParam); - SLANG_API SlangReflectionType* spReflectionTypeParameter_GetConstraintByIndex(SlangReflectionTypeParameter* typeParam, unsigned int index); - - // Shader Reflection - - SLANG_API unsigned spReflection_GetParameterCount(SlangReflection* reflection); - SLANG_API SlangReflectionParameter* spReflection_GetParameterByIndex(SlangReflection* reflection, unsigned index); - - SLANG_API unsigned int spReflection_GetTypeParameterCount(SlangReflection* reflection); - SLANG_API SlangReflectionTypeParameter* spReflection_GetTypeParameterByIndex(SlangReflection* reflection, unsigned int index); - SLANG_API SlangReflectionTypeParameter* spReflection_FindTypeParameter(SlangReflection* reflection, char const* name); - - SLANG_API SlangReflectionType* spReflection_FindTypeByName(SlangReflection* reflection, char const* name); - SLANG_API SlangReflectionTypeLayout* spReflection_GetTypeLayout(SlangReflection* reflection, SlangReflectionType* reflectionType, SlangLayoutRules rules); - - SLANG_API SlangReflectionFunction* spReflection_FindFunctionByName(SlangReflection* reflection, char const* name); - SLANG_API SlangReflectionFunction* spReflection_FindFunctionByNameInType(SlangReflection* reflection, SlangReflectionType* reflType, char const* name); - SLANG_API SlangReflectionVariable* spReflection_FindVarByNameInType(SlangReflection* reflection, SlangReflectionType* reflType, char const* name); - - SLANG_API SlangUInt spReflection_getEntryPointCount(SlangReflection* reflection); - SLANG_API SlangReflectionEntryPoint* spReflection_getEntryPointByIndex(SlangReflection* reflection, SlangUInt index); - SLANG_API SlangReflectionEntryPoint* spReflection_findEntryPointByName(SlangReflection* reflection, char const* name); - - SLANG_API SlangUInt spReflection_getGlobalConstantBufferBinding(SlangReflection* reflection); - SLANG_API size_t spReflection_getGlobalConstantBufferSize(SlangReflection* reflection); - - SLANG_API SlangReflectionType* spReflection_specializeType( - SlangReflection* reflection, - SlangReflectionType* type, - SlangInt specializationArgCount, - SlangReflectionType* const* specializationArgs, - ISlangBlob** outDiagnostics); - - SLANG_API SlangReflectionGeneric* spReflection_specializeGeneric( - SlangReflection* inProgramLayout, - SlangReflectionGeneric* generic, - SlangInt argCount, - SlangReflectionGenericArgType const* argTypes, - SlangReflectionGenericArg const* args, - ISlangBlob** outDiagnostics); - - SLANG_API bool spReflection_isSubType( - SlangReflection * reflection, - SlangReflectionType* subType, - SlangReflectionType* superType); - - /// Get the number of hashed strings - SLANG_API SlangUInt spReflection_getHashedStringCount( - SlangReflection* reflection); - - /// Get a hashed string. The number of chars is written in outCount. - /// The count does *NOT* including terminating 0. The returned string will be 0 terminated. - SLANG_API const char* spReflection_getHashedString( - SlangReflection* reflection, - SlangUInt index, - size_t* outCount); - - /// Compute a string hash. - /// Count should *NOT* include terminating zero. - SLANG_API SlangUInt32 spComputeStringHash(const char* chars, size_t count); - - /// Get a type layout representing reflection information for the global-scope prameters. - SLANG_API SlangReflectionTypeLayout* spReflection_getGlobalParamsTypeLayout( - SlangReflection* reflection); - - /// Get a variable layout representing reflection information for the global-scope prameters. - SLANG_API SlangReflectionVariableLayout* spReflection_getGlobalParamsVarLayout( - SlangReflection* reflection); + size_t getStride(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) + { + return spReflectionTypeLayout_GetStride((SlangReflectionTypeLayout*)this, category); + } -} -#ifdef __cplusplus + int32_t getAlignment(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) + { + return spReflectionTypeLayout_getAlignment((SlangReflectionTypeLayout*)this, category); + } -namespace slang -{ - struct ISession; -} + unsigned int getFieldCount() + { + return spReflectionTypeLayout_GetFieldCount((SlangReflectionTypeLayout*)this); + } -SLANG_API slang::ISession* spReflection_GetSession(SlangReflection* reflection); + VariableLayoutReflection* getFieldByIndex(unsigned int index) + { + return (VariableLayoutReflection*)spReflectionTypeLayout_GetFieldByIndex( + (SlangReflectionTypeLayout*)this, + index); + } -/* Helper interfaces for C++ users */ -namespace slang -{ - struct BufferReflection; - struct DeclReflection; - struct TypeLayoutReflection; - struct TypeReflection; - struct VariableLayoutReflection; - struct VariableReflection; - struct FunctionReflection; - struct GenericReflection; - - union GenericArgReflection - { - TypeReflection* typeVal; - int64_t intVal; - bool boolVal; - }; - - struct UserAttribute + SlangInt findFieldIndexByName(char const* nameBegin, char const* nameEnd = nullptr) { - char const* getName() - { - return spReflectionUserAttribute_GetName((SlangReflectionUserAttribute*)this); - } - uint32_t getArgumentCount() - { - return (uint32_t)spReflectionUserAttribute_GetArgumentCount((SlangReflectionUserAttribute*)this); - } - TypeReflection* getArgumentType(uint32_t index) - { - return (TypeReflection*)spReflectionUserAttribute_GetArgumentType((SlangReflectionUserAttribute*)this, index); - } - SlangResult getArgumentValueInt(uint32_t index, int * value) - { - return spReflectionUserAttribute_GetArgumentValueInt((SlangReflectionUserAttribute*)this, index, value); - } - SlangResult getArgumentValueFloat(uint32_t index, float * value) - { - return spReflectionUserAttribute_GetArgumentValueFloat((SlangReflectionUserAttribute*)this, index, value); - } - const char* getArgumentValueString(uint32_t index, size_t * outSize) - { - return spReflectionUserAttribute_GetArgumentValueString((SlangReflectionUserAttribute*)this, index, outSize); - } - }; + return spReflectionTypeLayout_findFieldIndexByName( + (SlangReflectionTypeLayout*)this, + nameBegin, + nameEnd); + } - struct TypeReflection + VariableLayoutReflection* getExplicitCounter() { - enum class Kind - { - None = SLANG_TYPE_KIND_NONE, - Struct = SLANG_TYPE_KIND_STRUCT, - Array = SLANG_TYPE_KIND_ARRAY, - Matrix = SLANG_TYPE_KIND_MATRIX, - Vector = SLANG_TYPE_KIND_VECTOR, - Scalar = SLANG_TYPE_KIND_SCALAR, - ConstantBuffer = SLANG_TYPE_KIND_CONSTANT_BUFFER, - Resource = SLANG_TYPE_KIND_RESOURCE, - SamplerState = SLANG_TYPE_KIND_SAMPLER_STATE, - TextureBuffer = SLANG_TYPE_KIND_TEXTURE_BUFFER, - ShaderStorageBuffer = SLANG_TYPE_KIND_SHADER_STORAGE_BUFFER, - ParameterBlock = SLANG_TYPE_KIND_PARAMETER_BLOCK, - GenericTypeParameter = SLANG_TYPE_KIND_GENERIC_TYPE_PARAMETER, - Interface = SLANG_TYPE_KIND_INTERFACE, - OutputStream = SLANG_TYPE_KIND_OUTPUT_STREAM, - Specialized = SLANG_TYPE_KIND_SPECIALIZED, - Feedback = SLANG_TYPE_KIND_FEEDBACK, - Pointer = SLANG_TYPE_KIND_POINTER, - DynamicResource = SLANG_TYPE_KIND_DYNAMIC_RESOURCE, - }; + return (VariableLayoutReflection*)spReflectionTypeLayout_GetExplicitCounter( + (SlangReflectionTypeLayout*)this); + } - enum ScalarType : SlangScalarTypeIntegral - { - None = SLANG_SCALAR_TYPE_NONE, - Void = SLANG_SCALAR_TYPE_VOID, - Bool = SLANG_SCALAR_TYPE_BOOL, - Int32 = SLANG_SCALAR_TYPE_INT32, - UInt32 = SLANG_SCALAR_TYPE_UINT32, - Int64 = SLANG_SCALAR_TYPE_INT64, - UInt64 = SLANG_SCALAR_TYPE_UINT64, - Float16 = SLANG_SCALAR_TYPE_FLOAT16, - Float32 = SLANG_SCALAR_TYPE_FLOAT32, - Float64 = SLANG_SCALAR_TYPE_FLOAT64, - Int8 = SLANG_SCALAR_TYPE_INT8, - UInt8 = SLANG_SCALAR_TYPE_UINT8, - Int16 = SLANG_SCALAR_TYPE_INT16, - UInt16 = SLANG_SCALAR_TYPE_UINT16, - }; + bool isArray() { return getType()->isArray(); } - Kind getKind() + TypeLayoutReflection* unwrapArray() + { + TypeLayoutReflection* typeLayout = this; + while (typeLayout->isArray()) { - return (Kind) spReflectionType_GetKind((SlangReflectionType*) this); + typeLayout = typeLayout->getElementTypeLayout(); } + return typeLayout; + } - // only useful if `getKind() == Kind::Struct` - unsigned int getFieldCount() - { - return spReflectionType_GetFieldCount((SlangReflectionType*) this); - } + // only useful if `getKind() == Kind::Array` + size_t getElementCount() { return getType()->getElementCount(); } - VariableReflection* getFieldByIndex(unsigned int index) - { - return (VariableReflection*) spReflectionType_GetFieldByIndex((SlangReflectionType*) this, index); - } + size_t getTotalArrayElementCount() { return getType()->getTotalArrayElementCount(); } - bool isArray() { return getKind() == TypeReflection::Kind::Array; } + size_t getElementStride(SlangParameterCategory category) + { + return spReflectionTypeLayout_GetElementStride((SlangReflectionTypeLayout*)this, category); + } - TypeReflection* unwrapArray() - { - TypeReflection* type = this; - while( type->isArray() ) - { - type = type->getElementType(); - } - return type; - } + TypeLayoutReflection* getElementTypeLayout() + { + return (TypeLayoutReflection*)spReflectionTypeLayout_GetElementTypeLayout( + (SlangReflectionTypeLayout*)this); + } - // only useful if `getKind() == Kind::Array` - size_t getElementCount() - { - return spReflectionType_GetElementCount((SlangReflectionType*) this); - } + VariableLayoutReflection* getElementVarLayout() + { + return (VariableLayoutReflection*)spReflectionTypeLayout_GetElementVarLayout( + (SlangReflectionTypeLayout*)this); + } - size_t getTotalArrayElementCount() - { - if(!isArray()) return 0; - size_t result = 1; - TypeReflection* type = this; - for(;;) - { - if(!type->isArray()) - return result; + VariableLayoutReflection* getContainerVarLayout() + { + return (VariableLayoutReflection*)spReflectionTypeLayout_getContainerVarLayout( + (SlangReflectionTypeLayout*)this); + } - result *= type->getElementCount(); - type = type->getElementType(); - } - } + // How is this type supposed to be bound? + ParameterCategory getParameterCategory() + { + return (ParameterCategory)spReflectionTypeLayout_GetParameterCategory( + (SlangReflectionTypeLayout*)this); + } - TypeReflection* getElementType() - { - return (TypeReflection*) spReflectionType_GetElementType((SlangReflectionType*) this); - } + unsigned int getCategoryCount() + { + return spReflectionTypeLayout_GetCategoryCount((SlangReflectionTypeLayout*)this); + } - unsigned getRowCount() - { - return spReflectionType_GetRowCount((SlangReflectionType*) this); - } + ParameterCategory getCategoryByIndex(unsigned int index) + { + return (ParameterCategory)spReflectionTypeLayout_GetCategoryByIndex( + (SlangReflectionTypeLayout*)this, + index); + } - unsigned getColumnCount() - { - return spReflectionType_GetColumnCount((SlangReflectionType*) this); - } + unsigned getRowCount() { return getType()->getRowCount(); } - ScalarType getScalarType() - { - return (ScalarType) spReflectionType_GetScalarType((SlangReflectionType*) this); - } + unsigned getColumnCount() { return getType()->getColumnCount(); } - TypeReflection* getResourceResultType() - { - return (TypeReflection*) spReflectionType_GetResourceResultType((SlangReflectionType*) this); - } + TypeReflection::ScalarType getScalarType() { return getType()->getScalarType(); } - SlangResourceShape getResourceShape() - { - return spReflectionType_GetResourceShape((SlangReflectionType*) this); - } + TypeReflection* getResourceResultType() { return getType()->getResourceResultType(); } - SlangResourceAccess getResourceAccess() - { - return spReflectionType_GetResourceAccess((SlangReflectionType*) this); - } + SlangResourceShape getResourceShape() { return getType()->getResourceShape(); } - char const* getName() - { - return spReflectionType_GetName((SlangReflectionType*) this); - } + SlangResourceAccess getResourceAccess() { return getType()->getResourceAccess(); } - SlangResult getFullName(ISlangBlob** outNameBlob) - { - return spReflectionType_GetFullName((SlangReflectionType*)this, outNameBlob); - } + char const* getName() { return getType()->getName(); } - unsigned int getUserAttributeCount() - { - return spReflectionType_GetUserAttributeCount((SlangReflectionType*)this); - } + SlangMatrixLayoutMode getMatrixLayoutMode() + { + return spReflectionTypeLayout_GetMatrixLayoutMode((SlangReflectionTypeLayout*)this); + } - UserAttribute* getUserAttributeByIndex(unsigned int index) - { - return (UserAttribute*)spReflectionType_GetUserAttribute((SlangReflectionType*)this, index); - } + int getGenericParamIndex() + { + return spReflectionTypeLayout_getGenericParamIndex((SlangReflectionTypeLayout*)this); + } - UserAttribute* findUserAttributeByName(char const* name) - { - return (UserAttribute*)spReflectionType_FindUserAttributeByName((SlangReflectionType*)this, name); - } + TypeLayoutReflection* getPendingDataTypeLayout() + { + return (TypeLayoutReflection*)spReflectionTypeLayout_getPendingDataTypeLayout( + (SlangReflectionTypeLayout*)this); + } - TypeReflection* applySpecializations(GenericReflection* generic) - { - return (TypeReflection*)spReflectionType_applySpecializations((SlangReflectionType*)this, (SlangReflectionGeneric*)generic); - } + VariableLayoutReflection* getSpecializedTypePendingDataVarLayout() + { + return (VariableLayoutReflection*) + spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout( + (SlangReflectionTypeLayout*)this); + } - GenericReflection* getGenericContainer() - { - return (GenericReflection*) spReflectionType_GetGenericContainer((SlangReflectionType*) this); - } - }; + SlangInt getBindingRangeCount() + { + return spReflectionTypeLayout_getBindingRangeCount((SlangReflectionTypeLayout*)this); + } - enum ParameterCategory : SlangParameterCategoryIntegral + BindingType getBindingRangeType(SlangInt index) { - // TODO: these aren't scoped... - None = SLANG_PARAMETER_CATEGORY_NONE, - Mixed = SLANG_PARAMETER_CATEGORY_MIXED, - ConstantBuffer = SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER, - ShaderResource = SLANG_PARAMETER_CATEGORY_SHADER_RESOURCE, - UnorderedAccess = SLANG_PARAMETER_CATEGORY_UNORDERED_ACCESS, - VaryingInput = SLANG_PARAMETER_CATEGORY_VARYING_INPUT, - VaryingOutput = SLANG_PARAMETER_CATEGORY_VARYING_OUTPUT, - SamplerState = SLANG_PARAMETER_CATEGORY_SAMPLER_STATE, - Uniform = SLANG_PARAMETER_CATEGORY_UNIFORM, - DescriptorTableSlot = SLANG_PARAMETER_CATEGORY_DESCRIPTOR_TABLE_SLOT, - SpecializationConstant = SLANG_PARAMETER_CATEGORY_SPECIALIZATION_CONSTANT, - PushConstantBuffer = SLANG_PARAMETER_CATEGORY_PUSH_CONSTANT_BUFFER, - RegisterSpace = SLANG_PARAMETER_CATEGORY_REGISTER_SPACE, - GenericResource = SLANG_PARAMETER_CATEGORY_GENERIC, + return (BindingType)spReflectionTypeLayout_getBindingRangeType( + (SlangReflectionTypeLayout*)this, + index); + } - RayPayload = SLANG_PARAMETER_CATEGORY_RAY_PAYLOAD, - HitAttributes = SLANG_PARAMETER_CATEGORY_HIT_ATTRIBUTES, - CallablePayload = SLANG_PARAMETER_CATEGORY_CALLABLE_PAYLOAD, + bool isBindingRangeSpecializable(SlangInt index) + { + return (bool)spReflectionTypeLayout_isBindingRangeSpecializable( + (SlangReflectionTypeLayout*)this, + index); + } - ShaderRecord = SLANG_PARAMETER_CATEGORY_SHADER_RECORD, + SlangInt getBindingRangeBindingCount(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeBindingCount( + (SlangReflectionTypeLayout*)this, + index); + } - ExistentialTypeParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM, - ExistentialObjectParam = SLANG_PARAMETER_CATEGORY_EXISTENTIAL_OBJECT_PARAM, + /* + SlangInt getBindingRangeIndexOffset(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeIndexOffset( + (SlangReflectionTypeLayout*) this, + index); + } - SubElementRegisterSpace = SLANG_PARAMETER_CATEGORY_SUB_ELEMENT_REGISTER_SPACE, + SlangInt getBindingRangeSpaceOffset(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeSpaceOffset( + (SlangReflectionTypeLayout*) this, + index); + } + */ - InputAttachmentIndex = SLANG_PARAMETER_CATEGORY_SUBPASS, + SlangInt getFieldBindingRangeOffset(SlangInt fieldIndex) + { + return spReflectionTypeLayout_getFieldBindingRangeOffset( + (SlangReflectionTypeLayout*)this, + fieldIndex); + } - MetalBuffer = SLANG_PARAMETER_CATEGORY_CONSTANT_BUFFER, - MetalTexture = SLANG_PARAMETER_CATEGORY_METAL_TEXTURE, - MetalArgumentBufferElement = SLANG_PARAMETER_CATEGORY_METAL_ARGUMENT_BUFFER_ELEMENT, - MetalAttribute = SLANG_PARAMETER_CATEGORY_METAL_ATTRIBUTE, - MetalPayload = SLANG_PARAMETER_CATEGORY_METAL_PAYLOAD, + SlangInt getExplicitCounterBindingRangeOffset() + { + return spReflectionTypeLayout_getExplicitCounterBindingRangeOffset( + (SlangReflectionTypeLayout*)this); + } - // DEPRECATED: - VertexInput = SLANG_PARAMETER_CATEGORY_VERTEX_INPUT, - FragmentOutput = SLANG_PARAMETER_CATEGORY_FRAGMENT_OUTPUT, - }; + TypeLayoutReflection* getBindingRangeLeafTypeLayout(SlangInt index) + { + return (TypeLayoutReflection*)spReflectionTypeLayout_getBindingRangeLeafTypeLayout( + (SlangReflectionTypeLayout*)this, + index); + } - enum class BindingType : SlangBindingTypeIntegral - { - Unknown = SLANG_BINDING_TYPE_UNKNOWN, - - Sampler = SLANG_BINDING_TYPE_SAMPLER, - Texture = SLANG_BINDING_TYPE_TEXTURE, - ConstantBuffer = SLANG_BINDING_TYPE_CONSTANT_BUFFER, - ParameterBlock = SLANG_BINDING_TYPE_PARAMETER_BLOCK, - TypedBuffer = SLANG_BINDING_TYPE_TYPED_BUFFER, - RawBuffer = SLANG_BINDING_TYPE_RAW_BUFFER, - CombinedTextureSampler = SLANG_BINDING_TYPE_COMBINED_TEXTURE_SAMPLER, - InputRenderTarget = SLANG_BINDING_TYPE_INPUT_RENDER_TARGET, - InlineUniformData = SLANG_BINDING_TYPE_INLINE_UNIFORM_DATA, - RayTracingAccelerationStructure = SLANG_BINDING_TYPE_RAY_TRACING_ACCELERATION_STRUCTURE, - VaryingInput = SLANG_BINDING_TYPE_VARYING_INPUT, - VaryingOutput = SLANG_BINDING_TYPE_VARYING_OUTPUT, - ExistentialValue = SLANG_BINDING_TYPE_EXISTENTIAL_VALUE, - PushConstant = SLANG_BINDING_TYPE_PUSH_CONSTANT, - - MutableFlag = SLANG_BINDING_TYPE_MUTABLE_FLAG, - - MutableTexture = SLANG_BINDING_TYPE_MUTABLE_TETURE, - MutableTypedBuffer = SLANG_BINDING_TYPE_MUTABLE_TYPED_BUFFER, - MutableRawBuffer = SLANG_BINDING_TYPE_MUTABLE_RAW_BUFFER, - - BaseMask = SLANG_BINDING_TYPE_BASE_MASK, - ExtMask = SLANG_BINDING_TYPE_EXT_MASK, - }; + VariableReflection* getBindingRangeLeafVariable(SlangInt index) + { + return (VariableReflection*)spReflectionTypeLayout_getBindingRangeLeafVariable( + (SlangReflectionTypeLayout*)this, + index); + } - struct TypeLayoutReflection + SlangImageFormat getBindingRangeImageFormat(SlangInt index) { - TypeReflection* getType() - { - return (TypeReflection*) spReflectionTypeLayout_GetType((SlangReflectionTypeLayout*) this); - } + return spReflectionTypeLayout_getBindingRangeImageFormat( + (SlangReflectionTypeLayout*)this, + index); + } - TypeReflection::Kind getKind() - { - return (TypeReflection::Kind) spReflectionTypeLayout_getKind((SlangReflectionTypeLayout*) this); - } + SlangInt getBindingRangeDescriptorSetIndex(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeDescriptorSetIndex( + (SlangReflectionTypeLayout*)this, + index); + } - size_t getSize(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) - { - return spReflectionTypeLayout_GetSize((SlangReflectionTypeLayout*) this, category); - } + SlangInt getBindingRangeFirstDescriptorRangeIndex(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex( + (SlangReflectionTypeLayout*)this, + index); + } - size_t getStride(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) - { - return spReflectionTypeLayout_GetStride((SlangReflectionTypeLayout*) this, category); - } + SlangInt getBindingRangeDescriptorRangeCount(SlangInt index) + { + return spReflectionTypeLayout_getBindingRangeDescriptorRangeCount( + (SlangReflectionTypeLayout*)this, + index); + } - int32_t getAlignment(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) - { - return spReflectionTypeLayout_getAlignment((SlangReflectionTypeLayout*) this, category); - } + SlangInt getDescriptorSetCount() + { + return spReflectionTypeLayout_getDescriptorSetCount((SlangReflectionTypeLayout*)this); + } - unsigned int getFieldCount() - { - return spReflectionTypeLayout_GetFieldCount((SlangReflectionTypeLayout*)this); - } + SlangInt getDescriptorSetSpaceOffset(SlangInt setIndex) + { + return spReflectionTypeLayout_getDescriptorSetSpaceOffset( + (SlangReflectionTypeLayout*)this, + setIndex); + } - VariableLayoutReflection* getFieldByIndex(unsigned int index) - { - return (VariableLayoutReflection*) spReflectionTypeLayout_GetFieldByIndex((SlangReflectionTypeLayout*) this, index); - } + SlangInt getDescriptorSetDescriptorRangeCount(SlangInt setIndex) + { + return spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount( + (SlangReflectionTypeLayout*)this, + setIndex); + } - SlangInt findFieldIndexByName(char const* nameBegin, char const* nameEnd = nullptr) - { - return spReflectionTypeLayout_findFieldIndexByName((SlangReflectionTypeLayout*) this, nameBegin, nameEnd); - } + SlangInt getDescriptorSetDescriptorRangeIndexOffset(SlangInt setIndex, SlangInt rangeIndex) + { + return spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset( + (SlangReflectionTypeLayout*)this, + setIndex, + rangeIndex); + } - VariableLayoutReflection* getExplicitCounter() - { - return (VariableLayoutReflection*) spReflectionTypeLayout_GetExplicitCounter((SlangReflectionTypeLayout*) this); - } + SlangInt getDescriptorSetDescriptorRangeDescriptorCount(SlangInt setIndex, SlangInt rangeIndex) + { + return spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount( + (SlangReflectionTypeLayout*)this, + setIndex, + rangeIndex); + } - bool isArray() { return getType()->isArray(); } + BindingType getDescriptorSetDescriptorRangeType(SlangInt setIndex, SlangInt rangeIndex) + { + return (BindingType)spReflectionTypeLayout_getDescriptorSetDescriptorRangeType( + (SlangReflectionTypeLayout*)this, + setIndex, + rangeIndex); + } - TypeLayoutReflection* unwrapArray() - { - TypeLayoutReflection* typeLayout = this; - while( typeLayout->isArray() ) - { - typeLayout = typeLayout->getElementTypeLayout(); - } - return typeLayout; - } + ParameterCategory getDescriptorSetDescriptorRangeCategory( + SlangInt setIndex, + SlangInt rangeIndex) + { + return (ParameterCategory)spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory( + (SlangReflectionTypeLayout*)this, + setIndex, + rangeIndex); + } - // only useful if `getKind() == Kind::Array` - size_t getElementCount() - { - return getType()->getElementCount(); - } + SlangInt getSubObjectRangeCount() + { + return spReflectionTypeLayout_getSubObjectRangeCount((SlangReflectionTypeLayout*)this); + } - size_t getTotalArrayElementCount() - { - return getType()->getTotalArrayElementCount(); - } + SlangInt getSubObjectRangeBindingRangeIndex(SlangInt subObjectRangeIndex) + { + return spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex( + (SlangReflectionTypeLayout*)this, + subObjectRangeIndex); + } - size_t getElementStride(SlangParameterCategory category) - { - return spReflectionTypeLayout_GetElementStride((SlangReflectionTypeLayout*) this, category); - } + SlangInt getSubObjectRangeSpaceOffset(SlangInt subObjectRangeIndex) + { + return spReflectionTypeLayout_getSubObjectRangeSpaceOffset( + (SlangReflectionTypeLayout*)this, + subObjectRangeIndex); + } - TypeLayoutReflection* getElementTypeLayout() - { - return (TypeLayoutReflection*) spReflectionTypeLayout_GetElementTypeLayout((SlangReflectionTypeLayout*) this); - } + VariableLayoutReflection* getSubObjectRangeOffset(SlangInt subObjectRangeIndex) + { + return (VariableLayoutReflection*)spReflectionTypeLayout_getSubObjectRangeOffset( + (SlangReflectionTypeLayout*)this, + subObjectRangeIndex); + } +}; - VariableLayoutReflection* getElementVarLayout() - { - return (VariableLayoutReflection*)spReflectionTypeLayout_GetElementVarLayout((SlangReflectionTypeLayout*) this); - } +struct Modifier +{ + enum ID : SlangModifierIDIntegral + { + Shared = SLANG_MODIFIER_SHARED, + NoDiff = SLANG_MODIFIER_NO_DIFF, + Static = SLANG_MODIFIER_STATIC, + Const = SLANG_MODIFIER_CONST, + Export = SLANG_MODIFIER_EXPORT, + Extern = SLANG_MODIFIER_EXTERN, + Differentiable = SLANG_MODIFIER_DIFFERENTIABLE, + Mutating = SLANG_MODIFIER_MUTATING, + In = SLANG_MODIFIER_IN, + Out = SLANG_MODIFIER_OUT, + InOut = SLANG_MODIFIER_INOUT + }; +}; - VariableLayoutReflection* getContainerVarLayout() - { - return (VariableLayoutReflection*)spReflectionTypeLayout_getContainerVarLayout((SlangReflectionTypeLayout*) this); - } +struct VariableReflection +{ + char const* getName() { return spReflectionVariable_GetName((SlangReflectionVariable*)this); } - // How is this type supposed to be bound? - ParameterCategory getParameterCategory() - { - return (ParameterCategory) spReflectionTypeLayout_GetParameterCategory((SlangReflectionTypeLayout*) this); - } + TypeReflection* getType() + { + return (TypeReflection*)spReflectionVariable_GetType((SlangReflectionVariable*)this); + } - unsigned int getCategoryCount() - { - return spReflectionTypeLayout_GetCategoryCount((SlangReflectionTypeLayout*) this); - } + Modifier* findModifier(Modifier::ID id) + { + return (Modifier*)spReflectionVariable_FindModifier( + (SlangReflectionVariable*)this, + (SlangModifierID)id); + } - ParameterCategory getCategoryByIndex(unsigned int index) - { - return (ParameterCategory) spReflectionTypeLayout_GetCategoryByIndex((SlangReflectionTypeLayout*) this, index); - } + unsigned int getUserAttributeCount() + { + return spReflectionVariable_GetUserAttributeCount((SlangReflectionVariable*)this); + } - unsigned getRowCount() - { - return getType()->getRowCount(); - } + UserAttribute* getUserAttributeByIndex(unsigned int index) + { + return (UserAttribute*)spReflectionVariable_GetUserAttribute( + (SlangReflectionVariable*)this, + index); + } - unsigned getColumnCount() - { - return getType()->getColumnCount(); - } + UserAttribute* findUserAttributeByName(SlangSession* globalSession, char const* name) + { + return (UserAttribute*)spReflectionVariable_FindUserAttributeByName( + (SlangReflectionVariable*)this, + globalSession, + name); + } - TypeReflection::ScalarType getScalarType() - { - return getType()->getScalarType(); - } + bool hasDefaultValue() + { + return spReflectionVariable_HasDefaultValue((SlangReflectionVariable*)this); + } - TypeReflection* getResourceResultType() - { - return getType()->getResourceResultType(); - } + GenericReflection* getGenericContainer() + { + return (GenericReflection*)spReflectionVariable_GetGenericContainer( + (SlangReflectionVariable*)this); + } - SlangResourceShape getResourceShape() - { - return getType()->getResourceShape(); - } + VariableReflection* applySpecializations(GenericReflection* generic) + { + return (VariableReflection*)spReflectionVariable_applySpecializations( + (SlangReflectionVariable*)this, + (SlangReflectionGeneric*)generic); + } +}; - SlangResourceAccess getResourceAccess() - { - return getType()->getResourceAccess(); - } +struct VariableLayoutReflection +{ + VariableReflection* getVariable() + { + return (VariableReflection*)spReflectionVariableLayout_GetVariable( + (SlangReflectionVariableLayout*)this); + } - char const* getName() - { - return getType()->getName(); - } + char const* getName() { return getVariable()->getName(); } - SlangMatrixLayoutMode getMatrixLayoutMode() - { - return spReflectionTypeLayout_GetMatrixLayoutMode((SlangReflectionTypeLayout*) this); - } + Modifier* findModifier(Modifier::ID id) { return getVariable()->findModifier(id); } - int getGenericParamIndex() - { - return spReflectionTypeLayout_getGenericParamIndex( - (SlangReflectionTypeLayout*) this); - } + TypeLayoutReflection* getTypeLayout() + { + return (TypeLayoutReflection*)spReflectionVariableLayout_GetTypeLayout( + (SlangReflectionVariableLayout*)this); + } - TypeLayoutReflection* getPendingDataTypeLayout() - { - return (TypeLayoutReflection*) spReflectionTypeLayout_getPendingDataTypeLayout( - (SlangReflectionTypeLayout*) this); - } + ParameterCategory getCategory() { return getTypeLayout()->getParameterCategory(); } - VariableLayoutReflection* getSpecializedTypePendingDataVarLayout() - { - return (VariableLayoutReflection*) spReflectionTypeLayout_getSpecializedTypePendingDataVarLayout( - (SlangReflectionTypeLayout*) this); - } + unsigned int getCategoryCount() { return getTypeLayout()->getCategoryCount(); } - SlangInt getBindingRangeCount() - { - return spReflectionTypeLayout_getBindingRangeCount( - (SlangReflectionTypeLayout*) this); - } + ParameterCategory getCategoryByIndex(unsigned int index) + { + return getTypeLayout()->getCategoryByIndex(index); + } - BindingType getBindingRangeType(SlangInt index) - { - return (BindingType) spReflectionTypeLayout_getBindingRangeType( - (SlangReflectionTypeLayout*) this, - index); - } - bool isBindingRangeSpecializable(SlangInt index) - { - return (bool)spReflectionTypeLayout_isBindingRangeSpecializable( - (SlangReflectionTypeLayout*)this, - index); + size_t getOffset(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) + { + return spReflectionVariableLayout_GetOffset((SlangReflectionVariableLayout*)this, category); + } - } + TypeReflection* getType() { return getVariable()->getType(); } - SlangInt getBindingRangeBindingCount(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeBindingCount( - (SlangReflectionTypeLayout*) this, - index); - } + unsigned getBindingIndex() + { + return spReflectionParameter_GetBindingIndex((SlangReflectionVariableLayout*)this); + } - /* - SlangInt getBindingRangeIndexOffset(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeIndexOffset( - (SlangReflectionTypeLayout*) this, - index); - } + unsigned getBindingSpace() + { + return spReflectionParameter_GetBindingSpace((SlangReflectionVariableLayout*)this); + } - SlangInt getBindingRangeSpaceOffset(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeSpaceOffset( - (SlangReflectionTypeLayout*) this, - index); - } - */ + size_t getBindingSpace(SlangParameterCategory category) + { + return spReflectionVariableLayout_GetSpace((SlangReflectionVariableLayout*)this, category); + } - SlangInt getFieldBindingRangeOffset(SlangInt fieldIndex) - { - return spReflectionTypeLayout_getFieldBindingRangeOffset( - (SlangReflectionTypeLayout*) this, - fieldIndex); - } + char const* getSemanticName() + { + return spReflectionVariableLayout_GetSemanticName((SlangReflectionVariableLayout*)this); + } - SlangInt getExplicitCounterBindingRangeOffset() - { - return spReflectionTypeLayout_getExplicitCounterBindingRangeOffset( - (SlangReflectionTypeLayout*) this); - } + size_t getSemanticIndex() + { + return spReflectionVariableLayout_GetSemanticIndex((SlangReflectionVariableLayout*)this); + } - TypeLayoutReflection* getBindingRangeLeafTypeLayout(SlangInt index) - { - return (TypeLayoutReflection*) spReflectionTypeLayout_getBindingRangeLeafTypeLayout( - (SlangReflectionTypeLayout*) this, - index); - } + SlangStage getStage() + { + return spReflectionVariableLayout_getStage((SlangReflectionVariableLayout*)this); + } - VariableReflection* getBindingRangeLeafVariable(SlangInt index) - { - return (VariableReflection*)spReflectionTypeLayout_getBindingRangeLeafVariable( - (SlangReflectionTypeLayout*)this, index); - } + VariableLayoutReflection* getPendingDataLayout() + { + return (VariableLayoutReflection*)spReflectionVariableLayout_getPendingDataLayout( + (SlangReflectionVariableLayout*)this); + } +}; - SlangInt getBindingRangeDescriptorSetIndex(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeDescriptorSetIndex( - (SlangReflectionTypeLayout*) this, - index); - } +struct FunctionReflection +{ + char const* getName() { return spReflectionFunction_GetName((SlangReflectionFunction*)this); } - SlangInt getBindingRangeFirstDescriptorRangeIndex(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeFirstDescriptorRangeIndex( - (SlangReflectionTypeLayout*) this, - index); - } + TypeReflection* getReturnType() + { + return (TypeReflection*)spReflectionFunction_GetResultType((SlangReflectionFunction*)this); + } - SlangInt getBindingRangeDescriptorRangeCount(SlangInt index) - { - return spReflectionTypeLayout_getBindingRangeDescriptorRangeCount( - (SlangReflectionTypeLayout*) this, - index); - } + unsigned int getParameterCount() + { + return spReflectionFunction_GetParameterCount((SlangReflectionFunction*)this); + } - SlangInt getDescriptorSetCount() - { - return spReflectionTypeLayout_getDescriptorSetCount( - (SlangReflectionTypeLayout*) this); - } + VariableReflection* getParameterByIndex(unsigned int index) + { + return (VariableReflection*)spReflectionFunction_GetParameter( + (SlangReflectionFunction*)this, + index); + } - SlangInt getDescriptorSetSpaceOffset(SlangInt setIndex) - { - return spReflectionTypeLayout_getDescriptorSetSpaceOffset( - (SlangReflectionTypeLayout*) this, - setIndex); - } - - SlangInt getDescriptorSetDescriptorRangeCount(SlangInt setIndex) - { - return spReflectionTypeLayout_getDescriptorSetDescriptorRangeCount( - (SlangReflectionTypeLayout*) this, - setIndex); - } + unsigned int getUserAttributeCount() + { + return spReflectionFunction_GetUserAttributeCount((SlangReflectionFunction*)this); + } + UserAttribute* getUserAttributeByIndex(unsigned int index) + { + return (UserAttribute*)spReflectionFunction_GetUserAttribute( + (SlangReflectionFunction*)this, + index); + } + UserAttribute* findUserAttributeByName(SlangSession* globalSession, char const* name) + { + return (UserAttribute*)spReflectionFunction_FindUserAttributeByName( + (SlangReflectionFunction*)this, + globalSession, + name); + } - SlangInt getDescriptorSetDescriptorRangeIndexOffset(SlangInt setIndex, SlangInt rangeIndex) - { - return spReflectionTypeLayout_getDescriptorSetDescriptorRangeIndexOffset( - (SlangReflectionTypeLayout*) this, - setIndex, - rangeIndex); - } + Modifier* findModifier(Modifier::ID id) + { + return (Modifier*)spReflectionFunction_FindModifier( + (SlangReflectionFunction*)this, + (SlangModifierID)id); + } - SlangInt getDescriptorSetDescriptorRangeDescriptorCount(SlangInt setIndex, SlangInt rangeIndex) - { - return spReflectionTypeLayout_getDescriptorSetDescriptorRangeDescriptorCount( - (SlangReflectionTypeLayout*) this, - setIndex, - rangeIndex); - } + GenericReflection* getGenericContainer() + { + return (GenericReflection*)spReflectionFunction_GetGenericContainer( + (SlangReflectionFunction*)this); + } - BindingType getDescriptorSetDescriptorRangeType(SlangInt setIndex, SlangInt rangeIndex) - { - return (BindingType) spReflectionTypeLayout_getDescriptorSetDescriptorRangeType( - (SlangReflectionTypeLayout*) this, - setIndex, - rangeIndex); - } + FunctionReflection* applySpecializations(GenericReflection* generic) + { + return (FunctionReflection*)spReflectionFunction_applySpecializations( + (SlangReflectionFunction*)this, + (SlangReflectionGeneric*)generic); + } - ParameterCategory getDescriptorSetDescriptorRangeCategory(SlangInt setIndex, SlangInt rangeIndex) - { - return (ParameterCategory) spReflectionTypeLayout_getDescriptorSetDescriptorRangeCategory( - (SlangReflectionTypeLayout*) this, - setIndex, - rangeIndex); - } + FunctionReflection* specializeWithArgTypes(unsigned int argCount, TypeReflection* const* types) + { + return (FunctionReflection*)spReflectionFunction_specializeWithArgTypes( + (SlangReflectionFunction*)this, + argCount, + (SlangReflectionType* const*)types); + } - SlangInt getSubObjectRangeCount() - { - return spReflectionTypeLayout_getSubObjectRangeCount( - (SlangReflectionTypeLayout*) this); - } + bool isOverloaded() + { + return spReflectionFunction_isOverloaded((SlangReflectionFunction*)this); + } - SlangInt getSubObjectRangeBindingRangeIndex(SlangInt subObjectRangeIndex) - { - return spReflectionTypeLayout_getSubObjectRangeBindingRangeIndex( - (SlangReflectionTypeLayout*) this, - subObjectRangeIndex); - } + unsigned int getOverloadCount() + { + return spReflectionFunction_getOverloadCount((SlangReflectionFunction*)this); + } - SlangInt getSubObjectRangeSpaceOffset(SlangInt subObjectRangeIndex) - { - return spReflectionTypeLayout_getSubObjectRangeSpaceOffset( - (SlangReflectionTypeLayout*) this, - subObjectRangeIndex); - } + FunctionReflection* getOverload(unsigned int index) + { + return (FunctionReflection*)spReflectionFunction_getOverload( + (SlangReflectionFunction*)this, + index); + } +}; - VariableLayoutReflection* getSubObjectRangeOffset(SlangInt subObjectRangeIndex) - { - return (VariableLayoutReflection*) spReflectionTypeLayout_getSubObjectRangeOffset( - (SlangReflectionTypeLayout*) this, - subObjectRangeIndex); - } - }; +struct GenericReflection +{ - struct Modifier + DeclReflection* asDecl() { - enum ID : SlangModifierIDIntegral - { - Shared = SLANG_MODIFIER_SHARED, - NoDiff = SLANG_MODIFIER_NO_DIFF, - Static = SLANG_MODIFIER_STATIC, - Const = SLANG_MODIFIER_CONST, - Export = SLANG_MODIFIER_EXPORT, - Extern = SLANG_MODIFIER_EXTERN, - Differentiable = SLANG_MODIFIER_DIFFERENTIABLE, - Mutating = SLANG_MODIFIER_MUTATING, - In = SLANG_MODIFIER_IN, - Out = SLANG_MODIFIER_OUT, - InOut = SLANG_MODIFIER_INOUT - }; - }; + return (DeclReflection*)spReflectionGeneric_asDecl((SlangReflectionGeneric*)this); + } + + char const* getName() { return spReflectionGeneric_GetName((SlangReflectionGeneric*)this); } - struct VariableReflection + unsigned int getTypeParameterCount() { - char const* getName() - { - return spReflectionVariable_GetName((SlangReflectionVariable*) this); - } + return spReflectionGeneric_GetTypeParameterCount((SlangReflectionGeneric*)this); + } - TypeReflection* getType() - { - return (TypeReflection*) spReflectionVariable_GetType((SlangReflectionVariable*) this); - } + VariableReflection* getTypeParameter(unsigned index) + { + return (VariableReflection*)spReflectionGeneric_GetTypeParameter( + (SlangReflectionGeneric*)this, + index); + } - Modifier* findModifier(Modifier::ID id) - { - return (Modifier*) spReflectionVariable_FindModifier((SlangReflectionVariable*) this, (SlangModifierID) id); - } + unsigned int getValueParameterCount() + { + return spReflectionGeneric_GetValueParameterCount((SlangReflectionGeneric*)this); + } - unsigned int getUserAttributeCount() - { - return spReflectionVariable_GetUserAttributeCount((SlangReflectionVariable*)this); - } + VariableReflection* getValueParameter(unsigned index) + { + return (VariableReflection*)spReflectionGeneric_GetValueParameter( + (SlangReflectionGeneric*)this, + index); + } - UserAttribute* getUserAttributeByIndex(unsigned int index) - { - return (UserAttribute*)spReflectionVariable_GetUserAttribute((SlangReflectionVariable*)this, index); - } + unsigned int getTypeParameterConstraintCount(VariableReflection* typeParam) + { + return spReflectionGeneric_GetTypeParameterConstraintCount( + (SlangReflectionGeneric*)this, + (SlangReflectionVariable*)typeParam); + } - UserAttribute* findUserAttributeByName(SlangSession* globalSession, char const* name) - { - return (UserAttribute*)spReflectionVariable_FindUserAttributeByName((SlangReflectionVariable*)this, globalSession, name); - } + TypeReflection* getTypeParameterConstraintType(VariableReflection* typeParam, unsigned index) + { + return (TypeReflection*)spReflectionGeneric_GetTypeParameterConstraintType( + (SlangReflectionGeneric*)this, + (SlangReflectionVariable*)typeParam, + index); + } - bool hasDefaultValue() - { - return spReflectionVariable_HasDefaultValue((SlangReflectionVariable*)this); - } + DeclReflection* getInnerDecl() + { + return (DeclReflection*)spReflectionGeneric_GetInnerDecl((SlangReflectionGeneric*)this); + } - GenericReflection* getGenericContainer() - { - return (GenericReflection*)spReflectionVariable_GetGenericContainer((SlangReflectionVariable*)this); - } + SlangDeclKind getInnerKind() + { + return spReflectionGeneric_GetInnerKind((SlangReflectionGeneric*)this); + } - VariableReflection* applySpecializations(GenericReflection* generic) - { - return (VariableReflection*)spReflectionVariable_applySpecializations((SlangReflectionVariable*)this, (SlangReflectionGeneric*)generic); - } - }; + GenericReflection* getOuterGenericContainer() + { + return (GenericReflection*)spReflectionGeneric_GetOuterGenericContainer( + (SlangReflectionGeneric*)this); + } - struct VariableLayoutReflection + TypeReflection* getConcreteType(VariableReflection* typeParam) { - VariableReflection* getVariable() - { - return (VariableReflection*) spReflectionVariableLayout_GetVariable((SlangReflectionVariableLayout*) this); - } + return (TypeReflection*)spReflectionGeneric_GetConcreteType( + (SlangReflectionGeneric*)this, + (SlangReflectionVariable*)typeParam); + } - char const* getName() - { - return getVariable()->getName(); - } + int64_t getConcreteIntVal(VariableReflection* valueParam) + { + return spReflectionGeneric_GetConcreteIntVal( + (SlangReflectionGeneric*)this, + (SlangReflectionVariable*)valueParam); + } - Modifier* findModifier(Modifier::ID id) - { - return getVariable()->findModifier(id); - } + GenericReflection* applySpecializations(GenericReflection* generic) + { + return (GenericReflection*)spReflectionGeneric_applySpecializations( + (SlangReflectionGeneric*)this, + (SlangReflectionGeneric*)generic); + } +}; - TypeLayoutReflection* getTypeLayout() - { - return (TypeLayoutReflection*) spReflectionVariableLayout_GetTypeLayout((SlangReflectionVariableLayout*) this); - } +struct EntryPointReflection +{ + char const* getName() + { + return spReflectionEntryPoint_getName((SlangReflectionEntryPoint*)this); + } - ParameterCategory getCategory() - { - return getTypeLayout()->getParameterCategory(); - } + char const* getNameOverride() + { + return spReflectionEntryPoint_getNameOverride((SlangReflectionEntryPoint*)this); + } - unsigned int getCategoryCount() - { - return getTypeLayout()->getCategoryCount(); - } + unsigned getParameterCount() + { + return spReflectionEntryPoint_getParameterCount((SlangReflectionEntryPoint*)this); + } - ParameterCategory getCategoryByIndex(unsigned int index) - { - return getTypeLayout()->getCategoryByIndex(index); - } + FunctionReflection* getFunction() + { + return (FunctionReflection*)spReflectionEntryPoint_getFunction( + (SlangReflectionEntryPoint*)this); + } + VariableLayoutReflection* getParameterByIndex(unsigned index) + { + return (VariableLayoutReflection*)spReflectionEntryPoint_getParameterByIndex( + (SlangReflectionEntryPoint*)this, + index); + } - size_t getOffset(SlangParameterCategory category = SLANG_PARAMETER_CATEGORY_UNIFORM) - { - return spReflectionVariableLayout_GetOffset((SlangReflectionVariableLayout*) this, category); - } + SlangStage getStage() + { + return spReflectionEntryPoint_getStage((SlangReflectionEntryPoint*)this); + } - TypeReflection* getType() - { - return getVariable()->getType(); - } + void getComputeThreadGroupSize(SlangUInt axisCount, SlangUInt* outSizeAlongAxis) + { + return spReflectionEntryPoint_getComputeThreadGroupSize( + (SlangReflectionEntryPoint*)this, + axisCount, + outSizeAlongAxis); + } - unsigned getBindingIndex() - { - return spReflectionParameter_GetBindingIndex((SlangReflectionVariableLayout*) this); - } + void getComputeWaveSize(SlangUInt* outWaveSize) + { + return spReflectionEntryPoint_getComputeWaveSize( + (SlangReflectionEntryPoint*)this, + outWaveSize); + } - unsigned getBindingSpace() - { - return spReflectionParameter_GetBindingSpace((SlangReflectionVariableLayout*) this); - } + bool usesAnySampleRateInput() + { + return 0 != spReflectionEntryPoint_usesAnySampleRateInput((SlangReflectionEntryPoint*)this); + } - size_t getBindingSpace(SlangParameterCategory category) - { - return spReflectionVariableLayout_GetSpace((SlangReflectionVariableLayout*) this, category); - } + VariableLayoutReflection* getVarLayout() + { + return (VariableLayoutReflection*)spReflectionEntryPoint_getVarLayout( + (SlangReflectionEntryPoint*)this); + } - char const* getSemanticName() - { - return spReflectionVariableLayout_GetSemanticName((SlangReflectionVariableLayout*) this); - } + TypeLayoutReflection* getTypeLayout() { return getVarLayout()->getTypeLayout(); } - size_t getSemanticIndex() - { - return spReflectionVariableLayout_GetSemanticIndex((SlangReflectionVariableLayout*) this); - } + VariableLayoutReflection* getResultVarLayout() + { + return (VariableLayoutReflection*)spReflectionEntryPoint_getResultVarLayout( + (SlangReflectionEntryPoint*)this); + } - SlangStage getStage() - { - return spReflectionVariableLayout_getStage((SlangReflectionVariableLayout*) this); - } + bool hasDefaultConstantBuffer() + { + return spReflectionEntryPoint_hasDefaultConstantBuffer((SlangReflectionEntryPoint*)this) != + 0; + } +}; - VariableLayoutReflection* getPendingDataLayout() - { - return (VariableLayoutReflection*) spReflectionVariableLayout_getPendingDataLayout((SlangReflectionVariableLayout*) this); - } - }; +typedef EntryPointReflection EntryPointLayout; - struct FunctionReflection +struct TypeParameterReflection +{ + char const* getName() { - char const* getName() - { - return spReflectionFunction_GetName((SlangReflectionFunction*)this); - } + return spReflectionTypeParameter_GetName((SlangReflectionTypeParameter*)this); + } + unsigned getIndex() + { + return spReflectionTypeParameter_GetIndex((SlangReflectionTypeParameter*)this); + } + unsigned getConstraintCount() + { + return spReflectionTypeParameter_GetConstraintCount((SlangReflectionTypeParameter*)this); + } + TypeReflection* getConstraintByIndex(int index) + { + return (TypeReflection*)spReflectionTypeParameter_GetConstraintByIndex( + (SlangReflectionTypeParameter*)this, + index); + } +}; - TypeReflection* getReturnType() - { - return (TypeReflection*)spReflectionFunction_GetResultType((SlangReflectionFunction*)this); - } +enum class LayoutRules : SlangLayoutRulesIntegral +{ + Default = SLANG_LAYOUT_RULES_DEFAULT, + MetalArgumentBufferTier2 = SLANG_LAYOUT_RULES_METAL_ARGUMENT_BUFFER_TIER_2, +}; - unsigned int getParameterCount() - { - return spReflectionFunction_GetParameterCount((SlangReflectionFunction*)this); - } +typedef struct ShaderReflection ProgramLayout; +typedef enum SlangReflectionGenericArgType GenericArgType; - VariableReflection* getParameterByIndex(unsigned int index) - { - return (VariableReflection*)spReflectionFunction_GetParameter((SlangReflectionFunction*)this, index); - } +struct ShaderReflection +{ + unsigned getParameterCount() { return spReflection_GetParameterCount((SlangReflection*)this); } - unsigned int getUserAttributeCount() - { - return spReflectionFunction_GetUserAttributeCount((SlangReflectionFunction*)this); - } - UserAttribute* getUserAttributeByIndex(unsigned int index) - { - return (UserAttribute*)spReflectionFunction_GetUserAttribute((SlangReflectionFunction*)this, index); - } - UserAttribute* findUserAttributeByName(SlangSession* globalSession, char const* name) - { - return (UserAttribute*)spReflectionFunction_FindUserAttributeByName((SlangReflectionFunction*)this, globalSession, name); - } + unsigned getTypeParameterCount() + { + return spReflection_GetTypeParameterCount((SlangReflection*)this); + } - Modifier* findModifier(Modifier::ID id) - { - return (Modifier*)spReflectionFunction_FindModifier((SlangReflectionFunction*)this, (SlangModifierID)id); - } + slang::ISession* getSession() { return spReflection_GetSession((SlangReflection*)this); } - GenericReflection* getGenericContainer() - { - return (GenericReflection*)spReflectionFunction_GetGenericContainer((SlangReflectionFunction*)this); - } + TypeParameterReflection* getTypeParameterByIndex(unsigned index) + { + return (TypeParameterReflection*)spReflection_GetTypeParameterByIndex( + (SlangReflection*)this, + index); + } - FunctionReflection* applySpecializations(GenericReflection* generic) - { - return (FunctionReflection*)spReflectionFunction_applySpecializations((SlangReflectionFunction*)this, (SlangReflectionGeneric*)generic); - } - }; + TypeParameterReflection* findTypeParameter(char const* name) + { + return ( + TypeParameterReflection*)spReflection_FindTypeParameter((SlangReflection*)this, name); + } - struct GenericReflection + VariableLayoutReflection* getParameterByIndex(unsigned index) { + return (VariableLayoutReflection*)spReflection_GetParameterByIndex( + (SlangReflection*)this, + index); + } - DeclReflection* asDecl() - { - return (DeclReflection*)spReflectionGeneric_asDecl((SlangReflectionGeneric*)this); - } + static ProgramLayout* get(SlangCompileRequest* request) + { + return (ProgramLayout*)spGetReflection(request); + } - char const* getName() - { - return spReflectionGeneric_GetName((SlangReflectionGeneric*)this); - } + SlangUInt getEntryPointCount() + { + return spReflection_getEntryPointCount((SlangReflection*)this); + } - unsigned int getTypeParameterCount() - { - return spReflectionGeneric_GetTypeParameterCount((SlangReflectionGeneric*)this); - } + EntryPointReflection* getEntryPointByIndex(SlangUInt index) + { + return ( + EntryPointReflection*)spReflection_getEntryPointByIndex((SlangReflection*)this, index); + } - VariableReflection* getTypeParameter(unsigned index) - { - return (VariableReflection*)spReflectionGeneric_GetTypeParameter((SlangReflectionGeneric*)this, index); - } + SlangUInt getGlobalConstantBufferBinding() + { + return spReflection_getGlobalConstantBufferBinding((SlangReflection*)this); + } - unsigned int getValueParameterCount() - { - return spReflectionGeneric_GetValueParameterCount((SlangReflectionGeneric*)this); - } + size_t getGlobalConstantBufferSize() + { + return spReflection_getGlobalConstantBufferSize((SlangReflection*)this); + } - VariableReflection* getValueParameter(unsigned index) - { - return (VariableReflection*)spReflectionGeneric_GetValueParameter((SlangReflectionGeneric*)this, index); - } + TypeReflection* findTypeByName(const char* name) + { + return (TypeReflection*)spReflection_FindTypeByName((SlangReflection*)this, name); + } - unsigned int getTypeParameterConstraintCount(VariableReflection* typeParam) - { - return spReflectionGeneric_GetTypeParameterConstraintCount((SlangReflectionGeneric*)this, (SlangReflectionVariable*)typeParam); - } + FunctionReflection* findFunctionByName(const char* name) + { + return (FunctionReflection*)spReflection_FindFunctionByName((SlangReflection*)this, name); + } - TypeReflection* getTypeParameterConstraintType(VariableReflection* typeParam, unsigned index) - { - return (TypeReflection*)spReflectionGeneric_GetTypeParameterConstraintType((SlangReflectionGeneric*)this, (SlangReflectionVariable*)typeParam, index); - } + FunctionReflection* findFunctionByNameInType(TypeReflection* type, const char* name) + { + return (FunctionReflection*)spReflection_FindFunctionByNameInType( + (SlangReflection*)this, + (SlangReflectionType*)type, + name); + } - DeclReflection* getInnerDecl() - { - return (DeclReflection*)spReflectionGeneric_GetInnerDecl((SlangReflectionGeneric*)this); - } + VariableReflection* findVarByNameInType(TypeReflection* type, const char* name) + { + return (VariableReflection*)spReflection_FindVarByNameInType( + (SlangReflection*)this, + (SlangReflectionType*)type, + name); + } - SlangDeclKind getInnerKind() - { - return spReflectionGeneric_GetInnerKind((SlangReflectionGeneric*)this); - } + TypeLayoutReflection* getTypeLayout( + TypeReflection* type, + LayoutRules rules = LayoutRules::Default) + { + return (TypeLayoutReflection*)spReflection_GetTypeLayout( + (SlangReflection*)this, + (SlangReflectionType*)type, + SlangLayoutRules(rules)); + } - GenericReflection* getOuterGenericContainer() - { - return (GenericReflection*)spReflectionGeneric_GetOuterGenericContainer((SlangReflectionGeneric*)this); - } + EntryPointReflection* findEntryPointByName(const char* name) + { + return ( + EntryPointReflection*)spReflection_findEntryPointByName((SlangReflection*)this, name); + } - TypeReflection* getConcreteType(VariableReflection* typeParam) - { - return (TypeReflection*)spReflectionGeneric_GetConcreteType((SlangReflectionGeneric*)this, (SlangReflectionVariable*)typeParam); - } + TypeReflection* specializeType( + TypeReflection* type, + SlangInt specializationArgCount, + TypeReflection* const* specializationArgs, + ISlangBlob** outDiagnostics) + { + return (TypeReflection*)spReflection_specializeType( + (SlangReflection*)this, + (SlangReflectionType*)type, + specializationArgCount, + (SlangReflectionType* const*)specializationArgs, + outDiagnostics); + } - int64_t getConcreteIntVal(VariableReflection* valueParam) - { - return spReflectionGeneric_GetConcreteIntVal((SlangReflectionGeneric*)this, (SlangReflectionVariable*)valueParam); - } + GenericReflection* specializeGeneric( + GenericReflection* generic, + SlangInt specializationArgCount, + GenericArgType const* specializationArgTypes, + GenericArgReflection const* specializationArgVals, + ISlangBlob** outDiagnostics) + { + return (GenericReflection*)spReflection_specializeGeneric( + (SlangReflection*)this, + (SlangReflectionGeneric*)generic, + specializationArgCount, + (SlangReflectionGenericArgType const*)specializationArgTypes, + (SlangReflectionGenericArg const*)specializationArgVals, + outDiagnostics); + } - GenericReflection* applySpecializations(GenericReflection* generic) - { - return (GenericReflection*)spReflectionGeneric_applySpecializations((SlangReflectionGeneric*)this, (SlangReflectionGeneric*)generic); - } - }; + bool isSubType(TypeReflection* subType, TypeReflection* superType) + { + return spReflection_isSubType( + (SlangReflection*)this, + (SlangReflectionType*)subType, + (SlangReflectionType*)superType); + } - struct EntryPointReflection + SlangUInt getHashedStringCount() const { - char const* getName() - { - return spReflectionEntryPoint_getName((SlangReflectionEntryPoint*) this); - } + return spReflection_getHashedStringCount((SlangReflection*)this); + } - char const* getNameOverride() - { - return spReflectionEntryPoint_getNameOverride((SlangReflectionEntryPoint*)this); - } + const char* getHashedString(SlangUInt index, size_t* outCount) const + { + return spReflection_getHashedString((SlangReflection*)this, index, outCount); + } - unsigned getParameterCount() - { - return spReflectionEntryPoint_getParameterCount((SlangReflectionEntryPoint*) this); - } + TypeLayoutReflection* getGlobalParamsTypeLayout() + { + return (TypeLayoutReflection*)spReflection_getGlobalParamsTypeLayout( + (SlangReflection*)this); + } - FunctionReflection* getFunction() - { - return (FunctionReflection*)spReflectionEntryPoint_getFunction((SlangReflectionEntryPoint*) this); - } + VariableLayoutReflection* getGlobalParamsVarLayout() + { + return (VariableLayoutReflection*)spReflection_getGlobalParamsVarLayout( + (SlangReflection*)this); + } - VariableLayoutReflection* getParameterByIndex(unsigned index) - { - return (VariableLayoutReflection*) spReflectionEntryPoint_getParameterByIndex((SlangReflectionEntryPoint*) this, index); - } + SlangResult toJson(ISlangBlob** outBlob) + { + return spReflection_ToJson((SlangReflection*)this, nullptr, outBlob); + } +}; - SlangStage getStage() - { - return spReflectionEntryPoint_getStage((SlangReflectionEntryPoint*) this); - } - void getComputeThreadGroupSize( - SlangUInt axisCount, - SlangUInt* outSizeAlongAxis) - { - return spReflectionEntryPoint_getComputeThreadGroupSize((SlangReflectionEntryPoint*) this, axisCount, outSizeAlongAxis); - } +struct DeclReflection +{ + enum class Kind + { + Unsupported = SLANG_DECL_KIND_UNSUPPORTED_FOR_REFLECTION, + Struct = SLANG_DECL_KIND_STRUCT, + Func = SLANG_DECL_KIND_FUNC, + Module = SLANG_DECL_KIND_MODULE, + Generic = SLANG_DECL_KIND_GENERIC, + Variable = SLANG_DECL_KIND_VARIABLE, + Namespace = SLANG_DECL_KIND_NAMESPACE, + }; - void getComputeWaveSize( - SlangUInt* outWaveSize) - { - return spReflectionEntryPoint_getComputeWaveSize((SlangReflectionEntryPoint*)this, outWaveSize); - } + char const* getName() { return spReflectionDecl_getName((SlangReflectionDecl*)this); } - bool usesAnySampleRateInput() - { - return 0 != spReflectionEntryPoint_usesAnySampleRateInput((SlangReflectionEntryPoint*) this); - } + Kind getKind() { return (Kind)spReflectionDecl_getKind((SlangReflectionDecl*)this); } - VariableLayoutReflection* getVarLayout() - { - return (VariableLayoutReflection*) spReflectionEntryPoint_getVarLayout((SlangReflectionEntryPoint*) this); - } + unsigned int getChildrenCount() + { + return spReflectionDecl_getChildrenCount((SlangReflectionDecl*)this); + } - TypeLayoutReflection* getTypeLayout() - { - return getVarLayout()->getTypeLayout(); - } + DeclReflection* getChild(unsigned int index) + { + return (DeclReflection*)spReflectionDecl_getChild((SlangReflectionDecl*)this, index); + } - VariableLayoutReflection* getResultVarLayout() - { - return (VariableLayoutReflection*) spReflectionEntryPoint_getResultVarLayout((SlangReflectionEntryPoint*) this); - } + TypeReflection* getType() + { + return (TypeReflection*)spReflection_getTypeFromDecl((SlangReflectionDecl*)this); + } - bool hasDefaultConstantBuffer() - { - return spReflectionEntryPoint_hasDefaultConstantBuffer((SlangReflectionEntryPoint*) this) != 0; - } - }; + VariableReflection* asVariable() + { + return (VariableReflection*)spReflectionDecl_castToVariable((SlangReflectionDecl*)this); + } - typedef EntryPointReflection EntryPointLayout; + FunctionReflection* asFunction() + { + return (FunctionReflection*)spReflectionDecl_castToFunction((SlangReflectionDecl*)this); + } - struct TypeParameterReflection + GenericReflection* asGeneric() { - char const* getName() - { - return spReflectionTypeParameter_GetName((SlangReflectionTypeParameter*) this); - } - unsigned getIndex() - { - return spReflectionTypeParameter_GetIndex((SlangReflectionTypeParameter*) this); - } - unsigned getConstraintCount() - { - return spReflectionTypeParameter_GetConstraintCount((SlangReflectionTypeParameter*) this); - } - TypeReflection* getConstraintByIndex(int index) - { - return (TypeReflection*)spReflectionTypeParameter_GetConstraintByIndex((SlangReflectionTypeParameter*) this, index); - } - }; + return (GenericReflection*)spReflectionDecl_castToGeneric((SlangReflectionDecl*)this); + } - enum class LayoutRules : SlangLayoutRulesIntegral + DeclReflection* getParent() { - Default = SLANG_LAYOUT_RULES_DEFAULT, - MetalArgumentBufferTier2 = SLANG_LAYOUT_RULES_METAL_ARGUMENT_BUFFER_TIER_2, - }; + return (DeclReflection*)spReflectionDecl_getParent((SlangReflectionDecl*)this); + } - typedef struct ShaderReflection ProgramLayout; - typedef enum SlangReflectionGenericArgType GenericArgType; + template + struct FilteredList + { + unsigned int count; + DeclReflection* parent; + + struct FilteredIterator + { + DeclReflection* parent; + unsigned int count; + unsigned int index; + + DeclReflection* operator*() { return parent->getChild(index); } + void operator++() + { + index++; + while (index < count && !(parent->getChild(index)->getKind() == K)) + { + index++; + } + } + bool operator!=(FilteredIterator const& other) { return index != other.index; } + }; - struct ShaderReflection - { - unsigned getParameterCount() + // begin/end for range-based for that checks the kind + FilteredIterator begin() { - return spReflection_GetParameterCount((SlangReflection*) this); + // Find the first child of the right kind + unsigned int index = 0; + while (index < count && !(parent->getChild(index)->getKind() == K)) + { + index++; + } + return FilteredIterator{parent, count, index}; } - unsigned getTypeParameterCount() - { - return spReflection_GetTypeParameterCount((SlangReflection*) this); - } + FilteredIterator end() { return FilteredIterator{parent, count, count}; } + }; - slang::ISession* getSession() - { - return spReflection_GetSession((SlangReflection*)this); - } + template + FilteredList getChildrenOfKind() + { + return FilteredList{getChildrenCount(), (DeclReflection*)this}; + } - TypeParameterReflection* getTypeParameterByIndex(unsigned index) - { - return (TypeParameterReflection*)spReflection_GetTypeParameterByIndex((SlangReflection*) this, index); - } + struct IteratedList + { + unsigned int count; + DeclReflection* parent; - TypeParameterReflection* findTypeParameter(char const* name) + struct Iterator { - return (TypeParameterReflection*)spReflection_FindTypeParameter((SlangReflection*)this, name); - } + DeclReflection* parent; + unsigned int count; + unsigned int index; - VariableLayoutReflection* getParameterByIndex(unsigned index) - { - return (VariableLayoutReflection*) spReflection_GetParameterByIndex((SlangReflection*) this, index); - } + DeclReflection* operator*() { return parent->getChild(index); } + void operator++() { index++; } + bool operator!=(Iterator const& other) { return index != other.index; } + }; - static ProgramLayout* get(SlangCompileRequest* request) - { - return (ProgramLayout*) spGetReflection(request); - } + // begin/end for range-based for that checks the kind + IteratedList::Iterator begin() { return IteratedList::Iterator{parent, count, 0}; } + IteratedList::Iterator end() { return IteratedList::Iterator{parent, count, count}; } + }; - SlangUInt getEntryPointCount() - { - return spReflection_getEntryPointCount((SlangReflection*) this); - } + IteratedList getChildren() { return IteratedList{getChildrenCount(), (DeclReflection*)this}; } +}; - EntryPointReflection* getEntryPointByIndex(SlangUInt index) - { - return (EntryPointReflection*) spReflection_getEntryPointByIndex((SlangReflection*) this, index); - } +typedef uint32_t CompileCoreModuleFlags; +struct CompileCoreModuleFlag +{ + enum Enum : CompileCoreModuleFlags + { + WriteDocumentation = 0x1, + }; +}; - SlangUInt getGlobalConstantBufferBinding() - { - return spReflection_getGlobalConstantBufferBinding((SlangReflection*)this); - } +typedef ISlangBlob IBlob; - size_t getGlobalConstantBufferSize() - { - return spReflection_getGlobalConstantBufferSize((SlangReflection*)this); - } +struct IComponentType; +struct ITypeConformance; +struct IGlobalSession; +struct IModule; - TypeReflection* findTypeByName(const char* name) - { - return (TypeReflection*)spReflection_FindTypeByName( - (SlangReflection*) this, - name); - } +struct SessionDesc; +struct SpecializationArg; +struct TargetDesc; - FunctionReflection* findFunctionByName(const char* name) - { - return (FunctionReflection*)spReflection_FindFunctionByName( - (SlangReflection*) this, - name); - } +/** A global session for interaction with the Slang library. - FunctionReflection* findFunctionByNameInType(TypeReflection* type, const char* name) - { - return (FunctionReflection*)spReflection_FindFunctionByNameInType( - (SlangReflection*) this, - (SlangReflectionType*) type, - name); - } +An application may create and re-use a single global session across +multiple sessions, in order to amortize startups costs (in current +Slang this is mostly the cost of loading the Slang standard library). - VariableReflection* findVarByNameInType(TypeReflection* type, const char* name) - { - return (VariableReflection*)spReflection_FindVarByNameInType( - (SlangReflection*) this, - (SlangReflectionType*) type, - name); - } +The global session is currently *not* thread-safe and objects created from +a single global session should only be used from a single thread at +a time. +*/ +struct IGlobalSession : public ISlangUnknown +{ + SLANG_COM_INTERFACE(0xc140b5fd, 0xc78, 0x452e, {0xba, 0x7c, 0x1a, 0x1e, 0x70, 0xc7, 0xf7, 0x1c}) - TypeLayoutReflection* getTypeLayout( - TypeReflection* type, - LayoutRules rules = LayoutRules::Default) - { - return (TypeLayoutReflection*)spReflection_GetTypeLayout( - (SlangReflection*) this, - (SlangReflectionType*)type, - SlangLayoutRules(rules)); - } + /** Create a new session for loading and compiling code. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createSession(SessionDesc const& desc, ISession** outSession) = 0; - EntryPointReflection* findEntryPointByName(const char* name) - { - return (EntryPointReflection*)spReflection_findEntryPointByName( - (SlangReflection*) this, - name); - } + /** Look up the internal ID of a profile by its `name`. - TypeReflection* specializeType( - TypeReflection* type, - SlangInt specializationArgCount, - TypeReflection* const* specializationArgs, - ISlangBlob** outDiagnostics) - { - return (TypeReflection*) spReflection_specializeType( - (SlangReflection*) this, - (SlangReflectionType*) type, - specializationArgCount, - (SlangReflectionType* const*) specializationArgs, - outDiagnostics); - } + Profile IDs are *not* guaranteed to be stable across versions + of the Slang library, so clients are expected to look up + profiles by name at runtime. + */ + virtual SLANG_NO_THROW SlangProfileID SLANG_MCALL findProfile(char const* name) = 0; - GenericReflection* specializeGeneric( - GenericReflection* generic, - SlangInt specializationArgCount, - GenericArgType const* specializationArgTypes, - GenericArgReflection const* specializationArgVals, - ISlangBlob** outDiagnostics) - { - return (GenericReflection*) spReflection_specializeGeneric( - (SlangReflection*) this, - (SlangReflectionGeneric*) generic, - specializationArgCount, - (SlangReflectionGenericArgType const*) specializationArgTypes, - (SlangReflectionGenericArg const*) specializationArgVals, - outDiagnostics); - } + /** Set the path that downstream compilers (aka back end compilers) will + be looked from. + @param passThrough Identifies the downstream compiler + @param path The path to find the downstream compiler (shared library/dll/executable) - bool isSubType( - TypeReflection* subType, - TypeReflection* superType) - { - return spReflection_isSubType( - (SlangReflection*) this, - (SlangReflectionType*) subType, - (SlangReflectionType*) superType); - } + For back ends that are dlls/shared libraries, it will mean the path will + be prefixed with the path when calls are made out to ISlangSharedLibraryLoader. + For executables - it will look for executables along the path */ + virtual SLANG_NO_THROW void SLANG_MCALL + setDownstreamCompilerPath(SlangPassThrough passThrough, char const* path) = 0; - SlangUInt getHashedStringCount() const { return spReflection_getHashedStringCount((SlangReflection*)this); } + /** DEPRECATED: Use setLanguagePrelude - const char* getHashedString(SlangUInt index, size_t* outCount) const - { - return spReflection_getHashedString((SlangReflection*)this, index, outCount); - } + Set the 'prelude' for generated code for a 'downstream compiler'. + @param passThrough The downstream compiler for generated code that will have the prelude applied + to it. + @param preludeText The text added pre-pended verbatim before the generated source - TypeLayoutReflection* getGlobalParamsTypeLayout() - { - return (TypeLayoutReflection*) spReflection_getGlobalParamsTypeLayout((SlangReflection*) this); - } + That for pass-through usage, prelude is not pre-pended, preludes are for code generation only. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setDownstreamCompilerPrelude(SlangPassThrough passThrough, const char* preludeText) = 0; - VariableLayoutReflection* getGlobalParamsVarLayout() - { - return (VariableLayoutReflection*) spReflection_getGlobalParamsVarLayout((SlangReflection*) this); - } - }; + /** DEPRECATED: Use getLanguagePrelude - - struct DeclReflection - { - enum class Kind - { - Unsupported = SLANG_DECL_KIND_UNSUPPORTED_FOR_REFLECTION, - Struct = SLANG_DECL_KIND_STRUCT, - Func = SLANG_DECL_KIND_FUNC, - Module = SLANG_DECL_KIND_MODULE, - Generic = SLANG_DECL_KIND_GENERIC, - Variable = SLANG_DECL_KIND_VARIABLE, - Namespace = SLANG_DECL_KIND_NAMESPACE, - }; + Get the 'prelude' for generated code for a 'downstream compiler'. + @param passThrough The downstream compiler for generated code that will have the prelude applied + to it. + @param outPrelude On exit holds a blob that holds the string of the prelude. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + getDownstreamCompilerPrelude(SlangPassThrough passThrough, ISlangBlob** outPrelude) = 0; - char const* getName() - { - return spReflectionDecl_getName((SlangReflectionDecl*) this); - } + /** Get the build version 'tag' string. The string is the same as produced via `git describe + --tags` for the project. If Slang is built separately from the automated build scripts the + contents will by default be 'unknown'. Any string can be set by changing the contents of + 'slang-tag-version.h' file and recompiling the project. - Kind getKind() - { - return (Kind)spReflectionDecl_getKind((SlangReflectionDecl*)this); - } + This method will return exactly the same result as the free function spGetBuildTagString. - unsigned int getChildrenCount() - { - return spReflectionDecl_getChildrenCount((SlangReflectionDecl*)this); - } + @return The build tag string + */ + virtual SLANG_NO_THROW const char* SLANG_MCALL getBuildTagString() = 0; - DeclReflection* getChild(unsigned int index) - { - return (DeclReflection*)spReflectionDecl_getChild((SlangReflectionDecl*)this, index); - } + /* For a given source language set the default compiler. + If a default cannot be chosen (for example the target cannot be achieved by the default), + the default will not be used. - TypeReflection* getType() - { - return (TypeReflection*)spReflection_getTypeFromDecl((SlangReflectionDecl*)this); - } + @param sourceLanguage the source language + @param defaultCompiler the default compiler for that language + @return + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL setDefaultDownstreamCompiler( + SlangSourceLanguage sourceLanguage, + SlangPassThrough defaultCompiler) = 0; - VariableReflection* asVariable() - { - return (VariableReflection*)spReflectionDecl_castToVariable((SlangReflectionDecl*)this); - } + /* For a source type get the default compiler - FunctionReflection* asFunction() - { - return (FunctionReflection*)spReflectionDecl_castToFunction((SlangReflectionDecl*)this); - } + @param sourceLanguage the source language + @return The downstream compiler for that source language */ + virtual SlangPassThrough SLANG_MCALL + getDefaultDownstreamCompiler(SlangSourceLanguage sourceLanguage) = 0; - GenericReflection* asGeneric() - { - return (GenericReflection*)spReflectionDecl_castToGeneric((SlangReflectionDecl*)this); - } + /* Set the 'prelude' placed before generated code for a specific language type. - DeclReflection* getParent() - { - return (DeclReflection*)spReflectionDecl_getParent((SlangReflectionDecl*)this); - } + @param sourceLanguage The language the prelude should be inserted on. + @param preludeText The text added pre-pended verbatim before the generated source - template - struct FilteredList - { - unsigned int count; - DeclReflection* parent; + Note! That for pass-through usage, prelude is not pre-pended, preludes are for code generation + only. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setLanguagePrelude(SlangSourceLanguage sourceLanguage, const char* preludeText) = 0; - struct FilteredIterator - { - DeclReflection* parent; - unsigned int count; - unsigned int index; + /** Get the 'prelude' associated with a specific source language. + @param sourceLanguage The language the prelude should be inserted on. + @param outPrelude On exit holds a blob that holds the string of the prelude. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + getLanguagePrelude(SlangSourceLanguage sourceLanguage, ISlangBlob** outPrelude) = 0; + + /** Create a compile request. + */ + [[deprecated]] virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createCompileRequest(slang::ICompileRequest** outCompileRequest) = 0; + + /** Add new builtin declarations to be used in subsequent compiles. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + addBuiltins(char const* sourcePath, char const* sourceString) = 0; + + /** Set the session shared library loader. If this changes the loader, it may cause shared + libraries to be unloaded + @param loader The loader to set. Setting nullptr sets the default loader. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + setSharedLibraryLoader(ISlangSharedLibraryLoader* loader) = 0; - DeclReflection* operator*() { return parent->getChild(index); } - void operator++() - { - index++; - while (index < count && !(parent->getChild(index)->getKind() == K)) - { - index++; - } - } - bool operator!=(FilteredIterator const& other) { return index != other.index; } - }; - - // begin/end for range-based for that checks the kind - FilteredIterator begin() - { - // Find the first child of the right kind - unsigned int index = 0; - while (index < count && !(parent->getChild(index)->getKind() == K)) - { - index++; - } - return FilteredIterator{parent, count, index}; - } + /** Gets the currently set shared library loader + @return Gets the currently set loader. If returns nullptr, it's the default loader + */ + virtual SLANG_NO_THROW ISlangSharedLibraryLoader* SLANG_MCALL getSharedLibraryLoader() = 0; + + /** Returns SLANG_OK if the compilation target is supported for this session + + @param target The compilation target to test + @return SLANG_OK if the target is available + SLANG_E_NOT_IMPLEMENTED if not implemented in this build + SLANG_E_NOT_FOUND if other resources (such as shared libraries) required to make target work + could not be found SLANG_FAIL other kinds of failures */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + checkCompileTargetSupport(SlangCompileTarget target) = 0; + + /** Returns SLANG_OK if the pass through support is supported for this session + @param session Session + @param target The compilation target to test + @return SLANG_OK if the target is available + SLANG_E_NOT_IMPLEMENTED if not implemented in this build + SLANG_E_NOT_FOUND if other resources (such as shared libraries) required to make target work + could not be found SLANG_FAIL other kinds of failures */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + checkPassThroughSupport(SlangPassThrough passThrough) = 0; + + /** Compile from (embedded source) the core module on the session. + Will return a failure if there is already a core module available + NOTE! API is experimental and not ready for production code + @param flags to control compilation + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compileCoreModule(CompileCoreModuleFlags flags) = 0; - FilteredIterator end() { return FilteredIterator{parent, count, count}; } - }; - - template - FilteredList getChildrenOfKind() - { - return FilteredList{ getChildrenCount(), (DeclReflection*)this }; - } + /** Load the core module. Currently loads modules from the file system. + @param coreModule Start address of the serialized core module + @param coreModuleSizeInBytes The size in bytes of the serialized core module - struct IteratedList - { - unsigned int count; - DeclReflection* parent; + NOTE! API is experimental and not ready for production code + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadCoreModule(const void* coreModule, size_t coreModuleSizeInBytes) = 0; - struct Iterator - { - DeclReflection* parent; - unsigned int count; - unsigned int index; - - DeclReflection* operator*() { return parent->getChild(index); } - void operator++() { index++; } - bool operator!=(Iterator const& other) { return index != other.index; } - }; - - // begin/end for range-based for that checks the kind - IteratedList::Iterator begin() { return IteratedList::Iterator{ parent, count, 0 }; } - IteratedList::Iterator end() { return IteratedList::Iterator{ parent, count, count }; } - }; + /** Save the core module to the file system + @param archiveType The type of archive used to hold the core module + @param outBlob The serialized blob containing the core module - IteratedList getChildren() - { - return IteratedList{ getChildrenCount(), (DeclReflection*)this }; - } + NOTE! API is experimental and not ready for production code */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + saveCoreModule(SlangArchiveType archiveType, ISlangBlob** outBlob) = 0; - }; + /** Look up the internal ID of a capability by its `name`. - typedef uint32_t CompileStdLibFlags; - struct CompileStdLibFlag - { - enum Enum : CompileStdLibFlags - { - WriteDocumentation = 0x1, - }; - }; + Capability IDs are *not* guaranteed to be stable across versions + of the Slang library, so clients are expected to look up + capabilities by name at runtime. + */ + virtual SLANG_NO_THROW SlangCapabilityID SLANG_MCALL findCapability(char const* name) = 0; - typedef ISlangBlob IBlob; + /** Set the downstream/pass through compiler to be used for a transition from the source type to + the target type + @param source The source 'code gen target' + @param target The target 'code gen target' + @param compiler The compiler/pass through to use for the transition from source to target + */ + virtual SLANG_NO_THROW void SLANG_MCALL setDownstreamCompilerForTransition( + SlangCompileTarget source, + SlangCompileTarget target, + SlangPassThrough compiler) = 0; + + /** Get the downstream/pass through compiler for a transition specified by source and target + @param source The source 'code gen target' + @param target The target 'code gen target' + @return The compiler that is used for the transition. Returns SLANG_PASS_THROUGH_NONE it is not + defined + */ + virtual SLANG_NO_THROW SlangPassThrough SLANG_MCALL + getDownstreamCompilerForTransition(SlangCompileTarget source, SlangCompileTarget target) = 0; + + /** Get the time in seconds spent in the slang and downstream compiler. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + getCompilerElapsedTime(double* outTotalTime, double* outDownstreamTime) = 0; + + /** Specify a spirv.core.grammar.json file to load and use when + * parsing and checking any SPIR-V code + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL setSPIRVCoreGrammar(char const* jsonPath) = 0; + + /** Parse slangc command line options into a SessionDesc that can be used to create a session + * with all the compiler options specified in the command line. + * @param argc The number of command line arguments. + * @param argv An input array of command line arguments to parse. + * @param outSessionDesc A pointer to a SessionDesc struct to receive parsed session desc. + * @param outAuxAllocation Auxiliary memory allocated to hold data used in the session desc. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL parseCommandLineArguments( + int argc, + const char* const* argv, + SessionDesc* outSessionDesc, + ISlangUnknown** outAuxAllocation) = 0; + + /** Computes a digest that uniquely identifies the session description. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getSessionDescDigest(SessionDesc* sessionDesc, ISlangBlob** outBlob) = 0; +}; - struct IComponentType; - struct ITypeConformance; - struct IGlobalSession; - struct IModule; + #define SLANG_UUID_IGlobalSession IGlobalSession::getTypeGuid() - struct SessionDesc; - struct SpecializationArg; - struct TargetDesc; +/** Description of a code generation target. + */ +struct TargetDesc +{ + /** The size of this structure, in bytes. + */ + size_t structureSize = sizeof(TargetDesc); - /** A global session for interaction with the Slang library. + /** The target format to generate code for (e.g., SPIR-V, DXIL, etc.) + */ + SlangCompileTarget format = SLANG_TARGET_UNKNOWN; - An application may create and re-use a single global session across - multiple sessions, in order to amortize startups costs (in current - Slang this is mostly the cost of loading the Slang standard library). + /** The compilation profile supported by the target (e.g., "Shader Model 5.1") + */ + SlangProfileID profile = SLANG_PROFILE_UNKNOWN; - The global session is currently *not* thread-safe and objects created from - a single global session should only be used from a single thread at - a time. - */ - struct IGlobalSession : public ISlangUnknown - { - SLANG_COM_INTERFACE(0xc140b5fd, 0xc78, 0x452e, { 0xba, 0x7c, 0x1a, 0x1e, 0x70, 0xc7, 0xf7, 0x1c }) - - /** Create a new session for loading and compiling code. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createSession( - SessionDesc const& desc, - ISession** outSession) = 0; - - /** Look up the internal ID of a profile by its `name`. - - Profile IDs are *not* guaranteed to be stable across versions - of the Slang library, so clients are expected to look up - profiles by name at runtime. - */ - virtual SLANG_NO_THROW SlangProfileID SLANG_MCALL findProfile( - char const* name) = 0; - - /** Set the path that downstream compilers (aka back end compilers) will - be looked from. - @param passThrough Identifies the downstream compiler - @param path The path to find the downstream compiler (shared library/dll/executable) - - For back ends that are dlls/shared libraries, it will mean the path will - be prefixed with the path when calls are made out to ISlangSharedLibraryLoader. - For executables - it will look for executables along the path */ - virtual SLANG_NO_THROW void SLANG_MCALL setDownstreamCompilerPath( - SlangPassThrough passThrough, - char const* path) = 0; - - /** DEPRECATED: Use setLanguagePrelude - - Set the 'prelude' for generated code for a 'downstream compiler'. - @param passThrough The downstream compiler for generated code that will have the prelude applied to it. - @param preludeText The text added pre-pended verbatim before the generated source - - That for pass-through usage, prelude is not pre-pended, preludes are for code generation only. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setDownstreamCompilerPrelude( - SlangPassThrough passThrough, - const char* preludeText) = 0; - - /** DEPRECATED: Use getLanguagePrelude - - Get the 'prelude' for generated code for a 'downstream compiler'. - @param passThrough The downstream compiler for generated code that will have the prelude applied to it. - @param outPrelude On exit holds a blob that holds the string of the prelude. - */ - virtual SLANG_NO_THROW void SLANG_MCALL getDownstreamCompilerPrelude( - SlangPassThrough passThrough, - ISlangBlob** outPrelude) = 0; - - /** Get the build version 'tag' string. The string is the same as produced via `git describe --tags` - for the project. If Slang is built separately from the automated build scripts - the contents will by default be 'unknown'. Any string can be set by changing the - contents of 'slang-tag-version.h' file and recompiling the project. - - This method will return exactly the same result as the free function spGetBuildTagString. - - @return The build tag string - */ - virtual SLANG_NO_THROW const char* SLANG_MCALL getBuildTagString() = 0; - - /* For a given source language set the default compiler. - If a default cannot be chosen (for example the target cannot be achieved by the default), - the default will not be used. - - @param sourceLanguage the source language - @param defaultCompiler the default compiler for that language - @return - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL setDefaultDownstreamCompiler( - SlangSourceLanguage sourceLanguage, - SlangPassThrough defaultCompiler) = 0; - - /* For a source type get the default compiler - - @param sourceLanguage the source language - @return The downstream compiler for that source language */ - virtual SlangPassThrough SLANG_MCALL getDefaultDownstreamCompiler( - SlangSourceLanguage sourceLanguage) = 0; - - /* Set the 'prelude' placed before generated code for a specific language type. - - @param sourceLanguage The language the prelude should be inserted on. - @param preludeText The text added pre-pended verbatim before the generated source - - Note! That for pass-through usage, prelude is not pre-pended, preludes are for code generation only. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setLanguagePrelude( - SlangSourceLanguage sourceLanguage, - const char* preludeText) = 0; - - /** Get the 'prelude' associated with a specific source language. - @param sourceLanguage The language the prelude should be inserted on. - @param outPrelude On exit holds a blob that holds the string of the prelude. - */ - virtual SLANG_NO_THROW void SLANG_MCALL getLanguagePrelude( - SlangSourceLanguage sourceLanguage, - ISlangBlob** outPrelude) = 0; - - /** Create a compile request. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCompileRequest( - slang::ICompileRequest** outCompileRequest) = 0; - - /** Add new builtin declarations to be used in subsequent compiles. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addBuiltins( - char const* sourcePath, - char const* sourceString) = 0; - - /** Set the session shared library loader. If this changes the loader, it may cause shared libraries to be unloaded - @param loader The loader to set. Setting nullptr sets the default loader. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setSharedLibraryLoader( - ISlangSharedLibraryLoader* loader) = 0; - - /** Gets the currently set shared library loader - @return Gets the currently set loader. If returns nullptr, it's the default loader - */ - virtual SLANG_NO_THROW ISlangSharedLibraryLoader* SLANG_MCALL getSharedLibraryLoader() = 0; - - /** Returns SLANG_OK if a the compilation target is supported for this session - - @param target The compilation target to test - @return SLANG_OK if the target is available - SLANG_E_NOT_IMPLEMENTED if not implemented in this build - SLANG_E_NOT_FOUND if other resources (such as shared libraries) required to make target work could not be found - SLANG_FAIL other kinds of failures */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL checkCompileTargetSupport( - SlangCompileTarget target) = 0; - - /** Returns SLANG_OK if a the pass through support is supported for this session - @param session Session - @param target The compilation target to test - @return SLANG_OK if the target is available - SLANG_E_NOT_IMPLEMENTED if not implemented in this build - SLANG_E_NOT_FOUND if other resources (such as shared libraries) required to make target work could not be found - SLANG_FAIL other kinds of failures */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL checkPassThroughSupport( - SlangPassThrough passThrough) = 0; - - /** Compile from (embedded source) the StdLib on the session. - Will return a failure if there is already a StdLib available - NOTE! API is experimental and not ready for production code - @param flags to control compilation - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compileStdLib(CompileStdLibFlags flags) = 0; - - /** Load the StdLib. Currently loads modules from the file system. - @param stdLib Start address of the serialized stdlib - @param stdLibSizeInBytes The size in bytes of the serialized stdlib - - NOTE! API is experimental and not ready for production code - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadStdLib(const void* stdLib, size_t stdLibSizeInBytes) = 0; - - /** Save the StdLib modules to the file system - @param archiveType The type of archive used to hold the stdlib - @param outBlob The serialized blob containing the standard library - - NOTE! API is experimental and not ready for production code */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveStdLib(SlangArchiveType archiveType, ISlangBlob** outBlob) = 0; - - /** Look up the internal ID of a capability by its `name`. - - Capability IDs are *not* guaranteed to be stable across versions - of the Slang library, so clients are expected to look up - capabilities by name at runtime. - */ - virtual SLANG_NO_THROW SlangCapabilityID SLANG_MCALL findCapability( - char const* name) = 0; - - /** Set the downstream/pass through compiler to be used for a transition from the source type to the target type - @param source The source 'code gen target' - @param target The target 'code gen target' - @param compiler The compiler/pass through to use for the transition from source to target - */ - virtual SLANG_NO_THROW void SLANG_MCALL setDownstreamCompilerForTransition(SlangCompileTarget source, SlangCompileTarget target, SlangPassThrough compiler) = 0; - - /** Get the downstream/pass through compiler for a transition specified by source and target - @param source The source 'code gen target' - @param target The target 'code gen target' - @return The compiler that is used for the transition. Returns SLANG_PASS_THROUGH_NONE it is not defined - */ - virtual SLANG_NO_THROW SlangPassThrough SLANG_MCALL getDownstreamCompilerForTransition(SlangCompileTarget source, SlangCompileTarget target) = 0; - - /** Get the time in seconds spent in the slang and downstream compiler. - */ - virtual SLANG_NO_THROW void SLANG_MCALL getCompilerElapsedTime(double* outTotalTime, double* outDownstreamTime) = 0; - - /** Specify a spirv.core.grammar.json file to load and use when - * parsing and checking any SPIR-V code - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL setSPIRVCoreGrammar( - char const* jsonPath) = 0; - - /** Parse slangc command line options into a SessionDesc that can be used to create a session - * with all the compiler options specified in the command line. - * @param argc The number of command line arguments. - * @param argv An input array of command line arguments to parse. - * @param outSessionDesc A pointer to a SessionDesc struct to receive parsed session desc. - * @param outAuxAllocation Auxillary memory allocated to hold data used in the sesion desc. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL parseCommandLineArguments( - int argc, const char* const* argv, SessionDesc* outSessionDesc, ISlangUnknown** outAuxAllocation) = 0; - - /** Computes a digest that uniquely identifies the session description. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSessionDescDigest(SessionDesc* sessionDesc, ISlangBlob** outBlob) = 0; - }; + /** Flags for the code generation target. Currently unused. */ + SlangTargetFlags flags = kDefaultTargetFlags; - #define SLANG_UUID_IGlobalSession IGlobalSession::getTypeGuid() + /** Default mode to use for floating-point operations on the target. + */ + SlangFloatingPointMode floatingPointMode = SLANG_FLOATING_POINT_MODE_DEFAULT; - /*! - @brief A request for one or more compilation actions to be performed. - */ - struct ICompileRequest : public ISlangUnknown - { - SLANG_COM_INTERFACE( 0x96d33993, 0x317c, 0x4db5, { 0xaf, 0xd8, 0x66, 0x6e, 0xe7, 0x72, 0x48, 0xe2 } ) - - /** Set the filesystem hook to use for a compile request - - The provided `fileSystem` will be used to load any files that - need to be loaded during processing of the compile `request`. - This includes: - - - Source files loaded via `spAddTranslationUnitSourceFile` - - Files referenced via `#include` - - Files loaded to resolve `#import` operations - */ - virtual SLANG_NO_THROW void SLANG_MCALL setFileSystem( - ISlangFileSystem* fileSystem) = 0; - - /*! - @brief Set flags to be used for compilation. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setCompileFlags( - SlangCompileFlags flags) = 0; - - /*! - @brief Returns the compilation flags previously set with `setCompileFlags` - */ - virtual SLANG_NO_THROW SlangCompileFlags SLANG_MCALL getCompileFlags() = 0; - - /*! - @brief Set whether to dump intermediate results (for debugging) or not. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediates( - int enable) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setDumpIntermediatePrefix( - const char* prefix) = 0; - - /*! - @brief Set whether (and how) `#line` directives should be output. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setLineDirectiveMode( - SlangLineDirectiveMode mode) = 0; - - /*! - @brief Sets the target for code generation. - @param target The code generation target. Possible values are: - - SLANG_GLSL. Generates GLSL code. - - SLANG_HLSL. Generates HLSL code. - - SLANG_SPIRV. Generates SPIR-V code. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setCodeGenTarget( - SlangCompileTarget target) = 0; - - /*! - @brief Add a code-generation target to be used. - */ - virtual SLANG_NO_THROW int SLANG_MCALL addCodeGenTarget( - SlangCompileTarget target) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setTargetProfile( - int targetIndex, - SlangProfileID profile) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setTargetFlags( - int targetIndex, - SlangTargetFlags flags) = 0; - - /*! - @brief Set the floating point mode (e.g., precise or fast) to use a target. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setTargetFloatingPointMode( - int targetIndex, - SlangFloatingPointMode mode) = 0; - - /* DEPRECATED: use `spSetMatrixLayoutMode` instead. */ - virtual SLANG_NO_THROW void SLANG_MCALL setTargetMatrixLayoutMode( - int targetIndex, - SlangMatrixLayoutMode mode) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setMatrixLayoutMode( - SlangMatrixLayoutMode mode) = 0; - - /*! - @brief Set the level of debug information to produce. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setDebugInfoLevel( - SlangDebugInfoLevel level) = 0; - - /*! - @brief Set the level of optimization to perform. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setOptimizationLevel( - SlangOptimizationLevel level) = 0; - - - - /*! - @brief Set the container format to be used for binary output. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setOutputContainerFormat( - SlangContainerFormat format) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setPassThrough( - SlangPassThrough passThrough) = 0; - - - virtual SLANG_NO_THROW void SLANG_MCALL setDiagnosticCallback( - SlangDiagnosticCallback callback, - void const* userData) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setWriter( - SlangWriterChannel channel, - ISlangWriter* writer) = 0; - - virtual SLANG_NO_THROW ISlangWriter* SLANG_MCALL getWriter( - SlangWriterChannel channel) = 0; - - /*! - @brief Add a path to use when searching for referenced files. - This will be used for both `#include` directives and also for explicit `__import` declarations. - @param ctx The compilation context. - @param searchDir The additional search directory. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addSearchPath( - const char* searchDir) = 0; - - /*! - @brief Add a macro definition to be used during preprocessing. - @param key The name of the macro to define. - @param value The value of the macro to define. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addPreprocessorDefine( - const char* key, - const char* value) = 0; - - /*! - @brief Set options using arguments as if specified via command line. - @return Returns SlangResult. On success SLANG_SUCCEEDED(result) is true. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL processCommandLineArguments( - char const* const* args, - int argCount) = 0; - - /** Add a distinct translation unit to the compilation request - - `name` is optional. - Returns the zero-based index of the translation unit created. - */ - virtual SLANG_NO_THROW int SLANG_MCALL addTranslationUnit( - SlangSourceLanguage language, - char const* name) = 0; - - - /** Set a default module name. Translation units will default to this module name if one is not - passed. If not set each translation unit will get a unique name. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setDefaultModuleName( - const char* defaultModuleName) = 0; - - /** Add a preprocessor definition that is scoped to a single translation unit. - - @param translationUnitIndex The index of the translation unit to get the definition. - @param key The name of the macro to define. - @param value The value of the macro to define. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitPreprocessorDefine( - int translationUnitIndex, - const char* key, - const char* value) = 0; - - - /** Add a source file to the given translation unit. - - If a user-defined file system has been specified via - `spSetFileSystem`, then it will be used to load the - file at `path`. Otherwise, Slang will use the OS - file system. - - This function does *not* search for a file using - the registered search paths (`spAddSearchPath`), - and instead using the given `path` as-is. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceFile( - int translationUnitIndex, - char const* path) = 0; - - /** Add a source string to the given translation unit. - - @param translationUnitIndex The index of the translation unit to add source to. - @param path The file-system path that should be assumed for the source code. - @param source A null-terminated UTF-8 encoded string of source code. - - The implementation will make a copy of the source code data. - An application may free the buffer immediately after this call returns. - - The `path` will be used in any diagnostic output, as well - as to determine the base path when resolving relative - `#include`s. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceString( - int translationUnitIndex, - char const* path, - char const* source) = 0; - - - /** Add a slang library - such that its contents can be referenced during linking. - This is equivalent to the -r command line option. - - @param basePath The base path used to lookup referenced modules. - @param libData The library data - @param libDataSize The size of the library data - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL addLibraryReference( - const char* basePath, - const void* libData, - size_t libDataSize) = 0; - - /** Add a source string to the given translation unit. - - @param translationUnitIndex The index of the translation unit to add source to. - @param path The file-system path that should be assumed for the source code. - @param sourceBegin A pointer to a buffer of UTF-8 encoded source code. - @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` - - The implementation will make a copy of the source code data. - An application may free the buffer immediately after this call returns. - - The `path` will be used in any diagnostic output, as well - as to determine the base path when resolving relative - `#include`s. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceStringSpan( - int translationUnitIndex, - char const* path, - char const* sourceBegin, - char const* sourceEnd) = 0; - - /** Add a blob of source code to the given translation unit. - - @param translationUnitIndex The index of the translation unit to add source to. - @param path The file-system path that should be assumed for the source code. - @param sourceBlob A blob containing UTF-8 encoded source code. - @param sourceEnd A pointer to to the end of the buffer specified in `sourceBegin` - - The compile request will retain a reference to the blob. - - The `path` will be used in any diagnostic output, as well - as to determine the base path when resolving relative - `#include`s. - */ - virtual SLANG_NO_THROW void SLANG_MCALL addTranslationUnitSourceBlob( - int translationUnitIndex, - char const* path, - ISlangBlob* sourceBlob) = 0; - - /** Add an entry point in a particular translation unit - */ - virtual SLANG_NO_THROW int SLANG_MCALL addEntryPoint( - int translationUnitIndex, - char const* name, - SlangStage stage) = 0; - - /** Add an entry point in a particular translation unit, - with additional arguments that specify the concrete - type names for entry-point generic type parameters. - */ - virtual SLANG_NO_THROW int SLANG_MCALL addEntryPointEx( - int translationUnitIndex, - char const* name, - SlangStage stage, - int genericArgCount, - char const** genericArgs) = 0; - - /** Specify the arguments to use for global generic parameters. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL setGlobalGenericArgs( - int genericArgCount, - char const** genericArgs) = 0; - - /** Specify the concrete type to be used for a global "existential slot." - - Every shader parameter (or leaf field of a `struct`-type shader parameter) - that has an interface or array-of-interface type introduces an existential - slot. The number of slots consumed by a shader parameter, and the starting - slot of each parameter can be queried via the reflection API using - `SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM`. - - In order to generate specialized code, a concrete type needs to be specified - for each existential slot. This function specifies the name of the type - (or in general a type *expression*) to use for a specific slot at the - global scope. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL setTypeNameForGlobalExistentialTypeParam( - int slotIndex, - char const* typeName) = 0; - - /** Specify the concrete type to be used for an entry-point "existential slot." - - Every shader parameter (or leaf field of a `struct`-type shader parameter) - that has an interface or array-of-interface type introduces an existential - slot. The number of slots consumed by a shader parameter, and the starting - slot of each parameter can be queried via the reflection API using - `SLANG_PARAMETER_CATEGORY_EXISTENTIAL_TYPE_PARAM`. - - In order to generate specialized code, a concrete type needs to be specified - for each existential slot. This function specifies the name of the type - (or in general a type *expression*) to use for a specific slot at the - entry-point scope. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL setTypeNameForEntryPointExistentialTypeParam( - int entryPointIndex, - int slotIndex, - char const* typeName) = 0; - - /** Enable or disable an experimental, best-effort GLSL frontend - */ - virtual SLANG_NO_THROW void SLANG_MCALL setAllowGLSLInput( - bool value) = 0; - - /** Execute the compilation request. - - @returns SlangResult, SLANG_OK on success. Use SLANG_SUCCEEDED() and SLANG_FAILED() to test SlangResult. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile() = 0; - - - /** Get any diagnostic messages reported by the compiler. - - @returns A null-terminated UTF-8 encoded string of diagnostic messages. - - The returned pointer is only guaranteed to be valid - until `request` is destroyed. Applications that wish to - hold on to the diagnostic output for longer should use - `getDiagnosticOutputBlob`. - */ - virtual SLANG_NO_THROW char const* SLANG_MCALL getDiagnosticOutput() = 0; - - /** Get diagnostic messages reported by the compiler. - - @param outBlob A pointer to receive a blob holding a nul-terminated UTF-8 encoded string of diagnostic messages. - @returns A `SlangResult` indicating success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getDiagnosticOutputBlob( - ISlangBlob** outBlob) = 0; - - - /** Get the number of files that this compilation depended on. - - This includes both the explicit source files, as well as any - additional files that were transitively referenced (e.g., via - a `#include` directive). - */ - virtual SLANG_NO_THROW int SLANG_MCALL getDependencyFileCount() = 0; - - /** Get the path to a file this compilation depended on. - */ - virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath( - int index) = 0; - - /** Get the number of translation units associated with the compilation request - */ - virtual SLANG_NO_THROW int SLANG_MCALL getTranslationUnitCount() = 0; - - /** Get the output source code associated with a specific entry point. - - The lifetime of the output pointer is the same as `request`. - */ - virtual SLANG_NO_THROW char const* SLANG_MCALL getEntryPointSource( - int entryPointIndex) = 0; - - /** Get the output bytecode associated with a specific entry point. - - The lifetime of the output pointer is the same as `request`. - */ - virtual SLANG_NO_THROW void const* SLANG_MCALL getEntryPointCode( - int entryPointIndex, - size_t* outSize) = 0; - - /** Get the output code associated with a specific entry point. - - @param entryPointIndex The index of the entry point to get code for. - @param targetIndex The index of the target to get code for (default: zero). - @param outBlob A pointer that will receive the blob of code - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointCodeBlob( - int entryPointIndex, - int targetIndex, - ISlangBlob** outBlob) = 0; - - /** Get entry point 'callable' functions accessible through the ISlangSharedLibrary interface. - - That the functions remain in scope as long as the ISlangSharedLibrary interface is in scope. - - NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. - - @param entryPointIndex The index of the entry point to get code for. - @param targetIndex The index of the target to get code for (default: zero). - @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried on. - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointHostCallable( - int entryPointIndex, - int targetIndex, - ISlangSharedLibrary** outSharedLibrary) = 0; - - /** Get the output code associated with a specific target. - - @param targetIndex The index of the target to get code for (default: zero). - @param outBlob A pointer that will receive the blob of code - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTargetCodeBlob( - int targetIndex, - ISlangBlob** outBlob) = 0; - - /** Get 'callable' functions for a target accessible through the ISlangSharedLibrary interface. - - That the functions remain in scope as long as the ISlangSharedLibrary interface is in scope. - - NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. - - @param targetIndex The index of the target to get code for (default: zero). - @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried on. - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTargetHostCallable( - int targetIndex, - ISlangSharedLibrary** outSharedLibrary) = 0; - - /** Get the output bytecode associated with an entire compile request. - - The lifetime of the output pointer is the same as `request` and the last spCompile. - - @param outSize The size of the containers contents in bytes. Will be zero if there is no code available. - @returns Pointer to start of the contained data, or nullptr if there is no code available. - */ - virtual SLANG_NO_THROW void const* SLANG_MCALL getCompileRequestCode( - size_t* outSize) = 0; - - /** Get the compilation result as a file system. - The result is not written to the actual OS file system, but is made avaiable as an - in memory representation. - */ - virtual SLANG_NO_THROW ISlangMutableFileSystem* SLANG_MCALL getCompileRequestResultAsFileSystem() = 0; - - /** Return the container code as a blob. The container blob is created as part of a compilation (with spCompile), - and a container is produced with a suitable ContainerFormat. - - @param outSize The blob containing the container data. - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getContainerCode( - ISlangBlob** outBlob) = 0; - - /** Load repro from memory specified. - - Should only be performed on a newly created request. - - NOTE! When using the fileSystem, files will be loaded via their `unique names` as if they are part of the flat file system. This - mechanism is described more fully in docs/repro.md. - - @param fileSystem An (optional) filesystem. Pass nullptr to just use contents of repro held in data. - @param data The data to load from. - @param size The size of the data to load from. - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadRepro( - ISlangFileSystem* fileSystem, - const void* data, - size_t size) = 0; - - /** Save repro state. Should *typically* be performed after spCompile, so that everything - that is needed for a compilation is available. - - @param outBlob Blob that will hold the serialized state - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL saveRepro( - ISlangBlob** outBlob) = 0; - - /** Enable repro capture. - - Should be set after any ISlangFileSystem has been set, but before any compilation. It ensures that everything - that the ISlangFileSystem accesses will be correctly recorded. - Note that if a ISlangFileSystem/ISlangFileSystemExt isn't explicitly set (ie the default is used), then the - request will automatically be set up to record everything appropriate. - - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL enableReproCapture() = 0; - - /** Get the (linked) program for a compile request. - - The linked program will include all of the global-scope modules for the - translation units in the program, plus any modules that they `import` - (transitively), specialized to any global specialization arguments that - were provided via the API. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgram( - slang::IComponentType** outProgram) = 0; - - /** Get the (partially linked) component type for an entry point. - - The returned component type will include the entry point at the - given index, and will be specialized using any specialization arguments - that were provided for it via the API. - - The returned component will *not* include the modules representing - the global scope and its dependencies/specialization, so a client - program will typically want to compose this component type with - the one returned by `spCompileRequest_getProgram` to get a complete - and usable component type from which kernel code can be requested. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPoint( - SlangInt entryPointIndex, - slang::IComponentType** outEntryPoint) = 0; - - /** Get the (un-linked) module for a translation unit. - - The returned module will not be linked against any dependencies, - nor against any entry points (even entry points declared inside - the module). Similarly, the module will not be specialized - to the arguments that might have been provided via the API. - - This function provides an atomic unit of loaded code that - is suitable for looking up types and entry points in the - given module, and for linking together to produce a composite - program that matches the needs of an application. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getModule( - SlangInt translationUnitIndex, - slang::IModule** outModule) = 0; - - /** Get the `ISession` handle behind the `SlangCompileRequest`. - TODO(JS): Arguably this should just return the session pointer. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getSession( - slang::ISession** outSession) = 0; - - /** get reflection data from a compilation request */ - virtual SLANG_NO_THROW SlangReflection* SLANG_MCALL getReflection() = 0; - - /** Make output specially handled for command line output */ - virtual SLANG_NO_THROW void SLANG_MCALL setCommandLineCompilerMode() = 0; - - /** Add a defined capability that should be assumed available on the target */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL addTargetCapability( - SlangInt targetIndex, - SlangCapabilityID capability) = 0; - - /** Get the (linked) program for a compile request, including all entry points. - - The resulting program will include all of the global-scope modules for the - translation units in the program, plus any modules that they `import` - (transitively), specialized to any global specialization arguments that - were provided via the API, as well as all entry points specified for compilation, - specialized to their entry-point specialization arguments. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getProgramWithEntryPoints( - slang::IComponentType** outProgram) = 0; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL isParameterLocationUsed( - SlangInt entryPointIndex, - SlangInt targetIndex, - SlangParameterCategory category, - SlangUInt spaceIndex, - SlangUInt registerIndex, - bool& outUsed) = 0; - - /** Set the line directive mode for a target. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setTargetLineDirectiveMode( - SlangInt targetIndex, - SlangLineDirectiveMode mode) = 0; - - /** Set whether to use scalar buffer layouts for GLSL/Vulkan targets. - If true, the generated GLSL/Vulkan code will use `scalar` layout for storage buffers. - If false, the resulting code will std430 for storage buffers. - */ - virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceGLSLScalarBufferLayout(int targetIndex, bool forceScalarLayout) = 0; - - /** Overrides the severity of a specific diagnostic message. - - @param messageID Numeric identifier of the message to override, - as defined in the 1st parameter of the DIAGNOSTIC macro. - @param overrideSeverity New severity of the message. If the message is originally Error or Fatal, - the new severity cannot be lower than that. - */ - virtual SLANG_NO_THROW void SLANG_MCALL overrideDiagnosticSeverity( - SlangInt messageID, - SlangSeverity overrideSeverity) = 0; - - /** Returns the currently active flags of the request's diagnostic sink. */ - virtual SLANG_NO_THROW SlangDiagnosticFlags SLANG_MCALL getDiagnosticFlags() = 0; - - /** Sets the flags of the request's diagnostic sink. - The previously specified flags are discarded. */ - virtual SLANG_NO_THROW void SLANG_MCALL setDiagnosticFlags(SlangDiagnosticFlags flags) = 0; - - /** Set the debug format to be used for debugging information */ - virtual SLANG_NO_THROW void SLANG_MCALL setDebugInfoFormat(SlangDebugInfoFormat debugFormat) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setEnableEffectAnnotations(bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setReportDownstreamTime(bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setReportPerfBenchmark(bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setSkipSPIRVValidation(bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setTargetUseMinimumSlangOptimization(int targetIndex, bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setIgnoreCapabilityCheck(bool value) = 0; + /** The line directive mode for output source code. + */ + SlangLineDirectiveMode lineDirectiveMode = SLANG_LINE_DIRECTIVE_MODE_DEFAULT; - // return a copy of internal profiling results, and if `shouldClear` is true, clear the internal profiling results before returning. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getCompileTimeProfile(ISlangProfiler** compileTimeProfile, bool shouldClear) = 0; + /** Whether to force `scalar` layout for glsl shader storage buffers. + */ + bool forceGLSLScalarBufferLayout = false; - virtual SLANG_NO_THROW void SLANG_MCALL setTargetGenerateWholeProgram( - int targetIndex, - bool value) = 0; - - virtual SLANG_NO_THROW void SLANG_MCALL setTargetForceDXLayout(int targetIndex, bool value) = 0; + /** Pointer to an array of compiler option entries, whose size is compilerOptionEntryCount. + */ + CompilerOptionEntry* compilerOptionEntries = nullptr; - virtual SLANG_NO_THROW void SLANG_MCALL setTargetEmbedDownstreamIR(int targetIndex, bool value) = 0; - }; + /** Number of additional compiler option entries. + */ + uint32_t compilerOptionEntryCount = 0; +}; - #define SLANG_UUID_ICompileRequest ICompileRequest::getTypeGuid() +typedef uint32_t SessionFlags; +enum +{ + kSessionFlags_None = 0 +}; - /** Description of a code generation target. - */ - struct TargetDesc - { - /** The size of this structure, in bytes. - */ - size_t structureSize = sizeof(TargetDesc); +struct PreprocessorMacroDesc +{ + const char* name; + const char* value; +}; - /** The target format to generate code for (e.g., SPIR-V, DXIL, etc.) - */ - SlangCompileTarget format = SLANG_TARGET_UNKNOWN; +struct SessionDesc +{ + /** The size of this structure, in bytes. + */ + size_t structureSize = sizeof(SessionDesc); - /** The compilation profile supported by the target (e.g., "Shader Model 5.1") - */ - SlangProfileID profile = SLANG_PROFILE_UNKNOWN; + /** Code generation targets to include in the session. + */ + TargetDesc const* targets = nullptr; + SlangInt targetCount = 0; - /** Flags for the code generation target. Currently unused. */ - SlangTargetFlags flags = kDefaultTargetFlags; + /** Flags to configure the session. + */ + SessionFlags flags = kSessionFlags_None; - /** Default mode to use for floating-point operations on the target. - */ - SlangFloatingPointMode floatingPointMode = SLANG_FLOATING_POINT_MODE_DEFAULT; + /** Default layout to assume for variables with matrix types. + */ + SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR; - /** The line directive mode for output source code. - */ - SlangLineDirectiveMode lineDirectiveMode = SLANG_LINE_DIRECTIVE_MODE_DEFAULT; + /** Paths to use when searching for `#include`d or `import`ed files. + */ + char const* const* searchPaths = nullptr; + SlangInt searchPathCount = 0; - /** Whether to force `scalar` layout for glsl shader storage buffers. - */ - bool forceGLSLScalarBufferLayout = false; + PreprocessorMacroDesc const* preprocessorMacros = nullptr; + SlangInt preprocessorMacroCount = 0; - /** Pointer to an array of compiler option entries, whose size is compilerOptionEntryCount. - */ - CompilerOptionEntry* compilerOptionEntries = nullptr; + ISlangFileSystem* fileSystem = nullptr; - /** Number of additional compiler option entries. - */ - uint32_t compilerOptionEntryCount = 0; + bool enableEffectAnnotations = false; + bool allowGLSLSyntax = false; - }; + /** Pointer to an array of compiler option entries, whose size is compilerOptionEntryCount. + */ + CompilerOptionEntry* compilerOptionEntries = nullptr; - typedef uint32_t SessionFlags; - enum - { - kSessionFlags_None = 0 - }; + /** Number of additional compiler option entries. + */ + uint32_t compilerOptionEntryCount = 0; +}; - struct PreprocessorMacroDesc - { - const char* name; - const char* value; - }; +enum class ContainerType +{ + None, + UnsizedArray, + StructuredBuffer, + ConstantBuffer, + ParameterBlock +}; + +/** A session provides a scope for code that is loaded. + +A session can be used to load modules of Slang source code, +and to request target-specific compiled binaries and layout +information. + +In order to be able to load code, the session owns a set +of active "search paths" for resolving `#include` directives +and `import` declarations, as well as a set of global +preprocessor definitions that will be used for all code +that gets `import`ed in the session. + +If multiple user shaders are loaded in the same session, +and import the same module (e.g., two source files do `import X`) +then there will only be one copy of `X` loaded within the session. + +In order to be able to generate target code, the session +owns a list of available compilation targets, which specify +code generation options. + +Code loaded and compiled within a session is owned by the session +and will remain resident in memory until the session is released. +Applications wishing to control the memory usage for compiled +and loaded code should use multiple sessions. +*/ +struct ISession : public ISlangUnknown +{ + SLANG_COM_INTERFACE(0x67618701, 0xd116, 0x468f, {0xab, 0x3b, 0x47, 0x4b, 0xed, 0xce, 0xe, 0x3d}) + + /** Get the global session thas was used to create this session. + */ + virtual SLANG_NO_THROW IGlobalSession* SLANG_MCALL getGlobalSession() = 0; + + /** Load a module as it would be by code using `import`. + */ + virtual SLANG_NO_THROW IModule* SLANG_MCALL + loadModule(const char* moduleName, IBlob** outDiagnostics = nullptr) = 0; + + /** Load a module from Slang source code. + */ + virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromSource( + const char* moduleName, + const char* path, + slang::IBlob* source, + slang::IBlob** outDiagnostics = nullptr) = 0; + + /** Combine multiple component types to create a composite component type. + + The `componentTypes` array must contain `componentTypeCount` pointers + to component types that were loaded or created using the same session. + + The shader parameters and specialization parameters of the composite will + be the union of those in `componentTypes`. The relative order of child + component types is significant, and will affect the order in which + parameters are reflected and laid out. + + The entry-point functions of the composite will be the union of those in + `componentTypes`, and will follow the ordering of `componentTypes`. + + The requirements of the composite component type will be a subset of + those in `componentTypes`. If an entry in `componentTypes` has a requirement + that can be satisfied by another entry, then the composition will + satisfy the requirement and it will not appear as a requirement of + the composite. If multiple entries in `componentTypes` have a requirement + for the same type, then only the first such requirement will be retained + on the composite. The relative ordering of requirements on the composite + will otherwise match that of `componentTypes`. + + If any diagnostics are generated during creation of the composite, they + will be written to `outDiagnostics`. If an error is encountered, the + function will return null. + + It is an error to create a composite component type that recursively + aggregates a single module more than once. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCompositeComponentType( + IComponentType* const* componentTypes, + SlangInt componentTypeCount, + IComponentType** outCompositeComponentType, + ISlangBlob** outDiagnostics = nullptr) = 0; + + /** Specialize a type based on type arguments. + */ + virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL specializeType( + TypeReflection* type, + SpecializationArg const* specializationArgs, + SlangInt specializationArgCount, + ISlangBlob** outDiagnostics = nullptr) = 0; + + + /** Get the layout `type` on the chosen `target`. + */ + virtual SLANG_NO_THROW TypeLayoutReflection* SLANG_MCALL getTypeLayout( + TypeReflection* type, + SlangInt targetIndex = 0, + LayoutRules rules = LayoutRules::Default, + ISlangBlob** outDiagnostics = nullptr) = 0; + + /** Get a container type from `elementType`. For example, given type `T`, returns + a type that represents `StructuredBuffer`. + + @param `elementType`: the element type to wrap around. + @param `containerType`: the type of the container to wrap `elementType` in. + @param `outDiagnostics`: a blob to receive diagnostic messages. + */ + virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL getContainerType( + TypeReflection* elementType, + ContainerType containerType, + ISlangBlob** outDiagnostics = nullptr) = 0; + + /** Return a `TypeReflection` that represents the `__Dynamic` type. + This type can be used as a specialization argument to indicate using + dynamic dispatch. + */ + virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL getDynamicType() = 0; + + /** Get the mangled name for a type RTTI object. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getTypeRTTIMangledName(TypeReflection* type, ISlangBlob** outNameBlob) = 0; + + /** Get the mangled name for a type witness. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTypeConformanceWitnessMangledName( + TypeReflection* type, + TypeReflection* interfaceType, + ISlangBlob** outNameBlob) = 0; + + /** Get the sequential ID used to identify a type witness in a dynamic object. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTypeConformanceWitnessSequentialID( + slang::TypeReflection* type, + slang::TypeReflection* interfaceType, + uint32_t* outId) = 0; + + /** Create a request to load/compile front-end code. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createCompileRequest(SlangCompileRequest** outCompileRequest) = 0; + + + /** Creates a `IComponentType` that represents a type's conformance to an interface. + The retrieved `ITypeConformance` objects can be included in a composite `IComponentType` + to explicitly specify which implementation types should be included in the final compiled + code. For example, if an module defines `IMaterial` interface and `AMaterial`, + `BMaterial`, `CMaterial` types that implements the interface, the user can exclude + `CMaterial` implementation from the resulting shader code by explicitly adding + `AMaterial:IMaterial` and `BMaterial:IMaterial` conformances to a composite + `IComponentType` and get entry point code from it. The resulting code will not have + anything related to `CMaterial` in the dynamic dispatch logic. If the user does not + explicitly include any `TypeConformances` to an interface type, all implementations to + that interface will be included by default. By linking a `ITypeConformance`, the user is + also given the opportunity to specify the dispatch ID of the implementation type. If + `conformanceIdOverride` is -1, there will be no override behavior and Slang will + automatically assign IDs to implementation types. The automatically assigned IDs can be + queried via `ISession::getTypeConformanceWitnessSequentialID`. + + Returns SLANG_OK if succeeds, or SLANG_FAIL if `type` does not conform to `interfaceType`. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createTypeConformanceComponentType( + slang::TypeReflection* type, + slang::TypeReflection* interfaceType, + ITypeConformance** outConformance, + SlangInt conformanceIdOverride, + ISlangBlob** outDiagnostics) = 0; + + /** Load a module from a Slang module blob. + */ + virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromIRBlob( + const char* moduleName, + const char* path, + slang::IBlob* source, + slang::IBlob** outDiagnostics = nullptr) = 0; + + virtual SLANG_NO_THROW SlangInt SLANG_MCALL getLoadedModuleCount() = 0; + virtual SLANG_NO_THROW IModule* SLANG_MCALL getLoadedModule(SlangInt index) = 0; + + /** Checks if a precompiled binary module is up-to-date with the current compiler + * option settings and the source file contents. + */ + virtual SLANG_NO_THROW bool SLANG_MCALL + isBinaryModuleUpToDate(const char* modulePath, slang::IBlob* binaryModuleBlob) = 0; + + /** Load a module from a string. + */ + virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromSourceString( + const char* moduleName, + const char* path, + const char* string, + slang::IBlob** outDiagnostics = nullptr) = 0; +}; - struct SessionDesc - { - /** The size of this structure, in bytes. - */ - size_t structureSize = sizeof(SessionDesc); + #define SLANG_UUID_ISession ISession::getTypeGuid() - /** Code generation targets to include in the session. - */ - TargetDesc const* targets = nullptr; - SlangInt targetCount = 0; +struct IMetadata : public ISlangCastable +{ + SLANG_COM_INTERFACE(0x8044a8a3, 0xddc0, 0x4b7f, {0xaf, 0x8e, 0x2, 0x6e, 0x90, 0x5d, 0x73, 0x32}) - /** Flags to configure the session. - */ - SessionFlags flags = kSessionFlags_None; + /* + Returns whether a resource parameter at the specified binding location is actually being used + in the compiled shader. + */ + virtual SlangResult isParameterLocationUsed( + SlangParameterCategory category, // is this a `t` register? `s` register? + SlangUInt spaceIndex, // `space` for D3D12, `set` for Vulkan + SlangUInt registerIndex, // `register` for D3D12, `binding` for Vulkan + bool& outUsed) = 0; +}; + #define SLANG_UUID_IMetadata IMetadata::getTypeGuid() - /** Default layout to assume for variables with matrix types. - */ - SlangMatrixLayoutMode defaultMatrixLayoutMode = SLANG_MATRIX_LAYOUT_ROW_MAJOR; +/** A component type is a unit of shader code layout, reflection, and linking. - /** Paths to use when searching for `#include`d or `import`ed files. - */ - char const* const* searchPaths = nullptr; - SlangInt searchPathCount = 0; +A component type is a unit of shader code that can be included into +a linked and compiled shader program. Each component type may have: - PreprocessorMacroDesc const* preprocessorMacros = nullptr; - SlangInt preprocessorMacroCount = 0; +* Zero or more uniform shader parameters, representing textures, + buffers, etc. that the code in the component depends on. - ISlangFileSystem* fileSystem = nullptr; +* Zero or more *specialization* parameters, which are type or + value parameters that can be used to synthesize specialized + versions of the component type. - bool enableEffectAnnotations = false; - bool allowGLSLSyntax = false; +* Zero or more entry points, which are the individually invocable + kernels that can have final code generated. - /** Pointer to an array of compiler option entries, whose size is compilerOptionEntryCount. - */ - CompilerOptionEntry* compilerOptionEntries = nullptr; +* Zero or more *requirements*, which are other component + types on which the component type depends. - /** Number of additional compiler option entries. - */ - uint32_t compilerOptionEntryCount = 0; +One example of a component type is a module of Slang code: - }; +* The global-scope shader parameters declared in the module are + the parameters when considered as a component type. - enum class ContainerType - { - None, UnsizedArray, StructuredBuffer, ConstantBuffer, ParameterBlock - }; +* Any global-scope generic or interface type parameters introduce + specialization parameters for the module. - /** A session provides a scope for code that is loaded. +* A module does not by default include any entry points when + considered as a component type (although the code of the + module might *declare* some entry points). - A session can be used to load modules of Slang source code, - and to request target-specific compiled binaries and layout - information. +* Any other modules that are `import`ed in the source code + become requirements of the module, when considered as a + component type. - In order to be able to load code, the session owns a set - of active "search paths" for resolving `#include` directives - and `import` declrations, as well as a set of global - preprocessor definitions that will be used for all code - that gets `import`ed in the session. +An entry point is another example of a component type: - If multiple user shaders are loaded in the same session, - and import the same module (e.g., two source files do `import X`) - then there will only be one copy of `X` loaded within the session. +* The `uniform` parameters of the entry point function are + its shader parameters when considered as a component type. - In order to be able to generate target code, the session - owns a list of available compilation targets, which specify - code generation options. +* Any generic or interface-type parameters of the entry point + introduce specialization parameters. - Code loaded and compiled within a session is owned by the session - and will remain resident in memory until the session is released. - Applications wishing to control the memory usage for compiled - and loaded code should use multiple sessions. - */ - struct ISession : public ISlangUnknown - { - SLANG_COM_INTERFACE( 0x67618701, 0xd116, 0x468f, { 0xab, 0x3b, 0x47, 0x4b, 0xed, 0xce, 0xe, 0x3d } ) +* An entry point component type exposes a single entry point (itself). - /** Get the global session thas was used to create this session. - */ - virtual SLANG_NO_THROW IGlobalSession* SLANG_MCALL getGlobalSession() = 0; +* An entry point has one requirement for the module in which + it was defined. - /** Load a module as it would be by code using `import`. - */ - virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModule( - const char* moduleName, - IBlob** outDiagnostics = nullptr) = 0; +Component types can be manipulated in a few ways: - /** Load a module from Slang source code. - */ - virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromSource( - const char* moduleName, - const char* path, - slang::IBlob* source, - slang::IBlob** outDiagnostics = nullptr) = 0; - - /** Combine multiple component types to create a composite component type. - - The `componentTypes` array must contain `componentTypeCount` pointers - to component types that were loaded or created using the same session. - - The shader parameters and specialization parameters of the composite will - be the union of those in `componentTypes`. The relative order of child - component types is significant, and will affect the order in which - parameters are reflected and laid out. - - The entry-point functions of the composite will be the union of those in - `componentTypes`, and will follow the ordering of `componentTypes`. - - The requirements of the composite component type will be a subset of - those in `componentTypes`. If an entry in `componentTypes` has a requirement - that can be satisfied by another entry, then the composition will - satisfy the requirement and it will not appear as a requirement of - the composite. If multiple entries in `componentTypes` have a requirement - for the same type, then only the first such requirement will be retained - on the composite. The relative ordering of requirements on the composite - will otherwise match that of `componentTypes`. - - If any diagnostics are generated during creation of the composite, they - will be written to `outDiagnostics`. If an error is encountered, the - function will return null. - - It is an error to create a composite component type that recursively - aggregates the a single module more than once. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCompositeComponentType( - IComponentType* const* componentTypes, - SlangInt componentTypeCount, - IComponentType** outCompositeComponentType, - ISlangBlob** outDiagnostics = nullptr) = 0; - - /** Specialize a type based on type arguments. - */ - virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL specializeType( - TypeReflection* type, - SpecializationArg const* specializationArgs, - SlangInt specializationArgCount, - ISlangBlob** outDiagnostics = nullptr) = 0; - - - /** Get the layout `type` on the chosen `target`. - */ - virtual SLANG_NO_THROW TypeLayoutReflection* SLANG_MCALL getTypeLayout( - TypeReflection* type, - SlangInt targetIndex = 0, - LayoutRules rules = LayoutRules::Default, - ISlangBlob** outDiagnostics = nullptr) = 0; - - /** Get a container type from `elementType`. For example, given type `T`, returns - a type that represents `StructuredBuffer`. - - @param `elementType`: the element type to wrap around. - @param `containerType`: the type of the container to wrap `elementType` in. - @param `outDiagnostics`: a blob to receive diagnostic messages. - */ - virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL getContainerType( - TypeReflection* elementType, - ContainerType containerType, - ISlangBlob** outDiagnostics = nullptr) = 0; - - /** Return a `TypeReflection` that represents the `__Dynamic` type. - This type can be used as a specialization argument to indicate using - dynamic dispatch. - */ - virtual SLANG_NO_THROW TypeReflection* SLANG_MCALL getDynamicType() = 0; - - /** Get the mangled name for a type RTTI object. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTypeRTTIMangledName( - TypeReflection* type, - ISlangBlob** outNameBlob) = 0; - - /** Get the mangled name for a type witness. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTypeConformanceWitnessMangledName( - TypeReflection* type, - TypeReflection* interfaceType, - ISlangBlob** outNameBlob) = 0; - - /** Get the sequential ID used to identify a type witness in a dynamic object. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTypeConformanceWitnessSequentialID( - slang::TypeReflection* type, - slang::TypeReflection* interfaceType, - uint32_t* outId) = 0; - - /** Create a request to load/compile front-end code. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createCompileRequest( - SlangCompileRequest** outCompileRequest) = 0; - - - /** Creates a `IComponentType` that represents a type's conformance to an interface. - The retrieved `ITypeConformance` objects can be included in a composite `IComponentType` - to explicitly specify which implementation types should be included in the final compiled - code. For example, if an module defines `IMaterial` interface and `AMaterial`, - `BMaterial`, `CMaterial` types that implements the interface, the user can exclude - `CMaterial` implementation from the resulting shader code by explcitly adding - `AMaterial:IMaterial` and `BMaterial:IMaterial` conformances to a composite - `IComponentType` and get entry point code from it. The resulting code will not have - anything related to `CMaterial` in the dynamic dispatch logic. If the user does not - explicitly include any `TypeConformances` to an interface type, all implementations to - that interface will be included by default. By linking a `ITypeConformance`, the user is - also given the opportunity to specify the dispatch ID of the implementation type. If - `conformanceIdOverride` is -1, there will be no override behavior and Slang will - automatically assign IDs to implementation types. The automatically assigned IDs can be - queried via `ISession::getTypeConformanceWitnessSequentialID`. - - Returns SLANG_OK if succeeds, or SLANG_FAIL if `type` does not conform to `interfaceType`. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createTypeConformanceComponentType( - slang::TypeReflection* type, - slang::TypeReflection* interfaceType, - ITypeConformance** outConformance, - SlangInt conformanceIdOverride, - ISlangBlob** outDiagnostics) = 0; - - /** Load a module from a Slang module blob. - */ - virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromIRBlob( - const char* moduleName, - const char* path, - slang::IBlob* source, - slang::IBlob** outDiagnostics = nullptr) = 0; - - virtual SLANG_NO_THROW SlangInt SLANG_MCALL getLoadedModuleCount() = 0; - virtual SLANG_NO_THROW IModule* SLANG_MCALL getLoadedModule(SlangInt index) = 0; - - /** Checks if a precompiled binary module is up-to-date with the current compiler - * option settings and the source file contents. - */ - virtual SLANG_NO_THROW bool SLANG_MCALL isBinaryModuleUpToDate( - const char* modulePath, slang::IBlob* binaryModuleBlob) = 0; - - /** Load a module from a string. - */ - virtual SLANG_NO_THROW IModule* SLANG_MCALL loadModuleFromSourceString( - const char* moduleName, - const char* path, - const char* string, - slang::IBlob** outDiagnostics = nullptr) = 0; - }; +* Multiple component types can be combined into a composite, which + combines all of their code, parameters, etc. - #define SLANG_UUID_ISession ISession::getTypeGuid() +* A component type can be specialized, by "plugging in" types and + values for its specialization parameters. - /** A component type is a unit of shader code layout, reflection, and linking. +* A component type can be laid out for a particular target, giving + offsets/bindings to the shader parameters it contains. - A component type is a unit of shader code that can be included into - a linked and compiled shader program. Each component type may have: +* Generated kernel code can be requested for entry points. - * Zero or more uniform shader parameters, representing textures, - buffers, etc. that the code in the component depends on. +*/ +struct IComponentType : public ISlangUnknown +{ + SLANG_COM_INTERFACE(0x5bc42be8, 0x5c50, 0x4929, {0x9e, 0x5e, 0xd1, 0x5e, 0x7c, 0x24, 0x1, 0x5f}) + + /** Get the runtime session that this component type belongs to. + */ + virtual SLANG_NO_THROW ISession* SLANG_MCALL getSession() = 0; + + /** Get the layout for this program for the chosen `targetIndex`. + + The resulting layout will establish offsets/bindings for all + of the global and entry-point shader parameters in the + component type. + + If this component type has specialization parameters (that is, + it is not fully specialized), then the resulting layout may + be incomplete, and plugging in arguments for generic specialization + parameters may result in a component type that doesn't have + a compatible layout. If the component type only uses + interface-type specialization parameters, then the layout + for a specialization should be compatible with an unspecialized + layout (all parameters in the unspecialized layout will have + the same offset/binding in the specialized layout). + + If this component type is combined into a composite, then + the absolute offsets/bindings of parameters may not stay the same. + If the shader parameters in a component type don't make + use of explicit binding annotations (e.g., `register(...)`), + then the *relative* offset of shader parameters will stay + the same when it is used in a composition. + */ + virtual SLANG_NO_THROW ProgramLayout* SLANG_MCALL + getLayout(SlangInt targetIndex = 0, IBlob** outDiagnostics = nullptr) = 0; - * Zero or more *specialization* parameters, which are type or - value parameters that can be used to synthesize specialized - versions of the component type. + /** Get the number of (unspecialized) specialization parameters for the component type. + */ + virtual SLANG_NO_THROW SlangInt SLANG_MCALL getSpecializationParamCount() = 0; - * Zero or more entry points, which are the individually invocable - kernels that can have final code generated. + /** Get the compiled code for the entry point at `entryPointIndex` for the chosen `targetIndex` - * Zero or more *requirements*, which are other component - types on which the component type depends. + Entry point code can only be computed for a component type that + has no specialization parameters (it must be fully specialized) + and that has no requirements (it must be fully linked). - One example of a component type is a module of Slang code: + If code has not already been generated for the given entry point and target, + then a compilation error may be detected, in which case `outDiagnostics` + (if non-null) will be filled in with a blob of messages diagnosing the error. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointCode( + SlangInt entryPointIndex, + SlangInt targetIndex, + IBlob** outCode, + IBlob** outDiagnostics = nullptr) = 0; - * The global-scope shader parameters declared in the module are - the parameters when considered as a component type. + /** Get the compilation result as a file system. - * Any global-scope generic or interface type parameters introduce - specialization parameters for the module. + Has the same requirements as getEntryPointCode. - * A module does not by default include any entry points when - considered as a component type (although the code of the - module might *declare* some entry points). + The result is not written to the actual OS file system, but is made available as an + in memory representation. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getResultAsFileSystem( + SlangInt entryPointIndex, + SlangInt targetIndex, + ISlangMutableFileSystem** outFileSystem) = 0; - * Any other modules that are `import`ed in the source code - become requirements of the module, when considered as a - component type. + /** Compute a hash for the entry point at `entryPointIndex` for the chosen `targetIndex`. - An entry point is another example of a component type: + This computes a hash based on all the dependencies for this component type as well as the + target settings affecting the compiler backend. The computed hash is used as a key for caching + the output of the compiler backend to implement shader caching. + */ + virtual SLANG_NO_THROW void SLANG_MCALL + getEntryPointHash(SlangInt entryPointIndex, SlangInt targetIndex, IBlob** outHash) = 0; - * The `uniform` parameters of the entry point function are - its shader parameters when considered as a component type. + /** Specialize the component by binding its specialization parameters to concrete arguments. - * Any generic or interface-type parameters of the entry point - introduce specialization parameters. + The `specializationArgs` array must have `specializationArgCount` entries, and + this must match the number of specialization parameters on this component type. - * An entry point component type exposes a single entry point (itself). + If any diagnostics (error or warnings) are produced, they will be written to `outDiagnostics`. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL specialize( + SpecializationArg const* specializationArgs, + SlangInt specializationArgCount, + IComponentType** outSpecializedComponentType, + ISlangBlob** outDiagnostics = nullptr) = 0; + + /** Link this component type against all of its unsatisfied dependencies. + + A component type may have unsatisfied dependencies. For example, a module + depends on any other modules it `import`s, and an entry point depends + on the module that defined it. + + A user can manually satisfy dependencies by creating a composite + component type, and when doing so they retain full control over + the relative ordering of shader parameters in the resulting layout. + + It is an error to try to generate/access compiled kernel code for + a component type with unresolved dependencies, so if dependencies + remain after whatever manual composition steps an application + cares to perform, the `link()` function can be used to automatically + compose in any remaining dependencies. The order of parameters + (and hence the global layout) that results will be deterministic, + but is not currently documented. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + link(IComponentType** outLinkedComponentType, ISlangBlob** outDiagnostics = nullptr) = 0; - * An entry point has one requirement for the module in which - it was defined. + /** Get entry point 'callable' functions accessible through the ISlangSharedLibrary interface. - Component types can be manipulated in a few ways: + The functions remain in scope as long as the ISlangSharedLibrary interface is in scope. - * Multiple component types can be combined into a composite, which - combines all of their code, parameters, etc. + NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. - * A component type can be specialized, by "plugging in" types and - values for its specialization parameters. + @param entryPointIndex The index of the entry point to get code for. + @param targetIndex The index of the target to get code for (default: zero). + @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried + on. + @returns A `SlangResult` to indicate success or failure. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointHostCallable( + int entryPointIndex, + int targetIndex, + ISlangSharedLibrary** outSharedLibrary, + slang::IBlob** outDiagnostics = 0) = 0; - * A component type can be laid out for a particular target, giving - offsets/bindings to the shader parameters it contains. + /** Get a new ComponentType object that represents a renamed entry point. - * Generated kernel code can be requested for entry points. + The current object must be a single EntryPoint, or a CompositeComponentType or + SpecializedComponentType that contains one EntryPoint component. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + renameEntryPoint(const char* newName, IComponentType** outEntryPoint) = 0; + + /** Link and specify additional compiler options when generating code + * from the linked program. + */ + virtual SLANG_NO_THROW SlangResult SLANG_MCALL linkWithOptions( + IComponentType** outLinkedComponentType, + uint32_t compilerOptionEntryCount, + CompilerOptionEntry* compilerOptionEntries, + ISlangBlob** outDiagnostics = nullptr) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getTargetCode(SlangInt targetIndex, IBlob** outCode, IBlob** outDiagnostics = nullptr) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTargetMetadata( + SlangInt targetIndex, + IMetadata** outMetadata, + IBlob** outDiagnostics = nullptr) = 0; - */ - struct IComponentType : public ISlangUnknown - { - SLANG_COM_INTERFACE(0x5bc42be8, 0x5c50, 0x4929, { 0x9e, 0x5e, 0xd1, 0x5e, 0x7c, 0x24, 0x1, 0x5f }) - - /** Get the runtime session that this component type belongs to. - */ - virtual SLANG_NO_THROW ISession* SLANG_MCALL getSession() = 0; - - /** Get the layout for this program for the chosen `targetIndex`. - - The resulting layout will establish offsets/bindings for all - of the global and entry-point shader parameters in the - component type. - - If this component type has specialization parameters (that is, - it is not fully specialized), then the resulting layout may - be incomplete, and plugging in arguments for generic specialization - parameters may result in a component type that doesn't have - a compatible layout. If the component type only uses - interface-type specialization parameters, then the layout - for a specialization should be compatible with an unspecialized - layout (all parameters in the unspecialized layout will have - the same offset/binding in the specialized layout). - - If this component type is combined into a composite, then - the absolute offsets/bindings of parameters may not stay the same. - If the shader parameters in a component type don't make - use of explicit binding annotations (e.g., `register(...)`), - then the *relative* offset of shader parameters will stay - the same when it is used in a composition. - */ - virtual SLANG_NO_THROW ProgramLayout* SLANG_MCALL getLayout( - SlangInt targetIndex = 0, - IBlob** outDiagnostics = nullptr) = 0; - - /** Get the number of (unspecialized) specialization parameters for the component type. - */ - virtual SLANG_NO_THROW SlangInt SLANG_MCALL getSpecializationParamCount() = 0; - - /** Get the compiled code for the entry point at `entryPointIndex` for the chosen `targetIndex` - - Entry point code can only be computed for a component type that - has no specialization parameters (it must be fully specialized) - and that has no requirements (it must be fully linked). - - If code has not already been generated for the given entry point and target, - then a compilation error may be detected, in which case `outDiagnostics` - (if non-null) will be filled in with a blob of messages diagnosing the error. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointCode( - SlangInt entryPointIndex, - SlangInt targetIndex, - IBlob** outCode, - IBlob** outDiagnostics = nullptr) = 0; - - /** Get the compilation result as a file system. - - Has the same requirements as getEntryPointCode. - - The result is not written to the actual OS file system, but is made avaiable as an - in memory representation. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getResultAsFileSystem( - SlangInt entryPointIndex, - SlangInt targetIndex, - ISlangMutableFileSystem** outFileSystem) = 0; - - /** Compute a hash for the entry point at `entryPointIndex` for the chosen `targetIndex`. - - This computes a hash based on all the dependencies for this component type as well as the - target settings affecting the compiler backend. The computed hash is used as a key for caching - the output of the compiler backend to implement shader caching. - */ - virtual SLANG_NO_THROW void SLANG_MCALL getEntryPointHash( - SlangInt entryPointIndex, - SlangInt targetIndex, - IBlob** outHash) = 0; - - /** Specialize the component by binding its specialization parameters to concrete arguments. - - The `specializationArgs` array must have `specializationArgCount` entries, and - this must match the number of specialization parameters on this component type. - - If any diagnostics (error or warnings) are produced, they will be written to `outDiagnostics`. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL specialize( - SpecializationArg const* specializationArgs, - SlangInt specializationArgCount, - IComponentType** outSpecializedComponentType, - ISlangBlob** outDiagnostics = nullptr) = 0; - - /** Link this component type against all of its unsatisifed dependencies. - - A component type may have unsatisfied dependencies. For example, a module - depends on any other modules it `import`s, and an entry point depends - on the module that defined it. - - A user can manually satisfy dependencies by creating a composite - component type, and when doing so they retain full control over - the relative ordering of shader parameters in the resulting layout. - - It is an error to try to generate/access compiled kernel code for - a component type with unresolved dependencies, so if dependencies - remain after whatever manual composition steps an application - cares to peform, the `link()` function can be used to automatically - compose in any remaining dependencies. The order of parameters - (and hence the global layout) that results will be deterministic, - but is not currently documented. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL link( - IComponentType** outLinkedComponentType, - ISlangBlob** outDiagnostics = nullptr) = 0; - - /** Get entry point 'callable' functions accessible through the ISlangSharedLibrary interface. - - The functions remain in scope as long as the ISlangSharedLibrary interface is in scope. - - NOTE! Requires a compilation target of SLANG_HOST_CALLABLE. - - @param entryPointIndex The index of the entry point to get code for. - @param targetIndex The index of the target to get code for (default: zero). - @param outSharedLibrary A pointer to a ISharedLibrary interface which functions can be queried on. - @returns A `SlangResult` to indicate success or failure. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointHostCallable( - int entryPointIndex, - int targetIndex, - ISlangSharedLibrary** outSharedLibrary, - slang::IBlob** outDiagnostics = 0) = 0; - - /** Get a new ComponentType object that represents a renamed entry point. - - The current object must be a single EntryPoint, or a CompositeComponentType or - SpecializedComponentType that contains one EntryPoint component. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL renameEntryPoint( - const char* newName, IComponentType** outEntryPoint) = 0; - - /** Link and specify additional compiler options when generating code - * from the linked program. - */ - virtual SLANG_NO_THROW SlangResult SLANG_MCALL linkWithOptions( - IComponentType** outLinkedComponentType, - uint32_t compilerOptionEntryCount, - CompilerOptionEntry* compilerOptionEntries, - ISlangBlob** outDiagnostics = nullptr) = 0; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getTargetCode( - SlangInt targetIndex, - IBlob** outCode, - IBlob** outDiagnostics = nullptr) = 0; - }; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getEntryPointMetadata( + SlangInt entryPointIndex, + SlangInt targetIndex, + IMetadata** outMetadata, + IBlob** outDiagnostics = nullptr) = 0; +}; #define SLANG_UUID_IComponentType IComponentType::getTypeGuid() - struct IEntryPoint : public IComponentType - { - SLANG_COM_INTERFACE(0x8f241361, 0xf5bd, 0x4ca0, { 0xa3, 0xac, 0x2, 0xf7, 0xfa, 0x24, 0x2, 0xb8 }) +struct IEntryPoint : public IComponentType +{ + SLANG_COM_INTERFACE(0x8f241361, 0xf5bd, 0x4ca0, {0xa3, 0xac, 0x2, 0xf7, 0xfa, 0x24, 0x2, 0xb8}) - virtual SLANG_NO_THROW FunctionReflection* SLANG_MCALL getFunctionReflection() = 0; - }; + virtual SLANG_NO_THROW FunctionReflection* SLANG_MCALL getFunctionReflection() = 0; +}; #define SLANG_UUID_IEntryPoint IEntryPoint::getTypeGuid() - struct ITypeConformance : public IComponentType - { - SLANG_COM_INTERFACE(0x73eb3147, 0xe544, 0x41b5, { 0xb8, 0xf0, 0xa2, 0x44, 0xdf, 0x21, 0x94, 0xb }) - }; +struct ITypeConformance : public IComponentType +{ + SLANG_COM_INTERFACE(0x73eb3147, 0xe544, 0x41b5, {0xb8, 0xf0, 0xa2, 0x44, 0xdf, 0x21, 0x94, 0xb}) +}; #define SLANG_UUID_ITypeConformance ITypeConformance::getTypeGuid() - /** A module is the granularity of shader code compilation and loading. +/** A module is the granularity of shader code compilation and loading. - In most cases a module corresponds to a single compile "translation unit." - This will often be a single `.slang` or `.hlsl` file and everything it - `#include`s. +In most cases a module corresponds to a single compile "translation unit." +This will often be a single `.slang` or `.hlsl` file and everything it +`#include`s. - Notably, a module `M` does *not* include the things it `import`s, as these - as distinct modules that `M` depends on. There is a directed graph of - module dependencies, and all modules in the graph must belong to the - same session (`ISession`). +Notably, a module `M` does *not* include the things it `import`s, as these +as distinct modules that `M` depends on. There is a directed graph of +module dependencies, and all modules in the graph must belong to the +same session (`ISession`). - A module establishes a namespace for looking up types, functions, etc. - */ - struct IModule : public IComponentType - { - SLANG_COM_INTERFACE(0xc720e64, 0x8722, 0x4d31, { 0x89, 0x90, 0x63, 0x8a, 0x98, 0xb1, 0xc2, 0x79 }) +A module establishes a namespace for looking up types, functions, etc. +*/ +struct IModule : public IComponentType +{ + SLANG_COM_INTERFACE(0xc720e64, 0x8722, 0x4d31, {0x89, 0x90, 0x63, 0x8a, 0x98, 0xb1, 0xc2, 0x79}) - virtual SLANG_NO_THROW SlangResult SLANG_MCALL findEntryPointByName( - char const* name, - IEntryPoint** outEntryPoint) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + findEntryPointByName(char const* name, IEntryPoint** outEntryPoint) = 0; - /// Get number of entry points defined in the module. An entry point defined in a module - /// is by default not included in the linkage, so calls to `IComponentType::getEntryPointCount` - /// on an `IModule` instance will always return 0. However `IModule::getDefinedEntryPointCount` - /// will return the number of defined entry points. - virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDefinedEntryPointCount() = 0; - /// Get the name of an entry point defined in the module. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL - getDefinedEntryPoint(SlangInt32 index, IEntryPoint** outEntryPoint) = 0; + /// Get number of entry points defined in the module. An entry point defined in a module + /// is by default not included in the linkage, so calls to `IComponentType::getEntryPointCount` + /// on an `IModule` instance will always return 0. However `IModule::getDefinedEntryPointCount` + /// will return the number of defined entry points. + virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDefinedEntryPointCount() = 0; + /// Get the name of an entry point defined in the module. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getDefinedEntryPoint(SlangInt32 index, IEntryPoint** outEntryPoint) = 0; - /// Get a serialized representation of the checked module. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL serialize(ISlangBlob** outSerializedBlob) = 0; + /// Get a serialized representation of the checked module. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL serialize(ISlangBlob** outSerializedBlob) = 0; - /// Write the serialized representation of this module to a file. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToFile(char const* fileName) = 0; + /// Write the serialized representation of this module to a file. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL writeToFile(char const* fileName) = 0; - /// Get the name of the module. - virtual SLANG_NO_THROW const char* SLANG_MCALL getName() = 0; + /// Get the name of the module. + virtual SLANG_NO_THROW const char* SLANG_MCALL getName() = 0; - /// Get the path of the module. - virtual SLANG_NO_THROW const char* SLANG_MCALL getFilePath() = 0; + /// Get the path of the module. + virtual SLANG_NO_THROW const char* SLANG_MCALL getFilePath() = 0; - /// Get the unique identity of the module. - virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() = 0; + /// Get the unique identity of the module. + virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() = 0; - /// Find and validate an entry point by name, even if the function is - /// not marked with the `[shader("...")]` attribute. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL findAndCheckEntryPoint( - char const* name, - SlangStage stage, - IEntryPoint** outEntryPoint, - ISlangBlob** outDiagnostics) = 0; + /// Find and validate an entry point by name, even if the function is + /// not marked with the `[shader("...")]` attribute. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL findAndCheckEntryPoint( + char const* name, + SlangStage stage, + IEntryPoint** outEntryPoint, + ISlangBlob** outDiagnostics) = 0; - /// Get the number of dependency files that this module depends on. - /// This includes both the explicit source files, as well as any - /// additional files that were transitively referenced (e.g., via - /// a `#include` directive). - virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDependencyFileCount() = 0; + /// Get the number of dependency files that this module depends on. + /// This includes both the explicit source files, as well as any + /// additional files that were transitively referenced (e.g., via + /// a `#include` directive). + virtual SLANG_NO_THROW SlangInt32 SLANG_MCALL getDependencyFileCount() = 0; - /// Get the path to a file this module depends on. - virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath( - SlangInt32 index) = 0; + /// Get the path to a file this module depends on. + virtual SLANG_NO_THROW char const* SLANG_MCALL getDependencyFilePath(SlangInt32 index) = 0; - virtual SLANG_NO_THROW DeclReflection* SLANG_MCALL getModuleReflection() = 0; + virtual SLANG_NO_THROW DeclReflection* SLANG_MCALL getModuleReflection() = 0; +}; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL precompileForTarget( - SlangCompileTarget target, - ISlangBlob** outDiagnostics) = 0; - }; - #define SLANG_UUID_IModule IModule::getTypeGuid() - /** Argument used for specialization to types/values. - */ - struct SpecializationArg - { - enum class Kind : int32_t - { - Unknown, /**< An invalid specialization argument. */ - Type, /**< Specialize to a type. */ - }; +/* Experimental interface for doing target precompilation of slang modules */ +struct IModulePrecompileService_Experimental : public ISlangUnknown +{ + // uuidgen output: 8e12e8e3 - 5fcd - 433e - afcb - 13a088bc5ee5 + SLANG_COM_INTERFACE( + 0x8e12e8e3, + 0x5fcd, + 0x433e, + {0xaf, 0xcb, 0x13, 0xa0, 0x88, 0xbc, 0x5e, 0xe5}) - /** The kind of specialization argument. */ - Kind kind; - union - { - /** A type specialization argument, used for `Kind::Type`. */ - TypeReflection* type; - }; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + precompileForTarget(SlangCompileTarget target, ISlangBlob** outDiagnostics) = 0; - static SpecializationArg fromType(TypeReflection* inType) - { - SpecializationArg rs; - rs.kind = Kind::Type; - rs.type = inType; - return rs; - } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getPrecompiledTargetCode( + SlangCompileTarget target, + IBlob** outCode, + IBlob** outDiagnostics = nullptr) = 0; + + virtual SLANG_NO_THROW SlangInt SLANG_MCALL getModuleDependencyCount() = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getModuleDependency( + SlangInt dependencyIndex, + IModule** outModule, + IBlob** outDiagnostics = nullptr) = 0; +}; + + #define SLANG_UUID_IModulePrecompileService_Experimental \ + IModulePrecompileService_Experimental::getTypeGuid() + +/** Argument used for specialization to types/values. + */ +struct SpecializationArg +{ + enum class Kind : int32_t + { + Unknown, /**< An invalid specialization argument. */ + Type, /**< Specialize to a type. */ }; -} -// Passed into functions to create globalSession to identify the API version client code is -// using. -#define SLANG_API_VERSION 0 + /** The kind of specialization argument. */ + Kind kind; + union + { + /** A type specialization argument, used for `Kind::Type`. */ + TypeReflection* type; + }; + + static SpecializationArg fromType(TypeReflection* inType) + { + SpecializationArg rs; + rs.kind = Kind::Type; + rs.type = inType; + return rs; + } +}; +} // namespace slang + + // Passed into functions to create globalSession to identify the API version client code is + // using. + #define SLANG_API_VERSION 0 -/* Create a global session, with built in StdLib. +/* Create a global session, with the built-in core module. @param apiVersion Pass in SLANG_API_VERSION -@param outGlobalSession (out)The created global session. +@param outGlobalSession (out)The created global session. */ -SLANG_EXTERN_C SLANG_API SlangResult slang_createGlobalSession( - SlangInt apiVersion, - slang::IGlobalSession** outGlobalSession); +SLANG_EXTERN_C SLANG_API SlangResult +slang_createGlobalSession(SlangInt apiVersion, slang::IGlobalSession** outGlobalSession); -/* Create a global session, but do not set up the stdlib. The stdlib can -then be loaded via loadStdLib or compileStdLib +/* Create a global session, but do not set up the core module. The core module can +then be loaded via loadCoreModule or compileCoreModule @param apiVersion Pass in SLANG_API_VERSION -@param outGlobalSession (out)The created global session that doesn't have a StdLib setup. +@param outGlobalSession (out)The created global session that doesn't have a core module setup. -NOTE! API is experimental and not ready for production code +NOTE! API is experimental and not ready for production code */ -SLANG_EXTERN_C SLANG_API SlangResult slang_createGlobalSessionWithoutStdLib( - SlangInt apiVersion, +SLANG_EXTERN_C SLANG_API SlangResult slang_createGlobalSessionWithoutCoreModule( + SlangInt apiVersion, slang::IGlobalSession** outGlobalSession); -/* Returns a blob that contains the serialized stdlib. -Returns nullptr if there isn't an embedded stdlib. +/* Returns a blob that contains the serialized core module. +Returns nullptr if there isn't an embedded core module. + +NOTE! API is experimental and not ready for production code */ -SLANG_API ISlangBlob* slang_getEmbeddedStdLib(); +SLANG_API ISlangBlob* slang_getEmbeddedCoreModule(); /* Cleanup all global allocations used by Slang, to prevent memory leak detectors from @@ -5601,70 +4415,29 @@ SLANG_API ISlangBlob* slang_getEmbeddedStdLib(); */ SLANG_EXTERN_C SLANG_API void slang_shutdown(); +/* Return the last signaled internal error message. + */ +SLANG_EXTERN_C SLANG_API const char* slang_getLastInternalErrorMessage(); + namespace slang { - inline SlangResult createGlobalSession( - slang::IGlobalSession** outGlobalSession) - { - return slang_createGlobalSession(SLANG_API_VERSION, outGlobalSession); - } - inline void shutdown() { slang_shutdown(); } +inline SlangResult createGlobalSession(slang::IGlobalSession** outGlobalSession) +{ + return slang_createGlobalSession(SLANG_API_VERSION, outGlobalSession); } +inline void shutdown() +{ + slang_shutdown(); +} +inline const char* getLastInternalErrorMessage() +{ + return slang_getLastInternalErrorMessage(); +} +} // namespace slang -/** @see slang::ICompileRequest::getProgram -*/ -SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getProgram( - SlangCompileRequest* request, - slang::IComponentType** outProgram); - -/** @see slang::ICompileRequest::getProgramWithEntryPoints -*/ -SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getProgramWithEntryPoints( - SlangCompileRequest* request, - slang::IComponentType** outProgram); - -/** @see slang::ICompileRequest::getEntryPoint -*/ -SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getEntryPoint( - SlangCompileRequest* request, - SlangInt entryPointIndex, - slang::IComponentType** outEntryPoint); - -/** @see slang::ICompileRequest::getModule -*/ -SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getModule( - SlangCompileRequest* request, - SlangInt translationUnitIndex, - slang::IModule** outModule); - -/** @see slang::ICompileRequest::getSession -*/ -SLANG_EXTERN_C SLANG_API SlangResult spCompileRequest_getSession( - SlangCompileRequest* request, - slang::ISession** outSession); -#endif - -/* DEPRECATED DEFINITIONS - -Everything below this point represents deprecated APIs/definition that are only -being kept around for source/binary compatibility with old client code. New -code should not use any of these declarations, and the Slang API will drop these -declarations over time. -*/ - -#ifdef __cplusplus -extern "C" { -#endif +#endif // C++ helpers #define SLANG_ERROR_INSUFFICIENT_BUFFER SLANG_E_BUFFER_TOO_SMALL #define SLANG_ERROR_INVALID_PARAMETER SLANG_E_INVALID_ARG -SLANG_API char const* spGetTranslationUnitSource( - SlangCompileRequest* request, - int translationUnitIndex); - -#ifdef __cplusplus -} -#endif - #endif diff --git a/prelude/CMakeLists.txt b/prelude/CMakeLists.txt index 173cce542a..3b0e2cf46a 100644 --- a/prelude/CMakeLists.txt +++ b/prelude/CMakeLists.txt @@ -3,28 +3,33 @@ # Construct a library called 'prelude' to be linked with by slang # -glob_append(SLANG_PRELUDE_HEADERS "*-prelude.h") +glob_append(prelude_headers "*-prelude.h") -set(SLANG_PRELUDE_SOURCE) -foreach(input ${SLANG_PRELUDE_HEADERS}) +set(prelude_source) +foreach(input ${prelude_headers}) get_filename_component(input_name ${input} NAME) set(output "${CMAKE_CURRENT_BINARY_DIR}/${input_name}.cpp") add_custom_command( OUTPUT ${output} - COMMAND slang-embed "${input}" ${output} + COMMAND + slang-embed "${input}" "${CMAKE_CURRENT_LIST_DIR}/../include" + ${output} DEPENDS ${input} slang-embed VERBATIM ) - list(APPEND SLANG_PRELUDE_SOURCE ${output}) + list(APPEND prelude_source ${output}) endforeach() slang_add_target( . OBJECT - EXPLICIT_SOURCE ${SLANG_PRELUDE_SOURCE} + EXPLICIT_SOURCE ${prelude_source} EXCLUDE_FROM_ALL TARGET_NAME prelude - INCLUDE_DIRECTORIES_PUBLIC ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/../include + INCLUDE_DIRECTORIES_PUBLIC + ${CMAKE_CURRENT_LIST_DIR} + ${CMAKE_CURRENT_LIST_DIR}/../include + LINK_WITH_PRIVATE unordered_dense::unordered_dense PUBLIC_HEADERS ${CMAKE_CURRENT_LIST_DIR}/slang*.h # It's an object library, so the install step only installs the headers INSTALL diff --git a/prelude/slang-cpp-host-prelude.h b/prelude/slang-cpp-host-prelude.h index 48056169d4..8bc0f5cadb 100644 --- a/prelude/slang-cpp-host-prelude.h +++ b/prelude/slang-cpp-host-prelude.h @@ -1,8 +1,8 @@ #ifndef SLANG_CPP_HOST_PRELUDE_H #define SLANG_CPP_HOST_PRELUDE_H -#include #include +#include #include #define SLANG_COM_PTR_ENABLE_REF_OPERATOR 1 @@ -14,42 +14,45 @@ #ifdef SLANG_LLVM #include "slang-llvm.h" #else // SLANG_LLVM -# if SLANG_GCC_FAMILY && __GNUC__ < 6 -# include -# define SLANG_PRELUDE_STD std:: -# else -# include -# define SLANG_PRELUDE_STD -# endif - -# include -# include -# include -# include +#if SLANG_GCC_FAMILY && __GNUC__ < 6 +#include +#define SLANG_PRELUDE_STD std:: +#else +#include +#define SLANG_PRELUDE_STD +#endif + +#include +#include +#include +#include #endif // SLANG_LLVM #if defined(_MSC_VER) -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) #else -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) -//# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) __attribute__((__visibility__("default"))) -#endif - -#ifdef __cplusplus -# define SLANG_PRELUDE_EXTERN_C extern "C" -# define SLANG_PRELUDE_EXTERN_C_START extern "C" { -# define SLANG_PRELUDE_EXTERN_C_END } +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) +// # define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) +// __attribute__((__visibility__("default"))) +#endif + +#ifdef __cplusplus +#define SLANG_PRELUDE_EXTERN_C extern "C" +#define SLANG_PRELUDE_EXTERN_C_START \ + extern "C" \ + { +#define SLANG_PRELUDE_EXTERN_C_END } #else -# define SLANG_PRELUDE_EXTERN_C -# define SLANG_PRELUDE_EXTERN_C_START -# define SLANG_PRELUDE_EXTERN_C_END -#endif +#define SLANG_PRELUDE_EXTERN_C +#define SLANG_PRELUDE_EXTERN_C_START +#define SLANG_PRELUDE_EXTERN_C_END +#endif #include "slang-cpp-scalar-intrinsics.h" using namespace Slang; template -using Slang_FuncType = TResult(SLANG_MCALL *)(Args...); +using Slang_FuncType = TResult(SLANG_MCALL*)(Args...); #endif diff --git a/prelude/slang-cpp-prelude.h b/prelude/slang-cpp-prelude.h index 2b848dc3b1..4dacac9c50 100644 --- a/prelude/slang-cpp-prelude.h +++ b/prelude/slang-cpp-prelude.h @@ -2,42 +2,45 @@ #define SLANG_CPP_PRELUDE_H // Because the signiture of isnan, isfinite, and is isinf changed in C++, we use the macro -// to use the version in the std namespace. +// to use the version in the std namespace. // https://stackoverflow.com/questions/39130040/cmath-hides-isnan-in-math-h-in-c14-c11 - + #ifdef SLANG_LLVM #include "slang-llvm.h" #else // SLANG_LLVM -# if SLANG_GCC_FAMILY && __GNUC__ < 6 -# include -# define SLANG_PRELUDE_STD std:: -# else -# include -# define SLANG_PRELUDE_STD -# endif - -# include -# include -# include -# include +#if SLANG_GCC_FAMILY && __GNUC__ < 6 +#include +#define SLANG_PRELUDE_STD std:: +#else +#include +#define SLANG_PRELUDE_STD +#endif + +#include +#include +#include +#include #endif // SLANG_LLVM #if defined(_MSC_VER) -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) #else -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) -//# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) __attribute__((__visibility__("default"))) -#endif - -#ifdef __cplusplus -# define SLANG_PRELUDE_EXTERN_C extern "C" -# define SLANG_PRELUDE_EXTERN_C_START extern "C" { -# define SLANG_PRELUDE_EXTERN_C_END } +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) +// # define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) +// __attribute__((__visibility__("default"))) +#endif + +#ifdef __cplusplus +#define SLANG_PRELUDE_EXTERN_C extern "C" +#define SLANG_PRELUDE_EXTERN_C_START \ + extern "C" \ + { +#define SLANG_PRELUDE_EXTERN_C_END } #else -# define SLANG_PRELUDE_EXTERN_C -# define SLANG_PRELUDE_EXTERN_C_START -# define SLANG_PRELUDE_EXTERN_C_END -#endif +#define SLANG_PRELUDE_EXTERN_C +#define SLANG_PRELUDE_EXTERN_C_START +#define SLANG_PRELUDE_EXTERN_C_END +#endif #define SLANG_PRELUDE_EXPORT SLANG_PRELUDE_EXTERN_C SLANG_PRELUDE_SHARED_LIB_EXPORT #define SLANG_PRELUDE_EXPORT_START SLANG_PRELUDE_EXTERN_C_START SLANG_PRELUDE_SHARED_LIB_EXPORT @@ -45,65 +48,65 @@ #ifndef INFINITY // Must overflow for double -# define INFINITY float(1e+300 * 1e+300) +#define INFINITY float(1e+300 * 1e+300) #endif #ifndef SLANG_INFINITY -# define SLANG_INFINITY INFINITY +#define SLANG_INFINITY INFINITY #endif // Detect the compiler type #ifndef SLANG_COMPILER -# define SLANG_COMPILER +#define SLANG_COMPILER /* Compiler defines, see http://sourceforge.net/p/predef/wiki/Compilers/ NOTE that SLANG_VC holds the compiler version - not just 1 or 0 */ -# if defined(_MSC_VER) -# if _MSC_VER >= 1900 -# define SLANG_VC 14 -# elif _MSC_VER >= 1800 -# define SLANG_VC 12 -# elif _MSC_VER >= 1700 -# define SLANG_VC 11 -# elif _MSC_VER >= 1600 -# define SLANG_VC 10 -# elif _MSC_VER >= 1500 -# define SLANG_VC 9 -# else -# error "unknown version of Visual C++ compiler" -# endif -# elif defined(__clang__) -# define SLANG_CLANG 1 -# elif defined(__SNC__) -# define SLANG_SNC 1 -# elif defined(__ghs__) -# define SLANG_GHS 1 -# elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */ -# define SLANG_GCC 1 -# else -# error "unknown compiler" -# endif +#if defined(_MSC_VER) +#if _MSC_VER >= 1900 +#define SLANG_VC 14 +#elif _MSC_VER >= 1800 +#define SLANG_VC 12 +#elif _MSC_VER >= 1700 +#define SLANG_VC 11 +#elif _MSC_VER >= 1600 +#define SLANG_VC 10 +#elif _MSC_VER >= 1500 +#define SLANG_VC 9 +#else +#error "unknown version of Visual C++ compiler" +#endif +#elif defined(__clang__) +#define SLANG_CLANG 1 +#elif defined(__SNC__) +#define SLANG_SNC 1 +#elif defined(__ghs__) +#define SLANG_GHS 1 +#elif defined(__GNUC__) /* note: __clang__, __SNC__, or __ghs__ imply __GNUC__ */ +#define SLANG_GCC 1 +#else +#error "unknown compiler" +#endif /* Any compilers not detected by the above logic are now now explicitly zeroed out. */ -# ifndef SLANG_VC -# define SLANG_VC 0 -# endif -# ifndef SLANG_CLANG -# define SLANG_CLANG 0 -# endif -# ifndef SLANG_SNC -# define SLANG_SNC 0 -# endif -# ifndef SLANG_GHS -# define SLANG_GHS 0 -# endif -# ifndef SLANG_GCC -# define SLANG_GCC 0 -# endif +#ifndef SLANG_VC +#define SLANG_VC 0 +#endif +#ifndef SLANG_CLANG +#define SLANG_CLANG 0 +#endif +#ifndef SLANG_SNC +#define SLANG_SNC 0 +#endif +#ifndef SLANG_GHS +#define SLANG_GHS 0 +#endif +#ifndef SLANG_GCC +#define SLANG_GCC 0 +#endif #endif /* SLANG_COMPILER */ /* @@ -116,89 +119,90 @@ used later in the file. Most applications should not need to touch this section. */ #ifndef SLANG_PLATFORM -# define SLANG_PLATFORM +#define SLANG_PLATFORM /** Operating system defines, see http://sourceforge.net/p/predef/wiki/OperatingSystems/ */ -# if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP -# define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */ -# elif defined(XBOXONE) -# define SLANG_XBOXONE 1 -# elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */ -# define SLANG_WIN64 1 -# elif defined(_M_PPC) -# define SLANG_X360 1 -# elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */ -# define SLANG_WIN32 1 -# elif defined(__ANDROID__) -# define SLANG_ANDROID 1 -# elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */ -# define SLANG_LINUX 1 -# elif defined(__APPLE__) && !defined(SLANG_LLVM) -# include "TargetConditionals.h" -# if TARGET_OS_MAC -# define SLANG_OSX 1 -# else -# define SLANG_IOS 1 -# endif -# elif defined(__APPLE__) -// On `slang-llvm` we can't inclue "TargetConditionals.h" in general, so for now assume its OSX. -# define SLANG_OSX 1 -# elif defined(__CELLOS_LV2__) -# define SLANG_PS3 1 -# elif defined(__ORBIS__) -# define SLANG_PS4 1 -# elif defined(__SNC__) && defined(__arm__) -# define SLANG_PSP2 1 -# elif defined(__ghs__) -# define SLANG_WIIU 1 -# else -# error "unknown target platform" -# endif +#if defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_PARTITION_APP +#define SLANG_WINRT 1 /* Windows Runtime, either on Windows RT or Windows 8 */ +#elif defined(XBOXONE) +#define SLANG_XBOXONE 1 +#elif defined(_WIN64) /* note: XBOXONE implies _WIN64 */ +#define SLANG_WIN64 1 +#elif defined(_M_PPC) +#define SLANG_X360 1 +#elif defined(_WIN32) /* note: _M_PPC implies _WIN32 */ +#define SLANG_WIN32 1 +#elif defined(__ANDROID__) +#define SLANG_ANDROID 1 +#elif defined(__linux__) || defined(__CYGWIN__) /* note: __ANDROID__ implies __linux__ */ +#define SLANG_LINUX 1 +#elif defined(__APPLE__) && !defined(SLANG_LLVM) +#include "TargetConditionals.h" +#if TARGET_OS_MAC +#define SLANG_OSX 1 +#else +#define SLANG_IOS 1 +#endif +#elif defined(__APPLE__) +// On `slang-llvm` we can't inclue "TargetConditionals.h" in general, so for now assume its +// OSX. +#define SLANG_OSX 1 +#elif defined(__CELLOS_LV2__) +#define SLANG_PS3 1 +#elif defined(__ORBIS__) +#define SLANG_PS4 1 +#elif defined(__SNC__) && defined(__arm__) +#define SLANG_PSP2 1 +#elif defined(__ghs__) +#define SLANG_WIIU 1 +#else +#error "unknown target platform" +#endif /* Any platforms not detected by the above logic are now now explicitly zeroed out. */ -# ifndef SLANG_WINRT -# define SLANG_WINRT 0 -# endif -# ifndef SLANG_XBOXONE -# define SLANG_XBOXONE 0 -# endif -# ifndef SLANG_WIN64 -# define SLANG_WIN64 0 -# endif -# ifndef SLANG_X360 -# define SLANG_X360 0 -# endif -# ifndef SLANG_WIN32 -# define SLANG_WIN32 0 -# endif -# ifndef SLANG_ANDROID -# define SLANG_ANDROID 0 -# endif -# ifndef SLANG_LINUX -# define SLANG_LINUX 0 -# endif -# ifndef SLANG_IOS -# define SLANG_IOS 0 -# endif -# ifndef SLANG_OSX -# define SLANG_OSX 0 -# endif -# ifndef SLANG_PS3 -# define SLANG_PS3 0 -# endif -# ifndef SLANG_PS4 -# define SLANG_PS4 0 -# endif -# ifndef SLANG_PSP2 -# define SLANG_PSP2 0 -# endif -# ifndef SLANG_WIIU -# define SLANG_WIIU 0 -# endif +#ifndef SLANG_WINRT +#define SLANG_WINRT 0 +#endif +#ifndef SLANG_XBOXONE +#define SLANG_XBOXONE 0 +#endif +#ifndef SLANG_WIN64 +#define SLANG_WIN64 0 +#endif +#ifndef SLANG_X360 +#define SLANG_X360 0 +#endif +#ifndef SLANG_WIN32 +#define SLANG_WIN32 0 +#endif +#ifndef SLANG_ANDROID +#define SLANG_ANDROID 0 +#endif +#ifndef SLANG_LINUX +#define SLANG_LINUX 0 +#endif +#ifndef SLANG_IOS +#define SLANG_IOS 0 +#endif +#ifndef SLANG_OSX +#define SLANG_OSX 0 +#endif +#ifndef SLANG_PS3 +#define SLANG_PS3 0 +#endif +#ifndef SLANG_PS4 +#define SLANG_PS4 0 +#endif +#ifndef SLANG_PSP2 +#define SLANG_PSP2 0 +#endif +#ifndef SLANG_WIIU +#define SLANG_WIIU 0 +#endif #endif /* SLANG_PLATFORM */ /* Shorthands for "families" of compilers/platforms */ @@ -206,37 +210,38 @@ Any platforms not detected by the above logic are now now explicitly zeroed out. #define SLANG_WINDOWS_FAMILY (SLANG_WINRT || SLANG_WIN32 || SLANG_WIN64) #define SLANG_MICROSOFT_FAMILY (SLANG_XBOXONE || SLANG_X360 || SLANG_WINDOWS_FAMILY) #define SLANG_LINUX_FAMILY (SLANG_LINUX || SLANG_ANDROID) -#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */ -#define SLANG_UNIX_FAMILY (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */ +#define SLANG_APPLE_FAMILY (SLANG_IOS || SLANG_OSX) /* equivalent to #if __APPLE__ */ +#define SLANG_UNIX_FAMILY \ + (SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY) /* shortcut for unix/posix platforms */ // GCC Specific #if SLANG_GCC_FAMILY -# define SLANG_ALIGN_OF(T) __alignof__(T) +#define SLANG_ALIGN_OF(T) __alignof__(T) -# define SLANG_BREAKPOINT(id) __builtin_trap() +#define SLANG_BREAKPOINT(id) __builtin_trap() -// Use this macro instead of offsetof, because gcc produces warning if offsetof is used on a +// Use this macro instead of offsetof, because gcc produces warning if offsetof is used on a // non POD type, even though it produces the correct result -# define SLANG_OFFSET_OF(T, ELEMENT) (size_t(&((T*)1)->ELEMENT) - 1) +#define SLANG_OFFSET_OF(T, ELEMENT) (size_t(&((T*)1)->ELEMENT) - 1) #endif // SLANG_GCC_FAMILY // Microsoft VC specific #if SLANG_VC -# define SLANG_ALIGN_OF(T) __alignof(T) +#define SLANG_ALIGN_OF(T) __alignof(T) -# define SLANG_BREAKPOINT(id) __debugbreak(); +#define SLANG_BREAKPOINT(id) __debugbreak(); #endif // SLANG_VC // Default impls #ifndef SLANG_OFFSET_OF -# define SLANG_OFFSET_OF(X, Y) offsetof(X, Y) +#define SLANG_OFFSET_OF(X, Y) offsetof(X, Y) #endif #ifndef SLANG_BREAKPOINT // Make it crash with a write to 0! -# define SLANG_BREAKPOINT(id) (*((int*)0) = int(id)); +#define SLANG_BREAKPOINT(id) (*((int*)0) = int(id)); #endif // If slang.h has been included we don't need any of these definitions @@ -244,33 +249,33 @@ Any platforms not detected by the above logic are now now explicitly zeroed out. /* Macro for declaring if a method is no throw. Should be set before the return parameter. */ #ifndef SLANG_NO_THROW -# if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) -# define SLANG_NO_THROW __declspec(nothrow) -# endif +#if SLANG_WINDOWS_FAMILY && !defined(SLANG_DISABLE_EXCEPTIONS) +#define SLANG_NO_THROW __declspec(nothrow) +#endif #endif #ifndef SLANG_NO_THROW -# define SLANG_NO_THROW +#define SLANG_NO_THROW #endif /* The `SLANG_STDCALL` and `SLANG_MCALL` defines are used to set the calling convention for interface methods. */ #ifndef SLANG_STDCALL -# if SLANG_MICROSOFT_FAMILY -# define SLANG_STDCALL __stdcall -# else -# define SLANG_STDCALL -# endif +#if SLANG_MICROSOFT_FAMILY +#define SLANG_STDCALL __stdcall +#else +#define SLANG_STDCALL +#endif #endif #ifndef SLANG_MCALL -# define SLANG_MCALL SLANG_STDCALL +#define SLANG_MCALL SLANG_STDCALL #endif #ifndef SLANG_FORCE_INLINE -# define SLANG_FORCE_INLINE inline +#define SLANG_FORCE_INLINE inline #endif -// TODO(JS): Should these be in slang-cpp-types.h? +// TODO(JS): Should these be in slang-cpp-types.h? // They are more likely to clash with slang.h struct SlangUUID @@ -278,24 +283,25 @@ struct SlangUUID uint32_t data1; uint16_t data2; uint16_t data3; - uint8_t data4[8]; + uint8_t data4[8]; }; typedef int32_t SlangResult; struct ISlangUnknown { - virtual SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) = 0; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + queryInterface(SlangUUID const& uuid, void** outObject) = 0; virtual SLANG_NO_THROW uint32_t SLANG_MCALL addRef() = 0; virtual SLANG_NO_THROW uint32_t SLANG_MCALL release() = 0; }; -#define SLANG_COM_INTERFACE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ - public: \ - SLANG_FORCE_INLINE static const SlangUUID& getTypeGuid() \ - { \ - static const SlangUUID guid = { a, b, c, d0, d1, d2, d3, d4, d5, d6, d7 }; \ - return guid; \ +#define SLANG_COM_INTERFACE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ +public: \ + SLANG_FORCE_INLINE static const SlangUUID& getTypeGuid() \ + { \ + static const SlangUUID guid = {a, b, c, d0, d1, d2, d3, d4, d5, d6, d7}; \ + return guid; \ } #endif // SLANG_H @@ -304,13 +310,13 @@ struct ISlangUnknown #include "slang-cpp-scalar-intrinsics.h" #include "slang-cpp-types.h" -// TODO(JS): Hack! Output C++ code from slang can copy uninitialized variables. +// TODO(JS): Hack! Output C++ code from slang can copy uninitialized variables. #if defined(_MSC_VER) -# pragma warning(disable : 4700) +#pragma warning(disable : 4700) #endif #ifndef SLANG_UNROLL -# define SLANG_UNROLL +#define SLANG_UNROLL #endif #endif diff --git a/prelude/slang-cpp-scalar-intrinsics.h b/prelude/slang-cpp-scalar-intrinsics.h index 55001cb217..6aa72df4f5 100644 --- a/prelude/slang-cpp-scalar-intrinsics.h +++ b/prelude/slang-cpp-scalar-intrinsics.h @@ -2,24 +2,26 @@ #define SLANG_PRELUDE_SCALAR_INTRINSICS_H #if !defined(SLANG_LLVM) && SLANG_PROCESSOR_X86_64 && SLANG_VC -// If we have visual studio and 64 bit processor, we can assume we have popcnt, and can include x86 intrinsics -# include +// If we have visual studio and 64 bit processor, we can assume we have popcnt, and can include +// x86 intrinsics +#include #endif #ifndef SLANG_FORCE_INLINE -# define SLANG_FORCE_INLINE inline +#define SLANG_FORCE_INLINE inline #endif #ifdef SLANG_PRELUDE_NAMESPACE -namespace SLANG_PRELUDE_NAMESPACE { +namespace SLANG_PRELUDE_NAMESPACE +{ #endif #ifndef SLANG_PRELUDE_PI -# define SLANG_PRELUDE_PI 3.14159265358979323846 +#define SLANG_PRELUDE_PI 3.14159265358979323846 #endif -union Union32 +union Union32 { uint32_t u; int32_t i; @@ -34,10 +36,30 @@ union Union64 }; // 32 bit cast conversions -SLANG_FORCE_INLINE int32_t _bitCastFloatToInt(float f) { Union32 u; u.f = f; return u.i; } -SLANG_FORCE_INLINE float _bitCastIntToFloat(int32_t i) { Union32 u; u.i = i; return u.f; } -SLANG_FORCE_INLINE uint32_t _bitCastFloatToUInt(float f) { Union32 u; u.f = f; return u.u; } -SLANG_FORCE_INLINE float _bitCastUIntToFloat(uint32_t ui) { Union32 u; u.u = ui; return u.f; } +SLANG_FORCE_INLINE int32_t _bitCastFloatToInt(float f) +{ + Union32 u; + u.f = f; + return u.i; +} +SLANG_FORCE_INLINE float _bitCastIntToFloat(int32_t i) +{ + Union32 u; + u.i = i; + return u.f; +} +SLANG_FORCE_INLINE uint32_t _bitCastFloatToUInt(float f) +{ + Union32 u; + u.f = f; + return u.u; +} +SLANG_FORCE_INLINE float _bitCastUIntToFloat(uint32_t ui) +{ + Union32 u; + u.u = ui; + return u.f; +} // ----------------------------- F16 ----------------------------------------- @@ -61,27 +83,27 @@ SLANG_FORCE_INLINE uint32_t f32tof16(const float value) if (e == 0xff) { // Could be a NAN or INF. Is INF if *input* mantissa is 0. - + // Remove last bit for rounding to make output mantissa. m >>= 1; - + // We *assume* float16/float32 signaling bit and remaining bits // semantics are the same. (The signalling bit convention is target specific!). // Non signal bit's usage within mantissa for a NAN are also target specific. - - // If the m is 0, it could be because the result is INF, but it could also be because all the - // bits that made NAN were dropped as we have less mantissa bits in f16. - + + // If the m is 0, it could be because the result is INF, but it could also be because all + // the bits that made NAN were dropped as we have less mantissa bits in f16. + // To fix for this we make non zero if m is 0 and the input mantissa was not. // This will (typically) produce a signalling NAN. m += uint32_t(m == 0 && (inBits & 0x007fffffu)); - + // Combine for output return (bits | 0x7c00u | m); } if (e > 142) { - // INF. + // INF. return bits | 0x7c00u; } if (e < 113) @@ -105,7 +127,7 @@ SLANG_FORCE_INLINE float f16tof32(const uint32_t value) if (exponent == 0) { - // If mantissa is 0 we are done, as output is 0. + // If mantissa is 0 we are done, as output is 0. // If it's not zero we must have a denormal. if (mantissa) { @@ -113,16 +135,17 @@ SLANG_FORCE_INLINE float f16tof32(const uint32_t value) return _bitCastIntToFloat(sign | ((value & 0x7fff) << 13)) * g_f16tof32Magic; } } - else + else { - // If the exponent is NAN or INF exponent is 0x1f on input. + // If the exponent is NAN or INF exponent is 0x1f on input. // If that's the case, we just need to set the exponent to 0xff on output - // and the mantissa can just stay the same. If its 0 it's INF, else it is NAN and we just copy the bits + // and the mantissa can just stay the same. If its 0 it's INF, else it is NAN and we just + // copy the bits // // Else we need to correct the exponent in the normalized case. exponent = (exponent == 0x1F) ? 0xff : (exponent + (-15 + 127)); } - + return _bitCastUIntToFloat(sign | (exponent << 23) | (mantissa << 13)); } @@ -135,7 +158,7 @@ SLANG_FORCE_INLINE float F32_calcSafeRadians(float radians); SLANG_PRELUDE_EXTERN_C_START -// Unary +// Unary float F32_ceil(float f); float F32_floor(float f); float F32_round(float f); @@ -158,12 +181,18 @@ float F32_trunc(float f); float F32_sqrt(float f); bool F32_isnan(float f); -bool F32_isfinite(float f); +bool F32_isfinite(float f); bool F32_isinf(float f); // Binary -SLANG_FORCE_INLINE float F32_min(float a, float b) { return a < b ? a : b; } -SLANG_FORCE_INLINE float F32_max(float a, float b) { return a > b ? a : b; } +SLANG_FORCE_INLINE float F32_min(float a, float b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE float F32_max(float a, float b) +{ + return a > b ? a : b; +} float F32_pow(float a, float b); float F32_fmod(float a, float b); float F32_remainder(float a, float b); @@ -174,47 +203,140 @@ float F32_frexp(float x, int* e); float F32_modf(float x, float* ip); // Ternary -SLANG_FORCE_INLINE float F32_fma(float a, float b, float c) { return a * b + c; } +SLANG_FORCE_INLINE float F32_fma(float a, float b, float c) +{ + return a * b + c; +} SLANG_PRELUDE_EXTERN_C_END #else -// Unary -SLANG_FORCE_INLINE float F32_ceil(float f) { return ::ceilf(f); } -SLANG_FORCE_INLINE float F32_floor(float f) { return ::floorf(f); } -SLANG_FORCE_INLINE float F32_round(float f) { return ::roundf(f); } -SLANG_FORCE_INLINE float F32_sin(float f) { return ::sinf(f); } -SLANG_FORCE_INLINE float F32_cos(float f) { return ::cosf(f); } -SLANG_FORCE_INLINE float F32_tan(float f) { return ::tanf(f); } -SLANG_FORCE_INLINE float F32_asin(float f) { return ::asinf(f); } -SLANG_FORCE_INLINE float F32_acos(float f) { return ::acosf(f); } -SLANG_FORCE_INLINE float F32_atan(float f) { return ::atanf(f); } -SLANG_FORCE_INLINE float F32_sinh(float f) { return ::sinhf(f); } -SLANG_FORCE_INLINE float F32_cosh(float f) { return ::coshf(f); } -SLANG_FORCE_INLINE float F32_tanh(float f) { return ::tanhf(f); } -SLANG_FORCE_INLINE float F32_log2(float f) { return ::log2f(f); } -SLANG_FORCE_INLINE float F32_log(float f) { return ::logf(f); } -SLANG_FORCE_INLINE float F32_log10(float f) { return ::log10f(f); } -SLANG_FORCE_INLINE float F32_exp2(float f) { return ::exp2f(f); } -SLANG_FORCE_INLINE float F32_exp(float f) { return ::expf(f); } -SLANG_FORCE_INLINE float F32_abs(float f) { return ::fabsf(f); } -SLANG_FORCE_INLINE float F32_trunc(float f) { return ::truncf(f); } -SLANG_FORCE_INLINE float F32_sqrt(float f) { return ::sqrtf(f); } - -SLANG_FORCE_INLINE bool F32_isnan(float f) { return SLANG_PRELUDE_STD isnan(f); } -SLANG_FORCE_INLINE bool F32_isfinite(float f) { return SLANG_PRELUDE_STD isfinite(f); } -SLANG_FORCE_INLINE bool F32_isinf(float f) { return SLANG_PRELUDE_STD isinf(f); } +// Unary +SLANG_FORCE_INLINE float F32_ceil(float f) +{ + return ::ceilf(f); +} +SLANG_FORCE_INLINE float F32_floor(float f) +{ + return ::floorf(f); +} +SLANG_FORCE_INLINE float F32_round(float f) +{ + return ::roundf(f); +} +SLANG_FORCE_INLINE float F32_sin(float f) +{ + return ::sinf(f); +} +SLANG_FORCE_INLINE float F32_cos(float f) +{ + return ::cosf(f); +} +SLANG_FORCE_INLINE float F32_tan(float f) +{ + return ::tanf(f); +} +SLANG_FORCE_INLINE float F32_asin(float f) +{ + return ::asinf(f); +} +SLANG_FORCE_INLINE float F32_acos(float f) +{ + return ::acosf(f); +} +SLANG_FORCE_INLINE float F32_atan(float f) +{ + return ::atanf(f); +} +SLANG_FORCE_INLINE float F32_sinh(float f) +{ + return ::sinhf(f); +} +SLANG_FORCE_INLINE float F32_cosh(float f) +{ + return ::coshf(f); +} +SLANG_FORCE_INLINE float F32_tanh(float f) +{ + return ::tanhf(f); +} +SLANG_FORCE_INLINE float F32_log2(float f) +{ + return ::log2f(f); +} +SLANG_FORCE_INLINE float F32_log(float f) +{ + return ::logf(f); +} +SLANG_FORCE_INLINE float F32_log10(float f) +{ + return ::log10f(f); +} +SLANG_FORCE_INLINE float F32_exp2(float f) +{ + return ::exp2f(f); +} +SLANG_FORCE_INLINE float F32_exp(float f) +{ + return ::expf(f); +} +SLANG_FORCE_INLINE float F32_abs(float f) +{ + return ::fabsf(f); +} +SLANG_FORCE_INLINE float F32_trunc(float f) +{ + return ::truncf(f); +} +SLANG_FORCE_INLINE float F32_sqrt(float f) +{ + return ::sqrtf(f); +} + +SLANG_FORCE_INLINE bool F32_isnan(float f) +{ + return SLANG_PRELUDE_STD isnan(f); +} +SLANG_FORCE_INLINE bool F32_isfinite(float f) +{ + return SLANG_PRELUDE_STD isfinite(f); +} +SLANG_FORCE_INLINE bool F32_isinf(float f) +{ + return SLANG_PRELUDE_STD isinf(f); +} // Binary -SLANG_FORCE_INLINE float F32_min(float a, float b) { return ::fminf(a, b); } -SLANG_FORCE_INLINE float F32_max(float a, float b) { return ::fmaxf(a, b); } -SLANG_FORCE_INLINE float F32_pow(float a, float b) { return ::powf(a, b); } -SLANG_FORCE_INLINE float F32_fmod(float a, float b) { return ::fmodf(a, b); } -SLANG_FORCE_INLINE float F32_remainder(float a, float b) { return ::remainderf(a, b); } -SLANG_FORCE_INLINE float F32_atan2(float a, float b) { return float(::atan2(a, b)); } +SLANG_FORCE_INLINE float F32_min(float a, float b) +{ + return ::fminf(a, b); +} +SLANG_FORCE_INLINE float F32_max(float a, float b) +{ + return ::fmaxf(a, b); +} +SLANG_FORCE_INLINE float F32_pow(float a, float b) +{ + return ::powf(a, b); +} +SLANG_FORCE_INLINE float F32_fmod(float a, float b) +{ + return ::fmodf(a, b); +} +SLANG_FORCE_INLINE float F32_remainder(float a, float b) +{ + return ::remainderf(a, b); +} +SLANG_FORCE_INLINE float F32_atan2(float a, float b) +{ + return float(::atan2(a, b)); +} -SLANG_FORCE_INLINE float F32_frexp(float x, int* e) { return ::frexpf(x, e); } +SLANG_FORCE_INLINE float F32_frexp(float x, int* e) +{ + return ::frexpf(x, e); +} SLANG_FORCE_INLINE float F32_modf(float x, float* ip) { @@ -222,26 +344,48 @@ SLANG_FORCE_INLINE float F32_modf(float x, float* ip) } // Ternary -SLANG_FORCE_INLINE float F32_fma(float a, float b, float c) { return ::fmaf(a, b, c); } +SLANG_FORCE_INLINE float F32_fma(float a, float b, float c) +{ + return ::fmaf(a, b, c); +} #endif SLANG_FORCE_INLINE float F32_calcSafeRadians(float radians) { - // Put 0 to 2pi cycles to cycle around 0 to 1 - float a = radians * (1.0f / float(SLANG_PRELUDE_PI * 2)); + // Put 0 to 2pi cycles to cycle around 0 to 1 + float a = radians * (1.0f / float(SLANG_PRELUDE_PI * 2)); // Get truncated fraction, as value in 0 - 1 range a = a - F32_floor(a); // Convert back to 0 - 2pi range - return (a * float(SLANG_PRELUDE_PI * 2)); + return (a * float(SLANG_PRELUDE_PI * 2)); } -SLANG_FORCE_INLINE float F32_rsqrt(float f) { return 1.0f / F32_sqrt(f); } -SLANG_FORCE_INLINE float F32_sign(float f) { return ( f == 0.0f) ? f : (( f < 0.0f) ? -1.0f : 1.0f); } -SLANG_FORCE_INLINE float F32_frac(float f) { return f - F32_floor(f); } +SLANG_FORCE_INLINE float F32_rsqrt(float f) +{ + return 1.0f / F32_sqrt(f); +} +SLANG_FORCE_INLINE float F32_sign(float f) +{ + return (f == 0.0f) ? f : ((f < 0.0f) ? -1.0f : 1.0f); +} +SLANG_FORCE_INLINE float F32_frac(float f) +{ + return f - F32_floor(f); +} -SLANG_FORCE_INLINE uint32_t F32_asuint(float f) { Union32 u; u.f = f; return u.u; } -SLANG_FORCE_INLINE int32_t F32_asint(float f) { Union32 u; u.f = f; return u.i; } +SLANG_FORCE_INLINE uint32_t F32_asuint(float f) +{ + Union32 u; + u.f = f; + return u.u; +} +SLANG_FORCE_INLINE int32_t F32_asint(float f) +{ + Union32 u; + u.f = f; + return u.i; +} // ----------------------------- F64 ----------------------------------------- @@ -251,7 +395,7 @@ SLANG_FORCE_INLINE double F64_calcSafeRadians(double radians); SLANG_PRELUDE_EXTERN_C_START -// Unary +// Unary double F64_ceil(double f); double F64_floor(double f); double F64_round(double f); @@ -278,8 +422,14 @@ bool F64_isfinite(double f); bool F64_isinf(double f); // Binary -SLANG_FORCE_INLINE double F64_min(double a, double b) { return a < b ? a : b; } -SLANG_FORCE_INLINE double F64_max(double a, double b) { return a > b ? a : b; } +SLANG_FORCE_INLINE double F64_min(double a, double b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE double F64_max(double a, double b) +{ + return a > b ? a : b; +} double F64_pow(double a, double b); double F64_fmod(double a, double b); double F64_remainder(double a, double b); @@ -290,48 +440,141 @@ double F64_frexp(double x, int* e); double F64_modf(double x, double* ip); // Ternary -SLANG_FORCE_INLINE double F64_fma(double a, double b, double c) { return a * b + c; } +SLANG_FORCE_INLINE double F64_fma(double a, double b, double c) +{ + return a * b + c; +} SLANG_PRELUDE_EXTERN_C_END #else // SLANG_LLVM -// Unary -SLANG_FORCE_INLINE double F64_ceil(double f) { return ::ceil(f); } -SLANG_FORCE_INLINE double F64_floor(double f) { return ::floor(f); } -SLANG_FORCE_INLINE double F64_round(double f) { return ::round(f); } -SLANG_FORCE_INLINE double F64_sin(double f) { return ::sin(f); } -SLANG_FORCE_INLINE double F64_cos(double f) { return ::cos(f); } -SLANG_FORCE_INLINE double F64_tan(double f) { return ::tan(f); } -SLANG_FORCE_INLINE double F64_asin(double f) { return ::asin(f); } -SLANG_FORCE_INLINE double F64_acos(double f) { return ::acos(f); } -SLANG_FORCE_INLINE double F64_atan(double f) { return ::atan(f); } -SLANG_FORCE_INLINE double F64_sinh(double f) { return ::sinh(f); } -SLANG_FORCE_INLINE double F64_cosh(double f) { return ::cosh(f); } -SLANG_FORCE_INLINE double F64_tanh(double f) { return ::tanh(f); } -SLANG_FORCE_INLINE double F64_log2(double f) { return ::log2(f); } -SLANG_FORCE_INLINE double F64_log(double f) { return ::log(f); } -SLANG_FORCE_INLINE double F64_log10(float f) { return ::log10(f); } -SLANG_FORCE_INLINE double F64_exp2(double f) { return ::exp2(f); } -SLANG_FORCE_INLINE double F64_exp(double f) { return ::exp(f); } -SLANG_FORCE_INLINE double F64_abs(double f) { return ::fabs(f); } -SLANG_FORCE_INLINE double F64_trunc(double f) { return ::trunc(f); } -SLANG_FORCE_INLINE double F64_sqrt(double f) { return ::sqrt(f); } - - -SLANG_FORCE_INLINE bool F64_isnan(double f) { return SLANG_PRELUDE_STD isnan(f); } -SLANG_FORCE_INLINE bool F64_isfinite(double f) { return SLANG_PRELUDE_STD isfinite(f); } -SLANG_FORCE_INLINE bool F64_isinf(double f) { return SLANG_PRELUDE_STD isinf(f); } +// Unary +SLANG_FORCE_INLINE double F64_ceil(double f) +{ + return ::ceil(f); +} +SLANG_FORCE_INLINE double F64_floor(double f) +{ + return ::floor(f); +} +SLANG_FORCE_INLINE double F64_round(double f) +{ + return ::round(f); +} +SLANG_FORCE_INLINE double F64_sin(double f) +{ + return ::sin(f); +} +SLANG_FORCE_INLINE double F64_cos(double f) +{ + return ::cos(f); +} +SLANG_FORCE_INLINE double F64_tan(double f) +{ + return ::tan(f); +} +SLANG_FORCE_INLINE double F64_asin(double f) +{ + return ::asin(f); +} +SLANG_FORCE_INLINE double F64_acos(double f) +{ + return ::acos(f); +} +SLANG_FORCE_INLINE double F64_atan(double f) +{ + return ::atan(f); +} +SLANG_FORCE_INLINE double F64_sinh(double f) +{ + return ::sinh(f); +} +SLANG_FORCE_INLINE double F64_cosh(double f) +{ + return ::cosh(f); +} +SLANG_FORCE_INLINE double F64_tanh(double f) +{ + return ::tanh(f); +} +SLANG_FORCE_INLINE double F64_log2(double f) +{ + return ::log2(f); +} +SLANG_FORCE_INLINE double F64_log(double f) +{ + return ::log(f); +} +SLANG_FORCE_INLINE double F64_log10(float f) +{ + return ::log10(f); +} +SLANG_FORCE_INLINE double F64_exp2(double f) +{ + return ::exp2(f); +} +SLANG_FORCE_INLINE double F64_exp(double f) +{ + return ::exp(f); +} +SLANG_FORCE_INLINE double F64_abs(double f) +{ + return ::fabs(f); +} +SLANG_FORCE_INLINE double F64_trunc(double f) +{ + return ::trunc(f); +} +SLANG_FORCE_INLINE double F64_sqrt(double f) +{ + return ::sqrt(f); +} + + +SLANG_FORCE_INLINE bool F64_isnan(double f) +{ + return SLANG_PRELUDE_STD isnan(f); +} +SLANG_FORCE_INLINE bool F64_isfinite(double f) +{ + return SLANG_PRELUDE_STD isfinite(f); +} +SLANG_FORCE_INLINE bool F64_isinf(double f) +{ + return SLANG_PRELUDE_STD isinf(f); +} // Binary -SLANG_FORCE_INLINE double F64_min(double a, double b) { return ::fmin(a, b); } -SLANG_FORCE_INLINE double F64_max(double a, double b) { return ::fmax(a, b); } -SLANG_FORCE_INLINE double F64_pow(double a, double b) { return ::pow(a, b); } -SLANG_FORCE_INLINE double F64_fmod(double a, double b) { return ::fmod(a, b); } -SLANG_FORCE_INLINE double F64_remainder(double a, double b) { return ::remainder(a, b); } -SLANG_FORCE_INLINE double F64_atan2(double a, double b) { return ::atan2(a, b); } +SLANG_FORCE_INLINE double F64_min(double a, double b) +{ + return ::fmin(a, b); +} +SLANG_FORCE_INLINE double F64_max(double a, double b) +{ + return ::fmax(a, b); +} +SLANG_FORCE_INLINE double F64_pow(double a, double b) +{ + return ::pow(a, b); +} +SLANG_FORCE_INLINE double F64_fmod(double a, double b) +{ + return ::fmod(a, b); +} +SLANG_FORCE_INLINE double F64_remainder(double a, double b) +{ + return ::remainder(a, b); +} +SLANG_FORCE_INLINE double F64_atan2(double a, double b) +{ + return ::atan2(a, b); +} -SLANG_FORCE_INLINE double F64_frexp(double x, int* e) { return ::frexp(x, e); } +SLANG_FORCE_INLINE double F64_frexp(double x, int* e) +{ + return ::frexp(x, e); +} SLANG_FORCE_INLINE double F64_modf(double x, double* ip) { @@ -339,13 +582,25 @@ SLANG_FORCE_INLINE double F64_modf(double x, double* ip) } // Ternary -SLANG_FORCE_INLINE double F64_fma(double a, double b, double c) { return ::fma(a, b, c); } +SLANG_FORCE_INLINE double F64_fma(double a, double b, double c) +{ + return ::fma(a, b, c); +} #endif // SLANG_LLVM -SLANG_FORCE_INLINE double F64_rsqrt(double f) { return 1.0 / F64_sqrt(f); } -SLANG_FORCE_INLINE double F64_sign(double f) { return (f == 0.0) ? f : ((f < 0.0) ? -1.0 : 1.0); } -SLANG_FORCE_INLINE double F64_frac(double f) { return f - F64_floor(f); } +SLANG_FORCE_INLINE double F64_rsqrt(double f) +{ + return 1.0 / F64_sqrt(f); +} +SLANG_FORCE_INLINE double F64_sign(double f) +{ + return (f == 0.0) ? f : ((f < 0.0) ? -1.0 : 1.0); +} +SLANG_FORCE_INLINE double F64_frac(double f) +{ + return f - F64_floor(f); +} SLANG_FORCE_INLINE void F64_asuint(double d, uint32_t* low, uint32_t* hi) { @@ -365,24 +620,41 @@ SLANG_FORCE_INLINE void F64_asint(double d, int32_t* low, int32_t* hi) SLANG_FORCE_INLINE double F64_calcSafeRadians(double radians) { - // Put 0 to 2pi cycles to cycle around 0 to 1 - double a = radians * (1.0f / (SLANG_PRELUDE_PI * 2)); + // Put 0 to 2pi cycles to cycle around 0 to 1 + double a = radians * (1.0f / (SLANG_PRELUDE_PI * 2)); // Get truncated fraction, as value in 0 - 1 range a = a - F64_floor(a); // Convert back to 0 - 2pi range - return (a * (SLANG_PRELUDE_PI * 2)); + return (a * (SLANG_PRELUDE_PI * 2)); } // ----------------------------- I32 ----------------------------------------- -SLANG_FORCE_INLINE int32_t I32_abs(int32_t f) { return (f < 0) ? -f : f; } +SLANG_FORCE_INLINE int32_t I32_abs(int32_t f) +{ + return (f < 0) ? -f : f; +} -SLANG_FORCE_INLINE int32_t I32_min(int32_t a, int32_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE int32_t I32_max(int32_t a, int32_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE int32_t I32_min(int32_t a, int32_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE int32_t I32_max(int32_t a, int32_t b) +{ + return a > b ? a : b; +} -SLANG_FORCE_INLINE float I32_asfloat(int32_t x) { Union32 u; u.i = x; return u.f; } -SLANG_FORCE_INLINE uint32_t I32_asuint(int32_t x) { return uint32_t(x); } -SLANG_FORCE_INLINE double I32_asdouble(int32_t low, int32_t hi ) +SLANG_FORCE_INLINE float I32_asfloat(int32_t x) +{ + Union32 u; + u.i = x; + return u.f; +} +SLANG_FORCE_INLINE uint32_t I32_asuint(int32_t x) +{ + return uint32_t(x); +} +SLANG_FORCE_INLINE double I32_asdouble(int32_t low, int32_t hi) { Union64 u; u.u = (uint64_t(hi) << 32) | uint32_t(low); @@ -391,13 +663,30 @@ SLANG_FORCE_INLINE double I32_asdouble(int32_t low, int32_t hi ) // ----------------------------- U32 ----------------------------------------- -SLANG_FORCE_INLINE uint32_t U32_abs(uint32_t f) { return f; } +SLANG_FORCE_INLINE uint32_t U32_abs(uint32_t f) +{ + return f; +} -SLANG_FORCE_INLINE uint32_t U32_min(uint32_t a, uint32_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE uint32_t U32_max(uint32_t a, uint32_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE uint32_t U32_min(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE uint32_t U32_max(uint32_t a, uint32_t b) +{ + return a > b ? a : b; +} -SLANG_FORCE_INLINE float U32_asfloat(uint32_t x) { Union32 u; u.u = x; return u.f; } -SLANG_FORCE_INLINE uint32_t U32_asint(int32_t x) { return uint32_t(x); } +SLANG_FORCE_INLINE float U32_asfloat(uint32_t x) +{ + Union32 u; + u.u = x; + return u.f; +} +SLANG_FORCE_INLINE uint32_t U32_asint(int32_t x) +{ + return uint32_t(x); +} SLANG_FORCE_INLINE double U32_asdouble(uint32_t low, uint32_t hi) { @@ -413,7 +702,7 @@ SLANG_FORCE_INLINE uint32_t U32_countbits(uint32_t v) return __builtin_popcount(v); #elif SLANG_PROCESSOR_X86_64 && SLANG_VC return __popcnt(v); -#else +#else uint32_t c = 0; while (v) { @@ -426,21 +715,30 @@ SLANG_FORCE_INLINE uint32_t U32_countbits(uint32_t v) // ----------------------------- U64 ----------------------------------------- -SLANG_FORCE_INLINE uint64_t U64_abs(uint64_t f) { return f; } +SLANG_FORCE_INLINE uint64_t U64_abs(uint64_t f) +{ + return f; +} -SLANG_FORCE_INLINE uint64_t U64_min(uint64_t a, uint64_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE uint64_t U64_max(uint64_t a, uint64_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE uint64_t U64_min(uint64_t a, uint64_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE uint64_t U64_max(uint64_t a, uint64_t b) +{ + return a > b ? a : b; +} -// TODO(JS): We don't define countbits for 64bit in stdlib currently. -// It's not clear from documentation if it should return 32 or 64 bits, if it exists. -// 32 bits can always hold the result, and will be implicitly promoted. +// TODO(JS): We don't define countbits for 64bit in the core module currently. +// It's not clear from documentation if it should return 32 or 64 bits, if it exists. +// 32 bits can always hold the result, and will be implicitly promoted. SLANG_FORCE_INLINE uint32_t U64_countbits(uint64_t v) { -#if SLANG_GCC_FAMILY && !defined(SLANG_LLVM) +#if SLANG_GCC_FAMILY && !defined(SLANG_LLVM) return uint32_t(__builtin_popcountl(v)); #elif SLANG_PROCESSOR_X86_64 && SLANG_VC return uint32_t(__popcnt64(v)); -#else +#else uint32_t c = 0; while (v) { @@ -453,10 +751,19 @@ SLANG_FORCE_INLINE uint32_t U64_countbits(uint64_t v) // ----------------------------- I64 ----------------------------------------- -SLANG_FORCE_INLINE int64_t I64_abs(int64_t f) { return (f < 0) ? -f : f; } +SLANG_FORCE_INLINE int64_t I64_abs(int64_t f) +{ + return (f < 0) ? -f : f; +} -SLANG_FORCE_INLINE int64_t I64_min(int64_t a, int64_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE int64_t I64_max(int64_t a, int64_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE int64_t I64_min(int64_t a, int64_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE int64_t I64_max(int64_t a, int64_t b) +{ + return a > b ? a : b; +} // ----------------------------- Interlocked --------------------------------- @@ -465,17 +772,17 @@ SLANG_FORCE_INLINE int64_t I64_max(int64_t a, int64_t b) { return a > b ? a : b; #else // SLANG_LLVM -# ifdef _WIN32 -# include -# endif +#ifdef _WIN32 +#include +#endif SLANG_FORCE_INLINE void InterlockedAdd(uint32_t* dest, uint32_t value, uint32_t* oldValue) { -# ifdef _WIN32 +#ifdef _WIN32 *oldValue = _InterlockedExchangeAdd((long*)dest, (long)value); -# else +#else *oldValue = __sync_fetch_and_add(dest, value); -# endif +#endif } #endif // SLANG_LLVM @@ -492,7 +799,7 @@ SLANG_FORCE_INLINE double _slang_fmod(double x, double y) } #ifdef SLANG_PRELUDE_NAMESPACE -} +} #endif #endif diff --git a/prelude/slang-cpp-types-core.h b/prelude/slang-cpp-types-core.h index 25fe472021..6c0bb75444 100644 --- a/prelude/slang-cpp-types-core.h +++ b/prelude/slang-cpp-types-core.h @@ -2,11 +2,11 @@ #define SLANG_PRELUDE_CPP_TYPES_CORE_H #ifndef SLANG_PRELUDE_ASSERT -# ifdef SLANG_PRELUDE_ENABLE_ASSERT -# define SLANG_PRELUDE_ASSERT(VALUE) assert(VALUE) -# else -# define SLANG_PRELUDE_ASSERT(VALUE) -# endif +#ifdef SLANG_PRELUDE_ENABLE_ASSERT +#define SLANG_PRELUDE_ASSERT(VALUE) assert(VALUE) +#else +#define SLANG_PRELUDE_ASSERT(VALUE) +#endif #endif // Since we are using unsigned arithmatic care is need in this comparison. @@ -15,35 +15,42 @@ // Asserts for bounds checking. // It is assumed index/count are unsigned types. -#define SLANG_BOUND_ASSERT(index, count) SLANG_PRELUDE_ASSERT(index < count); -#define SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_PRELUDE_ASSERT(index <= (sizeInBytes - elemSize) && (index & 3) == 0); +#define SLANG_BOUND_ASSERT(index, count) SLANG_PRELUDE_ASSERT(index < count); +#define SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_PRELUDE_ASSERT(index <= (sizeInBytes - elemSize) && (index & 3) == 0); // Macros to zero index if an access is out of range -#define SLANG_BOUND_ZERO_INDEX(index, count) index = (index < count) ? index : 0; -#define SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) index = (index <= (sizeInBytes - elemSize)) ? index : 0; - -// The 'FIX' macro define how the index is fixed. The default is to do nothing. If SLANG_ENABLE_BOUND_ZERO_INDEX -// the fix macro will zero the index, if out of range -#ifdef SLANG_ENABLE_BOUND_ZERO_INDEX -# define SLANG_BOUND_FIX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) -# define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) -# define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) SLANG_BOUND_ZERO_INDEX(index, count) +#define SLANG_BOUND_ZERO_INDEX(index, count) index = (index < count) ? index : 0; +#define SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + index = (index <= (sizeInBytes - elemSize)) ? index : 0; + +// The 'FIX' macro define how the index is fixed. The default is to do nothing. If +// SLANG_ENABLE_BOUND_ZERO_INDEX the fix macro will zero the index, if out of range +#ifdef SLANG_ENABLE_BOUND_ZERO_INDEX +#define SLANG_BOUND_FIX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) +#define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) SLANG_BOUND_ZERO_INDEX(index, count) #else -# define SLANG_BOUND_FIX(index, count) -# define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) -# define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) +#define SLANG_BOUND_FIX(index, count) +#define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) #endif #ifndef SLANG_BOUND_CHECK -# define SLANG_BOUND_CHECK(index, count) SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX(index, count) +#define SLANG_BOUND_CHECK(index, count) \ + SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX(index, count) #endif #ifndef SLANG_BOUND_CHECK_BYTE_ADDRESS -# define SLANG_BOUND_CHECK_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_CHECK_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) #endif #ifndef SLANG_BOUND_CHECK_FIXED_ARRAY -# define SLANG_BOUND_CHECK_FIXED_ARRAY(index, count) SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX_FIXED_ARRAY(index, count) +#define SLANG_BOUND_CHECK_FIXED_ARRAY(index, count) \ + SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX_FIXED_ARRAY(index, count) #endif struct TypeInfo @@ -51,34 +58,51 @@ struct TypeInfo size_t typeSize; }; -template +template struct FixedArray { - const T& operator[](size_t index) const { SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); return m_data[index]; } - T& operator[](size_t index) { SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); return m_data[index]; } + const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); + return m_data[index]; + } + T& operator[](size_t index) + { + SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); + return m_data[index]; + } T m_data[SIZE]; }; -// An array that has no specified size, becomes a 'Array'. This stores the size so it can potentially -// do bounds checking. -template +// An array that has no specified size, becomes a 'Array'. This stores the size so it can +// potentially do bounds checking. +template struct Array { - const T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - T& operator[](size_t index) { SLANG_BOUND_CHECK(index, count); return data[index]; } + const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + T& operator[](size_t index) + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } T* data; size_t count; }; -/* Constant buffers become a pointer to the contained type, so ConstantBuffer becomes T* in C++ code. -*/ +/* Constant buffers become a pointer to the contained type, so ConstantBuffer becomes T* in C++ + * code. + */ -template +template struct Vector; -template +template struct Vector { T x; @@ -86,58 +110,54 @@ struct Vector T& operator[](size_t /*index*/) { return x; } operator T() const { return x; } Vector() = default; - Vector(T scalar) - { - x = scalar; - } - template + Vector(T scalar) { x = scalar; } + template Vector(Vector other) { x = (T)other.x; } - template + template Vector(Vector other) { int minSize = 1; - if (otherSize < minSize) minSize = otherSize; + if (otherSize < minSize) + minSize = otherSize; for (int i = 0; i < minSize; i++) (*this)[i] = (T)other[i]; } }; -template +template struct Vector { T x, y; const T& operator[](size_t index) const { return index == 0 ? x : y; } T& operator[](size_t index) { return index == 0 ? x : y; } Vector() = default; - Vector(T scalar) - { - x = y = scalar; - } + Vector(T scalar) { x = y = scalar; } Vector(T _x, T _y) { x = _x; y = _y; } - template + template Vector(Vector other) { x = (T)other.x; y = (T)other.y; } - template + template Vector(Vector other) { int minSize = 2; - if (otherSize < minSize) minSize = otherSize; + if (otherSize < minSize) + minSize = otherSize; for (int i = 0; i < minSize; i++) (*this)[i] = (T)other[i]; } }; -template +template struct Vector { T x, y, z; @@ -145,34 +165,32 @@ struct Vector T& operator[](size_t index) { return *((T*)(this) + index); } Vector() = default; - Vector(T scalar) - { - x = y = z = scalar; - } + Vector(T scalar) { x = y = z = scalar; } Vector(T _x, T _y, T _z) { x = _x; y = _y; z = _z; } - template + template Vector(Vector other) { x = (T)other.x; y = (T)other.y; z = (T)other.z; } - template + template Vector(Vector other) { int minSize = 3; - if (otherSize < minSize) minSize = otherSize; + if (otherSize < minSize) + minSize = otherSize; for (int i = 0; i < minSize; i++) (*this)[i] = (T)other[i]; } }; -template +template struct Vector { T x, y, z, w; @@ -180,10 +198,7 @@ struct Vector const T& operator[](size_t index) const { return *((T*)(this) + index); } T& operator[](size_t index) { return *((T*)(this) + index); } Vector() = default; - Vector(T scalar) - { - x = y = z = w = scalar; - } + Vector(T scalar) { x = y = z = w = scalar; } Vector(T _x, T _y, T _z, T _w) { x = _x; @@ -191,19 +206,22 @@ struct Vector z = _z; w = _w; } - template + template Vector(Vector other) { int minSize = 4; - if (otherSize < minSize) minSize = otherSize; + if (otherSize < minSize) + minSize = otherSize; for (int i = 0; i < minSize; i++) (*this)[i] = (T)other[i]; } - }; template -SLANG_FORCE_INLINE Vector _slang_select(Vector condition, Vector v0, Vector v1) +SLANG_FORCE_INLINE Vector _slang_select( + Vector condition, + Vector v0, + Vector v1) { Vector result; for (int i = 0; i < N; i++) @@ -228,7 +246,7 @@ SLANG_FORCE_INLINE T _slang_vector_get_element(Vector x, int index) template SLANG_FORCE_INLINE const T* _slang_vector_get_element_ptr(const Vector* x, int index) { - return &((*const_cast*>(x))[index]); + return &((*const_cast*>(x))[index]); } template @@ -253,66 +271,70 @@ SLANG_FORCE_INLINE Vector _slang_vector_reshape(const Vector ot typedef uint32_t uint; -#define SLANG_VECTOR_BINARY_OP(T, op) \ - template \ - SLANG_FORCE_INLINE Vector operator op(const Vector& thisVal, const Vector& other) \ - { \ - Vector result;\ - for (int i = 0; i < n; i++) \ - result[i] = thisVal[i] op other[i]; \ - return result;\ - } -#define SLANG_VECTOR_BINARY_COMPARE_OP(T, op) \ - template \ - SLANG_FORCE_INLINE Vector operator op(const Vector& thisVal, const Vector& other) \ - { \ - Vector result;\ - for (int i = 0; i < n; i++) \ - result[i] = thisVal[i] op other[i]; \ - return result;\ - } - -#define SLANG_VECTOR_UNARY_OP(T, op) \ - template \ +#define SLANG_VECTOR_BINARY_OP(T, op) \ + template \ + SLANG_FORCE_INLINE Vector operator op( \ + const Vector& thisVal, \ + const Vector& other) \ + { \ + Vector result; \ + for (int i = 0; i < n; i++) \ + result[i] = thisVal[i] op other[i]; \ + return result; \ + } +#define SLANG_VECTOR_BINARY_COMPARE_OP(T, op) \ + template \ + SLANG_FORCE_INLINE Vector operator op( \ + const Vector& thisVal, \ + const Vector& other) \ + { \ + Vector result; \ + for (int i = 0; i < n; i++) \ + result[i] = thisVal[i] op other[i]; \ + return result; \ + } + +#define SLANG_VECTOR_UNARY_OP(T, op) \ + template \ SLANG_FORCE_INLINE Vector operator op(const Vector& thisVal) \ - { \ - Vector result;\ - for (int i = 0; i < n; i++) \ - result[i] = op thisVal[i]; \ - return result;\ - } -#define SLANG_INT_VECTOR_OPS(T) \ - SLANG_VECTOR_BINARY_OP(T, +)\ - SLANG_VECTOR_BINARY_OP(T, -)\ - SLANG_VECTOR_BINARY_OP(T, *)\ - SLANG_VECTOR_BINARY_OP(T, / )\ - SLANG_VECTOR_BINARY_OP(T, &)\ - SLANG_VECTOR_BINARY_OP(T, |)\ - SLANG_VECTOR_BINARY_OP(T, &&)\ - SLANG_VECTOR_BINARY_OP(T, ||)\ - SLANG_VECTOR_BINARY_OP(T, ^)\ - SLANG_VECTOR_BINARY_OP(T, %)\ - SLANG_VECTOR_BINARY_OP(T, >>)\ - SLANG_VECTOR_BINARY_OP(T, <<)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, >)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, <)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, >=)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, <=)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, ==)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, !=)\ - SLANG_VECTOR_UNARY_OP(T, !)\ + { \ + Vector result; \ + for (int i = 0; i < n; i++) \ + result[i] = op thisVal[i]; \ + return result; \ + } +#define SLANG_INT_VECTOR_OPS(T) \ + SLANG_VECTOR_BINARY_OP(T, +) \ + SLANG_VECTOR_BINARY_OP(T, -) \ + SLANG_VECTOR_BINARY_OP(T, *) \ + SLANG_VECTOR_BINARY_OP(T, /) \ + SLANG_VECTOR_BINARY_OP(T, &) \ + SLANG_VECTOR_BINARY_OP(T, |) \ + SLANG_VECTOR_BINARY_OP(T, &&) \ + SLANG_VECTOR_BINARY_OP(T, ||) \ + SLANG_VECTOR_BINARY_OP(T, ^) \ + SLANG_VECTOR_BINARY_OP(T, %) \ + SLANG_VECTOR_BINARY_OP(T, >>) \ + SLANG_VECTOR_BINARY_OP(T, <<) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, >) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, <) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, >=) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, <=) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, ==) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, !=) \ + SLANG_VECTOR_UNARY_OP(T, !) \ SLANG_VECTOR_UNARY_OP(T, ~) -#define SLANG_FLOAT_VECTOR_OPS(T) \ - SLANG_VECTOR_BINARY_OP(T, +)\ - SLANG_VECTOR_BINARY_OP(T, -)\ - SLANG_VECTOR_BINARY_OP(T, *)\ - SLANG_VECTOR_BINARY_OP(T, /)\ - SLANG_VECTOR_UNARY_OP(T, -)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, >)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, <)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, >=)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, <=)\ - SLANG_VECTOR_BINARY_COMPARE_OP(T, ==)\ +#define SLANG_FLOAT_VECTOR_OPS(T) \ + SLANG_VECTOR_BINARY_OP(T, +) \ + SLANG_VECTOR_BINARY_OP(T, -) \ + SLANG_VECTOR_BINARY_OP(T, *) \ + SLANG_VECTOR_BINARY_OP(T, /) \ + SLANG_VECTOR_UNARY_OP(T, -) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, >) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, <) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, >=) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, <=) \ + SLANG_VECTOR_BINARY_COMPARE_OP(T, ==) \ SLANG_VECTOR_BINARY_COMPARE_OP(T, !=) SLANG_INT_VECTOR_OPS(bool) @@ -328,14 +350,14 @@ SLANG_INT_VECTOR_OPS(uint64_t) SLANG_FLOAT_VECTOR_OPS(float) SLANG_FLOAT_VECTOR_OPS(double) -#define SLANG_VECTOR_INT_NEG_OP(T) \ - template\ +#define SLANG_VECTOR_INT_NEG_OP(T) \ + template \ Vector operator-(const Vector& thisVal) \ - { \ - Vector result;\ - for (int i = 0; i < N; i++) \ - result[i] = 0 - thisVal[i]; \ - return result;\ + { \ + Vector result; \ + for (int i = 0; i < N; i++) \ + result[i] = 0 - thisVal[i]; \ + return result; \ } SLANG_VECTOR_INT_NEG_OP(int) SLANG_VECTOR_INT_NEG_OP(int8_t) @@ -346,14 +368,14 @@ SLANG_VECTOR_INT_NEG_OP(uint8_t) SLANG_VECTOR_INT_NEG_OP(uint16_t) SLANG_VECTOR_INT_NEG_OP(uint64_t) -#define SLANG_FLOAT_VECTOR_MOD(T)\ - template \ +#define SLANG_FLOAT_VECTOR_MOD(T) \ + template \ Vector operator%(const Vector& left, const Vector& right) \ - {\ - Vector result;\ - for (int i = 0; i < N; i++) \ - result[i] = _slang_fmod(left[i], right[i]); \ - return result;\ + { \ + Vector result; \ + for (int i = 0; i < N; i++) \ + result[i] = _slang_fmod(left[i], right[i]); \ + return result; \ } SLANG_FLOAT_VECTOR_MOD(float) @@ -366,7 +388,7 @@ SLANG_FLOAT_VECTOR_MOD(double) #undef SLANG_VECTOR_INT_NEG_OP #undef SLANG_FLOAT_VECTOR_MOD -template +template struct Matrix { Vector rows[ROWS]; @@ -377,10 +399,7 @@ struct Matrix for (int i = 0; i < ROWS; i++) rows[i] = Vector(scalar); } - Matrix(const Vector& row0) - { - rows[0] = row0; - } + Matrix(const Vector& row0) { rows[0] = row0; } Matrix(const Vector& row0, const Vector& row1) { rows[0] = row0; @@ -392,7 +411,11 @@ struct Matrix rows[1] = row1; rows[2] = row2; } - Matrix(const Vector& row0, const Vector& row1, const Vector& row2, const Vector& row3) + Matrix( + const Vector& row0, + const Vector& row1, + const Vector& row2, + const Vector& row3) { rows[0] = row0; rows[1] = row1; @@ -404,116 +427,188 @@ struct Matrix { int minRow = ROWS; int minCol = COLS; - if (minRow > otherRow) minRow = otherRow; - if (minCol > otherCol) minCol = otherCol; + if (minRow > otherRow) + minRow = otherRow; + if (minCol > otherCol) + minCol = otherCol; for (int i = 0; i < minRow; i++) for (int j = 0; j < minCol; j++) rows[i][j] = (T)other.rows[i][j]; } Matrix(T v0, T v1, T v2, T v3) { - rows[0][0] = v0; rows[0][1] = v1; - rows[1][0] = v2; rows[1][1] = v3; + rows[0][0] = v0; + rows[0][1] = v1; + rows[1][0] = v2; + rows[1][1] = v3; } Matrix(T v0, T v1, T v2, T v3, T v4, T v5) { if (COLS == 3) { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; - rows[1][0] = v3; rows[1][1] = v4; rows[1][2] = v5; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[1][0] = v3; + rows[1][1] = v4; + rows[1][2] = v5; } else { - rows[0][0] = v0; rows[0][1] = v1; - rows[1][0] = v2; rows[1][1] = v3; - rows[2][0] = v4; rows[2][1] = v5; + rows[0][0] = v0; + rows[0][1] = v1; + rows[1][0] = v2; + rows[1][1] = v3; + rows[2][0] = v4; + rows[2][1] = v5; } } Matrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) { if (COLS == 4) { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; rows[0][3] = v3; - rows[1][0] = v4; rows[1][1] = v5; rows[1][2] = v6; rows[1][3] = v7; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[0][3] = v3; + rows[1][0] = v4; + rows[1][1] = v5; + rows[1][2] = v6; + rows[1][3] = v7; } else { - rows[0][0] = v0; rows[0][1] = v1; - rows[1][0] = v2; rows[1][1] = v3; - rows[2][0] = v4; rows[2][1] = v5; - rows[3][0] = v6; rows[3][1] = v7; + rows[0][0] = v0; + rows[0][1] = v1; + rows[1][0] = v2; + rows[1][1] = v3; + rows[2][0] = v4; + rows[2][1] = v5; + rows[3][0] = v6; + rows[3][1] = v7; } } Matrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8) { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; - rows[1][0] = v3; rows[1][1] = v4; rows[1][2] = v5; - rows[2][0] = v6; rows[2][1] = v7; rows[2][2] = v8; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[1][0] = v3; + rows[1][1] = v4; + rows[1][2] = v5; + rows[2][0] = v6; + rows[2][1] = v7; + rows[2][2] = v8; } Matrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11) { if (COLS == 4) { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; rows[0][3] = v3; - rows[1][0] = v4; rows[1][1] = v5; rows[1][2] = v6; rows[1][3] = v7; - rows[2][0] = v8; rows[2][1] = v9; rows[2][2] = v10; rows[2][3] = v11; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[0][3] = v3; + rows[1][0] = v4; + rows[1][1] = v5; + rows[1][2] = v6; + rows[1][3] = v7; + rows[2][0] = v8; + rows[2][1] = v9; + rows[2][2] = v10; + rows[2][3] = v11; } else { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; - rows[1][0] = v3; rows[1][1] = v4; rows[1][2] = v5; - rows[2][0] = v6; rows[2][1] = v7; rows[2][2] = v8; - rows[3][0] = v9; rows[3][1] = v10; rows[3][2] = v11; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[1][0] = v3; + rows[1][1] = v4; + rows[1][2] = v5; + rows[2][0] = v6; + rows[2][1] = v7; + rows[2][2] = v8; + rows[3][0] = v9; + rows[3][1] = v10; + rows[3][2] = v11; } } - Matrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15) + Matrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5, + T v6, + T v7, + T v8, + T v9, + T v10, + T v11, + T v12, + T v13, + T v14, + T v15) { - rows[0][0] = v0; rows[0][1] = v1; rows[0][2] = v2; rows[0][3] = v3; - rows[1][0] = v4; rows[1][1] = v5; rows[1][2] = v6; rows[1][3] = v7; - rows[2][0] = v8; rows[2][1] = v9; rows[2][2] = v10; rows[2][3] = v11; - rows[3][0] = v12; rows[3][1] = v13; rows[3][2] = v14; rows[3][3] = v15; + rows[0][0] = v0; + rows[0][1] = v1; + rows[0][2] = v2; + rows[0][3] = v3; + rows[1][0] = v4; + rows[1][1] = v5; + rows[1][2] = v6; + rows[1][3] = v7; + rows[2][0] = v8; + rows[2][1] = v9; + rows[2][2] = v10; + rows[2][3] = v11; + rows[3][0] = v12; + rows[3][1] = v13; + rows[3][2] = v14; + rows[3][3] = v15; } }; -#define SLANG_MATRIX_BINARY_OP(T, op) \ - template \ +#define SLANG_MATRIX_BINARY_OP(T, op) \ + template \ Matrix operator op(const Matrix& thisVal, const Matrix& other) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - result.rows[i][j] = thisVal.rows[i][j] op other.rows[i][j]; \ - return result;\ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + result.rows[i][j] = thisVal.rows[i][j] op other.rows[i][j]; \ + return result; \ } -#define SLANG_MATRIX_UNARY_OP(T, op) \ - template \ +#define SLANG_MATRIX_UNARY_OP(T, op) \ + template \ Matrix operator op(const Matrix& thisVal) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - result[i].rows[i][j] = op thisVal.rows[i][j]; \ - return result;\ - } -#define SLANG_INT_MATRIX_OPS(T) \ - SLANG_MATRIX_BINARY_OP(T, +)\ - SLANG_MATRIX_BINARY_OP(T, -)\ - SLANG_MATRIX_BINARY_OP(T, *)\ - SLANG_MATRIX_BINARY_OP(T, / )\ - SLANG_MATRIX_BINARY_OP(T, &)\ - SLANG_MATRIX_BINARY_OP(T, |)\ - SLANG_MATRIX_BINARY_OP(T, &&)\ - SLANG_MATRIX_BINARY_OP(T, ||)\ - SLANG_MATRIX_BINARY_OP(T, ^)\ - SLANG_MATRIX_BINARY_OP(T, %)\ - SLANG_MATRIX_UNARY_OP(T, !)\ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + result[i].rows[i][j] = op thisVal.rows[i][j]; \ + return result; \ + } +#define SLANG_INT_MATRIX_OPS(T) \ + SLANG_MATRIX_BINARY_OP(T, +) \ + SLANG_MATRIX_BINARY_OP(T, -) \ + SLANG_MATRIX_BINARY_OP(T, *) \ + SLANG_MATRIX_BINARY_OP(T, /) \ + SLANG_MATRIX_BINARY_OP(T, &) \ + SLANG_MATRIX_BINARY_OP(T, |) \ + SLANG_MATRIX_BINARY_OP(T, &&) \ + SLANG_MATRIX_BINARY_OP(T, ||) \ + SLANG_MATRIX_BINARY_OP(T, ^) \ + SLANG_MATRIX_BINARY_OP(T, %) \ + SLANG_MATRIX_UNARY_OP(T, !) \ SLANG_MATRIX_UNARY_OP(T, ~) #define SLANG_FLOAT_MATRIX_OPS(T) \ - SLANG_MATRIX_BINARY_OP(T, +)\ - SLANG_MATRIX_BINARY_OP(T, -)\ - SLANG_MATRIX_BINARY_OP(T, *)\ - SLANG_MATRIX_BINARY_OP(T, /)\ + SLANG_MATRIX_BINARY_OP(T, +) \ + SLANG_MATRIX_BINARY_OP(T, -) \ + SLANG_MATRIX_BINARY_OP(T, *) \ + SLANG_MATRIX_BINARY_OP(T, /) \ SLANG_MATRIX_UNARY_OP(T, -) SLANG_INT_MATRIX_OPS(int) SLANG_INT_MATRIX_OPS(int8_t) @@ -527,38 +622,38 @@ SLANG_INT_MATRIX_OPS(uint64_t) SLANG_FLOAT_MATRIX_OPS(float) SLANG_FLOAT_MATRIX_OPS(double) -#define SLANG_MATRIX_INT_NEG_OP(T) \ - template\ +#define SLANG_MATRIX_INT_NEG_OP(T) \ + template \ SLANG_FORCE_INLINE Matrix operator-(Matrix thisVal) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - result.rows[i][j] = 0 - thisVal.rows[i][j]; \ - return result;\ - } - SLANG_MATRIX_INT_NEG_OP(int) - SLANG_MATRIX_INT_NEG_OP(int8_t) - SLANG_MATRIX_INT_NEG_OP(int16_t) - SLANG_MATRIX_INT_NEG_OP(int64_t) - SLANG_MATRIX_INT_NEG_OP(uint) - SLANG_MATRIX_INT_NEG_OP(uint8_t) - SLANG_MATRIX_INT_NEG_OP(uint16_t) - SLANG_MATRIX_INT_NEG_OP(uint64_t) - -#define SLANG_FLOAT_MATRIX_MOD(T)\ - template \ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + result.rows[i][j] = 0 - thisVal.rows[i][j]; \ + return result; \ + } +SLANG_MATRIX_INT_NEG_OP(int) +SLANG_MATRIX_INT_NEG_OP(int8_t) +SLANG_MATRIX_INT_NEG_OP(int16_t) +SLANG_MATRIX_INT_NEG_OP(int64_t) +SLANG_MATRIX_INT_NEG_OP(uint) +SLANG_MATRIX_INT_NEG_OP(uint8_t) +SLANG_MATRIX_INT_NEG_OP(uint16_t) +SLANG_MATRIX_INT_NEG_OP(uint64_t) + +#define SLANG_FLOAT_MATRIX_MOD(T) \ + template \ SLANG_FORCE_INLINE Matrix operator%(Matrix left, Matrix right) \ - {\ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - result.rows[i][j] = _slang_fmod(left.rows[i][j], right.rows[i][j]); \ - return result;\ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + result.rows[i][j] = _slang_fmod(left.rows[i][j], right.rows[i][j]); \ + return result; \ } - SLANG_FLOAT_MATRIX_MOD(float) - SLANG_FLOAT_MATRIX_MOD(double) +SLANG_FLOAT_MATRIX_MOD(float) +SLANG_FLOAT_MATRIX_MOD(double) #undef SLANG_FLOAT_MATRIX_MOD #undef SLANG_MATRIX_BINARY_OP #undef SLANG_MATRIX_UNARY_OP @@ -574,5 +669,3 @@ TResult slang_bit_cast(TInput val) } #endif - - diff --git a/prelude/slang-cpp-types.h b/prelude/slang-cpp-types.h index 3f805a8b7d..010ab8d6c4 100644 --- a/prelude/slang-cpp-types.h +++ b/prelude/slang-cpp-types.h @@ -2,11 +2,12 @@ #define SLANG_PRELUDE_CPP_TYPES_H #ifdef SLANG_PRELUDE_NAMESPACE -namespace SLANG_PRELUDE_NAMESPACE { +namespace SLANG_PRELUDE_NAMESPACE +{ #endif #ifndef SLANG_FORCE_INLINE -# define SLANG_FORCE_INLINE inline +#define SLANG_FORCE_INLINE inline #endif #include "slang-cpp-types-core.h" @@ -23,8 +24,8 @@ typedef Vector uint2; typedef Vector uint3; typedef Vector uint4; -// We can just map `NonUniformResourceIndex` type directly to the index type on CPU, as CPU does not require -// any special handling around such accesses. +// We can just map `NonUniformResourceIndex` type directly to the index type on CPU, as CPU does not +// require any special handling around such accesses. typedef size_t NonUniformResourceIndex; // ----------------------------- ResourceType ----------------------------------------- @@ -32,47 +33,87 @@ typedef size_t NonUniformResourceIndex; // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-structuredbuffer-getdimensions // Missing Load(_In_ int Location, _Out_ uint Status); -template +template struct RWStructuredBuffer { - SLANG_FORCE_INLINE T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - const T& Load(size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) { *outNumStructs = uint32_t(count); *outStride = uint32_t(sizeof(T)); } - + SLANG_FORCE_INLINE T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + const T& Load(size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) + { + *outNumStructs = uint32_t(count); + *outStride = uint32_t(sizeof(T)); + } + T* data; size_t count; }; -template +template struct StructuredBuffer { - SLANG_FORCE_INLINE const T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - const T& Load(size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) { *outNumStructs = uint32_t(count); *outStride = uint32_t(sizeof(T)); } - + SLANG_FORCE_INLINE const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + const T& Load(size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) + { + *outNumStructs = uint32_t(count); + *outStride = uint32_t(sizeof(T)); + } + T* data; size_t count; }; -template +template struct RWBuffer { - SLANG_FORCE_INLINE T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - const T& Load(size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } + SLANG_FORCE_INLINE T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + const T& Load(size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } void GetDimensions(uint32_t* outCount) { *outCount = uint32_t(count); } - + T* data; size_t count; }; -template +template struct Buffer { - SLANG_FORCE_INLINE const T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - const T& Load(size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } + SLANG_FORCE_INLINE const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + const T& Load(size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } void GetDimensions(uint32_t* outCount) { *outCount = uint32_t(count); } - + T* data; size_t count; }; @@ -81,28 +122,28 @@ struct Buffer struct ByteAddressBuffer { void GetDimensions(uint32_t* outDim) const { *outDim = uint32_t(sizeInBytes); } - uint32_t Load(size_t index) const - { + uint32_t Load(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - return data[index >> 2]; + return data[index >> 2]; } - uint2 Load2(size_t index) const - { + uint2 Load2(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint2{data[dataIdx], data[dataIdx + 1]}; + const size_t dataIdx = index >> 2; + return uint2{data[dataIdx], data[dataIdx + 1]}; } - uint3 Load3(size_t index) const - { + uint3 Load3(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; + const size_t dataIdx = index >> 2; + return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; } - uint4 Load4(size_t index) const - { + uint4 Load4(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; + const size_t dataIdx = index >> 2; + return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; } template T Load(size_t index) const @@ -110,40 +151,40 @@ struct ByteAddressBuffer SLANG_BOUND_CHECK_BYTE_ADDRESS(index, sizeof(T), sizeInBytes); return *(const T*)(((const char*)data) + index); } - + const uint32_t* data; - size_t sizeInBytes; //< Must be multiple of 4 + size_t sizeInBytes; //< Must be multiple of 4 }; // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-rwbyteaddressbuffer -// Missing support for Atomic operations +// Missing support for Atomic operations // Missing support for Load with status struct RWByteAddressBuffer { void GetDimensions(uint32_t* outDim) const { *outDim = uint32_t(sizeInBytes); } - - uint32_t Load(size_t index) const - { + + uint32_t Load(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - return data[index >> 2]; + return data[index >> 2]; } - uint2 Load2(size_t index) const - { + uint2 Load2(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint2{data[dataIdx], data[dataIdx + 1]}; + const size_t dataIdx = index >> 2; + return uint2{data[dataIdx], data[dataIdx + 1]}; } - uint3 Load3(size_t index) const - { + uint3 Load3(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; + const size_t dataIdx = index >> 2; + return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; } - uint4 Load4(size_t index) const - { + uint4 Load4(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; + const size_t dataIdx = index >> 2; + return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; } template T Load(size_t index) const @@ -152,30 +193,30 @@ struct RWByteAddressBuffer return *(const T*)(((const char*)data) + index); } - void Store(size_t index, uint32_t v) const - { + void Store(size_t index, uint32_t v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - data[index >> 2] = v; + data[index >> 2] = v; } - void Store2(size_t index, uint2 v) const - { + void Store2(size_t index, uint2 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; } - void Store3(size_t index, uint3 v) const - { + void Store3(size_t index, uint3 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; data[dataIdx + 2] = v.z; } - void Store4(size_t index, uint4 v) const - { + void Store4(size_t index, uint4 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; data[dataIdx + 2] = v.z; @@ -189,7 +230,7 @@ struct RWByteAddressBuffer } uint32_t* data; - size_t sizeInBytes; //< Must be multiple of 4 + size_t sizeInBytes; //< Must be multiple of 4 }; struct ISamplerState; @@ -206,7 +247,7 @@ struct SamplerComparisonState }; #ifndef SLANG_RESOURCE_SHAPE -# define SLANG_RESOURCE_SHAPE +#define SLANG_RESOURCE_SHAPE typedef unsigned int SlangResourceShape; enum { @@ -243,7 +284,7 @@ enum }; #endif -// +// struct TextureDimensions { void reset() @@ -259,25 +300,25 @@ struct TextureDimensions int count = 0; switch (baseShape) { - case SLANG_TEXTURE_1D: + case SLANG_TEXTURE_1D: { outDims[count++] = width; break; } - case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_2D: { outDims[count++] = width; outDims[count++] = height; break; } - case SLANG_TEXTURE_3D: + case SLANG_TEXTURE_3D: { outDims[count++] = width; outDims[count++] = height; outDims[count++] = depth; break; } - case SLANG_TEXTURE_CUBE: + case SLANG_TEXTURE_CUBE: { outDims[count++] = width; outDims[count++] = height; @@ -298,19 +339,19 @@ struct TextureDimensions int count = 0; switch (baseShape) { - case SLANG_TEXTURE_1D: + case SLANG_TEXTURE_1D: { outDims[count++] = width; break; } - case SLANG_TEXTURE_CUBE: - case SLANG_TEXTURE_2D: + case SLANG_TEXTURE_CUBE: + case SLANG_TEXTURE_2D: { outDims[count++] = width; outDims[count++] = height; break; } - case SLANG_TEXTURE_3D: + case SLANG_TEXTURE_3D: { outDims[count++] = width; outDims[count++] = height; @@ -345,97 +386,146 @@ struct TextureDimensions uint32_t shape; uint32_t width, height, depth; uint32_t numberOfLevels; - uint32_t arrayElementCount; ///< For array types, 0 otherwise + uint32_t arrayElementCount; ///< For array types, 0 otherwise }; - - - // Texture struct ITexture { virtual TextureDimensions GetDimensions(int mipLevel = -1) = 0; virtual void Load(const int32_t* v, void* outData, size_t dataSize) = 0; - virtual void Sample(SamplerState samplerState, const float* loc, void* outData, size_t dataSize) = 0; - virtual void SampleLevel(SamplerState samplerState, const float* loc, float level, void* outData, size_t dataSize) = 0; + virtual void Sample( + SamplerState samplerState, + const float* loc, + void* outData, + size_t dataSize) = 0; + virtual void SampleLevel( + SamplerState samplerState, + const float* loc, + float level, + void* outData, + size_t dataSize) = 0; }; -template +template struct Texture1D { void GetDimensions(uint32_t* outWidth) { *outWidth = texture->GetDimensions().width; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outNumberOfLevels) - { - auto dims = texture->GetDimensions(mipLevel); - *outWidth = dims.width; - *outNumberOfLevels = dims.numberOfLevels; + void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; + *outNumberOfLevels = dims.numberOfLevels; } - + void GetDimensions(float* outWidth) { *outWidth = texture->GetDimensions().width; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outNumberOfLevels) - { - auto dims = texture->GetDimensions(mipLevel); - *outWidth = dims.width; - *outNumberOfLevels = dims.numberOfLevels; + void GetDimensions(uint32_t mipLevel, float* outWidth, float* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; + *outNumberOfLevels = dims.numberOfLevels; + } + + T Load(const int2& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; } - - T Load(const int2& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } - T Sample(SamplerState samplerState, float loc) const { T out; texture->Sample(samplerState, &loc, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, float loc, float level) { T out; texture->SampleLevel(samplerState, &loc, level, &out, sizeof(out)); return out; } - - ITexture* texture; + T Sample(SamplerState samplerState, float loc) const + { + T out; + texture->Sample(samplerState, &loc, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, float loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; -template +template struct Texture2D { - void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - void GetDimensions(float* outWidth, float* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(float* outWidth, float* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int3& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } - T Sample(SamplerState samplerState, const float2& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float2& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + T Load(const int3& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } + T Sample(SamplerState samplerState, const float2& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float2& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; -template +template struct Texture3D { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outDepth) { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; *outDepth = dims.depth; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outDepth, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outDepth, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -445,12 +535,17 @@ struct Texture3D } void GetDimensions(float* outWidth, float* outHeight, float* outDepth) { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; *outDepth = dims.depth; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outDepth, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outDepth, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -458,78 +553,144 @@ struct Texture3D *outDepth = dims.depth; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int4& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } - T Sample(SamplerState samplerState, const float3& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float3& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + T Load(const int4& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } + T Sample(SamplerState samplerState, const float3& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float3& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; -template +template struct TextureCube { - void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - void GetDimensions(float* outWidth, float* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(float* outWidth, float* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - - T Sample(SamplerState samplerState, const float3& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float3& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + T Sample(SamplerState samplerState, const float3& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float3& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; -template +template struct Texture1DArray { - void GetDimensions(uint32_t* outWidth, uint32_t* outElements) { auto dims = texture->GetDimensions(); *outWidth = dims.width; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions(uint32_t* outWidth, uint32_t* outElements) { - auto dims = texture->GetDimensions(mipLevel); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outElements = dims.arrayElementCount; + } + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outElements, + uint32_t* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; *outNumberOfLevels = dims.numberOfLevels; - *outElements = dims.arrayElementCount; - } - void GetDimensions(float* outWidth, float* outElements) { auto dims = texture->GetDimensions(); *outWidth = dims.width; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outElements, float* outNumberOfLevels) + *outElements = dims.arrayElementCount; + } + void GetDimensions(float* outWidth, float* outElements) { - auto dims = texture->GetDimensions(mipLevel); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outElements = dims.arrayElementCount; + } + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outElements, + float* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; *outNumberOfLevels = dims.numberOfLevels; - *outElements = dims.arrayElementCount; + *outElements = dims.arrayElementCount; + } + + T Load(const int3& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } + T Sample(SamplerState samplerState, const float2& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float2& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; } - - T Load(const int3& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } - T Sample(SamplerState samplerState, const float2& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float2& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + ITexture* texture; }; -template +template struct Texture2DArray { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements) @@ -539,7 +700,12 @@ struct Texture2DArray *outHeight = dims.height; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outElements, + uint32_t* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -547,7 +713,7 @@ struct Texture2DArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - + void GetDimensions(uint32_t* outWidth, float* outHeight, float* outElements) { auto dims = texture->GetDimensions(); @@ -555,7 +721,12 @@ struct Texture2DArray *outHeight = dims.height; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outElements, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outElements, + float* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -563,15 +734,30 @@ struct Texture2DArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int4& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } - T Sample(SamplerState samplerState, const float3& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float3& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + T Load(const int4& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } + T Sample(SamplerState samplerState, const float3& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float3& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; -template +template struct TextureCubeArray { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements) @@ -581,7 +767,12 @@ struct TextureCubeArray *outHeight = dims.height; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outElements, + uint32_t* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -589,7 +780,7 @@ struct TextureCubeArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - + void GetDimensions(uint32_t* outWidth, float* outHeight, float* outElements) { auto dims = texture->GetDimensions(); @@ -597,7 +788,12 @@ struct TextureCubeArray *outHeight = dims.height; *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outElements, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outElements, + float* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -605,81 +801,124 @@ struct TextureCubeArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - - T Sample(SamplerState samplerState, const float4& loc) const { T out; texture->Sample(samplerState, &loc.x, &out, sizeof(out)); return out; } - T SampleLevel(SamplerState samplerState, const float4& loc, float level) { T out; texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); return out; } - - ITexture* texture; + + T Sample(SamplerState samplerState, const float4& loc) const + { + T out; + texture->Sample(samplerState, &loc.x, &out, sizeof(out)); + return out; + } + T SampleLevel(SamplerState samplerState, const float4& loc, float level) + { + T out; + texture->SampleLevel(samplerState, &loc.x, level, &out, sizeof(out)); + return out; + } + + ITexture* texture; }; /* !!!!!!!!!!!!!!!!!!!!!!!!!!! RWTexture !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ struct IRWTexture : ITexture { - /// Get the reference to the element at loc. + /// Get the reference to the element at loc. virtual void* refAt(const uint32_t* loc) = 0; }; -template +template struct RWTexture1D { void GetDimensions(uint32_t* outWidth) { *outWidth = texture->GetDimensions().width; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outNumberOfLevels = dims.numberOfLevels; } - + void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; + *outNumberOfLevels = dims.numberOfLevels; + } + void GetDimensions(float* outWidth) { *outWidth = texture->GetDimensions().width; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outNumberOfLevels) { auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(int32_t loc) const { T out; texture->Load(&loc, &out, sizeof(out)); return out; } + void GetDimensions(uint32_t mipLevel, float* outWidth, float* outNumberOfLevels) + { + auto dims = texture->GetDimensions(mipLevel); + *outWidth = dims.width; + *outNumberOfLevels = dims.numberOfLevels; + } + + T Load(int32_t loc) const + { + T out; + texture->Load(&loc, &out, sizeof(out)); + return out; + } T& operator[](uint32_t loc) { return *(T*)texture->refAt(&loc); } - IRWTexture* texture; + IRWTexture* texture; }; -template +template struct RWTexture2D { - void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - void GetDimensions(float* outWidth, float* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(float* outWidth, float* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int2& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } + + T Load(const int2& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } T& operator[](const uint2& loc) { return *(T*)texture->refAt(&loc.x); } IRWTexture* texture; }; -template +template struct RWTexture3D { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outDepth) { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; *outDepth = dims.depth; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outDepth, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outDepth, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -689,12 +928,17 @@ struct RWTexture3D } void GetDimensions(float* outWidth, float* outHeight, float* outDepth) { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; *outDepth = dims.depth; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outDepth, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outDepth, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -702,60 +946,83 @@ struct RWTexture3D *outDepth = dims.depth; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int3& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } + + T Load(const int3& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } T& operator[](const uint3& loc) { return *(T*)texture->refAt(&loc.x); } IRWTexture* texture; }; -template +template struct RWTexture1DArray { - void GetDimensions(uint32_t* outWidth, uint32_t* outElements) - { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outElements = dims.arrayElementCount; + void GetDimensions(uint32_t* outWidth, uint32_t* outElements) + { + auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outElements, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - void GetDimensions(float* outWidth, float* outElements) - { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outElements = dims.arrayElementCount; + void GetDimensions(float* outWidth, float* outElements) + { + auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outElements, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outElements, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(int2 loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } + + T Load(int2 loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } T& operator[](uint2 loc) { return *(T*)texture->refAt(&loc.x); } IRWTexture* texture; }; -template +template struct RWTexture2DArray { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements) { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; *outHeight = dims.height; - *outElements = dims.arrayElementCount; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outElements, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -765,12 +1032,17 @@ struct RWTexture2DArray } void GetDimensions(float* outWidth, float* outHeight, float* outElements) { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; *outHeight = dims.height; - *outElements = dims.arrayElementCount; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outElements, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outElements, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -778,8 +1050,13 @@ struct RWTexture2DArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - - T Load(const int3& loc) const { T out; texture->Load(&loc.x, &out, sizeof(out)); return out; } + + T Load(const int3& loc) const + { + T out; + texture->Load(&loc.x, &out, sizeof(out)); + return out; + } T& operator[](const uint3& loc) { return *(T*)texture->refAt(&loc.x); } IRWTexture* texture; @@ -787,91 +1064,167 @@ struct RWTexture2DArray // FeedbackTexture -struct FeedbackType {}; -struct SAMPLER_FEEDBACK_MIN_MIP : FeedbackType {}; -struct SAMPLER_FEEDBACK_MIP_REGION_USED : FeedbackType {}; +struct FeedbackType +{ +}; +struct SAMPLER_FEEDBACK_MIN_MIP : FeedbackType +{ +}; +struct SAMPLER_FEEDBACK_MIP_REGION_USED : FeedbackType +{ +}; struct IFeedbackTexture { virtual TextureDimensions GetDimensions(int mipLevel = -1) = 0; - // Note here we pass the optional clamp parameter as a pointer. Passing nullptr means no clamp. - // This was preferred over having two function definitions, and having to differentiate their names - virtual void WriteSamplerFeedback(ITexture* tex, SamplerState samp, const float* location, const float* clamp = nullptr) = 0; - virtual void WriteSamplerFeedbackBias(ITexture* tex, SamplerState samp, const float* location, float bias, const float* clamp = nullptr) = 0; - virtual void WriteSamplerFeedbackGrad(ITexture* tex, SamplerState samp, const float* location, const float* ddx, const float* ddy, const float* clamp = nullptr) = 0; - - virtual void WriteSamplerFeedbackLevel(ITexture* tex, SamplerState samp, const float* location, float lod) = 0; + // Note here we pass the optional clamp parameter as a pointer. Passing nullptr means no clamp. + // This was preferred over having two function definitions, and having to differentiate their + // names + virtual void WriteSamplerFeedback( + ITexture* tex, + SamplerState samp, + const float* location, + const float* clamp = nullptr) = 0; + virtual void WriteSamplerFeedbackBias( + ITexture* tex, + SamplerState samp, + const float* location, + float bias, + const float* clamp = nullptr) = 0; + virtual void WriteSamplerFeedbackGrad( + ITexture* tex, + SamplerState samp, + const float* location, + const float* ddx, + const float* ddy, + const float* clamp = nullptr) = 0; + + virtual void WriteSamplerFeedbackLevel( + ITexture* tex, + SamplerState samp, + const float* location, + float lod) = 0; }; -template +template struct FeedbackTexture2D { - void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(uint32_t* outWidth, uint32_t* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - void GetDimensions(float* outWidth, float* outHeight) - { - const auto dims = texture->GetDimensions(); - *outWidth = dims.width; - *outHeight = dims.height; + void GetDimensions(float* outWidth, float* outHeight) + { + const auto dims = texture->GetDimensions(); + *outWidth = dims.width; + *outHeight = dims.height; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; *outHeight = dims.height; *outNumberOfLevels = dims.numberOfLevels; } - - template - void WriteSamplerFeedback(Texture2D tex, SamplerState samp, float2 location, float clamp) { texture->WriteSamplerFeedback(tex.texture, samp, &location.x, &clamp); } - template - void WriteSamplerFeedbackBias(Texture2D tex, SamplerState samp, float2 location, float bias, float clamp) { texture->WriteSamplerFeedbackBias(tex.texture, samp, &location.x, bias, &clamp); } + template + void WriteSamplerFeedback(Texture2D tex, SamplerState samp, float2 location, float clamp) + { + texture->WriteSamplerFeedback(tex.texture, samp, &location.x, &clamp); + } - template - void WriteSamplerFeedbackGrad(Texture2D tex, SamplerState samp, float2 location, float2 ddx, float2 ddy, float clamp) { texture->WriteSamplerFeedbackGrad(tex.texture, samp, &location.x, &ddx.x, &ddy.x, &clamp); } + template + void WriteSamplerFeedbackBias( + Texture2D tex, + SamplerState samp, + float2 location, + float bias, + float clamp) + { + texture->WriteSamplerFeedbackBias(tex.texture, samp, &location.x, bias, &clamp); + } + + template + void WriteSamplerFeedbackGrad( + Texture2D tex, + SamplerState samp, + float2 location, + float2 ddx, + float2 ddy, + float clamp) + { + texture->WriteSamplerFeedbackGrad(tex.texture, samp, &location.x, &ddx.x, &ddy.x, &clamp); + } // Level - template - void WriteSamplerFeedbackLevel(Texture2D tex, SamplerState samp, float2 location, float lod) { texture->WriteSamplerFeedbackLevel(tex.texture, samp, &location.x, lod); } - + template + void WriteSamplerFeedbackLevel(Texture2D tex, SamplerState samp, float2 location, float lod) + { + texture->WriteSamplerFeedbackLevel(tex.texture, samp, &location.x, lod); + } + // Without Clamp - template - void WriteSamplerFeedback(Texture2D tex, SamplerState samp, float2 location) { texture->WriteSamplerFeedback(tex.texture, samp, &location.x); } + template + void WriteSamplerFeedback(Texture2D tex, SamplerState samp, float2 location) + { + texture->WriteSamplerFeedback(tex.texture, samp, &location.x); + } + + template + void WriteSamplerFeedbackBias(Texture2D tex, SamplerState samp, float2 location, float bias) + { + texture->WriteSamplerFeedbackBias(tex.texture, samp, &location.x, bias); + } - template - void WriteSamplerFeedbackBias(Texture2D tex, SamplerState samp, float2 location, float bias) { texture->WriteSamplerFeedbackBias(tex.texture, samp, &location.x, bias); } + template + void WriteSamplerFeedbackGrad( + Texture2D tex, + SamplerState samp, + float2 location, + float2 ddx, + float2 ddy) + { + texture->WriteSamplerFeedbackGrad(tex.texture, samp, &location.x, &ddx.x, &ddy.x); + } - template - void WriteSamplerFeedbackGrad(Texture2D tex, SamplerState samp, float2 location, float2 ddx, float2 ddy) { texture->WriteSamplerFeedbackGrad(tex.texture, samp, &location.x, &ddx.x, &ddy.x); } - IFeedbackTexture* texture; }; -template +template struct FeedbackTexture2DArray { void GetDimensions(uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements) { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; *outHeight = dims.height; - *outElements = dims.arrayElementCount; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outElements, uint32_t* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + uint32_t* outWidth, + uint32_t* outHeight, + uint32_t* outElements, + uint32_t* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -881,12 +1234,17 @@ struct FeedbackTexture2DArray } void GetDimensions(float* outWidth, float* outHeight, float* outElements) { - auto dims = texture->GetDimensions(); - *outWidth = dims.width; + auto dims = texture->GetDimensions(); + *outWidth = dims.width; *outHeight = dims.height; - *outElements = dims.arrayElementCount; + *outElements = dims.arrayElementCount; } - void GetDimensions(uint32_t mipLevel, float* outWidth, float* outHeight, float* outElements, float* outNumberOfLevels) + void GetDimensions( + uint32_t mipLevel, + float* outWidth, + float* outHeight, + float* outElements, + float* outNumberOfLevels) { const auto dims = texture->GetDimensions(mipLevel); *outWidth = dims.width; @@ -894,31 +1252,81 @@ struct FeedbackTexture2DArray *outElements = dims.arrayElementCount; *outNumberOfLevels = dims.numberOfLevels; } - - template - void WriteSamplerFeedback(Texture2DArray texArray, SamplerState samp, float3 location, float clamp) { texture->WriteSamplerFeedback(texArray.texture, samp, &location.x, &clamp); } - template - void WriteSamplerFeedbackBias(Texture2DArray texArray, SamplerState samp, float3 location, float bias, float clamp) { texture->WriteSamplerFeedbackBias(texArray.texture, samp, &location.x, bias, &clamp); } + template + void WriteSamplerFeedback( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float clamp) + { + texture->WriteSamplerFeedback(texArray.texture, samp, &location.x, &clamp); + } + + template + void WriteSamplerFeedbackBias( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float bias, + float clamp) + { + texture->WriteSamplerFeedbackBias(texArray.texture, samp, &location.x, bias, &clamp); + } - template - void WriteSamplerFeedbackGrad(Texture2DArray texArray, SamplerState samp, float3 location, float3 ddx, float3 ddy, float clamp) { texture->WriteSamplerFeedbackGrad(texArray.texture, samp, &location.x, &ddx.x, &ddy.x, &clamp); } + template + void WriteSamplerFeedbackGrad( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float3 ddx, + float3 ddy, + float clamp) + { + texture + ->WriteSamplerFeedbackGrad(texArray.texture, samp, &location.x, &ddx.x, &ddy.x, &clamp); + } // Level - template - void WriteSamplerFeedbackLevel(Texture2DArray texArray, SamplerState samp, float3 location, float lod) { texture->WriteSamplerFeedbackLevel(texArray.texture, samp, &location.x, lod); } + template + void WriteSamplerFeedbackLevel( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float lod) + { + texture->WriteSamplerFeedbackLevel(texArray.texture, samp, &location.x, lod); + } // Without Clamp - template - void WriteSamplerFeedback(Texture2DArray texArray, SamplerState samp, float3 location) { texture->WriteSamplerFeedback(texArray.texture, samp, &location.x); } + template + void WriteSamplerFeedback(Texture2DArray texArray, SamplerState samp, float3 location) + { + texture->WriteSamplerFeedback(texArray.texture, samp, &location.x); + } - template - void WriteSamplerFeedbackBias(Texture2DArray texArray, SamplerState samp, float3 location, float bias) { texture->WriteSamplerFeedbackBias(texArray.texture, samp, &location.x, bias); } + template + void WriteSamplerFeedbackBias( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float bias) + { + texture->WriteSamplerFeedbackBias(texArray.texture, samp, &location.x, bias); + } + + template + void WriteSamplerFeedbackGrad( + Texture2DArray texArray, + SamplerState samp, + float3 location, + float3 ddx, + float3 ddy) + { + texture->WriteSamplerFeedbackGrad(texArray.texture, samp, &location.x, &ddx.x, &ddy.x); + } - template - void WriteSamplerFeedbackGrad(Texture2DArray texArray, SamplerState samp, float3 location, float3 ddx, float3 ddy) { texture->WriteSamplerFeedbackGrad(texArray.texture, samp, &location.x, &ddx.x, &ddy.x); } - IFeedbackTexture* texture; }; @@ -933,20 +1341,24 @@ struct ComputeThreadVaryingInput struct ComputeVaryingInput { - uint3 startGroupID; ///< start groupID - uint3 endGroupID; ///< Non inclusive end groupID + uint3 startGroupID; ///< start groupID + uint3 endGroupID; ///< Non inclusive end groupID }; -// The uniformEntryPointParams and uniformState must be set to structures that match layout that the kernel expects. -// This can be determined via reflection for example. +// The uniformEntryPointParams and uniformState must be set to structures that match layout that the +// kernel expects. This can be determined via reflection for example. -typedef void(*ComputeThreadFunc)(ComputeThreadVaryingInput* varyingInput, void* uniformEntryPointParams, void* uniformState); -typedef void(*ComputeFunc)(ComputeVaryingInput* varyingInput, void* uniformEntryPointParams, void* uniformState); +typedef void (*ComputeThreadFunc)( + ComputeThreadVaryingInput* varyingInput, + void* uniformEntryPointParams, + void* uniformState); +typedef void (*ComputeFunc)( + ComputeVaryingInput* varyingInput, + void* uniformEntryPointParams, + void* uniformState); #ifdef SLANG_PRELUDE_NAMESPACE } #endif #endif - - diff --git a/prelude/slang-cuda-prelude.h b/prelude/slang-cuda-prelude.h index 96ef22dd13..46c6a43949 100644 --- a/prelude/slang-cuda-prelude.h +++ b/prelude/slang-cuda-prelude.h @@ -15,51 +15,53 @@ #endif -// Define SLANG_CUDA_ENABLE_HALF to use the cuda_fp16 include to add half support. +// Define SLANG_CUDA_ENABLE_HALF to use the cuda_fp16 include to add half support. // For this to work NVRTC needs to have the path to the CUDA SDK. // -// As it stands the includes paths defined for Slang are passed down to NVRTC. Similarly defines defined for the Slang compile -// are passed down. +// As it stands the includes paths defined for Slang are passed down to NVRTC. Similarly defines +// defined for the Slang compile are passed down. #ifdef SLANG_CUDA_ENABLE_HALF -// We don't want half2 operators, because it will implement comparison operators that return a bool(!). We want to generate -// those functions. Doing so means that we will have to define all the other half2 operators. -# define __CUDA_NO_HALF2_OPERATORS__ -# include +// We don't want half2 operators, because it will implement comparison operators that return a +// bool(!). We want to generate those functions. Doing so means that we will have to define all +// the other half2 operators. +#define __CUDA_NO_HALF2_OPERATORS__ +#include #endif #ifdef SLANG_CUDA_ENABLE_OPTIX #include #endif -// Define slang offsetof implementation +// Define slang offsetof implementation #ifndef SLANG_OFFSET_OF -# define SLANG_OFFSET_OF(type, member) (size_t)((char*)&(((type *)0)->member) - (char*)0) +#define SLANG_OFFSET_OF(type, member) (size_t)((char*)&(((type*)0)->member) - (char*)0) #endif #ifndef SLANG_ALIGN_OF -# define SLANG_ALIGN_OF(type) __alignof__(type) +#define SLANG_ALIGN_OF(type) __alignof__(type) #endif // Must be large enough to cause overflow and therefore infinity #ifndef SLANG_INFINITY -# define SLANG_INFINITY ((float)(1e+300 * 1e+300)) +#define SLANG_INFINITY ((float)(1e+300 * 1e+300)) #endif // For now we'll disable any asserts in this prelude -#define SLANG_PRELUDE_ASSERT(x) +#define SLANG_PRELUDE_ASSERT(x) -#ifndef SLANG_CUDA_WARP_SIZE -# define SLANG_CUDA_WARP_SIZE 32 +#ifndef SLANG_CUDA_WARP_SIZE +#define SLANG_CUDA_WARP_SIZE 32 #endif -#define SLANG_CUDA_WARP_MASK (SLANG_CUDA_WARP_SIZE - 1) // Used for masking threadIdx.x to the warp lane index +#define SLANG_CUDA_WARP_MASK \ + (SLANG_CUDA_WARP_SIZE - 1) // Used for masking threadIdx.x to the warp lane index #define SLANG_CUDA_WARP_BITMASK (~int(0)) // #define SLANG_FORCE_INLINE inline -#define SLANG_CUDA_CALL __device__ +#define SLANG_CUDA_CALL __device__ #define SLANG_FORCE_INLINE inline #define SLANG_INLINE inline @@ -71,54 +73,63 @@ // Asserts for bounds checking. // It is assumed index/count are unsigned types. -#define SLANG_BOUND_ASSERT(index, count) SLANG_PRELUDE_ASSERT(index < count); -#define SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_PRELUDE_ASSERT(index <= (sizeInBytes - elemSize) && (index & 3) == 0); +#define SLANG_BOUND_ASSERT(index, count) SLANG_PRELUDE_ASSERT(index < count); +#define SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_PRELUDE_ASSERT(index <= (sizeInBytes - elemSize) && (index & 3) == 0); // Macros to zero index if an access is out of range -#define SLANG_BOUND_ZERO_INDEX(index, count) index = (index < count) ? index : 0; -#define SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) index = (index <= (sizeInBytes - elemSize)) ? index : 0; - -// The 'FIX' macro define how the index is fixed. The default is to do nothing. If SLANG_ENABLE_BOUND_ZERO_INDEX -// the fix macro will zero the index, if out of range -#ifdef SLANG_ENABLE_BOUND_ZERO_INDEX -# define SLANG_BOUND_FIX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) -# define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) -# define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) SLANG_BOUND_ZERO_INDEX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) +#define SLANG_BOUND_ZERO_INDEX(index, count) index = (index < count) ? index : 0; +#define SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + index = (index <= (sizeInBytes - elemSize)) ? index : 0; + +// The 'FIX' macro define how the index is fixed. The default is to do nothing. If +// SLANG_ENABLE_BOUND_ZERO_INDEX the fix macro will zero the index, if out of range +#ifdef SLANG_ENABLE_BOUND_ZERO_INDEX +#define SLANG_BOUND_FIX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) +#define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_ZERO_INDEX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) \ + SLANG_BOUND_ZERO_INDEX(index, count) SLANG_BOUND_ZERO_INDEX(index, count) #else -# define SLANG_BOUND_FIX(index, count) -# define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) -# define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) +#define SLANG_BOUND_FIX(index, count) +#define SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_FIX_FIXED_ARRAY(index, count) #endif #ifndef SLANG_BOUND_CHECK -# define SLANG_BOUND_CHECK(index, count) SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX(index, count) +#define SLANG_BOUND_CHECK(index, count) \ + SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX(index, count) #endif #ifndef SLANG_BOUND_CHECK_BYTE_ADDRESS -# define SLANG_BOUND_CHECK_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) +#define SLANG_BOUND_CHECK_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_ASSERT_BYTE_ADDRESS(index, elemSize, sizeInBytes) \ + SLANG_BOUND_FIX_BYTE_ADDRESS(index, elemSize, sizeInBytes) #endif #ifndef SLANG_BOUND_CHECK_FIXED_ARRAY -# define SLANG_BOUND_CHECK_FIXED_ARRAY(index, count) SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX_FIXED_ARRAY(index, count) +#define SLANG_BOUND_CHECK_FIXED_ARRAY(index, count) \ + SLANG_BOUND_ASSERT(index, count) SLANG_BOUND_FIX_FIXED_ARRAY(index, count) #endif - // This macro handles how out-of-range surface coordinates are handled; - // I can equal - // cudaBoundaryModeClamp, in which case out-of-range coordinates are clamped to the valid range - // cudaBoundaryModeZero, in which case out-of-range reads return zero and out-of-range writes are ignored - // cudaBoundaryModeTrap, in which case out-of-range accesses cause the kernel execution to fail. - +// This macro handles how out-of-range surface coordinates are handled; +// I can equal +// cudaBoundaryModeClamp, in which case out-of-range coordinates are clamped to the valid range +// cudaBoundaryModeZero, in which case out-of-range reads return zero and out-of-range writes are +// ignored cudaBoundaryModeTrap, in which case out-of-range accesses cause the kernel execution to +// fail. + #ifndef SLANG_CUDA_BOUNDARY_MODE -# define SLANG_CUDA_BOUNDARY_MODE cudaBoundaryModeZero +#define SLANG_CUDA_BOUNDARY_MODE cudaBoundaryModeZero // Can be one of SLANG_CUDA_PTX_BOUNDARY_MODE. Only applies *PTX* emitted CUDA operations // which currently is just RWTextureRW format writes -// +// // .trap causes an execution trap on out-of-bounds addresses // .clamp stores data at the nearest surface location (sized appropriately) -// .zero drops stores to out-of-bounds addresses +// .zero drops stores to out-of-bounds addresses -# define SLANG_PTX_BOUNDARY_MODE "zero" +#define SLANG_PTX_BOUNDARY_MODE "zero" #endif struct TypeInfo @@ -126,51 +137,67 @@ struct TypeInfo size_t typeSize; }; -template +template struct FixedArray { - SLANG_CUDA_CALL const T& operator[](size_t index) const { SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); return m_data[index]; } - SLANG_CUDA_CALL T& operator[](size_t index) { SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); return m_data[index]; } - + SLANG_CUDA_CALL const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); + return m_data[index]; + } + SLANG_CUDA_CALL T& operator[](size_t index) + { + SLANG_BOUND_CHECK_FIXED_ARRAY(index, SIZE); + return m_data[index]; + } + T m_data[SIZE]; }; -// An array that has no specified size, becomes a 'Array'. This stores the size so it can potentially -// do bounds checking. -template +// An array that has no specified size, becomes a 'Array'. This stores the size so it can +// potentially do bounds checking. +template struct Array { - SLANG_CUDA_CALL const T& operator[](size_t index) const { SLANG_BOUND_CHECK(index, count); return data[index]; } - SLANG_CUDA_CALL T& operator[](size_t index) { SLANG_BOUND_CHECK(index, count); return data[index]; } - + SLANG_CUDA_CALL const T& operator[](size_t index) const + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + SLANG_CUDA_CALL T& operator[](size_t index) + { + SLANG_BOUND_CHECK(index, count); + return data[index]; + } + T* data; size_t count; }; // Typically defined in cuda.h, but we can't ship/rely on that, so just define here -typedef unsigned long long CUtexObject; -typedef unsigned long long CUsurfObject; +typedef unsigned long long CUtexObject; +typedef unsigned long long CUsurfObject; -// On CUDA sampler state is actually bound up with the texture object. We have a SamplerState type, -// backed as a pointer, to simplify code generation, with the downside that such a binding will take up -// uniform space, even though it will have no effect. +// On CUDA sampler state is actually bound up with the texture object. We have a SamplerState type, +// backed as a pointer, to simplify code generation, with the downside that such a binding will take +// up uniform space, even though it will have no effect. // TODO(JS): Consider ways to strip use of variables of this type so have no binding, struct SamplerStateUnused; typedef SamplerStateUnused* SamplerState; // TODO(JS): Not clear yet if this can be handled on CUDA, by just ignoring. -// For now, just map to the index type. +// For now, just map to the index type. typedef size_t NonUniformResourceIndex; // Code generator will generate the specific type -template +template struct Matrix; typedef int1 bool1; typedef int2 bool2; typedef int3 bool3; -typedef int4 bool4; +typedef int4 bool4; #if SLANG_CUDA_RTC @@ -193,7 +220,7 @@ typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; -union Union32 +union Union32 { uint32_t u; int32_t i; @@ -225,16 +252,37 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL double _slang_fmod(double x, double y) #if SLANG_CUDA_ENABLE_HALF // Add the other vector half types -struct __half1 { __half x; }; -struct __align__(4) __half3 { __half x, y, z; }; -struct __align__(4) __half4 { __half x, y, z, w; }; +struct __half1 +{ + __half x; +}; +struct __align__(4) __half3 +{ + __half x, y, z; +}; +struct __align__(4) __half4 +{ + __half x, y, z, w; +}; #endif -#define SLANG_VECTOR_GET_ELEMENT(T) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##1 x, int index) { return ((T*)(&x))[index]; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##2 x, int index) { return ((T*)(&x))[index]; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##3 x, int index) { return ((T*)(&x))[index]; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##4 x, int index) { return ((T*)(&x))[index]; } +#define SLANG_VECTOR_GET_ELEMENT(T) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##1 x, int index) \ + { \ + return ((T*)(&x))[index]; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##2 x, int index) \ + { \ + return ((T*)(&x))[index]; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##3 x, int index) \ + { \ + return ((T*)(&x))[index]; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_vector_get_element(T##4 x, int index) \ + { \ + return ((T*)(&x))[index]; \ + } SLANG_VECTOR_GET_ELEMENT(int) SLANG_VECTOR_GET_ELEMENT(uint) SLANG_VECTOR_GET_ELEMENT(short) @@ -246,11 +294,23 @@ SLANG_VECTOR_GET_ELEMENT(ulonglong) SLANG_VECTOR_GET_ELEMENT(float) SLANG_VECTOR_GET_ELEMENT(double) -#define SLANG_VECTOR_GET_ELEMENT_PTR(T) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##1* x, int index) { return ((T*)(x)) + index; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##2* x, int index) { return ((T*)(x)) + index; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##3* x, int index) { return ((T*)(x)) + index; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##4* x, int index) { return ((T*)(x)) + index; } +#define SLANG_VECTOR_GET_ELEMENT_PTR(T) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##1 * x, int index) \ + { \ + return ((T*)(x)) + index; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##2 * x, int index) \ + { \ + return ((T*)(x)) + index; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##3 * x, int index) \ + { \ + return ((T*)(x)) + index; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T* _slang_vector_get_element_ptr(T##4 * x, int index) \ + { \ + return ((T*)(x)) + index; \ + } SLANG_VECTOR_GET_ELEMENT_PTR(int) SLANG_VECTOR_GET_ELEMENT_PTR(uint) SLANG_VECTOR_GET_ELEMENT_PTR(short) @@ -267,57 +327,60 @@ SLANG_VECTOR_GET_ELEMENT(__half) SLANG_VECTOR_GET_ELEMENT_PTR(__half) #endif -#define SLANG_CUDA_VECTOR_BINARY_OP(T, n, op) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator op(T##n thisVal, T##n other) \ - { \ - T##n result;\ - for (int i = 0; i < n; i++) \ - *_slang_vector_get_element_ptr(&result, i) = _slang_vector_get_element(thisVal,i) op _slang_vector_get_element(other,i); \ - return result;\ +#define SLANG_CUDA_VECTOR_BINARY_OP(T, n, op) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator op(T##n thisVal, T##n other) \ + { \ + T##n result; \ + for (int i = 0; i < n; i++) \ + *_slang_vector_get_element_ptr(&result, i) = \ + _slang_vector_get_element(thisVal, i) op _slang_vector_get_element(other, i); \ + return result; \ } -#define SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, op) \ +#define SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, op) \ SLANG_FORCE_INLINE SLANG_CUDA_CALL bool##n operator op(T##n thisVal, T##n other) \ - { \ - bool##n result;\ - for (int i = 0; i < n; i++) \ - *_slang_vector_get_element_ptr(&result, i) = (int)(_slang_vector_get_element(thisVal,i) op _slang_vector_get_element(other,i)); \ - return result;\ - } -#define SLANG_CUDA_VECTOR_UNARY_OP(T, n, op) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator op(T##n thisVal) \ - { \ - T##n result;\ - for (int i = 0; i < n; i++) \ - *_slang_vector_get_element_ptr(&result, i) = op _slang_vector_get_element(thisVal,i); \ - return result;\ - } - -#define SLANG_CUDA_VECTOR_INT_OP(T, n) \ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, +)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, -)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, *)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, /)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, %)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, ^)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, &)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, |)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, &&)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, ||)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, >>)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, <<)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >=)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <=)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, ==)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, !=)\ - SLANG_CUDA_VECTOR_UNARY_OP(T, n, !)\ - SLANG_CUDA_VECTOR_UNARY_OP(T, n, -)\ + { \ + bool##n result; \ + for (int i = 0; i < n; i++) \ + *_slang_vector_get_element_ptr(&result, i) = \ + (int)(_slang_vector_get_element(thisVal, i) \ + op _slang_vector_get_element(other, i)); \ + return result; \ + } +#define SLANG_CUDA_VECTOR_UNARY_OP(T, n, op) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator op(T##n thisVal) \ + { \ + T##n result; \ + for (int i = 0; i < n; i++) \ + *_slang_vector_get_element_ptr(&result, i) = op _slang_vector_get_element(thisVal, i); \ + return result; \ + } + +#define SLANG_CUDA_VECTOR_INT_OP(T, n) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, +) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, -) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, *) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, /) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, %) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, ^) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, &) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, |) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, &&) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, ||) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, >>) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, <<) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >=) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <=) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, ==) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, !=) \ + SLANG_CUDA_VECTOR_UNARY_OP(T, n, !) \ + SLANG_CUDA_VECTOR_UNARY_OP(T, n, -) \ SLANG_CUDA_VECTOR_UNARY_OP(T, n, ~) #define SLANG_CUDA_VECTOR_INT_OPS(T) \ - SLANG_CUDA_VECTOR_INT_OP(T, 2) \ - SLANG_CUDA_VECTOR_INT_OP(T, 3) \ + SLANG_CUDA_VECTOR_INT_OP(T, 2) \ + SLANG_CUDA_VECTOR_INT_OP(T, 3) \ SLANG_CUDA_VECTOR_INT_OP(T, 4) SLANG_CUDA_VECTOR_INT_OPS(int) @@ -329,23 +392,23 @@ SLANG_CUDA_VECTOR_INT_OPS(uchar) SLANG_CUDA_VECTOR_INT_OPS(longlong) SLANG_CUDA_VECTOR_INT_OPS(ulonglong) -#define SLANG_CUDA_VECTOR_FLOAT_OP(T, n) \ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, +)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, -)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, *)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, /)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, &&)\ - SLANG_CUDA_VECTOR_BINARY_OP(T, n, ||)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >=)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <=)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, ==)\ - SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, !=)\ +#define SLANG_CUDA_VECTOR_FLOAT_OP(T, n) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, +) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, -) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, *) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, /) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, &&) \ + SLANG_CUDA_VECTOR_BINARY_OP(T, n, ||) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, >=) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, <=) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, ==) \ + SLANG_CUDA_VECTOR_BINARY_COMPARE_OP(T, n, !=) \ SLANG_CUDA_VECTOR_UNARY_OP(T, n, -) #define SLANG_CUDA_VECTOR_FLOAT_OPS(T) \ - SLANG_CUDA_VECTOR_FLOAT_OP(T, 2) \ - SLANG_CUDA_VECTOR_FLOAT_OP(T, 3) \ + SLANG_CUDA_VECTOR_FLOAT_OP(T, 2) \ + SLANG_CUDA_VECTOR_FLOAT_OP(T, 3) \ SLANG_CUDA_VECTOR_FLOAT_OP(T, 4) SLANG_CUDA_VECTOR_FLOAT_OPS(float) @@ -353,27 +416,38 @@ SLANG_CUDA_VECTOR_FLOAT_OPS(double) #if SLANG_CUDA_ENABLE_HALF SLANG_CUDA_VECTOR_FLOAT_OPS(__half) #endif -#define SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, n)\ +#define SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, n) \ SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n operator%(const T##n& left, const T##n& right) \ - {\ - T##n result;\ - for (int i = 0; i < n; i++) \ - *_slang_vector_get_element_ptr(&result, i) = _slang_fmod(_slang_vector_get_element(left,i), _slang_vector_get_element(right,i)); \ - return result;\ - } -#define SLANG_CUDA_FLOAT_VECTOR_MOD(T) \ - SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, 2)\ - SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, 3)\ + { \ + T##n result; \ + for (int i = 0; i < n; i++) \ + *_slang_vector_get_element_ptr(&result, i) = _slang_fmod( \ + _slang_vector_get_element(left, i), \ + _slang_vector_get_element(right, i)); \ + return result; \ + } +#define SLANG_CUDA_FLOAT_VECTOR_MOD(T) \ + SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, 2) \ + SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, 3) \ SLANG_CUDA_FLOAT_VECTOR_MOD_IMPL(T, 4) SLANG_CUDA_FLOAT_VECTOR_MOD(float) SLANG_CUDA_FLOAT_VECTOR_MOD(double) #if SLANG_CUDA_RTC || SLANG_CUDA_ENABLE_HALF -#define SLANG_MAKE_VECTOR(T) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x, T y) { return T##2{x, y}; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x, T y, T z) { return T##3{ x, y, z }; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x, T y, T z, T w) { return T##4{ x, y, z, w }; } +#define SLANG_MAKE_VECTOR(T) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x, T y) \ + { \ + return T##2 {x, y}; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x, T y, T z) \ + { \ + return T##3 {x, y, z}; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x, T y, T z, T w) \ + { \ + return T##4 {x, y, z, w}; \ + } #endif #if SLANG_CUDA_RTC @@ -393,25 +467,67 @@ SLANG_MAKE_VECTOR(ulonglong) SLANG_MAKE_VECTOR(__half) #endif -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool1 make_bool1(bool x) { return bool1{ x }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2(bool x, bool y) { return bool2{ x, y }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3(bool x, bool y, bool z) { return bool3{ x, y, z }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4(bool x, bool y, bool z, bool w) { return bool4{ x, y, z, w }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2(bool x) { return bool2{ x, x }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3(bool x) { return bool3{ x, x, x }; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4(bool x) { return bool4{ x, x, x, x }; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool1 make_bool1(bool x) +{ + return bool1{x}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2(bool x, bool y) +{ + return bool2{x, y}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3(bool x, bool y, bool z) +{ + return bool3{x, y, z}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4(bool x, bool y, bool z, bool w) +{ + return bool4{x, y, z, w}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool2 make_bool2(bool x) +{ + return bool2{x, x}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool3 make_bool3(bool x) +{ + return bool3{x, x, x}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool4 make_bool4(bool x) +{ + return bool4{x, x, x, x}; +} #if SLANG_CUDA_RTC -#define SLANG_MAKE_VECTOR_FROM_SCALAR(T) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##1 make_##T##1(T x) { return T##1{x}; }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) { return make_##T##2(x, x); }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) { return make_##T##3(x, x, x); }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) { return make_##T##4(x, x, x, x); } +#define SLANG_MAKE_VECTOR_FROM_SCALAR(T) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##1 make_##T##1(T x) \ + { \ + return T##1 {x}; \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) \ + { \ + return make_##T##2(x, x); \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) \ + { \ + return make_##T##3(x, x, x); \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) \ + { \ + return make_##T##4(x, x, x, x); \ + } #else -#define SLANG_MAKE_VECTOR_FROM_SCALAR(T) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) { return make_##T##2(x, x); }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) { return make_##T##3(x, x, x); }\ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) { return make_##T##4(x, x, x, x); } +#define SLANG_MAKE_VECTOR_FROM_SCALAR(T) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##2 make_##T##2(T x) \ + { \ + return make_##T##2(x, x); \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##3 make_##T##3(T x) \ + { \ + return make_##T##3(x, x, x); \ + } \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##4 make_##T##4(T x) \ + { \ + return make_##T##4(x, x, x, x); \ + } #endif SLANG_MAKE_VECTOR_FROM_SCALAR(int) SLANG_MAKE_VECTOR_FROM_SCALAR(uint) @@ -426,18 +542,22 @@ SLANG_MAKE_VECTOR_FROM_SCALAR(double) #if SLANG_CUDA_ENABLE_HALF SLANG_MAKE_VECTOR_FROM_SCALAR(__half) #if !SLANG_CUDA_RTC -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half1 make___half1(__half x) { return __half1{x}; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL __half1 make___half1(__half x) +{ + return __half1{x}; +} #endif #endif -#define SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL(Fn,T,N) \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL T##N Fn(T##N* address, T##N val) \ - {\ - T##N result; \ - for (int i = 0; i < N; i++) \ - *_slang_vector_get_element_ptr(&result, i) = Fn(_slang_vector_get_element_ptr(address, i), _slang_vector_get_element(val, i)); \ - return result; \ - }\ +#define SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL(Fn, T, N) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T##N Fn(T##N* address, T##N val) \ + { \ + T##N result; \ + for (int i = 0; i < N; i++) \ + *_slang_vector_get_element_ptr(&result, i) = \ + Fn(_slang_vector_get_element_ptr(address, i), _slang_vector_get_element(val, i)); \ + return result; \ + } #if defined(__CUDA_ARCH__) && __CUDA_ARCH__ < 900 SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL(atomicAdd, float, 2) @@ -455,19 +575,24 @@ SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL(atomicAdd, ulonglong, 3) SLANG_CUDA_VECTOR_ATOMIC_BINARY_IMPL(atomicAdd, ulonglong, 4) template -struct GetVectorTypeImpl {}; - -#define GET_VECTOR_TYPE_IMPL(T, n)\ -template<>\ -struct GetVectorTypeImpl\ -{\ - typedef T##n type;\ - static SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n fromScalar(T v) { return make_##T##n(v); } \ +struct GetVectorTypeImpl +{ }; -#define GET_VECTOR_TYPE_IMPL_N(T)\ - GET_VECTOR_TYPE_IMPL(T, 1)\ - GET_VECTOR_TYPE_IMPL(T, 2)\ - GET_VECTOR_TYPE_IMPL(T, 3)\ + +#define GET_VECTOR_TYPE_IMPL(T, n) \ + template<> \ + struct GetVectorTypeImpl \ + { \ + typedef T##n type; \ + static SLANG_FORCE_INLINE SLANG_CUDA_CALL T##n fromScalar(T v) \ + { \ + return make_##T##n(v); \ + } \ + }; +#define GET_VECTOR_TYPE_IMPL_N(T) \ + GET_VECTOR_TYPE_IMPL(T, 1) \ + GET_VECTOR_TYPE_IMPL(T, 2) \ + GET_VECTOR_TYPE_IMPL(T, 3) \ GET_VECTOR_TYPE_IMPL(T, 4) GET_VECTOR_TYPE_IMPL_N(int) @@ -500,11 +625,14 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector _slang_vector_reshape(const Vect return result; } -template +template struct Matrix { Vector rows[ROWS]; - SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector& operator[](size_t index) { return rows[index]; } + SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector& operator[](size_t index) + { + return rows[index]; + } }; @@ -515,7 +643,6 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T scalar) for (int i = 0; i < ROWS; i++) result.rows[i] = GetVectorTypeImpl::fromScalar(scalar); return result; - } template @@ -527,7 +654,9 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector& row0, const Vector& row1) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + const Vector& row0, + const Vector& row1) { Matrix result; result.rows[0] = row0; @@ -536,7 +665,10 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector& row0, const Vector& row1, const Vector& row2) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + const Vector& row0, + const Vector& row1, + const Vector& row2) { Matrix result; result.rows[0] = row0; @@ -546,7 +678,11 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector& row0, const Vector& row1, const Vector& row2, const Vector& row3) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + const Vector& row0, + const Vector& row1, + const Vector& row2, + const Vector& row3) { Matrix result; result.rows[0] = row0; @@ -557,16 +693,20 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Vector } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(const Matrix& other) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + const Matrix& other) { Matrix result; int minRow = ROWS; int minCol = COLS; - if (minRow > otherRow) minRow = otherRow; - if (minCol > otherCol) minCol = otherCol; + if (minRow > otherRow) + minRow = otherRow; + if (minCol > otherCol) + minCol = otherCol; for (int i = 0; i < minRow; i++) for (int j = 0; j < minCol; j++) - *_slang_vector_get_element_ptr(result.rows + i, j) = (T)_slang_vector_get_element(other.rows[i], j); + *_slang_vector_get_element_ptr(result.rows + i, j) = + (T)_slang_vector_get_element(other.rows[i], j); return result; } @@ -574,129 +714,238 @@ template SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3) { Matrix rs; - rs.rows[0].x = v0; rs.rows[0].y = v1; - rs.rows[1].x = v2; rs.rows[1].y = v3; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[1].x = v2; + rs.rows[1].y = v3; return rs; } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3, T v4, T v5) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5) { Matrix rs; if (COLS == 3) { - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; - rs.rows[1].x = v3; rs.rows[1].y = v4; rs.rows[1].z = v5; + *_slang_vector_get_element_ptr(&rs.rows[0], 0) = v0; + *_slang_vector_get_element_ptr(&rs.rows[0], 1) = v1; + *_slang_vector_get_element_ptr(&rs.rows[0], 2) = v2; + *_slang_vector_get_element_ptr(&rs.rows[1], 0) = v3; + *_slang_vector_get_element_ptr(&rs.rows[1], 1) = v4; + *_slang_vector_get_element_ptr(&rs.rows[1], 2) = v5; } else { - rs.rows[0].x = v0; rs.rows[0].y = v1; - rs.rows[1].x = v2; rs.rows[1].y = v3; - rs.rows[2].x = v4; rs.rows[2].y = v5; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[1].x = v2; + rs.rows[1].y = v3; + rs.rows[2].x = v4; + rs.rows[2].y = v5; } return rs; - } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5, + T v6, + T v7) { Matrix rs; if (COLS == 4) { - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; rs.rows[0].w = v3; - rs.rows[1].x = v4; rs.rows[1].y = v5; rs.rows[1].z = v6; rs.rows[1].w = v7; + *_slang_vector_get_element_ptr(&rs.rows[0], 0) = v0; + *_slang_vector_get_element_ptr(&rs.rows[0], 1) = v1; + *_slang_vector_get_element_ptr(&rs.rows[0], 2) = v2; + *_slang_vector_get_element_ptr(&rs.rows[0], 3) = v3; + *_slang_vector_get_element_ptr(&rs.rows[1], 0) = v4; + *_slang_vector_get_element_ptr(&rs.rows[1], 1) = v5; + *_slang_vector_get_element_ptr(&rs.rows[1], 2) = v6; + *_slang_vector_get_element_ptr(&rs.rows[1], 3) = v7; } else { - rs.rows[0].x = v0; rs.rows[0].y = v1; - rs.rows[1].x = v2; rs.rows[1].y = v3; - rs.rows[2].x = v4; rs.rows[2].y = v5; - rs.rows[3].x = v6; rs.rows[3].y = v7; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[1].x = v2; + rs.rows[1].y = v3; + rs.rows[2].x = v4; + rs.rows[2].y = v5; + rs.rows[3].x = v6; + rs.rows[3].y = v7; } return rs; } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5, + T v6, + T v7, + T v8) { Matrix rs; - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; - rs.rows[1].x = v3; rs.rows[1].y = v4; rs.rows[1].z = v5; - rs.rows[2].x = v6; rs.rows[2].y = v7; rs.rows[2].z = v8; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[0].z = v2; + rs.rows[1].x = v3; + rs.rows[1].y = v4; + rs.rows[1].z = v5; + rs.rows[2].x = v6; + rs.rows[2].y = v7; + rs.rows[2].z = v8; return rs; } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5, + T v6, + T v7, + T v8, + T v9, + T v10, + T v11) { Matrix rs; if (COLS == 4) { - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; rs.rows[0].w = v3; - rs.rows[1].x = v4; rs.rows[1].y = v5; rs.rows[1].z = v6; rs.rows[1].w = v7; - rs.rows[2].x = v8; rs.rows[2].y = v9; rs.rows[2].z = v10; rs.rows[2].w = v11; + *_slang_vector_get_element_ptr(&rs.rows[0], 0) = v0; + *_slang_vector_get_element_ptr(&rs.rows[0], 1) = v1; + *_slang_vector_get_element_ptr(&rs.rows[0], 2) = v2; + *_slang_vector_get_element_ptr(&rs.rows[0], 3) = v3; + *_slang_vector_get_element_ptr(&rs.rows[1], 0) = v4; + *_slang_vector_get_element_ptr(&rs.rows[1], 1) = v5; + *_slang_vector_get_element_ptr(&rs.rows[1], 2) = v6; + *_slang_vector_get_element_ptr(&rs.rows[1], 3) = v7; + *_slang_vector_get_element_ptr(&rs.rows[2], 0) = v8; + *_slang_vector_get_element_ptr(&rs.rows[2], 1) = v9; + *_slang_vector_get_element_ptr(&rs.rows[2], 2) = v10; + *_slang_vector_get_element_ptr(&rs.rows[2], 3) = v11; } else { - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; - rs.rows[1].x = v3; rs.rows[1].y = v4; rs.rows[1].z = v5; - rs.rows[2].x = v6; rs.rows[2].y = v7; rs.rows[2].z = v8; - rs.rows[3].x = v9; rs.rows[3].y = v10; rs.rows[3].z = v11; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[0].z = v2; + rs.rows[1].x = v3; + rs.rows[1].y = v4; + rs.rows[1].z = v5; + rs.rows[2].x = v6; + rs.rows[2].y = v7; + rs.rows[2].z = v8; + rs.rows[3].x = v9; + rs.rows[3].y = v10; + rs.rows[3].z = v11; } return rs; } template -SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix(T v0, T v1, T v2, T v3, T v4, T v5, T v6, T v7, T v8, T v9, T v10, T v11, T v12, T v13, T v14, T v15) +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix makeMatrix( + T v0, + T v1, + T v2, + T v3, + T v4, + T v5, + T v6, + T v7, + T v8, + T v9, + T v10, + T v11, + T v12, + T v13, + T v14, + T v15) { Matrix rs; - rs.rows[0].x = v0; rs.rows[0].y = v1; rs.rows[0].z = v2; rs.rows[0].w = v3; - rs.rows[1].x = v4; rs.rows[1].y = v5; rs.rows[1].z = v6; rs.rows[1].w = v7; - rs.rows[2].x = v8; rs.rows[2].y = v9; rs.rows[2].z = v10; rs.rows[2].w = v11; - rs.rows[3].x = v12; rs.rows[3].y = v13; rs.rows[3].z = v14; rs.rows[3].w = v15; + rs.rows[0].x = v0; + rs.rows[0].y = v1; + rs.rows[0].z = v2; + rs.rows[0].w = v3; + rs.rows[1].x = v4; + rs.rows[1].y = v5; + rs.rows[1].z = v6; + rs.rows[1].w = v7; + rs.rows[2].x = v8; + rs.rows[2].y = v9; + rs.rows[2].z = v10; + rs.rows[2].w = v11; + rs.rows[3].x = v12; + rs.rows[3].y = v13; + rs.rows[3].z = v14; + rs.rows[3].w = v15; return rs; } -#define SLANG_MATRIX_BINARY_OP(T, op) \ - template \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator op(const Matrix& thisVal, const Matrix& other) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - *_slang_vector_get_element_ptr(result.rows+i,j) = _slang_vector_get_element(thisVal.rows[i], j) op _slang_vector_get_element(other.rows[i], j); \ - return result;\ +#define SLANG_MATRIX_BINARY_OP(T, op) \ + template \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator op( \ + const Matrix& thisVal, \ + const Matrix& other) \ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + *_slang_vector_get_element_ptr(result.rows + i, j) = \ + _slang_vector_get_element(thisVal.rows[i], j) \ + op _slang_vector_get_element(other.rows[i], j); \ + return result; \ } -#define SLANG_MATRIX_UNARY_OP(T, op) \ - template \ +#define SLANG_MATRIX_UNARY_OP(T, op) \ + template \ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator op(const Matrix& thisVal) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - *_slang_vector_get_element_ptr(result.rows+i,j) = op _slang_vector_get_element(thisVal.rows[i], j); \ - return result;\ - } -#define SLANG_INT_MATRIX_OPS(T) \ - SLANG_MATRIX_BINARY_OP(T, +)\ - SLANG_MATRIX_BINARY_OP(T, -)\ - SLANG_MATRIX_BINARY_OP(T, *)\ - SLANG_MATRIX_BINARY_OP(T, / )\ - SLANG_MATRIX_BINARY_OP(T, &)\ - SLANG_MATRIX_BINARY_OP(T, |)\ - SLANG_MATRIX_BINARY_OP(T, &&)\ - SLANG_MATRIX_BINARY_OP(T, ||)\ - SLANG_MATRIX_BINARY_OP(T, ^)\ - SLANG_MATRIX_BINARY_OP(T, %)\ - SLANG_MATRIX_UNARY_OP(T, !)\ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + *_slang_vector_get_element_ptr(result.rows + i, j) = \ + op _slang_vector_get_element(thisVal.rows[i], j); \ + return result; \ + } +#define SLANG_INT_MATRIX_OPS(T) \ + SLANG_MATRIX_BINARY_OP(T, +) \ + SLANG_MATRIX_BINARY_OP(T, -) \ + SLANG_MATRIX_BINARY_OP(T, *) \ + SLANG_MATRIX_BINARY_OP(T, /) \ + SLANG_MATRIX_BINARY_OP(T, &) \ + SLANG_MATRIX_BINARY_OP(T, |) \ + SLANG_MATRIX_BINARY_OP(T, &&) \ + SLANG_MATRIX_BINARY_OP(T, ||) \ + SLANG_MATRIX_BINARY_OP(T, ^) \ + SLANG_MATRIX_BINARY_OP(T, %) \ + SLANG_MATRIX_UNARY_OP(T, !) \ SLANG_MATRIX_UNARY_OP(T, ~) #define SLANG_FLOAT_MATRIX_OPS(T) \ - SLANG_MATRIX_BINARY_OP(T, +)\ - SLANG_MATRIX_BINARY_OP(T, -)\ - SLANG_MATRIX_BINARY_OP(T, *)\ - SLANG_MATRIX_BINARY_OP(T, /)\ + SLANG_MATRIX_BINARY_OP(T, +) \ + SLANG_MATRIX_BINARY_OP(T, -) \ + SLANG_MATRIX_BINARY_OP(T, *) \ + SLANG_MATRIX_BINARY_OP(T, /) \ SLANG_MATRIX_UNARY_OP(T, -) SLANG_INT_MATRIX_OPS(int) SLANG_INT_MATRIX_OPS(uint) @@ -711,48 +960,57 @@ SLANG_FLOAT_MATRIX_OPS(double) #if SLANG_CUDA_ENABLE_HALF SLANG_FLOAT_MATRIX_OPS(__half) #endif -#define SLANG_MATRIX_INT_NEG_OP(T) \ - template\ +#define SLANG_MATRIX_INT_NEG_OP(T) \ + template \ SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator-(Matrix thisVal) \ - { \ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - *_slang_vector_get_element_ptr(result.rows+i,j) = 0 - _slang_vector_get_element(thisVal.rows[i], j); \ - return result;\ - } - SLANG_MATRIX_INT_NEG_OP(int) - SLANG_MATRIX_INT_NEG_OP(uint) - SLANG_MATRIX_INT_NEG_OP(short) - SLANG_MATRIX_INT_NEG_OP(ushort) - SLANG_MATRIX_INT_NEG_OP(char) - SLANG_MATRIX_INT_NEG_OP(uchar) - SLANG_MATRIX_INT_NEG_OP(longlong) - SLANG_MATRIX_INT_NEG_OP(ulonglong) - -#define SLANG_FLOAT_MATRIX_MOD(T)\ - template \ - SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator%(Matrix left, Matrix right) \ - {\ - Matrix result;\ - for (int i = 0; i < R; i++) \ - for (int j = 0; j < C; j++) \ - *_slang_vector_get_element_ptr(result.rows+i,j) = _slang_fmod(_slang_vector_get_element(left.rows[i], j), _slang_vector_get_element(right.rows[i], j)); \ - return result;\ - } - - SLANG_FLOAT_MATRIX_MOD(float) - SLANG_FLOAT_MATRIX_MOD(double) + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + *_slang_vector_get_element_ptr(result.rows + i, j) = \ + 0 - _slang_vector_get_element(thisVal.rows[i], j); \ + return result; \ + } +SLANG_MATRIX_INT_NEG_OP(int) +SLANG_MATRIX_INT_NEG_OP(uint) +SLANG_MATRIX_INT_NEG_OP(short) +SLANG_MATRIX_INT_NEG_OP(ushort) +SLANG_MATRIX_INT_NEG_OP(char) +SLANG_MATRIX_INT_NEG_OP(uchar) +SLANG_MATRIX_INT_NEG_OP(longlong) +SLANG_MATRIX_INT_NEG_OP(ulonglong) + +#define SLANG_FLOAT_MATRIX_MOD(T) \ + template \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix operator%( \ + Matrix left, \ + Matrix right) \ + { \ + Matrix result; \ + for (int i = 0; i < R; i++) \ + for (int j = 0; j < C; j++) \ + *_slang_vector_get_element_ptr(result.rows + i, j) = _slang_fmod( \ + _slang_vector_get_element(left.rows[i], j), \ + _slang_vector_get_element(right.rows[i], j)); \ + return result; \ + } + +SLANG_FLOAT_MATRIX_MOD(float) +SLANG_FLOAT_MATRIX_MOD(double) #if SLANG_CUDA_ENABLE_HALF - template - SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix<__half, R, C> operator%(Matrix<__half, R, C> left, Matrix<__half, R, C> right) - { - Matrix<__half, R, C> result; - for (int i = 0; i < R; i++) - for (int j = 0; j < C; j++) - * _slang_vector_get_element_ptr(result.rows + i, j) = __float2half(_slang_fmod(__half2float(_slang_vector_get_element(left.rows[i], j)), __half2float(_slang_vector_get_element(right.rows[i], j)))); - return result; - } +template +SLANG_FORCE_INLINE SLANG_CUDA_CALL Matrix<__half, R, C> operator%( + Matrix<__half, R, C> left, + Matrix<__half, R, C> right) +{ + Matrix<__half, R, C> result; + for (int i = 0; i < R; i++) + for (int j = 0; j < C; j++) + *_slang_vector_get_element_ptr(result.rows + i, j) = __float2half(_slang_fmod( + __half2float(_slang_vector_get_element(left.rows[i], j)), + __half2float(_slang_vector_get_element(right.rows[i], j)))); + return result; +} #endif #undef SLANG_FLOAT_MATRIX_MOD #undef SLANG_MATRIX_BINARY_OP @@ -762,19 +1020,24 @@ SLANG_FLOAT_MATRIX_OPS(__half) #undef SLANG_MATRIX_INT_NEG_OP #undef SLANG_FLOAT_MATRIX_MOD -#define SLANG_SELECT_IMPL(T, N)\ -SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector _slang_select(bool##N condition, Vector v0, Vector v1) \ -{ \ - Vector result; \ - for (int i = 0; i < N; i++) \ - { \ - *_slang_vector_get_element_ptr(&result, i) = _slang_vector_get_element(condition, i) ? _slang_vector_get_element(v0, i) : _slang_vector_get_element(v1, i); \ - } \ - return result; \ -} -#define SLANG_SELECT_T(T)\ - SLANG_SELECT_IMPL(T, 2)\ - SLANG_SELECT_IMPL(T, 3)\ +#define SLANG_SELECT_IMPL(T, N) \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL Vector _slang_select( \ + bool##N condition, \ + Vector v0, \ + Vector v1) \ + { \ + Vector result; \ + for (int i = 0; i < N; i++) \ + { \ + *_slang_vector_get_element_ptr(&result, i) = _slang_vector_get_element(condition, i) \ + ? _slang_vector_get_element(v0, i) \ + : _slang_vector_get_element(v1, i); \ + } \ + return result; \ + } +#define SLANG_SELECT_T(T) \ + SLANG_SELECT_IMPL(T, 2) \ + SLANG_SELECT_IMPL(T, 3) \ SLANG_SELECT_IMPL(T, 4) SLANG_SELECT_T(int) @@ -794,53 +1057,103 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL T _slang_select(bool condition, T v0, T v1) // // Half support -// +// #if SLANG_CUDA_ENABLE_HALF SLANG_SELECT_T(__half) // Convenience functions ushort -> half -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 __ushort_as_half(const ushort2& i) { return __halves2half2(__ushort_as_half(i.x), __ushort_as_half(i.y)); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half3 __ushort_as_half(const ushort3& i) { return __half3{__ushort_as_half(i.x), __ushort_as_half(i.y), __ushort_as_half(i.z)}; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 __ushort_as_half(const ushort4& i) { return __half4{ __ushort_as_half(i.x), __ushort_as_half(i.y), __ushort_as_half(i.z), __ushort_as_half(i.w) }; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 __ushort_as_half(const ushort2& i) +{ + return __halves2half2(__ushort_as_half(i.x), __ushort_as_half(i.y)); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL __half3 __ushort_as_half(const ushort3& i) +{ + return __half3{__ushort_as_half(i.x), __ushort_as_half(i.y), __ushort_as_half(i.z)}; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 __ushort_as_half(const ushort4& i) +{ + return __half4{ + __ushort_as_half(i.x), + __ushort_as_half(i.y), + __ushort_as_half(i.z), + __ushort_as_half(i.w)}; +} // Convenience functions half -> ushort -SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort2 __half_as_ushort(const __half2& i) { return make_ushort2(__half_as_ushort(i.x), __half_as_ushort(i.y)); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort3 __half_as_ushort(const __half3& i) { return make_ushort3(__half_as_ushort(i.x), __half_as_ushort(i.y), __half_as_ushort(i.z)); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort4 __half_as_ushort(const __half4& i) { return make_ushort4(__half_as_ushort(i.x), __half_as_ushort(i.y), __half_as_ushort(i.z), __half_as_ushort(i.w)); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort2 __half_as_ushort(const __half2& i) +{ + return make_ushort2(__half_as_ushort(i.x), __half_as_ushort(i.y)); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort3 __half_as_ushort(const __half3& i) +{ + return make_ushort3(__half_as_ushort(i.x), __half_as_ushort(i.y), __half_as_ushort(i.z)); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL ushort4 __half_as_ushort(const __half4& i) +{ + return make_ushort4( + __half_as_ushort(i.x), + __half_as_ushort(i.y), + __half_as_ushort(i.z), + __half_as_ushort(i.w)); +} -// This is a little bit of a hack. Fortunately CUDA has the definitions of the templated types in +// This is a little bit of a hack. Fortunately CUDA has the definitions of the templated types in // include/surface_indirect_functions.h -// Here we find the template definition requires a specialization of __nv_isurf_trait to allow -// a specialization of the surface write functions. -// This *isn't* a problem on the read functions as they don't have a return type that uses this mechanism +// Here we find the template definition requires a specialization of __nv_isurf_trait to allow +// a specialization of the surface write functions. +// This *isn't* a problem on the read functions as they don't have a return type that uses this +// mechanism -template<> struct __nv_isurf_trait<__half> { typedef void type; }; -template<> struct __nv_isurf_trait<__half2> { typedef void type; }; -template<> struct __nv_isurf_trait<__half4> { typedef void type; }; +template<> +struct __nv_isurf_trait<__half> +{ + typedef void type; +}; +template<> +struct __nv_isurf_trait<__half2> +{ + typedef void type; +}; +template<> +struct __nv_isurf_trait<__half4> +{ + typedef void type; +}; #define SLANG_DROP_PARENS(...) __VA_ARGS__ -#define SLANG_SURFACE_READ(FUNC_NAME, TYPE_ARGS, ARGS) \ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half FUNC_NAME<__half>(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - return __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 FUNC_NAME<__half2>(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - return __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 FUNC_NAME<__half4>(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - return __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ -} +#define SLANG_SURFACE_READ(FUNC_NAME, TYPE_ARGS, ARGS) \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL __half FUNC_NAME<__half>( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + return __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL __half2 FUNC_NAME<__half2>( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + return __ushort_as_half( \ + FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL __half4 FUNC_NAME<__half4>( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + return __ushort_as_half( \ + FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + } SLANG_SURFACE_READ(surf1Dread, (int x), (x)) SLANG_SURFACE_READ(surf2Dread, (int x, int y), (x, y)) @@ -850,24 +1163,36 @@ SLANG_SURFACE_READ(surf2DLayeredread, (int x, int y, int layer), (x, y, layer)) SLANG_SURFACE_READ(surfCubemapread, (int x, int y, int face), (x, y, face)) SLANG_SURFACE_READ(surfCubemapLayeredread, (int x, int y, int layerFace), (x, y, layerFace)) -#define SLANG_SURFACE_WRITE(FUNC_NAME, TYPE_ARGS, ARGS) \ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half>(__half data, cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half2>(__half2 data, cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half4>(__half4 data, cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ -} +#define SLANG_SURFACE_WRITE(FUNC_NAME, TYPE_ARGS, ARGS) \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half>( \ + __half data, \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half2>( \ + __half2 data, \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL void FUNC_NAME<__half4>( \ + __half4 data, \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + FUNC_NAME(__half_as_ushort(data), surfObj, SLANG_DROP_PARENS ARGS, boundaryMode); \ + } SLANG_SURFACE_WRITE(surf1Dwrite, (int x), (x)) SLANG_SURFACE_WRITE(surf2Dwrite, (int x, int y), (x, y)) @@ -878,38 +1203,54 @@ SLANG_SURFACE_WRITE(surfCubemapwrite, (int x, int y, int face), (x, y, face)) SLANG_SURFACE_WRITE(surfCubemapLayeredwrite, (int x, int y, int layerFace), (x, y, layerFace)) // ! Hack to test out reading !!! -// Only works converting *from* half - -//template -//SLANG_FORCE_INLINE SLANG_CUDA_CALL T surf2Dread_convert(cudaSurfaceObject_t surfObj, int x, int y, cudaSurfaceBoundaryMode boundaryMode); - -#define SLANG_SURFACE_READ_HALF_CONVERT(FUNC_NAME, TYPE_ARGS, ARGS) \ -\ -template \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL T FUNC_NAME##_convert(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode); \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL float FUNC_NAME##_convert(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - return __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL float2 FUNC_NAME##_convert(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - const __half2 v = __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ - return float2{v.x, v.y}; \ -} \ -\ -template <> \ -SLANG_FORCE_INLINE SLANG_CUDA_CALL float4 FUNC_NAME##_convert(cudaSurfaceObject_t surfObj, SLANG_DROP_PARENS TYPE_ARGS, cudaSurfaceBoundaryMode boundaryMode) \ -{ \ - const __half4 v = __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ - return float4{v.x, v.y, v.z, v.w}; \ -} - -SLANG_SURFACE_READ_HALF_CONVERT(surf1Dread, (int x), (x)) -SLANG_SURFACE_READ_HALF_CONVERT(surf2Dread, (int x, int y), (x, y)) +// Only works converting *from* half + +// template +// SLANG_FORCE_INLINE SLANG_CUDA_CALL T surf2Dread_convert(cudaSurfaceObject_t surfObj, int x, int +// y, cudaSurfaceBoundaryMode boundaryMode); + +#define SLANG_SURFACE_READ_HALF_CONVERT(FUNC_NAME, TYPE_ARGS, ARGS) \ + \ + template \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL T FUNC_NAME##_convert( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode); \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL float FUNC_NAME##_convert( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + return __ushort_as_half( \ + FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL float2 FUNC_NAME##_convert( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + const __half2 v = \ + __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + return float2{v.x, v.y}; \ + } \ + \ + template<> \ + SLANG_FORCE_INLINE SLANG_CUDA_CALL float4 FUNC_NAME##_convert( \ + cudaSurfaceObject_t surfObj, \ + SLANG_DROP_PARENS TYPE_ARGS, \ + cudaSurfaceBoundaryMode boundaryMode) \ + { \ + const __half4 v = \ + __ushort_as_half(FUNC_NAME(surfObj, SLANG_DROP_PARENS ARGS, boundaryMode)); \ + return float4{v.x, v.y, v.z, v.w}; \ + } + +SLANG_SURFACE_READ_HALF_CONVERT(surf1Dread, (int x), (x)) +SLANG_SURFACE_READ_HALF_CONVERT(surf2Dread, (int x, int y), (x, y)) SLANG_SURFACE_READ_HALF_CONVERT(surf3Dread, (int x, int y, int z), (x, y, z)) #endif @@ -917,178 +1258,506 @@ SLANG_SURFACE_READ_HALF_CONVERT(surf3Dread, (int x, int y, int z), (x, y, z)) // Support for doing format conversion when writing to a surface/RWTexture // NOTE! For normal surface access x values are *byte* addressed. -// For the _convert versions they are *not*. They don't need to be because sust.p does not require it. +// For the _convert versions they are *not*. They don't need to be because sust.p does not require +// it. -template -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert(T, cudaSurfaceObject_t surfObj, int x, cudaSurfaceBoundaryMode boundaryMode); -template -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert(T, cudaSurfaceObject_t surfObj, int x, int y, cudaSurfaceBoundaryMode boundaryMode); -template -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert(T, cudaSurfaceObject_t surfObj, int x, int y, int z, cudaSurfaceBoundaryMode boundaryMode); +template +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert( + T, + cudaSurfaceObject_t surfObj, + int x, + cudaSurfaceBoundaryMode boundaryMode); +template +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert( + T, + cudaSurfaceObject_t surfObj, + int x, + int y, + cudaSurfaceBoundaryMode boundaryMode); +template +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert( + T, + cudaSurfaceObject_t surfObj, + int x, + int y, + int z, + cudaSurfaceBoundaryMode boundaryMode); // https://docs.nvidia.com/cuda/inline-ptx-assembly/index.html // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#surface-instructions-sust // Float -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert(float v, cudaSurfaceObject_t surfObj, int x, cudaSurfaceBoundaryMode boundaryMode) +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert( + float v, + cudaSurfaceObject_t surfObj, + int x, + cudaSurfaceBoundaryMode boundaryMode) { - asm volatile ( "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2};}\n\t" :: "l"(surfObj),"r"(x),"f"(v)); + asm volatile( + "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2};}\n\t" ::"l"(surfObj), + "r"(x), + "f"(v)); } - -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert(float v, cudaSurfaceObject_t surfObj, int x, int y, cudaSurfaceBoundaryMode boundaryMode) + +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert( + float v, + cudaSurfaceObject_t surfObj, + int x, + int y, + cudaSurfaceBoundaryMode boundaryMode) { - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2}], {%3};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"f"(v)); + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2}], {%3};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "f"(v)); } -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert(float v, cudaSurfaceObject_t surfObj, int x, int y, int z, cudaSurfaceBoundaryMode boundaryMode) -{ - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2,%3}], {%4};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"r"(z),"f"(v)); +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert( + float v, + cudaSurfaceObject_t surfObj, + int x, + int y, + int z, + cudaSurfaceBoundaryMode boundaryMode) +{ + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2,%3}], {%4};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "r"(z), + "f"(v)); } // Float2 -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert(float2 v, cudaSurfaceObject_t surfObj, int x, cudaSurfaceBoundaryMode boundaryMode) +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert( + float2 v, + cudaSurfaceObject_t surfObj, + int x, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y; - asm volatile ( "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2,%3};}\n\t" :: "l"(surfObj),"r"(x),"f"(vx),"f"(vy)); + asm volatile( + "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2,%3};}\n\t" ::"l"(surfObj), + "r"(x), + "f"(vx), + "f"(vy)); } - -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert(float2 v, cudaSurfaceObject_t surfObj, int x, int y, cudaSurfaceBoundaryMode boundaryMode) + +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert( + float2 v, + cudaSurfaceObject_t surfObj, + int x, + int y, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y; - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2}], {%3,%4};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"f"(vx),"f"(vy)); + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2}], {%3,%4};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "f"(vx), + "f"(vy)); } -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert(float2 v, cudaSurfaceObject_t surfObj, int x, int y, int z, cudaSurfaceBoundaryMode boundaryMode) +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert( + float2 v, + cudaSurfaceObject_t surfObj, + int x, + int y, + int z, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y; - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2,%3}], {%4,%5};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"r"(z),"f"(vx),"f"(vy)); + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2,%3}], {%4,%5};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "r"(z), + "f"(vx), + "f"(vy)); } // Float4 -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert(float4 v, cudaSurfaceObject_t surfObj, int x, cudaSurfaceBoundaryMode boundaryMode) +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf1Dwrite_convert( + float4 v, + cudaSurfaceObject_t surfObj, + int x, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y, vz = v.z, vw = v.w; - asm volatile ( "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2,%3,%4,%5};}\n\t" :: "l"(surfObj),"r"(x),"f"(vx),"f"(vy),"f"(vz),"f"(vw)); + asm volatile( + "{sust.p.1d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1}], {%2,%3,%4,%5};}\n\t" ::"l"(surfObj), + "r"(x), + "f"(vx), + "f"(vy), + "f"(vz), + "f"(vw)); } - -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert(float4 v, cudaSurfaceObject_t surfObj, int x, int y, cudaSurfaceBoundaryMode boundaryMode) + +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf2Dwrite_convert( + float4 v, + cudaSurfaceObject_t surfObj, + int x, + int y, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y, vz = v.z, vw = v.w; - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2}], {%3,%4,%5,%6};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"f"(vx),"f"(vy),"f"(vz),"f"(vw)); + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE + " [%0, {%1,%2}], {%3,%4,%5,%6};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "f"(vx), + "f"(vy), + "f"(vz), + "f"(vw)); } -template <> -SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert(float4 v, cudaSurfaceObject_t surfObj, int x, int y, int z, cudaSurfaceBoundaryMode boundaryMode) +template<> +SLANG_FORCE_INLINE SLANG_CUDA_CALL void surf3Dwrite_convert( + float4 v, + cudaSurfaceObject_t surfObj, + int x, + int y, + int z, + cudaSurfaceBoundaryMode boundaryMode) { const float vx = v.x, vy = v.y, vz = v.z, vw = v.w; - asm volatile ( "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE " [%0, {%1,%2,%3}], {%4,%5,%6,%7};}\n\t" :: "l"(surfObj),"r"(x),"r"(y),"r"(z),"f"(vx),"f"(vy),"f"(vz),"f"(vw)); + asm volatile( + "{sust.p.2d.b32." SLANG_PTX_BOUNDARY_MODE + " [%0, {%1,%2,%3}], {%4,%5,%6,%7};}\n\t" ::"l"(surfObj), + "r"(x), + "r"(y), + "r"(z), + "f"(vx), + "f"(vy), + "f"(vz), + "f"(vw)); } // ----------------------------- F32 ----------------------------------------- -// Unary -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_ceil(float f) { return ::ceilf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_floor(float f) { return ::floorf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_round(float f) { return ::roundf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sin(float f) { return ::sinf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cos(float f) { return ::cosf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL void F32_sincos(float f, float* s, float* c) { ::sincosf(f, s, c); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tan(float f) { return ::tanf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_asin(float f) { return ::asinf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_acos(float f) { return ::acosf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan(float f) { return ::atanf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sinh(float f) { return ::sinhf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cosh(float f) { return ::coshf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tanh(float f) { return ::tanhf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log2(float f) { return ::log2f(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log(float f) { return ::logf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log10(float f) { return ::log10f(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp2(float f) { return ::exp2f(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp(float f) { return ::expf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_abs(float f) { return ::fabsf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_trunc(float f) { return ::truncf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sqrt(float f) { return ::sqrtf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_rsqrt(float f) { return ::rsqrtf(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sign(float f) { return ( f == 0.0f) ? f : (( f < 0.0f) ? -1.0f : 1.0f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frac(float f) { return f - F32_floor(f); } - -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isnan(float f) { return isnan(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isfinite(float f) { return isfinite(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isinf(float f) { return isinf(f); } +// Unary +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_ceil(float f) +{ + return ::ceilf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_floor(float f) +{ + return ::floorf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_round(float f) +{ + return ::roundf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sin(float f) +{ + return ::sinf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cos(float f) +{ + return ::cosf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL void F32_sincos(float f, float* s, float* c) +{ + ::sincosf(f, s, c); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tan(float f) +{ + return ::tanf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_asin(float f) +{ + return ::asinf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_acos(float f) +{ + return ::acosf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan(float f) +{ + return ::atanf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sinh(float f) +{ + return ::sinhf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_cosh(float f) +{ + return ::coshf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_tanh(float f) +{ + return ::tanhf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log2(float f) +{ + return ::log2f(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log(float f) +{ + return ::logf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_log10(float f) +{ + return ::log10f(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp2(float f) +{ + return ::exp2f(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_exp(float f) +{ + return ::expf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_abs(float f) +{ + return ::fabsf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_trunc(float f) +{ + return ::truncf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sqrt(float f) +{ + return ::sqrtf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_rsqrt(float f) +{ + return ::rsqrtf(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_sign(float f) +{ + return (f == 0.0f) ? f : ((f < 0.0f) ? -1.0f : 1.0f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frac(float f) +{ + return f - F32_floor(f); +} + +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isnan(float f) +{ + return isnan(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isfinite(float f) +{ + return isfinite(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F32_isinf(float f) +{ + return isinf(f); +} // Binary -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_min(float a, float b) { return ::fminf(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_max(float a, float b) { return ::fmaxf(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_pow(float a, float b) { return ::powf(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fmod(float a, float b) { return ::fmodf(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_remainder(float a, float b) { return ::remainderf(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan2(float a, float b) { return float(::atan2(a, b)); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_min(float a, float b) +{ + return ::fminf(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_max(float a, float b) +{ + return ::fmaxf(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_pow(float a, float b) +{ + return ::powf(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fmod(float a, float b) +{ + return ::fmodf(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_remainder(float a, float b) +{ + return ::remainderf(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_atan2(float a, float b) +{ + return float(::atan2(a, b)); +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frexp(float x, int* e) { return frexpf(x, e); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_frexp(float x, int* e) +{ + return frexpf(x, e); +} SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_modf(float x, float* ip) { return ::modff(x, ip); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t F32_asuint(float f) { Union32 u; u.f = f; return u.u; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t F32_asint(float f) { Union32 u; u.f = f; return u.i; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t F32_asuint(float f) +{ + Union32 u; + u.f = f; + return u.u; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t F32_asint(float f) +{ + Union32 u; + u.f = f; + return u.i; +} // Ternary -SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fma(float a, float b, float c) { return ::fmaf(a, b, c); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL float F32_fma(float a, float b, float c) +{ + return ::fmaf(a, b, c); +} // ----------------------------- F64 ----------------------------------------- -// Unary -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_ceil(double f) { return ::ceil(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_floor(double f) { return ::floor(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_round(double f) { return ::round(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sin(double f) { return ::sin(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cos(double f) { return ::cos(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_sincos(double f, double* s, double* c) { ::sincos(f, s, c); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tan(double f) { return ::tan(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_asin(double f) { return ::asin(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_acos(double f) { return ::acos(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan(double f) { return ::atan(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sinh(double f) { return ::sinh(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cosh(double f) { return ::cosh(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tanh(double f) { return ::tanh(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log2(double f) { return ::log2(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log(double f) { return ::log(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log10(float f) { return ::log10(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp2(double f) { return ::exp2(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp(double f) { return ::exp(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_abs(double f) { return ::fabs(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_trunc(double f) { return ::trunc(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sqrt(double f) { return ::sqrt(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_rsqrt(double f) { return ::rsqrt(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sign(double f) { return (f == 0.0) ? f : ((f < 0.0) ? -1.0 : 1.0); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frac(double f) { return f - F64_floor(f); } - -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isnan(double f) { return isnan(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isfinite(double f) { return isfinite(f); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isinf(double f) { return isinf(f); } +// Unary +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_ceil(double f) +{ + return ::ceil(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_floor(double f) +{ + return ::floor(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_round(double f) +{ + return ::round(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sin(double f) +{ + return ::sin(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cos(double f) +{ + return ::cos(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_sincos(double f, double* s, double* c) +{ + ::sincos(f, s, c); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tan(double f) +{ + return ::tan(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_asin(double f) +{ + return ::asin(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_acos(double f) +{ + return ::acos(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan(double f) +{ + return ::atan(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sinh(double f) +{ + return ::sinh(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_cosh(double f) +{ + return ::cosh(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_tanh(double f) +{ + return ::tanh(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log2(double f) +{ + return ::log2(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log(double f) +{ + return ::log(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_log10(float f) +{ + return ::log10(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp2(double f) +{ + return ::exp2(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_exp(double f) +{ + return ::exp(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_abs(double f) +{ + return ::fabs(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_trunc(double f) +{ + return ::trunc(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sqrt(double f) +{ + return ::sqrt(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_rsqrt(double f) +{ + return ::rsqrt(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_sign(double f) +{ + return (f == 0.0) ? f : ((f < 0.0) ? -1.0 : 1.0); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frac(double f) +{ + return f - F64_floor(f); +} + +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isnan(double f) +{ + return isnan(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isfinite(double f) +{ + return isfinite(f); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL bool F64_isinf(double f) +{ + return isinf(f); +} // Binary -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_min(double a, double b) { return ::fmin(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_max(double a, double b) { return ::fmax(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_pow(double a, double b) { return ::pow(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fmod(double a, double b) { return ::fmod(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_remainder(double a, double b) { return ::remainder(a, b); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan2(double a, double b) { return ::atan2(a, b); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_min(double a, double b) +{ + return ::fmin(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_max(double a, double b) +{ + return ::fmax(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_pow(double a, double b) +{ + return ::pow(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fmod(double a, double b) +{ + return ::fmod(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_remainder(double a, double b) +{ + return ::remainder(a, b); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_atan2(double a, double b) +{ + return ::atan2(a, b); +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frexp(double x, int* e) { return ::frexp(x, e); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_frexp(double x, int* e) +{ + return ::frexp(x, e); +} SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_modf(double x, double* ip) { @@ -1112,20 +1781,40 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL void F64_asint(double d, int32_t* low, int32_ } // Ternary -SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fma(double a, double b, double c) { return ::fma(a, b, c); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL double F64_fma(double a, double b, double c) +{ + return ::fma(a, b, c); +} // ----------------------------- I32 ----------------------------------------- // Unary -SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_abs(int32_t f) { return (f < 0) ? -f : f; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_abs(int32_t f) +{ + return (f < 0) ? -f : f; +} // Binary -SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_min(int32_t a, int32_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_max(int32_t a, int32_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_min(int32_t a, int32_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL int32_t I32_max(int32_t a, int32_t b) +{ + return a > b ? a : b; +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL float I32_asfloat(int32_t x) { Union32 u; u.i = x; return u.f; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_asuint(int32_t x) { return uint32_t(x); } -SLANG_FORCE_INLINE SLANG_CUDA_CALL double I32_asdouble(int32_t low, int32_t hi ) +SLANG_FORCE_INLINE SLANG_CUDA_CALL float I32_asfloat(int32_t x) +{ + Union32 u; + u.i = x; + return u.f; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t I32_asuint(int32_t x) +{ + return uint32_t(x); +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL double I32_asdouble(int32_t low, int32_t hi) { Union64 u; u.u = (uint64_t(hi) << 32) | uint32_t(low); @@ -1134,15 +1823,32 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL double I32_asdouble(int32_t low, int32_t hi ) // ----------------------------- U32 ----------------------------------------- -// Unary -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_abs(uint32_t f) { return f; } +// Unary +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_abs(uint32_t f) +{ + return f; +} // Binary -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_min(uint32_t a, uint32_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_max(uint32_t a, uint32_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_min(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_max(uint32_t a, uint32_t b) +{ + return a > b ? a : b; +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL float U32_asfloat(uint32_t x) { Union32 u; u.u = x; return u.f; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_asint(int32_t x) { return uint32_t(x); } +SLANG_FORCE_INLINE SLANG_CUDA_CALL float U32_asfloat(uint32_t x) +{ + Union32 u; + u.u = x; + return u.f; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_asint(int32_t x) +{ + return uint32_t(x); +} SLANG_FORCE_INLINE SLANG_CUDA_CALL double U32_asdouble(uint32_t low, uint32_t hi) { @@ -1160,17 +1866,35 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U32_countbits(uint32_t v) // ----------------------------- I64 ----------------------------------------- -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_abs(int64_t f) { return (f < 0) ? -f : f; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_abs(int64_t f) +{ + return (f < 0) ? -f : f; +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_min(int64_t a, int64_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_max(int64_t a, int64_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_min(int64_t a, int64_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t I64_max(int64_t a, int64_t b) +{ + return a > b ? a : b; +} // ----------------------------- U64 ----------------------------------------- -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_abs(uint64_t f) { return f; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_abs(uint64_t f) +{ + return f; +} -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_min(uint64_t a, uint64_t b) { return a < b ? a : b; } -SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_max(uint64_t a, uint64_t b) { return a > b ? a : b; } +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_min(uint64_t a, uint64_t b) +{ + return a < b ? a : b; +} +SLANG_FORCE_INLINE SLANG_CUDA_CALL int64_t U64_max(uint64_t a, uint64_t b) +{ + return a > b ? a : b; +} SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U64_countbits(uint64_t v) { @@ -1185,7 +1909,7 @@ SLANG_FORCE_INLINE SLANG_CUDA_CALL uint32_t U64_countbits(uint64_t v) // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-structuredbuffer-getdimensions // Missing Load(_In_ int Location, _Out_ uint Status); -template +template struct StructuredBuffer { SLANG_CUDA_CALL const T& operator[](size_t index) const @@ -1205,7 +1929,11 @@ struct StructuredBuffer } #ifndef SLANG_CUDA_STRUCTURED_BUFFER_NO_COUNT - SLANG_CUDA_CALL void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) { *outNumStructs = uint32_t(count); *outStride = uint32_t(sizeof(T)); } + SLANG_CUDA_CALL void GetDimensions(uint32_t* outNumStructs, uint32_t* outStride) + { + *outNumStructs = uint32_t(count); + *outStride = uint32_t(sizeof(T)); + } #endif T* data; @@ -1214,7 +1942,7 @@ struct StructuredBuffer #endif }; -template +template struct RWStructuredBuffer : StructuredBuffer { SLANG_CUDA_CALL T& operator[](size_t index) const @@ -1230,28 +1958,28 @@ struct RWStructuredBuffer : StructuredBuffer struct ByteAddressBuffer { SLANG_CUDA_CALL void GetDimensions(uint32_t* outDim) const { *outDim = uint32_t(sizeInBytes); } - SLANG_CUDA_CALL uint32_t Load(size_t index) const - { + SLANG_CUDA_CALL uint32_t Load(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - return data[index >> 2]; + return data[index >> 2]; } - SLANG_CUDA_CALL uint2 Load2(size_t index) const - { - SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint2{data[dataIdx], data[dataIdx + 1]}; + SLANG_CUDA_CALL uint2 Load2(size_t index) const + { + SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); + const size_t dataIdx = index >> 2; + return uint2{data[dataIdx], data[dataIdx + 1]}; } - SLANG_CUDA_CALL uint3 Load3(size_t index) const - { + SLANG_CUDA_CALL uint3 Load3(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; + const size_t dataIdx = index >> 2; + return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; } - SLANG_CUDA_CALL uint4 Load4(size_t index) const - { + SLANG_CUDA_CALL uint4 Load4(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; + const size_t dataIdx = index >> 2; + return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; } template SLANG_CUDA_CALL T Load(size_t index) const @@ -1261,40 +1989,47 @@ struct ByteAddressBuffer memcpy(&data, ((const char*)this->data) + index, sizeof(T)); return data; } - + template + SLANG_CUDA_CALL StructuredBuffer asStructuredBuffer() const + { + StructuredBuffer rs; + rs.data = (T*)data; + rs.count = sizeInBytes / sizeof(T); + return rs; + } const uint32_t* data; - size_t sizeInBytes; //< Must be multiple of 4 + size_t sizeInBytes; //< Must be multiple of 4 }; // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/sm5-object-rwbyteaddressbuffer -// Missing support for Atomic operations +// Missing support for Atomic operations // Missing support for Load with status struct RWByteAddressBuffer { SLANG_CUDA_CALL void GetDimensions(uint32_t* outDim) const { *outDim = uint32_t(sizeInBytes); } - - SLANG_CUDA_CALL uint32_t Load(size_t index) const - { + + SLANG_CUDA_CALL uint32_t Load(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - return data[index >> 2]; + return data[index >> 2]; } - SLANG_CUDA_CALL uint2 Load2(size_t index) const - { + SLANG_CUDA_CALL uint2 Load2(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint2{data[dataIdx], data[dataIdx + 1]}; + const size_t dataIdx = index >> 2; + return uint2{data[dataIdx], data[dataIdx + 1]}; } - SLANG_CUDA_CALL uint3 Load3(size_t index) const - { + SLANG_CUDA_CALL uint3 Load3(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; + const size_t dataIdx = index >> 2; + return uint3{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2]}; } - SLANG_CUDA_CALL uint4 Load4(size_t index) const - { + SLANG_CUDA_CALL uint4 Load4(size_t index) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; - return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; + const size_t dataIdx = index >> 2; + return uint4{data[dataIdx], data[dataIdx + 1], data[dataIdx + 2], data[dataIdx + 3]}; } template SLANG_CUDA_CALL T Load(size_t index) const @@ -1304,31 +2039,31 @@ struct RWByteAddressBuffer memcpy(&data, ((const char*)this->data) + index, sizeof(T)); return data; } - - SLANG_CUDA_CALL void Store(size_t index, uint32_t v) const - { + + SLANG_CUDA_CALL void Store(size_t index, uint32_t v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 4, sizeInBytes); - data[index >> 2] = v; + data[index >> 2] = v; } - SLANG_CUDA_CALL void Store2(size_t index, uint2 v) const - { + SLANG_CUDA_CALL void Store2(size_t index, uint2 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 8, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; } - SLANG_CUDA_CALL void Store3(size_t index, uint3 v) const - { + SLANG_CUDA_CALL void Store3(size_t index, uint3 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 12, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; data[dataIdx + 2] = v.z; } - SLANG_CUDA_CALL void Store4(size_t index, uint4 v) const - { + SLANG_CUDA_CALL void Store4(size_t index, uint4 v) const + { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, 16, sizeInBytes); - const size_t dataIdx = index >> 2; + const size_t dataIdx = index >> 2; data[dataIdx + 0] = v.x; data[dataIdx + 1] = v.y; data[dataIdx + 2] = v.z; @@ -1340,79 +2075,88 @@ struct RWByteAddressBuffer SLANG_BOUND_CHECK_BYTE_ADDRESS(index, sizeof(T), sizeInBytes); memcpy((char*)data + index, &value, sizeof(T)); } - - /// Can be used in stdlib to gain access - template + + /// Can be used in the core module to gain access + template SLANG_CUDA_CALL T* _getPtrAt(size_t index) { SLANG_BOUND_CHECK_BYTE_ADDRESS(index, sizeof(T), sizeInBytes); return (T*)(((char*)data) + index); } - + template + SLANG_CUDA_CALL RWStructuredBuffer asStructuredBuffer() const + { + RWStructuredBuffer rs; + rs.data = (T*)data; + rs.count = sizeInBytes / sizeof(T); + return rs; + } uint32_t* data; - size_t sizeInBytes; //< Must be multiple of 4 + size_t sizeInBytes; //< Must be multiple of 4 }; // ---------------------- Wave -------------------------------------- -// TODO(JS): It appears that cuda does not have a simple way to get a lane index. -// -// Another approach could be... -// laneId = ((threadIdx.z * blockDim.y + threadIdx.y) * blockDim.x + threadIdx.x) & SLANG_CUDA_WARP_MASK -// If that is really true another way to do this, would be for code generator to add this function -// with the [numthreads] baked in. -// -// For now I'll just assume you have a launch that makes the following correct if the kernel uses WaveGetLaneIndex() +// TODO(JS): It appears that cuda does not have a simple way to get a lane index. +// +// Another approach could be... +// laneId = ((threadIdx.z * blockDim.y + threadIdx.y) * blockDim.x + threadIdx.x) & +// SLANG_CUDA_WARP_MASK If that is really true another way to do this, would be for code generator +// to add this function with the [numthreads] baked in. +// +// For now I'll just assume you have a launch that makes the following correct if the kernel uses +// WaveGetLaneIndex() #ifndef SLANG_USE_ASM_LANE_ID - __forceinline__ __device__ uint32_t _getLaneId() +__forceinline__ __device__ uint32_t _getLaneId() { - // If the launch is (or I guess some multiple of the warp size) - // we try this mechanism, which is apparently faster. + // If the launch is (or I guess some multiple of the warp size) + // we try this mechanism, which is apparently faster. return threadIdx.x & SLANG_CUDA_WARP_MASK; } #else __forceinline__ __device__ uint32_t _getLaneId() { // https://stackoverflow.com/questions/44337309/whats-the-most-efficient-way-to-calculate-the-warp-id-lane-id-in-a-1-d-grid# - // This mechanism is not the fastest way to do it, and that is why the other mechanism - // is the default. But the other mechanism relies on a launch that makes the assumption + // This mechanism is not the fastest way to do it, and that is why the other mechanism + // is the default. But the other mechanism relies on a launch that makes the assumption // true. - unsigned ret; - asm volatile ("mov.u32 %0, %laneid;" : "=r"(ret)); + unsigned ret; + asm volatile("mov.u32 %0, %laneid;" : "=r"(ret)); return ret; } #endif typedef int WarpMask; -// It appears that the __activemask() cannot always be used because -// threads need to be converged. -// +// It appears that the __activemask() cannot always be used because +// threads need to be converged. +// // For CUDA the article claims mask has to be used carefully // https://devblogs.nvidia.com/using-cuda-warp-level-primitives/ -// With the Warp intrinsics there is no mask, and it's just the 'active lanes'. +// With the Warp intrinsics there is no mask, and it's just the 'active lanes'. // __activemask() though does not require there is convergence, so that doesn't work. -// -// '__ballot_sync' produces a convergance. -// +// +// '__ballot_sync' produces a convergance. +// // From the CUDA docs: -// ```For __all_sync, __any_sync, and __ballot_sync, a mask must be passed that specifies the threads -// participating in the call. A bit, representing the thread's lane ID, must be set for each participating thread -// to ensure they are properly converged before the intrinsic is executed by the hardware. All active threads named -// in mask must execute the same intrinsic with the same mask, or the result is undefined.``` +// ```For __all_sync, __any_sync, and __ballot_sync, a mask must be passed that specifies the +// threads participating in the call. A bit, representing the thread's lane ID, must be set for each +// participating thread to ensure they are properly converged before the intrinsic is executed by +// the hardware. All active threads named in mask must execute the same intrinsic with the same +// mask, or the result is undefined.``` // // Currently there isn't a mechanism to correctly get the mask without it being passed through. -// Doing so will most likely require some changes to slang code generation to track masks, for now then we use -// _getActiveMask. +// Doing so will most likely require some changes to slang code generation to track masks, for now +// then we use _getActiveMask. // Return mask of all the lanes less than the current lane __forceinline__ __device__ WarpMask _getLaneLtMask() { return (int(1) << _getLaneId()) - 1; -} +} -// TODO(JS): +// TODO(JS): // THIS IS NOT CORRECT! That determining the appropriate active mask requires appropriate // mask tracking. __forceinline__ __device__ WarpMask _getActiveMask() @@ -1464,30 +2208,30 @@ __inline__ __device__ int _waveCalcPow2Offset(WarpMask mask) __inline__ __device__ bool _waveIsFirstLane() { const WarpMask mask = __activemask(); - // We special case bit 0, as that most warps are expected to be fully active. - + // We special case bit 0, as that most warps are expected to be fully active. + // mask & -mask, isolates the lowest set bit. - //return (mask & 1 ) || ((mask & -mask) == (1 << _getLaneId())); - - // This mechanism is most similar to what was in an nVidia post, so assume it is prefered. - return (mask & 1 ) || ((__ffs(mask) - 1) == _getLaneId()); + // return (mask & 1 ) || ((mask & -mask) == (1 << _getLaneId())); + + // This mechanism is most similar to what was in an nVidia post, so assume it is prefered. + return (mask & 1) || ((__ffs(mask) - 1) == _getLaneId()); } -template +template struct WaveOpOr { __inline__ __device__ static T getInitial(T a) { return 0; } __inline__ __device__ static T doOp(T a, T b) { return a | b; } }; -template +template struct WaveOpAnd { __inline__ __device__ static T getInitial(T a) { return ~T(0); } __inline__ __device__ static T doOp(T a, T b) { return a & b; } }; -template +template struct WaveOpXor { __inline__ __device__ static T getInitial(T a) { return 0; } @@ -1495,7 +2239,7 @@ struct WaveOpXor __inline__ __device__ static T doInverse(T a, T b) { return a ^ b; } }; -template +template struct WaveOpAdd { __inline__ __device__ static T getInitial(T a) { return 0; } @@ -1503,77 +2247,166 @@ struct WaveOpAdd __inline__ __device__ static T doInverse(T a, T b) { return a - b; } }; -template +template struct WaveOpMul { __inline__ __device__ static T getInitial(T a) { return T(1); } __inline__ __device__ static T doOp(T a, T b) { return a * b; } - // Using this inverse for int is probably undesirable - because in general it requires T to have more precision - // There is also a performance aspect to it, where divides are generally significantly slower + // Using this inverse for int is probably undesirable - because in general it requires T to have + // more precision There is also a performance aspect to it, where divides are generally + // significantly slower __inline__ __device__ static T doInverse(T a, T b) { return a / b; } }; -template +template struct WaveOpMax { __inline__ __device__ static T getInitial(T a) { return a; } __inline__ __device__ static T doOp(T a, T b) { return a > b ? a : b; } }; -template +template struct WaveOpMin { - __inline__ __device__ static T getInitial(T a) { return a; } + __inline__ __device__ static T getInitial(T a) { return a; } __inline__ __device__ static T doOp(T a, T b) { return a < b ? a : b; } }; -template +template struct ElementTypeTrait; // Scalar -template <> struct ElementTypeTrait { typedef int Type; }; -template <> struct ElementTypeTrait { typedef uint Type; }; -template <> struct ElementTypeTrait { typedef float Type; }; -template <> struct ElementTypeTrait { typedef double Type; }; -template <> struct ElementTypeTrait { typedef uint64_t Type; }; -template <> struct ElementTypeTrait { typedef int64_t Type; }; +template<> +struct ElementTypeTrait +{ + typedef int Type; +}; +template<> +struct ElementTypeTrait +{ + typedef uint Type; +}; +template<> +struct ElementTypeTrait +{ + typedef float Type; +}; +template<> +struct ElementTypeTrait +{ + typedef double Type; +}; +template<> +struct ElementTypeTrait +{ + typedef uint64_t Type; +}; +template<> +struct ElementTypeTrait +{ + typedef int64_t Type; +}; // Vector -template <> struct ElementTypeTrait { typedef int Type; }; -template <> struct ElementTypeTrait { typedef int Type; }; -template <> struct ElementTypeTrait { typedef int Type; }; -template <> struct ElementTypeTrait { typedef int Type; }; - -template <> struct ElementTypeTrait { typedef uint Type; }; -template <> struct ElementTypeTrait { typedef uint Type; }; -template <> struct ElementTypeTrait { typedef uint Type; }; -template <> struct ElementTypeTrait { typedef uint Type; }; - -template <> struct ElementTypeTrait { typedef float Type; }; -template <> struct ElementTypeTrait { typedef float Type; }; -template <> struct ElementTypeTrait { typedef float Type; }; -template <> struct ElementTypeTrait { typedef float Type; }; - -template <> struct ElementTypeTrait { typedef double Type; }; -template <> struct ElementTypeTrait { typedef double Type; }; -template <> struct ElementTypeTrait { typedef double Type; }; -template <> struct ElementTypeTrait { typedef double Type; }; +template<> +struct ElementTypeTrait +{ + typedef int Type; +}; +template<> +struct ElementTypeTrait +{ + typedef int Type; +}; +template<> +struct ElementTypeTrait +{ + typedef int Type; +}; +template<> +struct ElementTypeTrait +{ + typedef int Type; +}; + +template<> +struct ElementTypeTrait +{ + typedef uint Type; +}; +template<> +struct ElementTypeTrait +{ + typedef uint Type; +}; +template<> +struct ElementTypeTrait +{ + typedef uint Type; +}; +template<> +struct ElementTypeTrait +{ + typedef uint Type; +}; + +template<> +struct ElementTypeTrait +{ + typedef float Type; +}; +template<> +struct ElementTypeTrait +{ + typedef float Type; +}; +template<> +struct ElementTypeTrait +{ + typedef float Type; +}; +template<> +struct ElementTypeTrait +{ + typedef float Type; +}; + +template<> +struct ElementTypeTrait +{ + typedef double Type; +}; +template<> +struct ElementTypeTrait +{ + typedef double Type; +}; +template<> +struct ElementTypeTrait +{ + typedef double Type; +}; +template<> +struct ElementTypeTrait +{ + typedef double Type; +}; // Matrix -template -struct ElementTypeTrait > -{ - typedef T Type; +template +struct ElementTypeTrait> +{ + typedef T Type; }; -// Scalar -template +// Scalar +template __device__ T _waveReduceScalar(WarpMask mask, T val) { const int offsetSize = _waveCalcPow2Offset(mask); if (offsetSize > 0) { - // Fast path O(log2(activeLanes)) + // Fast path O(log2(activeLanes)) for (int offset = offsetSize >> 1; offset > 0; offset >>= 1) { val = INTF::doOp(val, __shfl_xor_sync(mask, val, offset)); @@ -1586,9 +2419,9 @@ __device__ T _waveReduceScalar(WarpMask mask, T val) while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) result = INTF::doOp(result, __shfl_sync(mask, val, srcLane)); remaining &= ~laneBit; } @@ -1599,13 +2432,13 @@ __device__ T _waveReduceScalar(WarpMask mask, T val) // Multiple values -template +template __device__ void _waveReduceMultiple(WarpMask mask, T* val) { const int offsetSize = _waveCalcPow2Offset(mask); if (offsetSize > 0) { - // Fast path O(log2(activeLanes)) + // Fast path O(log2(activeLanes)) for (int offset = offsetSize >> 1; offset > 0; offset >>= 1) { for (size_t i = 0; i < COUNT; ++i) @@ -1624,14 +2457,14 @@ __device__ void _waveReduceMultiple(WarpMask mask, T* val) originalVal[i] = v; val[i] = INTF::getInitial(v); } - + int remaining = mask; while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) for (size_t i = 0; i < COUNT; ++i) { val[i] = INTF::doOp(val[i], __shfl_sync(mask, originalVal[i], srcLane)); @@ -1641,99 +2474,182 @@ __device__ void _waveReduceMultiple(WarpMask mask, T* val) } } -template +template __device__ void _waveReduceMultiple(WarpMask mask, T* val) { - typedef typename ElementTypeTrait::Type ElemType; + typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple(mask, (ElemType*)val); } -template -__inline__ __device__ T _waveOr(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveOr(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveAnd(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveAnd(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveXor(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveXor(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveProduct(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveProduct(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveSum(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveSum(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveMin(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveMin(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} -template -__inline__ __device__ T _waveMax(WarpMask mask, T val) { return _waveReduceScalar, T>(mask, val); } +template +__inline__ __device__ T _waveMax(WarpMask mask, T val) +{ + return _waveReduceScalar, T>(mask, val); +} // Fast-path specializations when CUDA warp reduce operators are available #if __CUDA_ARCH__ >= 800 // 8.x or higher template<> -__inline__ __device__ unsigned _waveOr(WarpMask mask, unsigned val) { return __reduce_or_sync(mask, val); } +__inline__ __device__ unsigned _waveOr(WarpMask mask, unsigned val) +{ + return __reduce_or_sync(mask, val); +} template<> -__inline__ __device__ unsigned _waveAnd(WarpMask mask, unsigned val) { return __reduce_and_sync(mask, val); } +__inline__ __device__ unsigned _waveAnd(WarpMask mask, unsigned val) +{ + return __reduce_and_sync(mask, val); +} template<> -__inline__ __device__ unsigned _waveXor(WarpMask mask, unsigned val) { return __reduce_xor_sync(mask, val); } +__inline__ __device__ unsigned _waveXor(WarpMask mask, unsigned val) +{ + return __reduce_xor_sync(mask, val); +} template<> -__inline__ __device__ unsigned _waveSum(WarpMask mask, unsigned val) { return __reduce_add_sync(mask, val); } +__inline__ __device__ unsigned _waveSum(WarpMask mask, unsigned val) +{ + return __reduce_add_sync(mask, val); +} template<> -__inline__ __device__ int _waveSum(WarpMask mask, int val) { return __reduce_add_sync(mask, val); } +__inline__ __device__ int _waveSum(WarpMask mask, int val) +{ + return __reduce_add_sync(mask, val); +} template<> -__inline__ __device__ unsigned _waveMin(WarpMask mask, unsigned val) { return __reduce_min_sync(mask, val); } +__inline__ __device__ unsigned _waveMin(WarpMask mask, unsigned val) +{ + return __reduce_min_sync(mask, val); +} template<> -__inline__ __device__ int _waveMin(WarpMask mask, int val) { return __reduce_min_sync(mask, val); } +__inline__ __device__ int _waveMin(WarpMask mask, int val) +{ + return __reduce_min_sync(mask, val); +} template<> -__inline__ __device__ unsigned _waveMax(WarpMask mask, unsigned val) { return __reduce_max_sync(mask, val); } +__inline__ __device__ unsigned _waveMax(WarpMask mask, unsigned val) +{ + return __reduce_max_sync(mask, val); +} template<> -__inline__ __device__ int _waveMax(WarpMask mask, int val) { return __reduce_max_sync(mask, val); } +__inline__ __device__ int _waveMax(WarpMask mask, int val) +{ + return __reduce_max_sync(mask, val); +} #endif // Multiple -template -__inline__ __device__ T _waveOrMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveOrMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveAndMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveAndMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveXorMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveXorMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveProductMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveProductMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveSumMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveSumMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveMinMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveMinMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ T _waveMaxMultiple(WarpMask mask, T val) { typedef typename ElementTypeTrait::Type ElemType; _waveReduceMultiple >(mask, &val); return val; } +template +__inline__ __device__ T _waveMaxMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _waveReduceMultiple>(mask, &val); + return val; +} -template -__inline__ __device__ bool _waveAllEqual(WarpMask mask, T val) +template +__inline__ __device__ bool _waveAllEqual(WarpMask mask, T val) { int pred; __match_all_sync(mask, val, &pred); return pred != 0; } -template -__inline__ __device__ bool _waveAllEqualMultiple(WarpMask mask, T inVal) +template +__inline__ __device__ bool _waveAllEqualMultiple(WarpMask mask, T inVal) { typedef typename ElementTypeTrait::Type ElemType; const size_t count = sizeof(T) / sizeof(ElemType); @@ -1750,15 +2666,15 @@ __inline__ __device__ bool _waveAllEqualMultiple(WarpMask mask, T inVal) return true; } -template -__inline__ __device__ T _waveReadFirst(WarpMask mask, T val) +template +__inline__ __device__ T _waveReadFirst(WarpMask mask, T val) { const int lowestLaneId = __ffs(mask) - 1; - return __shfl_sync(mask, val, lowestLaneId); + return __shfl_sync(mask, val, lowestLaneId); } -template -__inline__ __device__ T _waveReadFirstMultiple(WarpMask mask, T inVal) +template +__inline__ __device__ T _waveReadFirstMultiple(WarpMask mask, T inVal) { typedef typename ElementTypeTrait::Type ElemType; const size_t count = sizeof(T) / sizeof(ElemType); @@ -1768,12 +2684,12 @@ __inline__ __device__ T _waveReadFirstMultiple(WarpMask mask, T inVal) const int lowestLaneId = __ffs(mask) - 1; for (size_t i = 0; i < count; ++i) { - dst[i] = __shfl_sync(mask, src[i], lowestLaneId); + dst[i] = __shfl_sync(mask, src[i], lowestLaneId); } return outVal; } -template +template __inline__ __device__ T _waveShuffleMultiple(WarpMask mask, T inVal, int lane) { typedef typename ElementTypeTrait::Type ElemType; @@ -1783,27 +2699,27 @@ __inline__ __device__ T _waveShuffleMultiple(WarpMask mask, T inVal, int lane) ElemType* dst = (ElemType*)&outVal; for (size_t i = 0; i < count; ++i) { - dst[i] = __shfl_sync(mask, src[i], lane); + dst[i] = __shfl_sync(mask, src[i], lane); } return outVal; } -// Scalar +// Scalar -// Invertable means that when we get to the end of the reduce, we can remove val (to make exclusive), using -// the inverse of the op. -template +// Invertable means that when we get to the end of the reduce, we can remove val (to make +// exclusive), using the inverse of the op. +template __device__ T _wavePrefixInvertableScalar(WarpMask mask, T val) { const int offsetSize = _waveCalcPow2Offset(mask); - + const int laneId = _getLaneId(); T result; if (offsetSize > 0) - { + { // Sum is calculated inclusive of this lanes value result = val; - for (int i = 1; i < offsetSize; i += i) + for (int i = 1; i < offsetSize; i += i) { const T readVal = __shfl_up_sync(mask, result, i, offsetSize); if (laneId >= i) @@ -1814,7 +2730,7 @@ __device__ T _wavePrefixInvertableScalar(WarpMask mask, T val) // Remove val from the result, by applyin inverse result = INTF::doInverse(result, val); } - else + else { result = INTF::getInitial(val); if (!_waveIsSingleLane(mask)) @@ -1823,9 +2739,9 @@ __device__ T _wavePrefixInvertableScalar(WarpMask mask, T val) while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) const T readValue = __shfl_sync(mask, val, srcLane); // Only accumulate if srcLane is less than this lane if (srcLane < laneId) @@ -1834,27 +2750,28 @@ __device__ T _wavePrefixInvertableScalar(WarpMask mask, T val) } remaining &= ~laneBit; } - } + } } return result; } - + // This implementation separately tracks the value to be propogated, and the value -// that is the final result -template +// that is the final result +template __device__ T _wavePrefixScalar(WarpMask mask, T val) { const int offsetSize = _waveCalcPow2Offset(mask); - + const int laneId = _getLaneId(); - T result = INTF::getInitial(val); + T result = INTF::getInitial(val); if (offsetSize > 0) - { + { // For transmitted value we will do it inclusively with this lanes value - // For the result we do not include the lanes value. This means an extra multiply for each iteration - // but means we don't need to have a divide at the end and also removes overflow issues in that scenario. - for (int i = 1; i < offsetSize; i += i) + // For the result we do not include the lanes value. This means an extra multiply for each + // iteration but means we don't need to have a divide at the end and also removes overflow + // issues in that scenario. + for (int i = 1; i < offsetSize; i += i) { const T readVal = __shfl_up_sync(mask, val, i, offsetSize); if (laneId >= i) @@ -1864,7 +2781,7 @@ __device__ T _wavePrefixScalar(WarpMask mask, T val) } } } - else + else { if (!_waveIsSingleLane(mask)) { @@ -1872,9 +2789,9 @@ __device__ T _wavePrefixScalar(WarpMask mask, T val) while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) const T readValue = __shfl_sync(mask, val, srcLane); // Only accumulate if srcLane is less than this lane if (srcLane < laneId) @@ -1889,51 +2806,51 @@ __device__ T _wavePrefixScalar(WarpMask mask, T val) } -template +template __device__ T _waveOpCopy(T* dst, const T* src) { for (size_t j = 0; j < COUNT; ++j) { dst[j] = src[j]; } -} +} -template +template __device__ T _waveOpDoInverse(T* inOut, const T* val) { for (size_t j = 0; j < COUNT; ++j) { inOut[j] = INTF::doInverse(inOut[j], val[j]); } -} +} -template +template __device__ T _waveOpSetInitial(T* out, const T* val) { for (size_t j = 0; j < COUNT; ++j) { out[j] = INTF::getInitial(val[j]); } -} +} -template +template __device__ T _wavePrefixInvertableMultiple(WarpMask mask, T* val) { const int offsetSize = _waveCalcPow2Offset(mask); - + const int laneId = _getLaneId(); T originalVal[COUNT]; _waveOpCopy(originalVal, val); - + if (offsetSize > 0) - { + { // Sum is calculated inclusive of this lanes value - for (int i = 1; i < offsetSize; i += i) + for (int i = 1; i < offsetSize; i += i) { // TODO(JS): Note that here I don't split the laneId outside so it's only tested once. - // This may be better but it would also mean that there would be shfl between lanes - // that are on different (albeit identical) instructions. So this seems more likely to + // This may be better but it would also mean that there would be shfl between lanes + // that are on different (albeit identical) instructions. So this seems more likely to // work as expected with everything in lock step. for (size_t j = 0; j < COUNT; ++j) { @@ -1947,7 +2864,7 @@ __device__ T _wavePrefixInvertableMultiple(WarpMask mask, T* val) // Remove originalVal from the result, by applyin inverse _waveOpDoInverse(val, originalVal); } - else + else { _waveOpSetInitial(val, val); if (!_waveIsSingleLane(mask)) @@ -1956,12 +2873,12 @@ __device__ T _wavePrefixInvertableMultiple(WarpMask mask, T* val) while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - + for (size_t j = 0; j < COUNT; ++j) { - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) const T readValue = __shfl_sync(mask, originalVal[j], srcLane); // Only accumulate if srcLane is less than this lane if (srcLane < laneId) @@ -1971,27 +2888,28 @@ __device__ T _wavePrefixInvertableMultiple(WarpMask mask, T* val) remaining &= ~laneBit; } } - } + } } } - -template + +template __device__ T _wavePrefixMultiple(WarpMask mask, T* val) { const int offsetSize = _waveCalcPow2Offset(mask); - + const int laneId = _getLaneId(); - + T work[COUNT]; _waveOpCopy(work, val); _waveOpSetInitial(val, val); - + if (offsetSize > 0) - { + { // For transmitted value we will do it inclusively with this lanes value - // For the result we do not include the lanes value. This means an extra op for each iteration - // but means we don't need to have a divide at the end and also removes overflow issues in that scenario. - for (int i = 1; i < offsetSize; i += i) + // For the result we do not include the lanes value. This means an extra op for each + // iteration but means we don't need to have a divide at the end and also removes overflow + // issues in that scenario. + for (int i = 1; i < offsetSize; i += i) { for (size_t j = 0; j < COUNT; ++j) { @@ -1999,12 +2917,12 @@ __device__ T _wavePrefixMultiple(WarpMask mask, T* val) if (laneId >= i) { work[j] = INTF::doOp(work[j], readVal); - val[j] = INTF::doOp(val[j], readVal); + val[j] = INTF::doOp(val[j], readVal); } } } } - else + else { if (!_waveIsSingleLane(mask)) { @@ -2012,12 +2930,12 @@ __device__ T _wavePrefixMultiple(WarpMask mask, T* val) while (remaining) { const int laneBit = remaining & -remaining; - // Get the sourceLane + // Get the sourceLane const int srcLane = __ffs(laneBit) - 1; - + for (size_t j = 0; j < COUNT; ++j) { - // Broadcast (can also broadcast to self) + // Broadcast (can also broadcast to self) const T readValue = __shfl_sync(mask, work[j], srcLane); // Only accumulate if srcLane is less than this lane if (srcLane < laneId) @@ -2031,71 +2949,96 @@ __device__ T _wavePrefixMultiple(WarpMask mask, T* val) } } -template -__inline__ __device__ T _wavePrefixProduct(WarpMask mask, T val) { return _wavePrefixScalar, T>(mask, val); } - -template -__inline__ __device__ T _wavePrefixSum(WarpMask mask, T val) { return _wavePrefixInvertableScalar, T>(mask, val); } - -template -__inline__ __device__ T _wavePrefixXor(WarpMask mask, T val) { return _wavePrefixInvertableScalar, T>(mask, val); } - -template -__inline__ __device__ T _wavePrefixOr(WarpMask mask, T val) { return _wavePrefixScalar, T>(mask, val); } - -template -__inline__ __device__ T _wavePrefixAnd(WarpMask mask, T val) { return _wavePrefixScalar, T>(mask, val); } - - -template -__inline__ __device__ T _wavePrefixProductMultiple(WarpMask mask, T val) -{ - typedef typename ElementTypeTrait::Type ElemType; - _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>(mask, (ElemType*)&val); +template +__inline__ __device__ T _wavePrefixProduct(WarpMask mask, T val) +{ + return _wavePrefixScalar, T>(mask, val); +} + +template +__inline__ __device__ T _wavePrefixSum(WarpMask mask, T val) +{ + return _wavePrefixInvertableScalar, T>(mask, val); +} + +template +__inline__ __device__ T _wavePrefixXor(WarpMask mask, T val) +{ + return _wavePrefixInvertableScalar, T>(mask, val); +} + +template +__inline__ __device__ T _wavePrefixOr(WarpMask mask, T val) +{ + return _wavePrefixScalar, T>(mask, val); +} + +template +__inline__ __device__ T _wavePrefixAnd(WarpMask mask, T val) +{ + return _wavePrefixScalar, T>(mask, val); +} + + +template +__inline__ __device__ T _wavePrefixProductMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>( + mask, + (ElemType*)&val); return val; } -template -__inline__ __device__ T _wavePrefixSumMultiple(WarpMask mask, T val) -{ - typedef typename ElementTypeTrait::Type ElemType; - _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>(mask, (ElemType*)&val); +template +__inline__ __device__ T _wavePrefixSumMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>( + mask, + (ElemType*)&val); return val; } -template -__inline__ __device__ T _wavePrefixXorMultiple(WarpMask mask, T val) -{ - typedef typename ElementTypeTrait::Type ElemType; - _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>(mask, (ElemType*)&val); +template +__inline__ __device__ T _wavePrefixXorMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _wavePrefixInvertableMultiple, ElemType, sizeof(T) / sizeof(ElemType)>( + mask, + (ElemType*)&val); return val; } -template -__inline__ __device__ T _wavePrefixOrMultiple(WarpMask mask, T val) -{ - typedef typename ElementTypeTrait::Type ElemType; - _wavePrefixMultiple, ElemType, sizeof(T) / sizeof(ElemType)>(mask, (ElemType*)&val); +template +__inline__ __device__ T _wavePrefixOrMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _wavePrefixMultiple, ElemType, sizeof(T) / sizeof(ElemType)>( + mask, + (ElemType*)&val); return val; } -template -__inline__ __device__ T _wavePrefixAndMultiple(WarpMask mask, T val) -{ - typedef typename ElementTypeTrait::Type ElemType; - _wavePrefixMultiple, ElemType, sizeof(T) / sizeof(ElemType)>(mask, (ElemType*)&val); +template +__inline__ __device__ T _wavePrefixAndMultiple(WarpMask mask, T val) +{ + typedef typename ElementTypeTrait::Type ElemType; + _wavePrefixMultiple, ElemType, sizeof(T) / sizeof(ElemType)>( + mask, + (ElemType*)&val); return val; } -template -__inline__ __device__ uint4 _waveMatchScalar(WarpMask mask, T val) +template +__inline__ __device__ uint4 _waveMatchScalar(WarpMask mask, T val) { int pred; return make_uint4(__match_all_sync(mask, val, &pred), 0, 0, 0); } -template -__inline__ __device__ uint4 _waveMatchMultiple(WarpMask mask, const T& inVal) +template +__inline__ __device__ uint4 _waveMatchMultiple(WarpMask mask, const T& inVal) { typedef typename ElementTypeTrait::Type ElemType; const size_t count = sizeof(T) / sizeof(ElemType); @@ -2109,7 +3052,7 @@ __inline__ __device__ uint4 _waveMatchMultiple(WarpMask mask, const T& inVal) return make_uint4(matchBits, 0, 0, 0); } -__device__ uint getAt(dim3 a, int b) +__device__ uint getAt(dim3 a, int b) { SLANG_PRELUDE_ASSERT(b >= 0 && b < 3); return (&a.x)[b]; @@ -2132,8 +3075,9 @@ __inline__ __device__ TResult slang_bit_cast(TInput val) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* Type that defines the uniform entry point params. The actual content of this type is dependent on the entry point parameters, and can be -found via reflection or defined such that it matches the shader appropriately. +/* Type that defines the uniform entry point params. The actual content of this type is dependent on +the entry point parameters, and can be found via reflection or defined such that it matches the +shader appropriately. */ struct UniformEntryPointParams; struct UniformState; @@ -2143,28 +3087,29 @@ struct UniformState; struct RayDesc { float3 Origin; - float TMin; + float TMin; float3 Direction; - float TMax; + float TMax; }; -static __forceinline__ __device__ -void *unpackOptiXRayPayloadPointer(uint32_t i0, uint32_t i1) +static __forceinline__ __device__ void* unpackOptiXRayPayloadPointer(uint32_t i0, uint32_t i1) { const uint64_t uptr = static_cast(i0) << 32 | i1; - void* ptr = reinterpret_cast(uptr); + void* ptr = reinterpret_cast(uptr); return ptr; } -static __forceinline__ __device__ -void packOptiXRayPayloadPointer(void* ptr, uint32_t& i0, uint32_t& i1) +static __forceinline__ __device__ void packOptiXRayPayloadPointer( + void* ptr, + uint32_t& i0, + uint32_t& i1) { const uint64_t uptr = reinterpret_cast(ptr); i0 = uptr >> 32; i1 = uptr & 0x00000000ffffffff; } -static __forceinline__ __device__ void *getOptiXRayPayloadPtr() +static __forceinline__ __device__ void* getOptiXRayPayloadPtr() { const uint32_t u0 = optixGetPayload_0(); const uint32_t u1 = optixGetPayload_1(); @@ -2172,7 +3117,7 @@ static __forceinline__ __device__ void *getOptiXRayPayloadPtr() } template -__forceinline__ __device__ void *traceOptiXRay( +__forceinline__ __device__ void* traceOptiXRay( OptixTraversableHandle AccelerationStructure, uint32_t RayFlags, uint32_t InstanceInclusionMask, @@ -2180,8 +3125,8 @@ __forceinline__ __device__ void *traceOptiXRay( uint32_t MultiplierForGeometryContributionToHitGroupIndex, uint32_t MissShaderIndex, RayDesc Ray, - T *Payload -) { + T* Payload) +{ uint32_t r0, r1; packOptiXRayPayloadPointer((void*)Payload, r0, r1); optixTrace( @@ -2196,8 +3141,8 @@ __forceinline__ __device__ void *traceOptiXRay( RayContributionToHitGroupIndex, MultiplierForGeometryContributionToHitGroupIndex, MissShaderIndex, - r0, r1 - ); + r0, + r1); } #endif @@ -2242,7 +3187,8 @@ struct TensorView template __device__ T* data_ptr_at(uint4 index) { - uint64_t offset = strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + strides[3] * index.w; + uint64_t offset = strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + + strides[3] * index.w; return reinterpret_cast(data + offset); } @@ -2280,22 +3226,28 @@ struct TensorView template __device__ T& load(uint3 index) { - return *reinterpret_cast(data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z); + return *reinterpret_cast( + data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z); } template __device__ T& load(uint32_t x, uint32_t y, uint32_t z, uint32_t w) { - return *reinterpret_cast(data + strides[0] * x + strides[1] * y + strides[2] * z + strides[3] * w); + return *reinterpret_cast( + data + strides[0] * x + strides[1] * y + strides[2] * z + strides[3] * w); } template __device__ T& load(uint4 index) { - return *reinterpret_cast(data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + strides[3] * index.w); + return *reinterpret_cast( + data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + + strides[3] * index.w); } template __device__ T& load(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4) { - return *reinterpret_cast(data + strides[0] * i0 + strides[1] * i1 + strides[2] * i2 + strides[3] * i3 + strides[4] * i4); + return *reinterpret_cast( + data + strides[0] * i0 + strides[1] * i1 + strides[2] * i2 + strides[3] * i3 + + strides[4] * i4); } // Generic version of load @@ -2333,7 +3285,8 @@ struct TensorView template __device__ void store(uint3 index, T val) { - *reinterpret_cast(data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z) = val; + *reinterpret_cast( + data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z) = val; } template __device__ void store(uint32_t x, uint32_t y, uint32_t z, uint32_t w, T val) @@ -2344,12 +3297,16 @@ struct TensorView template __device__ void store(uint4 index, T val) { - *reinterpret_cast(data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + strides[3] * index.w) = val; + *reinterpret_cast( + data + strides[0] * index.x + strides[1] * index.y + strides[2] * index.z + + strides[3] * index.w) = val; } template __device__ void store(uint32_t i0, uint32_t i1, uint32_t i2, uint32_t i3, uint32_t i4, T val) { - *reinterpret_cast(data + strides[0] * i0 + strides[1] * i1 + strides[2] * i2 + strides[3] * i3 + strides[4] * i4) = val; + *reinterpret_cast( + data + strides[0] * i0 + strides[1] * i1 + strides[2] * i2 + strides[3] * i3 + + strides[4] * i4) = val; } // Generic version diff --git a/prelude/slang-hlsl-prelude.h b/prelude/slang-hlsl-prelude.h index d892f228c5..8e77201f98 100644 --- a/prelude/slang-hlsl-prelude.h +++ b/prelude/slang-hlsl-prelude.h @@ -3,6 +3,6 @@ #endif #ifndef __DXC_VERSION_MAJOR - // warning X3557: loop doesn't seem to do anything, forcing loop to unroll - #pragma warning(disable: 3557) +// warning X3557: loop doesn't seem to do anything, forcing loop to unroll +#pragma warning(disable : 3557) #endif diff --git a/prelude/slang-llvm.h b/prelude/slang-llvm.h index b413805810..e0bbbd14a9 100644 --- a/prelude/slang-llvm.h +++ b/prelude/slang-llvm.h @@ -1,46 +1,54 @@ #ifndef SLANG_LLVM_H #define SLANG_LLVM_H -// TODO(JS): +// TODO(JS): // Disable exception declspecs, as not supported on LLVM without some extra options. // We could enable with `-fms-extensions` #define SLANG_DISABLE_EXCEPTIONS 1 #ifndef SLANG_PRELUDE_ASSERT -# ifdef SLANG_PRELUDE_ENABLE_ASSERT +#ifdef SLANG_PRELUDE_ENABLE_ASSERT extern "C" void assertFailure(const char* msg); -# define SLANG_PRELUDE_EXPECT(VALUE, MSG) if(VALUE) {} else assertFailure("assertion failed: '" MSG "'") -# define SLANG_PRELUDE_ASSERT(VALUE) SLANG_PRELUDE_EXPECT(VALUE, #VALUE) -# else // SLANG_PRELUDE_ENABLE_ASSERT -# define SLANG_PRELUDE_EXPECT(VALUE, MSG) -# define SLANG_PRELUDE_ASSERT(x) -# endif // SLANG_PRELUDE_ENABLE_ASSERT +#define SLANG_PRELUDE_EXPECT(VALUE, MSG) \ + if (VALUE) \ + { \ + } \ + else \ + assertFailure("assertion failed: '" MSG "'") +#define SLANG_PRELUDE_ASSERT(VALUE) SLANG_PRELUDE_EXPECT(VALUE, #VALUE) +#else // SLANG_PRELUDE_ENABLE_ASSERT +#define SLANG_PRELUDE_EXPECT(VALUE, MSG) +#define SLANG_PRELUDE_ASSERT(x) +#endif // SLANG_PRELUDE_ENABLE_ASSERT #endif /* -Taken from stddef.h +Taken from stddef.h */ typedef __PTRDIFF_TYPE__ ptrdiff_t; typedef __SIZE_TYPE__ size_t; typedef __SIZE_TYPE__ rsize_t; -//typedef __WCHAR_TYPE__ wchar_t; +// typedef __WCHAR_TYPE__ wchar_t; #if defined(__need_NULL) #undef NULL #ifdef __cplusplus -# if !defined(__MINGW32__) && !defined(_MSC_VER) -# define NULL __null -# else -# define NULL 0 -# endif +#if !defined(__MINGW32__) && !defined(_MSC_VER) +#define NULL __null #else -# define NULL ((void*)0) +#define NULL 0 +#endif +#else +#define NULL ((void*)0) #endif #ifdef __cplusplus #if defined(_MSC_EXTENSIONS) && defined(_NATIVE_NULLPTR_SUPPORTED) -namespace std { typedef decltype(nullptr) nullptr_t; } +namespace std +{ +typedef decltype(nullptr) nullptr_t; +} using ::std::nullptr_t; #endif #endif @@ -49,18 +57,18 @@ using ::std::nullptr_t; /* -The following are taken verbatim from stdint.h from Clang in LLVM. Only 8/16/32/64 types are needed. +The following are taken verbatim from stdint.h from Clang in LLVM. Only 8/16/32/64 types are needed. */ // LLVM/Clang types such that we can use LLVM/Clang without headers for C++ output from Slang #ifdef __INT64_TYPE__ -# ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/ +#ifndef __int8_t_defined /* glibc sys/types.h also defines int64_t*/ typedef __INT64_TYPE__ int64_t; -# endif /* __int8_t_defined */ +#endif /* __int8_t_defined */ typedef __UINT64_TYPE__ uint64_t; -# define __int_least64_t int64_t -# define __uint_least64_t uint64_t +#define __int_least64_t int64_t +#define __uint_least64_t uint64_t #endif /* __INT64_TYPE__ */ #ifdef __int_least64_t @@ -72,17 +80,17 @@ typedef __uint_least64_t uint_fast64_t; #ifdef __INT32_TYPE__ -# ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/ +#ifndef __int8_t_defined /* glibc sys/types.h also defines int32_t*/ typedef __INT32_TYPE__ int32_t; -# endif /* __int8_t_defined */ +#endif /* __int8_t_defined */ -# ifndef __uint32_t_defined /* more glibc compatibility */ -# define __uint32_t_defined +#ifndef __uint32_t_defined /* more glibc compatibility */ +#define __uint32_t_defined typedef __UINT32_TYPE__ uint32_t; -# endif /* __uint32_t_defined */ +#endif /* __uint32_t_defined */ -# define __int_least32_t int32_t -# define __uint_least32_t uint32_t +#define __int_least32_t int32_t +#define __uint_least32_t uint32_t #endif /* __INT32_TYPE__ */ #ifdef __int_least32_t @@ -97,8 +105,8 @@ typedef __uint_least32_t uint_fast32_t; typedef __INT16_TYPE__ int16_t; #endif /* __int8_t_defined */ typedef __UINT16_TYPE__ uint16_t; -# define __int_least16_t int16_t -# define __uint_least16_t uint16_t +#define __int_least16_t int16_t +#define __uint_least16_t uint16_t #endif /* __INT16_TYPE__ */ #ifdef __int_least16_t @@ -109,12 +117,12 @@ typedef __uint_least16_t uint_fast16_t; #endif /* __int_least16_t */ #ifdef __INT8_TYPE__ -#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/ +#ifndef __int8_t_defined /* glibc sys/types.h also defines int8_t*/ typedef __INT8_TYPE__ int8_t; #endif /* __int8_t_defined */ typedef __UINT8_TYPE__ uint8_t; -# define __int_least8_t int8_t -# define __uint_least8_t uint8_t +#define __int_least8_t int8_t +#define __uint_least8_t uint8_t #endif /* __INT8_TYPE__ */ #ifdef __int_least8_t @@ -126,12 +134,12 @@ typedef __uint_least8_t uint_fast8_t; /* prevent glibc sys/types.h from defining conflicting types */ #ifndef __int8_t_defined -# define __int8_t_defined +#define __int8_t_defined #endif /* __int8_t_defined */ /* C99 7.18.1.4 Integer types capable of holding object pointers. */ -#define __stdint_join3(a,b,c) a ## b ## c +#define __stdint_join3(a, b, c) a##b##c #ifndef _INTPTR_T #ifndef __intptr_t_defined @@ -148,7 +156,7 @@ typedef __UINTPTR_TYPE__ uintptr_t; /* C99 7.18.1.5 Greatest-width integer types. */ -typedef __INTMAX_TYPE__ intmax_t; +typedef __INTMAX_TYPE__ intmax_t; typedef __UINTMAX_TYPE__ uintmax_t; /* C99 7.18.4 Macros for minimum-width integer constants. @@ -168,82 +176,82 @@ typedef __UINTMAX_TYPE__ uintmax_t; * claims of the C standard (see C++ 18.3.1p2, [cstdint.syn]). */ -#define __int_c_join(a, b) a ## b +#define __int_c_join(a, b) a##b #define __int_c(v, suffix) __int_c_join(v, suffix) #define __uint_c(v, suffix) __int_c_join(v##U, suffix) #ifdef __INT64_TYPE__ -# ifdef __INT64_C_SUFFIX__ -# define __int64_c_suffix __INT64_C_SUFFIX__ -# else -# undef __int64_c_suffix -# endif /* __INT64_C_SUFFIX__ */ +#ifdef __INT64_C_SUFFIX__ +#define __int64_c_suffix __INT64_C_SUFFIX__ +#else +#undef __int64_c_suffix +#endif /* __INT64_C_SUFFIX__ */ #endif /* __INT64_TYPE__ */ #ifdef __int_least64_t -# ifdef __int64_c_suffix -# define INT64_C(v) __int_c(v, __int64_c_suffix) -# define UINT64_C(v) __uint_c(v, __int64_c_suffix) -# else -# define INT64_C(v) v -# define UINT64_C(v) v ## U -# endif /* __int64_c_suffix */ +#ifdef __int64_c_suffix +#define INT64_C(v) __int_c(v, __int64_c_suffix) +#define UINT64_C(v) __uint_c(v, __int64_c_suffix) +#else +#define INT64_C(v) v +#define UINT64_C(v) v##U +#endif /* __int64_c_suffix */ #endif /* __int_least64_t */ #ifdef __INT32_TYPE__ -# ifdef __INT32_C_SUFFIX__ -# define __int32_c_suffix __INT32_C_SUFFIX__ +#ifdef __INT32_C_SUFFIX__ +#define __int32_c_suffix __INT32_C_SUFFIX__ #else -# undef __int32_c_suffix -# endif /* __INT32_C_SUFFIX__ */ +#undef __int32_c_suffix +#endif /* __INT32_C_SUFFIX__ */ #endif /* __INT32_TYPE__ */ #ifdef __int_least32_t -# ifdef __int32_c_suffix -# define INT32_C(v) __int_c(v, __int32_c_suffix) -# define UINT32_C(v) __uint_c(v, __int32_c_suffix) -# else -# define INT32_C(v) v -# define UINT32_C(v) v ## U -# endif /* __int32_c_suffix */ +#ifdef __int32_c_suffix +#define INT32_C(v) __int_c(v, __int32_c_suffix) +#define UINT32_C(v) __uint_c(v, __int32_c_suffix) +#else +#define INT32_C(v) v +#define UINT32_C(v) v##U +#endif /* __int32_c_suffix */ #endif /* __int_least32_t */ #ifdef __INT16_TYPE__ -# ifdef __INT16_C_SUFFIX__ -# define __int16_c_suffix __INT16_C_SUFFIX__ +#ifdef __INT16_C_SUFFIX__ +#define __int16_c_suffix __INT16_C_SUFFIX__ #else -# undef __int16_c_suffix -# endif /* __INT16_C_SUFFIX__ */ +#undef __int16_c_suffix +#endif /* __INT16_C_SUFFIX__ */ #endif /* __INT16_TYPE__ */ #ifdef __int_least16_t -# ifdef __int16_c_suffix -# define INT16_C(v) __int_c(v, __int16_c_suffix) -# define UINT16_C(v) __uint_c(v, __int16_c_suffix) -# else -# define INT16_C(v) v -# define UINT16_C(v) v ## U -# endif /* __int16_c_suffix */ +#ifdef __int16_c_suffix +#define INT16_C(v) __int_c(v, __int16_c_suffix) +#define UINT16_C(v) __uint_c(v, __int16_c_suffix) +#else +#define INT16_C(v) v +#define UINT16_C(v) v##U +#endif /* __int16_c_suffix */ #endif /* __int_least16_t */ #ifdef __INT8_TYPE__ -# ifdef __INT8_C_SUFFIX__ -# define __int8_c_suffix __INT8_C_SUFFIX__ +#ifdef __INT8_C_SUFFIX__ +#define __int8_c_suffix __INT8_C_SUFFIX__ #else -# undef __int8_c_suffix -# endif /* __INT8_C_SUFFIX__ */ +#undef __int8_c_suffix +#endif /* __INT8_C_SUFFIX__ */ #endif /* __INT8_TYPE__ */ #ifdef __int_least8_t -# ifdef __int8_c_suffix -# define INT8_C(v) __int_c(v, __int8_c_suffix) -# define UINT8_C(v) __uint_c(v, __int8_c_suffix) -# else -# define INT8_C(v) v -# define UINT8_C(v) v ## U -# endif /* __int8_c_suffix */ +#ifdef __int8_c_suffix +#define INT8_C(v) __int_c(v, __int8_c_suffix) +#define UINT8_C(v) __uint_c(v, __int8_c_suffix) +#else +#define INT8_C(v) v +#define UINT8_C(v) v##U +#endif /* __int8_c_suffix */ #endif /* __int_least8_t */ /* C99 7.18.2.1 Limits of exact-width integer types. @@ -266,133 +274,131 @@ typedef __UINTMAX_TYPE__ uintmax_t; */ #ifdef __INT64_TYPE__ -# define INT64_MAX INT64_C( 9223372036854775807) -# define INT64_MIN (-INT64_C( 9223372036854775807)-1) -# define UINT64_MAX UINT64_C(18446744073709551615) -# define __INT_LEAST64_MIN INT64_MIN -# define __INT_LEAST64_MAX INT64_MAX -# define __UINT_LEAST64_MAX UINT64_MAX +#define INT64_MAX INT64_C(9223372036854775807) +#define INT64_MIN (-INT64_C(9223372036854775807) - 1) +#define UINT64_MAX UINT64_C(18446744073709551615) +#define __INT_LEAST64_MIN INT64_MIN +#define __INT_LEAST64_MAX INT64_MAX +#define __UINT_LEAST64_MAX UINT64_MAX #endif /* __INT64_TYPE__ */ #ifdef __INT_LEAST64_MIN -# define INT_LEAST64_MIN __INT_LEAST64_MIN -# define INT_LEAST64_MAX __INT_LEAST64_MAX -# define UINT_LEAST64_MAX __UINT_LEAST64_MAX -# define INT_FAST64_MIN __INT_LEAST64_MIN -# define INT_FAST64_MAX __INT_LEAST64_MAX -# define UINT_FAST64_MAX __UINT_LEAST64_MAX +#define INT_LEAST64_MIN __INT_LEAST64_MIN +#define INT_LEAST64_MAX __INT_LEAST64_MAX +#define UINT_LEAST64_MAX __UINT_LEAST64_MAX +#define INT_FAST64_MIN __INT_LEAST64_MIN +#define INT_FAST64_MAX __INT_LEAST64_MAX +#define UINT_FAST64_MAX __UINT_LEAST64_MAX #endif /* __INT_LEAST64_MIN */ #ifdef __INT32_TYPE__ -# define INT32_MAX INT32_C(2147483647) -# define INT32_MIN (-INT32_C(2147483647)-1) -# define UINT32_MAX UINT32_C(4294967295) -# define __INT_LEAST32_MIN INT32_MIN -# define __INT_LEAST32_MAX INT32_MAX -# define __UINT_LEAST32_MAX UINT32_MAX +#define INT32_MAX INT32_C(2147483647) +#define INT32_MIN (-INT32_C(2147483647) - 1) +#define UINT32_MAX UINT32_C(4294967295) +#define __INT_LEAST32_MIN INT32_MIN +#define __INT_LEAST32_MAX INT32_MAX +#define __UINT_LEAST32_MAX UINT32_MAX #endif /* __INT32_TYPE__ */ #ifdef __INT_LEAST32_MIN -# define INT_LEAST32_MIN __INT_LEAST32_MIN -# define INT_LEAST32_MAX __INT_LEAST32_MAX -# define UINT_LEAST32_MAX __UINT_LEAST32_MAX -# define INT_FAST32_MIN __INT_LEAST32_MIN -# define INT_FAST32_MAX __INT_LEAST32_MAX -# define UINT_FAST32_MAX __UINT_LEAST32_MAX +#define INT_LEAST32_MIN __INT_LEAST32_MIN +#define INT_LEAST32_MAX __INT_LEAST32_MAX +#define UINT_LEAST32_MAX __UINT_LEAST32_MAX +#define INT_FAST32_MIN __INT_LEAST32_MIN +#define INT_FAST32_MAX __INT_LEAST32_MAX +#define UINT_FAST32_MAX __UINT_LEAST32_MAX #endif /* __INT_LEAST32_MIN */ #ifdef __INT16_TYPE__ -#define INT16_MAX INT16_C(32767) -#define INT16_MIN (-INT16_C(32767)-1) -#define UINT16_MAX UINT16_C(65535) -# define __INT_LEAST16_MIN INT16_MIN -# define __INT_LEAST16_MAX INT16_MAX -# define __UINT_LEAST16_MAX UINT16_MAX +#define INT16_MAX INT16_C(32767) +#define INT16_MIN (-INT16_C(32767) - 1) +#define UINT16_MAX UINT16_C(65535) +#define __INT_LEAST16_MIN INT16_MIN +#define __INT_LEAST16_MAX INT16_MAX +#define __UINT_LEAST16_MAX UINT16_MAX #endif /* __INT16_TYPE__ */ #ifdef __INT_LEAST16_MIN -# define INT_LEAST16_MIN __INT_LEAST16_MIN -# define INT_LEAST16_MAX __INT_LEAST16_MAX -# define UINT_LEAST16_MAX __UINT_LEAST16_MAX -# define INT_FAST16_MIN __INT_LEAST16_MIN -# define INT_FAST16_MAX __INT_LEAST16_MAX -# define UINT_FAST16_MAX __UINT_LEAST16_MAX +#define INT_LEAST16_MIN __INT_LEAST16_MIN +#define INT_LEAST16_MAX __INT_LEAST16_MAX +#define UINT_LEAST16_MAX __UINT_LEAST16_MAX +#define INT_FAST16_MIN __INT_LEAST16_MIN +#define INT_FAST16_MAX __INT_LEAST16_MAX +#define UINT_FAST16_MAX __UINT_LEAST16_MAX #endif /* __INT_LEAST16_MIN */ #ifdef __INT8_TYPE__ -# define INT8_MAX INT8_C(127) -# define INT8_MIN (-INT8_C(127)-1) -# define UINT8_MAX UINT8_C(255) -# define __INT_LEAST8_MIN INT8_MIN -# define __INT_LEAST8_MAX INT8_MAX -# define __UINT_LEAST8_MAX UINT8_MAX +#define INT8_MAX INT8_C(127) +#define INT8_MIN (-INT8_C(127) - 1) +#define UINT8_MAX UINT8_C(255) +#define __INT_LEAST8_MIN INT8_MIN +#define __INT_LEAST8_MAX INT8_MAX +#define __UINT_LEAST8_MAX UINT8_MAX #endif /* __INT8_TYPE__ */ #ifdef __INT_LEAST8_MIN -# define INT_LEAST8_MIN __INT_LEAST8_MIN -# define INT_LEAST8_MAX __INT_LEAST8_MAX -# define UINT_LEAST8_MAX __UINT_LEAST8_MAX -# define INT_FAST8_MIN __INT_LEAST8_MIN -# define INT_FAST8_MAX __INT_LEAST8_MAX -# define UINT_FAST8_MAX __UINT_LEAST8_MAX +#define INT_LEAST8_MIN __INT_LEAST8_MIN +#define INT_LEAST8_MAX __INT_LEAST8_MAX +#define UINT_LEAST8_MAX __UINT_LEAST8_MAX +#define INT_FAST8_MIN __INT_LEAST8_MIN +#define INT_FAST8_MAX __INT_LEAST8_MAX +#define UINT_FAST8_MAX __UINT_LEAST8_MAX #endif /* __INT_LEAST8_MIN */ /* Some utility macros */ -#define __INTN_MIN(n) __stdint_join3( INT, n, _MIN) -#define __INTN_MAX(n) __stdint_join3( INT, n, _MAX) -#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX) -#define __INTN_C(n, v) __stdint_join3( INT, n, _C(v)) +#define __INTN_MIN(n) __stdint_join3(INT, n, _MIN) +#define __INTN_MAX(n) __stdint_join3(INT, n, _MAX) +#define __UINTN_MAX(n) __stdint_join3(UINT, n, _MAX) +#define __INTN_C(n, v) __stdint_join3(INT, n, _C(v)) #define __UINTN_C(n, v) __stdint_join3(UINT, n, _C(v)) /* C99 7.18.2.4 Limits of integer types capable of holding object pointers. */ /* C99 7.18.3 Limits of other integer types. */ -#define INTPTR_MIN (-__INTPTR_MAX__-1) -#define INTPTR_MAX __INTPTR_MAX__ -#define UINTPTR_MAX __UINTPTR_MAX__ -#define PTRDIFF_MIN (-__PTRDIFF_MAX__-1) -#define PTRDIFF_MAX __PTRDIFF_MAX__ -#define SIZE_MAX __SIZE_MAX__ +#define INTPTR_MIN (-__INTPTR_MAX__ - 1) +#define INTPTR_MAX __INTPTR_MAX__ +#define UINTPTR_MAX __UINTPTR_MAX__ +#define PTRDIFF_MIN (-__PTRDIFF_MAX__ - 1) +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ /* ISO9899:2011 7.20 (C11 Annex K): Define RSIZE_MAX if __STDC_WANT_LIB_EXT1__ * is enabled. */ #if defined(__STDC_WANT_LIB_EXT1__) && __STDC_WANT_LIB_EXT1__ >= 1 -#define RSIZE_MAX (SIZE_MAX >> 1) +#define RSIZE_MAX (SIZE_MAX >> 1) #endif /* C99 7.18.2.5 Limits of greatest-width integer types. */ -#define INTMAX_MIN (-__INTMAX_MAX__-1) -#define INTMAX_MAX __INTMAX_MAX__ -#define UINTMAX_MAX __UINTMAX_MAX__ +#define INTMAX_MIN (-__INTMAX_MAX__ - 1) +#define INTMAX_MAX __INTMAX_MAX__ +#define UINTMAX_MAX __UINTMAX_MAX__ /* C99 7.18.3 Limits of other integer types. */ #define SIG_ATOMIC_MIN __INTN_MIN(__SIG_ATOMIC_WIDTH__) #define SIG_ATOMIC_MAX __INTN_MAX(__SIG_ATOMIC_WIDTH__) #ifdef __WINT_UNSIGNED__ -# define WINT_MIN __UINTN_C(__WINT_WIDTH__, 0) -# define WINT_MAX __UINTN_MAX(__WINT_WIDTH__) +#define WINT_MIN __UINTN_C(__WINT_WIDTH__, 0) +#define WINT_MAX __UINTN_MAX(__WINT_WIDTH__) #else -# define WINT_MIN __INTN_MIN(__WINT_WIDTH__) -# define WINT_MAX __INTN_MAX(__WINT_WIDTH__) +#define WINT_MIN __INTN_MIN(__WINT_WIDTH__) +#define WINT_MAX __INTN_MAX(__WINT_WIDTH__) #endif #ifndef WCHAR_MAX -# define WCHAR_MAX __WCHAR_MAX__ +#define WCHAR_MAX __WCHAR_MAX__ #endif #ifndef WCHAR_MIN -# if __WCHAR_MAX__ == __INTN_MAX(__WCHAR_WIDTH__) -# define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__) -# else -# define WCHAR_MIN __UINTN_C(__WCHAR_WIDTH__, 0) -# endif +#if __WCHAR_MAX__ == __INTN_MAX(__WCHAR_WIDTH__) +#define WCHAR_MIN __INTN_MIN(__WCHAR_WIDTH__) +#else +#define WCHAR_MIN __UINTN_C(__WCHAR_WIDTH__, 0) +#endif #endif /* 7.18.4.2 Macros for greatest-width integer constants. */ -#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__) +#define INTMAX_C(v) __int_c(v, __INTMAX_C_SUFFIX__) #define UINTMAX_C(v) __int_c(v, __UINTMAX_C_SUFFIX__) #endif // SLANG_LLVM_H - - diff --git a/prelude/slang-torch-prelude.h b/prelude/slang-torch-prelude.h index 11ffe3b666..8ece877b6b 100644 --- a/prelude/slang-torch-prelude.h +++ b/prelude/slang-torch-prelude.h @@ -1,64 +1,70 @@ // Prelude for PyTorch cpp binding. +// clang-format off #include +// clang-format on + #include #include -#include #include #include +#include #ifdef SLANG_LLVM #include "slang-llvm.h" #else // SLANG_LLVM -# if SLANG_GCC_FAMILY && __GNUC__ < 6 -# include -# define SLANG_PRELUDE_STD std:: -# else -# include -# define SLANG_PRELUDE_STD -# endif - -# include -# include -# include -# include +#if SLANG_GCC_FAMILY && __GNUC__ < 6 +#include +#define SLANG_PRELUDE_STD std:: +#else +#include +#define SLANG_PRELUDE_STD +#endif + +#include +#include +#include +#include #endif // SLANG_LLVM #include "../source/core/slang-string.h" #if defined(_MSC_VER) -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __declspec(dllexport) #else -# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) -//# define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) __attribute__((__visibility__("default"))) -#endif - -#ifdef __cplusplus -# define SLANG_PRELUDE_EXTERN_C extern "C" -# define SLANG_PRELUDE_EXTERN_C_START extern "C" { -# define SLANG_PRELUDE_EXTERN_C_END } +#define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__((__visibility__("default"))) +// # define SLANG_PRELUDE_SHARED_LIB_EXPORT __attribute__ ((dllexport)) +// __attribute__((__visibility__("default"))) +#endif + +#ifdef __cplusplus +#define SLANG_PRELUDE_EXTERN_C extern "C" +#define SLANG_PRELUDE_EXTERN_C_START \ + extern "C" \ + { +#define SLANG_PRELUDE_EXTERN_C_END } #else -# define SLANG_PRELUDE_EXTERN_C -# define SLANG_PRELUDE_EXTERN_C_START -# define SLANG_PRELUDE_EXTERN_C_END -#endif +#define SLANG_PRELUDE_EXTERN_C +#define SLANG_PRELUDE_EXTERN_C_START +#define SLANG_PRELUDE_EXTERN_C_END +#endif #define SLANG_PRELUDE_NAMESPACE #ifndef SLANG_NO_THROW -# define SLANG_NO_THROW +#define SLANG_NO_THROW #endif #ifndef SLANG_STDCALL -# define SLANG_STDCALL +#define SLANG_STDCALL #endif #ifndef SLANG_MCALL -# define SLANG_MCALL SLANG_STDCALL +#define SLANG_MCALL SLANG_STDCALL #endif #ifndef SLANG_FORCE_INLINE -# define SLANG_FORCE_INLINE inline +#define SLANG_FORCE_INLINE inline #endif -#include "slang-cpp-types-core.h" #include "slang-cpp-scalar-intrinsics.h" +#include "slang-cpp-types-core.h" static const int kSlangTorchTensorMaxDim = 5; @@ -72,20 +78,26 @@ struct TensorView }; -TensorView make_tensor_view(torch::Tensor val, const char* name, torch::ScalarType targetScalarType, bool requireContiguous) +TensorView make_tensor_view( + torch::Tensor val, + const char* name, + torch::ScalarType targetScalarType, + bool requireContiguous) { // We're currently not trying to implicitly cast or transfer to device for two reasons: // 1. There appears to be a bug with .to() where successive calls after the first one fail. - // 2. Silent casts like this can cause large memory allocations & unexpected overheads. + // 2. Silent casts like this can cause large memory allocations & unexpected overheads. // It's better to be explicit. // Expect tensors to be on CUDA device if (!val.device().is_cuda()) - throw std::runtime_error(std::string(name).append(": tensor is not on CUDA device.").c_str()); + throw std::runtime_error( + std::string(name).append(": tensor is not on CUDA device.").c_str()); // Expect tensors to be the right type. if (val.dtype() != targetScalarType) - throw std::runtime_error(std::string(name).append(": tensor is not of the expected type.").c_str()); + throw std::runtime_error( + std::string(name).append(": tensor is not of the expected type.").c_str()); // Check that the tensor is contiguous if (requireContiguous && !val.is_contiguous()) @@ -138,14 +150,22 @@ TensorView make_tensor_view(torch::Tensor val, const char* name, torch::ScalarTy } if (val.dim() > kSlangTorchTensorMaxDim) - throw std::runtime_error(std::string(name).append(": number of dimensions exceeds limit (").append(std::to_string(kSlangTorchTensorMaxDim)).append(")").c_str()); + throw std::runtime_error(std::string(name) + .append(": number of dimensions exceeds limit (") + .append(std::to_string(kSlangTorchTensorMaxDim)) + .append(")") + .c_str()); bool isEmpty = true; for (int i = 0; i < val.dim(); ++i) { res.strides[i] = val.stride(i) * elementSize; if (res.strides[i] == 0) - throw std::runtime_error(std::string(name).append(": tensors with broadcasted dimensions are not supported (use tensor.contiguous() to make tensor whole)").c_str()); + throw std::runtime_error( + std::string(name) + .append(": tensors with broadcasted dimensions are not supported (use " + "tensor.contiguous() to make tensor whole)") + .c_str()); res.sizes[i] = val.size(i); if (res.sizes[i] > 0) diff --git a/source/compiler-core/CMakeLists.txt b/source/compiler-core/CMakeLists.txt new file mode 100644 index 0000000000..4d1bff17b1 --- /dev/null +++ b/source/compiler-core/CMakeLists.txt @@ -0,0 +1,16 @@ +slang_add_target( + . + STATIC + EXCLUDE_FROM_ALL + USE_EXTRA_WARNINGS + LINK_WITH_PRIVATE core + INCLUDE_FROM_PUBLIC SPIRV-Headers +) +if(NOT MSVC) + # This is necessary to compile the DXC headers + set_source_files_properties( + slang-dxc-compiler.cpp + PROPERTIES COMPILE_OPTIONS "-fms-extensions" + DIRECTORY ${slang_SOURCE_DIR} + ) +endif() diff --git a/source/compiler-core/slang-artifact-associated-impl.cpp b/source/compiler-core/slang-artifact-associated-impl.cpp index f29c0f596f..88ed9f665f 100644 --- a/source/compiler-core/slang-artifact-associated-impl.cpp +++ b/source/compiler-core/slang-artifact-associated-impl.cpp @@ -1,30 +1,28 @@ // slang-artifact-associated-impl.cpp #include "slang-artifact-associated-impl.h" -#include "../core/slang-file-system.h" - -#include "../core/slang-type-text-util.h" -#include "../core/slang-io.h" #include "../core/slang-array-view.h" - #include "../core/slang-char-util.h" - +#include "../core/slang-file-system.h" +#include "../core/slang-io.h" +#include "../core/slang-type-text-util.h" #include "slang-artifact-diagnostic-util.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnostics !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -ArtifactDiagnostics::ArtifactDiagnostics(const ThisType& rhs): - ComBaseObject(), - m_result(rhs.m_result), - m_diagnostics(rhs.m_diagnostics), - m_raw(rhs.m_raw.getLength() + 1) +ArtifactDiagnostics::ArtifactDiagnostics(const ThisType& rhs) + : ComBaseObject() + , m_result(rhs.m_result) + , m_diagnostics(rhs.m_diagnostics) + , m_raw(rhs.m_raw.getLength() + 1) { // We need to be careful with raw, we want a new *copy* not a non atomic ref counting // In initialization we should have enough space m_raw.append(rhs.m_raw.getUnownedSlice()); - + // Reallocate all the strings for (auto& diagnostic : m_diagnostics) { @@ -41,17 +39,15 @@ void* ArtifactDiagnostics::clone(const Guid& guid) { return ptr; } - // If the cast fails, we delete the item. + // If the cast fails, we delete the item. delete copy; return nullptr; } void* ArtifactDiagnostics::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || - guid == IClonable::getTypeGuid() || - guid == IArtifactDiagnostics::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || + guid == IClonable::getTypeGuid() || guid == IArtifactDiagnostics::getTypeGuid()) { return static_cast(this); } @@ -108,7 +104,7 @@ void ArtifactDiagnostics::appendRaw(const CharSlice& slice) m_raw << asStringSlice(slice); } -Count ArtifactDiagnostics::getCountAtLeastSeverity(Diagnostic::Severity severity) +Count ArtifactDiagnostics::getCountAtLeastSeverity(Diagnostic::Severity severity) { Index count = 0; for (const auto& msg : m_diagnostics) @@ -140,7 +136,9 @@ bool ArtifactDiagnostics::hasOfAtLeastSeverity(Diagnostic::Severity severity) return false; } -Count ArtifactDiagnostics::getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) +Count ArtifactDiagnostics::getCountByStage( + Diagnostic::Stage stage, + Count outCounts[Int(Diagnostic::Severity::CountOf)]) { Int count = 0; ::memset(outCounts, 0, sizeof(Index) * Int(Diagnostic::Severity::CountOf)); @@ -174,7 +172,7 @@ void ArtifactDiagnostics::maybeAddNote(const CharSlice& in) ArtifactDiagnosticUtil::maybeAddNote(asStringSlice(in), this); } -void ArtifactDiagnostics::requireErrorDiagnostic() +void ArtifactDiagnostics::requireErrorDiagnostic() { // If we find an error, we don't need to add a generic diagnostic for (const auto& msg : m_diagnostics) @@ -193,19 +191,25 @@ void ArtifactDiagnostics::requireErrorDiagnostic() m_diagnostics.add(diagnostic); } -/* static */UnownedStringSlice _getSeverityText(ArtifactDiagnostic::Severity severity) +/* static */ UnownedStringSlice _getSeverityText(ArtifactDiagnostic::Severity severity) { typedef ArtifactDiagnostic::Severity Severity; switch (severity) { - default: return UnownedStringSlice::fromLiteral("Unknown"); - case Severity::Info: return UnownedStringSlice::fromLiteral("Info"); - case Severity::Warning: return UnownedStringSlice::fromLiteral("Warning"); - case Severity::Error: return UnownedStringSlice::fromLiteral("Error"); + default: + return UnownedStringSlice::fromLiteral("Unknown"); + case Severity::Info: + return UnownedStringSlice::fromLiteral("Info"); + case Severity::Warning: + return UnownedStringSlice::fromLiteral("Warning"); + case Severity::Error: + return UnownedStringSlice::fromLiteral("Error"); } } -static void _appendCounts(const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], StringBuilder& out) +static void _appendCounts( + const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], + StringBuilder& out) { typedef ArtifactDiagnostic::Severity Severity; @@ -218,7 +222,9 @@ static void _appendCounts(const Index counts[Int(ArtifactDiagnostic::Severity::C } } -static void _appendSimplified(const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], StringBuilder& out) +static void _appendSimplified( + const Index counts[Int(ArtifactDiagnostic::Severity::CountOf)], + StringBuilder& out) { typedef ArtifactDiagnostic::Severity Severity; for (Index i = 0; i < Int(Severity::CountOf); i++) @@ -276,8 +282,7 @@ void ArtifactDiagnostics::calcSimplifiedSummary(ISlangBlob** outBlob) void* ArtifactPostEmitMetadata::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IArtifactPostEmitMetadata::getTypeGuid()) { return static_cast(this); @@ -304,13 +309,35 @@ void* ArtifactPostEmitMetadata::castAs(const Guid& guid) } Slice ArtifactPostEmitMetadata::getUsedBindingRanges() -{ - return Slice(m_usedBindings.getBuffer(), m_usedBindings.getCount()); +{ + return Slice(m_usedBindings.getBuffer(), m_usedBindings.getCount()); } Slice ArtifactPostEmitMetadata::getExportedFunctionMangledNames() { - return Slice(m_exportedFunctionMangledNames.getBuffer(), m_exportedFunctionMangledNames.getCount()); + return Slice( + m_exportedFunctionMangledNames.getBuffer(), + m_exportedFunctionMangledNames.getCount()); +} + +SlangResult ArtifactPostEmitMetadata::isParameterLocationUsed( + SlangParameterCategory category, + SlangUInt spaceIndex, + SlangUInt registerIndex, + bool& outUsed) +{ + for (const auto& range : getUsedBindingRanges()) + { + if (range.containsBinding((slang::ParameterCategory)category, spaceIndex, registerIndex)) + { + outUsed = true; + return SLANG_OK; + } + } + + outUsed = false; + return SLANG_OK; } + } // namespace Slang diff --git a/source/compiler-core/slang-artifact-associated-impl.h b/source/compiler-core/slang-artifact-associated-impl.h index a6e323b0a1..8a89f865b6 100644 --- a/source/compiler-core/slang-artifact-associated-impl.h +++ b/source/compiler-core/slang-artifact-associated-impl.h @@ -2,17 +2,13 @@ #ifndef SLANG_ARTIFACT_ASSOCIATED_IMPL_H #define SLANG_ARTIFACT_ASSOCIATED_IMPL_H -#include "slang-com-helper.h" -#include "slang-com-ptr.h" - #include "../core/slang-com-object.h" #include "../core/slang-memory-arena.h" - #include "slang-artifact-associated.h" - -#include "slang-artifact-util.h" - #include "slang-artifact-diagnostic-util.h" +#include "slang-artifact-util.h" +#include "slang-com-helper.h" +#include "slang-com-ptr.h" namespace Slang { @@ -29,33 +25,61 @@ class ArtifactDiagnostics : public ComBaseObject, public IArtifactDiagnostics // IClonable SLANG_NO_THROW virtual void* SLANG_MCALL clone(const Guid& intf) SLANG_OVERRIDE; // IDiagnostic - SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE { return &m_diagnostics[i]; } - SLANG_NO_THROW virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE { return m_diagnostics.getCount(); } - SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE { m_diagnostics.removeAt(i); } + SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) SLANG_OVERRIDE + { + return &m_diagnostics[i]; + } + SLANG_NO_THROW virtual Count SLANG_MCALL getCount() SLANG_OVERRIDE + { + return m_diagnostics.getCount(); + } + SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) SLANG_OVERRIDE + { + m_diagnostics.removeAt(i); + } SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() SLANG_OVERRIDE { return m_result; } - SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE { m_result = res; } + SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) SLANG_OVERRIDE + { + m_result = res; + } SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const CharSlice& slice) SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL appendRaw(const CharSlice& slice) SLANG_OVERRIDE; - SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE { return SliceUtil::asTerminatedCharSlice(m_raw); } + SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() SLANG_OVERRIDE + { + return SliceUtil::asTerminatedCharSlice(m_raw); + } SLANG_NO_THROW virtual void SLANG_MCALL reset() SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; - SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Diagnostic::Severity severity) SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) + SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) + SLANG_OVERRIDE; + SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Diagnostic::Severity severity) + SLANG_OVERRIDE; + SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage( + Diagnostic::Stage stage, + Count outCounts[Int(Diagnostic::Severity::CountOf)]) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Diagnostic::Severity severity) + SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const CharSlice& in) SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL requireErrorDiagnostic() SLANG_OVERRIDE; SLANG_NO_THROW virtual void SLANG_MCALL calcSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; - SLANG_NO_THROW virtual void SLANG_MCALL calcSimplifiedSummary(ISlangBlob** outBlob) SLANG_OVERRIDE; + SLANG_NO_THROW virtual void SLANG_MCALL calcSimplifiedSummary(ISlangBlob** outBlob) + SLANG_OVERRIDE; - /// Default ctor - ArtifactDiagnostics():ComBaseObject() {} - /// Copy ctor + /// Default ctor + ArtifactDiagnostics() + : ComBaseObject() + { + } + /// Copy ctor ArtifactDiagnostics(const ThisType& rhs); - /// Create - static ComPtr create() { return ComPtr(new ThisType); } + /// Create + static ComPtr create() + { + return ComPtr(new ThisType); + } protected: void* getInterface(const Guid& uuid); @@ -65,7 +89,7 @@ class ArtifactDiagnostics : public ComBaseObject, public IArtifactDiagnostics List m_diagnostics; SlangResult m_result = SLANG_OK; - + // Raw diagnostics StringBuilder m_raw; }; @@ -79,17 +103,14 @@ struct ShaderBindingRange UInt registerIndex = 0; UInt registerCount = 0; // 0 for unsized - bool isInfinite() const - { - return registerCount == 0; - } + bool isInfinite() const { return registerCount == 0; } - bool containsBinding(slang::ParameterCategory _category, UInt _spaceIndex, UInt _registerIndex) const + bool containsBinding(slang::ParameterCategory _category, UInt _spaceIndex, UInt _registerIndex) + const { - return category == _category - && spaceIndex == _spaceIndex - && registerIndex <= _registerIndex - && (isInfinite() || registerCount + registerIndex > _registerIndex); + return category == _category && spaceIndex == _spaceIndex && + registerIndex <= _registerIndex && + (isInfinite() || registerCount + registerIndex > _registerIndex); } bool intersectsWith(const ShaderBindingRange& other) const @@ -97,8 +118,10 @@ struct ShaderBindingRange if (category != other.category || spaceIndex != other.spaceIndex) return false; - const bool leftIntersection = (registerIndex < other.registerIndex + other.registerCount) || other.isInfinite(); - const bool rightIntersection = (other.registerIndex < registerIndex + registerCount) || isInfinite(); + const bool leftIntersection = + (registerIndex < other.registerIndex + other.registerCount) || other.isInfinite(); + const bool rightIntersection = + (other.registerIndex < registerIndex + registerCount) || isInfinite(); return leftIntersection && rightIntersection; } @@ -108,8 +131,10 @@ struct ShaderBindingRange if (category != other.category || spaceIndex != other.spaceIndex) return false; - const bool leftIntersection = (registerIndex <= other.registerIndex + other.registerCount) || other.isInfinite(); - const bool rightIntersection = (other.registerIndex <= registerIndex + registerCount) || isInfinite(); + const bool leftIntersection = + (registerIndex <= other.registerIndex + other.registerCount) || other.isInfinite(); + const bool rightIntersection = + (other.registerIndex <= registerIndex + registerCount) || isInfinite(); return leftIntersection && rightIntersection; } @@ -121,7 +146,10 @@ struct ShaderBindingRange if (other.isInfinite()) registerCount = 0; else if (!isInfinite()) - registerCount = Math::Max(registerIndex + registerCount, other.registerIndex + other.registerCount) - newRegisterIndex; + registerCount = Math::Max( + registerIndex + registerCount, + other.registerIndex + other.registerCount) - + newRegisterIndex; registerIndex = newRegisterIndex; } @@ -134,6 +162,7 @@ struct ShaderBindingRange case slang::ShaderResource: case slang::UnorderedAccess: case slang::SamplerState: + case slang::DescriptorTableSlot: return true; default: return false; @@ -146,21 +175,33 @@ class ArtifactPostEmitMetadata : public ComBaseObject, public IArtifactPostEmitM public: typedef ArtifactPostEmitMetadata ThisType; - SLANG_CLASS_GUID(0x6f82509f, 0xe48b, 0x4b83, { 0xa3, 0x84, 0x5d, 0x70, 0x83, 0x19, 0x83, 0xcc }) + SLANG_CLASS_GUID(0x6f82509f, 0xe48b, 0x4b83, {0xa3, 0x84, 0x5d, 0x70, 0x83, 0x19, 0x83, 0xcc}) SLANG_COM_BASE_IUNKNOWN_ALL // ICastable SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - + // IArtifactPostEmitMetadata - SLANG_NO_THROW virtual Slice SLANG_MCALL getUsedBindingRanges() SLANG_OVERRIDE; - SLANG_NO_THROW virtual Slice SLANG_MCALL getExportedFunctionMangledNames() SLANG_OVERRIDE; + SLANG_NO_THROW virtual Slice SLANG_MCALL getUsedBindingRanges() + SLANG_OVERRIDE; + SLANG_NO_THROW virtual Slice SLANG_MCALL getExportedFunctionMangledNames() + SLANG_OVERRIDE; + + // IMetadata + SLANG_NO_THROW virtual SlangResult isParameterLocationUsed( + SlangParameterCategory category, // is this a `t` register? `s` register? + SlangUInt spaceIndex, // `space` for D3D12, `set` for Vulkan + SlangUInt registerIndex, // `register` for D3D12, `binding` for Vulkan + bool& outUsed) SLANG_OVERRIDE; void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); - static ComPtr create() { return ComPtr(new ThisType); } + static ComPtr create() + { + return ComPtr(new ThisType); + } List m_usedBindings; List m_exportedFunctionMangledNames; diff --git a/source/compiler-core/slang-artifact-associated.h b/source/compiler-core/slang-artifact-associated.h index 7664942713..c8e74f98b9 100644 --- a/source/compiler-core/slang-artifact-associated.h +++ b/source/compiler-core/slang-artifact-associated.h @@ -28,29 +28,29 @@ struct ArtifactDiagnostic struct Location { typedef Location ThisType; - bool operator==(const ThisType& rhs) const { return line == rhs.line && column == rhs.column; } + bool operator==(const ThisType& rhs) const + { + return line == rhs.line && column == rhs.column; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - Int line = 0; ///< One indexed line number. 0 if not defined - Int column = 0; ///< One indexed *character (not byte)* column number. 0 if not defined + Int line = 0; ///< One indexed line number. 0 if not defined + Int column = 0; ///< One indexed *character (not byte)* column number. 0 if not defined }; bool operator==(const ThisType& rhs) const { - return severity == rhs.severity && - stage == rhs.stage && - text == rhs.text && - code == rhs.code && - location == rhs.location; + return severity == rhs.severity && stage == rhs.stage && text == rhs.text && + code == rhs.code && location == rhs.location; } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - Severity severity = Severity::Unknown; ///< The severity of error - Stage stage = Stage::Compile; ///< The stage the error came from - TerminatedCharSlice text; ///< The text of the error - TerminatedCharSlice code; ///< The compiler specific error code - TerminatedCharSlice filePath; ///< The path the error originated from - Location location; ///< The location of the diagnostic in the filePath + Severity severity = Severity::Unknown; ///< The severity of error + Stage stage = Stage::Compile; ///< The stage the error came from + TerminatedCharSlice text; ///< The text of the error + TerminatedCharSlice code; ///< The compiler specific error code + TerminatedCharSlice filePath; ///< The path the error originated from + Location location; ///< The location of the diagnostic in the filePath }; /* Artifact diagnostics interface. @@ -60,72 +60,83 @@ IArtifactDiagnostics are added as associated types on an IArtifact typically. class IArtifactDiagnostics : public IClonable { public: - SLANG_COM_INTERFACE(0x91f9b857, 0xcd6b, 0x45ca, { 0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a }); + SLANG_COM_INTERFACE( + 0x91f9b857, + 0xcd6b, + 0x45ca, + {0x8e, 0x3, 0x8f, 0xa3, 0x3c, 0x5c, 0xf0, 0x1a}); typedef ArtifactDiagnostic Diagnostic; - /// Get the diagnostic at the index + /// Get the diagnostic at the index SLANG_NO_THROW virtual const Diagnostic* SLANG_MCALL getAt(Index i) = 0; - /// Get the amount of diangostics + /// Get the amount of diangostics SLANG_NO_THROW virtual Count SLANG_MCALL getCount() = 0; - /// Add a diagnostic + /// Add a diagnostic SLANG_NO_THROW virtual void SLANG_MCALL add(const Diagnostic& diagnostic) = 0; - /// Remove the diagnostic at the index + /// Remove the diagnostic at the index SLANG_NO_THROW virtual void SLANG_MCALL removeAt(Index i) = 0; - /// Get raw diagnostics information + /// Get raw diagnostics information SLANG_NO_THROW virtual TerminatedCharSlice SLANG_MCALL getRaw() = 0; - /// Set the raw diagnostic info + /// Set the raw diagnostic info SLANG_NO_THROW virtual void SLANG_MCALL setRaw(const CharSlice& slice) = 0; - /// Append to the raw diagnostic + /// Append to the raw diagnostic SLANG_NO_THROW virtual void SLANG_MCALL appendRaw(const CharSlice& slice) = 0; - /// Get the result for a compilation + /// Get the result for a compilation SLANG_NO_THROW virtual SlangResult SLANG_MCALL getResult() = 0; - /// Set the result + /// Set the result SLANG_NO_THROW virtual void SLANG_MCALL setResult(SlangResult res) = 0; - /// Reset all state + /// Reset all state SLANG_NO_THROW virtual void SLANG_MCALL reset() = 0; - /// Count the number of diagnostics which have 'severity' or greater - SLANG_NO_THROW virtual Count SLANG_MCALL getCountAtLeastSeverity(Diagnostic::Severity severity) = 0; + /// Count the number of diagnostics which have 'severity' or greater + SLANG_NO_THROW virtual Count SLANG_MCALL + getCountAtLeastSeverity(Diagnostic::Severity severity) = 0; - /// Get the number of diagnostics by severity + /// Get the number of diagnostics by severity SLANG_NO_THROW virtual Count SLANG_MCALL getCountBySeverity(Diagnostic::Severity severity) = 0; - /// True if there are any diagnostics of severity or worse + /// True if there are any diagnostics of severity or worse SLANG_NO_THROW virtual bool SLANG_MCALL hasOfAtLeastSeverity(Diagnostic::Severity severity) = 0; - /// Stores in outCounts, the amount of diagnostics for the stage of each severity - SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage(Diagnostic::Stage stage, Count outCounts[Int(Diagnostic::Severity::CountOf)]) = 0; + /// Stores in outCounts, the amount of diagnostics for the stage of each severity + SLANG_NO_THROW virtual Count SLANG_MCALL getCountByStage( + Diagnostic::Stage stage, + Count outCounts[Int(Diagnostic::Severity::CountOf)]) = 0; - /// Remove all diagnostics of the type + /// Remove all diagnostics of the type SLANG_NO_THROW virtual void SLANG_MCALL removeBySeverity(Diagnostic::Severity severity) = 0; - /// Add a note + /// Add a note SLANG_NO_THROW virtual void SLANG_MCALL maybeAddNote(const CharSlice& in) = 0; - /// If there are no error diagnostics, adds a generic error diagnostic + /// If there are no error diagnostics, adds a generic error diagnostic SLANG_NO_THROW virtual void SLANG_MCALL requireErrorDiagnostic() = 0; - /// Creates summary text and place in outBlob + /// Creates summary text and place in outBlob SLANG_NO_THROW virtual void SLANG_MCALL calcSummary(ISlangBlob** outBlob) = 0; - /// Creates a simplified summary text and places it in out blob + /// Creates a simplified summary text and places it in out blob SLANG_NO_THROW virtual void SLANG_MCALL calcSimplifiedSummary(ISlangBlob** outBlob) = 0; }; struct ShaderBindingRange; -class IArtifactPostEmitMetadata : public ICastable +class IArtifactPostEmitMetadata : public slang::IMetadata { public: - SLANG_COM_INTERFACE(0x5d03bce9, 0xafb1, 0x4fc8, { 0xa4, 0x6f, 0x3c, 0xe0, 0x7b, 0x6, 0x1b, 0x1b }); + SLANG_COM_INTERFACE( + 0x5d03bce9, + 0xafb1, + 0x4fc8, + {0xa4, 0x6f, 0x3c, 0xe0, 0x7b, 0x6, 0x1b, 0x1b}); - /// Get the binding ranges + /// Get the binding ranges SLANG_NO_THROW virtual Slice SLANG_MCALL getUsedBindingRanges() = 0; - /// Get the list of functions that were exported in the linked IR + /// Get the list of functions that were exported in the linked IR SLANG_NO_THROW virtual Slice SLANG_MCALL getExportedFunctionMangledNames() = 0; }; diff --git a/source/compiler-core/slang-artifact-container-util.cpp b/source/compiler-core/slang-artifact-container-util.cpp index 1c9bb5a690..574028c48c 100644 --- a/source/compiler-core/slang-artifact-container-util.cpp +++ b/source/compiler-core/slang-artifact-container-util.cpp @@ -1,27 +1,27 @@ // slang-artifact-container-util.cpp #include "slang-artifact-container-util.h" -#include "slang-artifact-util.h" -#include "slang-artifact-desc-util.h" -#include "slang-artifact-representation-impl.h" - +#include "../core/slang-castable.h" #include "../core/slang-file-system.h" #include "../core/slang-io.h" -#include "../core/slang-zip-file-system.h" -#include "../core/slang-castable.h" #include "../core/slang-string-slice-pool.h" +#include "../core/slang-zip-file-system.h" +#include "slang-artifact-desc-util.h" +#include "slang-artifact-representation-impl.h" +#include "slang-artifact-util.h" -namespace Slang { +namespace Slang +{ -/* +/* Artifact file structure ======================= -There is many ways this could work, with different trade offs. The approach taken here is -to make *every* artifact be a directory. There are two special case directories "associated" and "children", -which hold the artifacts associated/chidren artifacts. +There is many ways this could work, with different trade offs. The approach taken here is +to make *every* artifact be a directory. There are two special case directories "associated" and +"children", which hold the artifacts associated/chidren artifacts. -So for example if we have +So for example if we have ``` thing.spv @@ -53,11 +53,12 @@ associated/0a0a0a/0a0a0a.map associated/0b0b0b/0b0b0b.map ``` -That is a little verbose, but if the associated artifacts have children/associated, then things still work. +That is a little verbose, but if the associated artifacts have children/associated, then things +still work. ``` container - a.spv + a.spv associated diagnostics b.dxil @@ -127,7 +128,7 @@ struct ArtifactContainerWriter { push(name); - const char*const path = m_entry.path.getBuffer(); + const char* const path = m_entry.path.getBuffer(); SlangPathType pathType; if (SLANG_SUCCEEDED(m_fileSystem->getPathType(path, &pathType))) @@ -137,7 +138,7 @@ struct ArtifactContainerWriter return SLANG_FAIL; } } - + // Make sure there is a path to this return m_fileSystem->createDirectory(m_entry.path.getBuffer()); } @@ -150,12 +151,12 @@ struct ArtifactContainerWriter SlangResult getBaseName(IArtifact* artifact, String& out); - /// Write the artifact in the current scope + /// Write the artifact in the current scope SlangResult write(IArtifact* artifact); SlangResult writeInDirectory(IArtifact* artifact, const String& baseName); - ArtifactContainerWriter(ISlangMutableFileSystem* fileSystem): - m_fileSystem(fileSystem) + ArtifactContainerWriter(ISlangMutableFileSystem* fileSystem) + : m_fileSystem(fileSystem) { } @@ -175,11 +176,13 @@ SlangResult ArtifactContainerWriter::getBaseName(IArtifact* artifact, String& ou auto artifactName = artifact->getName(); if (artifactName && artifactName[0] != 0) { - baseName = ArtifactDescUtil::getBaseNameFromPath(artifactDesc, UnownedStringSlice(artifactName)); + baseName = ArtifactDescUtil::getBaseNameFromPath( + artifactDesc, + UnownedStringSlice(artifactName)); } } - // If we don't have name, use a generated one + // If we don't have name, use a generated one if (baseName.getLength() == 0) { baseName.append(m_entry.uniqueIndex++); @@ -194,7 +197,7 @@ SlangResult ArtifactContainerWriter::writeInDirectory(IArtifact* artifact, const // TODO(JS): // We could now output information about the desc/artifact, say as some json. // For now we assume the extension is good enough for most purposes. - + // If it's an "arbitrary" container, we don't need to write it if (artifact->getDesc().kind != ArtifactKind::Container) { @@ -204,7 +207,10 @@ SlangResult ArtifactContainerWriter::writeInDirectory(IArtifact* artifact, const // Get the name of the artifact StringBuilder artifactName; - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcNameForDesc(artifact->getDesc(), baseName.getUnownedSlice(), artifactName)); + SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcNameForDesc( + artifact->getDesc(), + baseName.getUnownedSlice(), + artifactName)); const auto combinedPath = Path::combine(m_entry.path, artifactName); // Write out the blob @@ -269,13 +275,22 @@ struct FileSystemContents struct IndexRange { SLANG_FORCE_INLINE Index getCount() const { return endIndex - startIndex; } - + SLANG_FORCE_INLINE Index begin() const { return startIndex; } SLANG_FORCE_INLINE Index end() const { return endIndex; } - void set(Index inStart, Index inEnd) { startIndex = inStart; endIndex = inEnd; } + void set(Index inStart, Index inEnd) + { + startIndex = inStart; + endIndex = inEnd; + } - static IndexRange make(Index inStart, Index inEnd) { IndexRange range; range.set(inStart, inEnd); return range; } + static IndexRange make(Index inStart, Index inEnd) + { + IndexRange range; + range.set(inStart, inEnd); + return range; + } Index startIndex; Index endIndex; @@ -289,7 +304,10 @@ struct FileSystemContents void setDirectory() { range.set(0, 0); } void setFile() { range.set(-1, -1); } - void setType(SlangPathType type) { (type == SLANG_PATH_TYPE_FILE) ? setFile() : setDirectory(); } + void setType(SlangPathType type) + { + (type == SLANG_PATH_TYPE_FILE) ? setFile() : setDirectory(); + } void setDirectoryRange(Index inStartIndex, Index inEndIndex) { @@ -298,33 +316,34 @@ struct FileSystemContents range.set(inStartIndex, inEndIndex); } - Index parentDirectoryIndex = -1; ///< The directory this entry is in. -1 is root. - UnownedStringSlice name; ///< Name of this entry - IndexRange range = IndexRange::make(-1, -1); ///< Default to file + Index parentDirectoryIndex = -1; ///< The directory this entry is in. -1 is root. + UnownedStringSlice name; ///< Name of this entry + IndexRange range = IndexRange::make(-1, -1); ///< Default to file }; - + void clear() { m_pool.clear(); m_entries.clear(); } - + IndexRange getContentsRange(Index index) const { return m_entries[index].range; } - - ConstArrayView getContents(Index index) const { return getContents(m_entries[index]); } + + ConstArrayView getContents(Index index) const { return getContents(m_entries[index]); } ConstArrayView getContents(const Entry& entry) const { - return entry.range.getCount() ? - makeConstArrayView(m_entries.getBuffer() + entry.range.startIndex, entry.range.getCount()) : - makeConstArrayView(nullptr, 0); + return entry.range.getCount() ? makeConstArrayView( + m_entries.getBuffer() + entry.range.startIndex, + entry.range.getCount()) + : makeConstArrayView(nullptr, 0); } - + void appendPath(Index entryIndex, StringBuilder& buf); SlangResult find(ISlangFileSystemExt* fileSyste, const UnownedStringSlice& path); - FileSystemContents(): - m_pool(StringSlicePool::Style::Default) + FileSystemContents() + : m_pool(StringSlicePool::Style::Default) { clear(); } @@ -334,7 +353,7 @@ struct FileSystemContents FileSystemContents* contents = (FileSystemContents*)userData; Entry entry; - + entry.parentDirectoryIndex = contents->m_currentParent; entry.name = contents->m_pool.addAndGetSlice(name); entry.setType(pathType); @@ -342,10 +361,10 @@ struct FileSystemContents contents->m_entries.add(entry); } - Index m_currentParent = -1; ///< Convenience for adding entries when using enumerate + Index m_currentParent = -1; ///< Convenience for adding entries when using enumerate - StringSlicePool m_pool; ///< Holds strings - List m_entries; ///< The entries + StringSlicePool m_pool; ///< Holds strings + List m_entries; ///< The entries }; void FileSystemContents::appendPath(Index entryIndex, StringBuilder& buf) @@ -366,7 +385,9 @@ void FileSystemContents::appendPath(Index entryIndex, StringBuilder& buf) buf.append(entry.name); } -SlangResult FileSystemContents::find(ISlangFileSystemExt* fileSystem, const UnownedStringSlice& inPath) +SlangResult FileSystemContents::find( + ISlangFileSystemExt* fileSystem, + const UnownedStringSlice& inPath) { clear(); @@ -400,7 +421,7 @@ SlangResult FileSystemContents::find(ISlangFileSystemExt* fileSystem, const Unow { Entry directoryEntry; directoryEntry.setDirectory(); - + directoryEntry.name = m_pool.addAndGetSlice(inPath); m_entries.add(directoryEntry); @@ -420,12 +441,12 @@ SlangResult FileSystemContents::find(ISlangFileSystemExt* fileSystem, const Unow const auto startIndex = m_entries.getCount(); - const char*const path = currentPath.getLength() ? currentPath.getBuffer() : "."; + const char* const path = currentPath.getLength() ? currentPath.getBuffer() : "."; const auto res = fileSystem->enumeratePathContents(path, _add, this); - + m_entries[i].setDirectoryRange(startIndex, m_entries.getCount()); - + SLANG_RETURN_ON_FAIL(res); } } @@ -436,12 +457,15 @@ SlangResult FileSystemContents::find(ISlangFileSystemExt* fileSystem, const Unow /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactContainerUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */SlangResult ArtifactContainerUtil::writeContainer(IArtifact* artifact, const String& defaultFileName, ISlangMutableFileSystem* fileSystem) +/* static */ SlangResult ArtifactContainerUtil::writeContainer( + IArtifact* artifact, + const String& defaultFileName, + ISlangMutableFileSystem* fileSystem) { ArtifactContainerWriter writer(fileSystem); String baseName; - + { const char* name = artifact->getName(); if (name == nullptr || name[0] == 0) @@ -454,9 +478,9 @@ SlangResult FileSystemContents::find(ISlangFileSystemExt* fileSystem, const Unow // If it's still not set try generating it. if (baseName.getLength() == 0) { - SLANG_RETURN_ON_FAIL(writer.getBaseName(artifact, baseName)); + SLANG_RETURN_ON_FAIL(writer.getBaseName(artifact, baseName)); } - + SLANG_RETURN_ON_FAIL(writer.writeInDirectory(artifact, baseName)); return SLANG_OK; @@ -472,7 +496,9 @@ static SlangResult _remove(ISlangMutableFileSystem* fileSystem, const String& pa return SLANG_OK; } -/* static */SlangResult ArtifactContainerUtil::writeContainer(IArtifact* artifact, const String& fileName) +/* static */ SlangResult ArtifactContainerUtil::writeContainer( + IArtifact* artifact, + const String& fileName) { auto osFileSystem = OSFileSystem::getMutableSingleton(); @@ -502,7 +528,7 @@ static SlangResult _remove(ISlangMutableFileSystem* fileSystem, const String& pa } else if (ext == toSlice("dir")) { - // We use the special extension "dir" to write out to a directory. + // We use the special extension "dir" to write out to a directory. // This is a little hokey arguably... auto path = Path::getPathWithoutExt(fileName); @@ -517,7 +543,8 @@ static SlangResult _remove(ISlangMutableFileSystem* fileSystem, const String& pa } // In order to write out as a artifact hierarchy we need a file system. If we don't have that - // we only write out the "main" (or root) artifact. All associated/children are typically ignored. + // we only write out the "main" (or root) artifact. All associated/children are typically + // ignored. { // Get the artifact as a blob ComPtr containerBlob; @@ -534,9 +561,12 @@ struct ArtifactContainerReader { SlangResult read(ISlangFileSystemExt* fileSystem, ComPtr& outArtifact); - /// A directory that contains multiple artifact directories - SlangResult _readContainerDirectory(Index directoryIndex, IArtifact::ContainedKind kind, IArtifact* container); - /// A directory that holds a single + /// A directory that contains multiple artifact directories + SlangResult _readContainerDirectory( + Index directoryIndex, + IArtifact::ContainedKind kind, + IArtifact* container); + /// A directory that holds a single SlangResult _readArtifactDirectory(Index directoryIndex, ComPtr& outArtifact); SlangResult _readFile(Index fileIndex, ComPtr& outArtifact); @@ -545,7 +575,9 @@ struct ArtifactContainerReader ISlangFileSystemExt* m_fileSystem; }; -SlangResult ArtifactContainerReader::read(ISlangFileSystemExt* fileSystem, ComPtr& outArtifact) +SlangResult ArtifactContainerReader::read( + ISlangFileSystemExt* fileSystem, + ComPtr& outArtifact) { m_fileSystem = fileSystem; m_contents.find(fileSystem, toSlice("")); @@ -556,7 +588,7 @@ SlangResult ArtifactContainerReader::read(ISlangFileSystemExt* fileSystem, ComPt SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtr& outArtifact) { outArtifact.setNull(); - + const auto& entry = m_contents.m_entries[fileIndex]; SLANG_ASSERT(entry.isFile()); @@ -565,8 +597,8 @@ SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtrsetName(entry.name.begin()); } @@ -608,17 +638,21 @@ SlangResult ArtifactContainerReader::_readFile(Index fileIndex, ComPtraddRepresentation(rep); - + outArtifact = artifact; return SLANG_OK; } -SlangResult ArtifactContainerReader::_readContainerDirectory(Index directoryIndex, IArtifact::ContainedKind kind, IArtifact* containerArtifact) +SlangResult ArtifactContainerReader::_readContainerDirectory( + Index directoryIndex, + IArtifact::ContainedKind kind, + IArtifact* containerArtifact) { // This directory only contains other directories which are artifacts - // Files are ignored + // Files are ignored auto indexRange = m_contents.getContentsRange(directoryIndex); @@ -635,14 +669,20 @@ SlangResult ArtifactContainerReader::_readContainerDirectory(Index directoryInde ComPtr artifact; SLANG_RETURN_ON_FAIL(_readArtifactDirectory(i, artifact)); - + if (artifact) { switch (kind) { - case IArtifact::ContainedKind::Associated: containerArtifact->addAssociated(artifact); break; - case IArtifact::ContainedKind::Children: containerArtifact->addChild(artifact); break; - default: SLANG_ASSERT(!"Can't add artifact to this kind"); return SLANG_FAIL; + case IArtifact::ContainedKind::Associated: + containerArtifact->addAssociated(artifact); + break; + case IArtifact::ContainedKind::Children: + containerArtifact->addChild(artifact); + break; + default: + SLANG_ASSERT(!"Can't add artifact to this kind"); + return SLANG_FAIL; } } } @@ -650,7 +690,9 @@ SlangResult ArtifactContainerReader::_readContainerDirectory(Index directoryInde return SLANG_OK; } -SlangResult ArtifactContainerReader::_readArtifactDirectory(Index directoryIndex, ComPtr& outArtifact) +SlangResult ArtifactContainerReader::_readArtifactDirectory( + Index directoryIndex, + ComPtr& outArtifact) { auto indexRange = m_contents.getContentsRange(directoryIndex); @@ -667,7 +709,7 @@ SlangResult ArtifactContainerReader::_readArtifactDirectory(Index directoryIndex { ComPtr readArtifact; SLANG_RETURN_ON_FAIL(_readFile(i, readArtifact)); - + if (readArtifact) { if (artifact) @@ -697,7 +739,8 @@ SlangResult ArtifactContainerReader::_readArtifactDirectory(Index directoryIndex // If we have children/associated we can assume it's a container if (childrenIndex >= 0 || associatedIndex >= 0) { - artifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::Unknown)); + artifact = ArtifactUtil::createArtifact( + ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::Unknown)); artifact->setName(m_contents.m_entries[directoryIndex].name.begin()); } else @@ -709,26 +752,32 @@ SlangResult ArtifactContainerReader::_readArtifactDirectory(Index directoryIndex if (childrenIndex >= 0) { - SLANG_RETURN_ON_FAIL(_readContainerDirectory(childrenIndex, IArtifact::ContainedKind::Children, artifact)); + SLANG_RETURN_ON_FAIL( + _readContainerDirectory(childrenIndex, IArtifact::ContainedKind::Children, artifact)); } if (associatedIndex >= 0) { - SLANG_RETURN_ON_FAIL(_readContainerDirectory(associatedIndex, IArtifact::ContainedKind::Associated, artifact)); + SLANG_RETURN_ON_FAIL(_readContainerDirectory( + associatedIndex, + IArtifact::ContainedKind::Associated, + artifact)); } outArtifact = artifact; return SLANG_OK; } -SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtr& outArtifact) +SlangResult ArtifactContainerUtil::readContainer( + IArtifact* artifact, + ComPtr& outArtifact) { auto desc = artifact->getDesc(); ComPtr fileSystem; - + switch (desc.kind) { - case ArtifactKind::Zip: + case ArtifactKind::Zip: { SLANG_RETURN_ON_FAIL(ZipFileSystem::create(fileSystem)); @@ -741,10 +790,11 @@ SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtr(fileSystem); SLANG_ASSERT(archiveFileSystem); - SLANG_RETURN_ON_FAIL(archiveFileSystem->loadArchive(blob->getBufferPointer(), blob->getBufferSize())); + SLANG_RETURN_ON_FAIL( + archiveFileSystem->loadArchive(blob->getBufferPointer(), blob->getBufferSize())); break; } - default: + default: { return SLANG_FAIL; } @@ -754,7 +804,9 @@ SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtr& outArtifact) +/* static */ SlangResult ArtifactContainerUtil::readContainer( + ISlangFileSystemExt* fileSystem, + ComPtr& outArtifact) { SLANG_UNUSED(outArtifact); @@ -764,7 +816,9 @@ SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtr& outArtifact) +/* static */ SlangResult ArtifactContainerUtil::filter( + IArtifact* artifact, + ComPtr& outArtifact) { outArtifact.setNull(); @@ -821,17 +875,15 @@ SlangResult ArtifactContainerUtil::readContainer(IArtifact* artifact, ComPtrgetChildren().count || - dstArtifact->getAssociated().count) + if (blob || dstArtifact->getChildren().count || dstArtifact->getAssociated().count) { outArtifact = dstArtifact; } - + // If we return an artifact or not, this was successful return SLANG_OK; } diff --git a/source/compiler-core/slang-artifact-container-util.h b/source/compiler-core/slang-artifact-container-util.h index eb0a12dfcc..83090074ee 100644 --- a/source/compiler-core/slang-artifact-container-util.h +++ b/source/compiler-core/slang-artifact-container-util.h @@ -3,43 +3,47 @@ #define SLANG_ARTIFACT_CONTAINER_UTIL_H #include "slang-artifact-representation.h" - #include "slang-com-helper.h" #include "slang-com-ptr.h" namespace Slang { -/* Functionality to save of and read artifact hierarchies via the slang +/* Functionality to save of and read artifact hierarchies via the slang artifact container style. This style treats storage as a file system. -Since this represention, is not directly a file system representation +Since this represention, is not directly a file system representation some conventions are used to associate data, via names etc. -The use of ISlangMutableFileSystem, allows writing this structure, to memory, zip, riff, directory +The use of ISlangMutableFileSystem, allows writing this structure, to memory, zip, riff, directory or other file like representations */ -struct ArtifactContainerUtil +struct ArtifactContainerUtil { - /// Write the container using the specified path. - /// Uses the extension of the path to determine how to write + /// Write the container using the specified path. + /// Uses the extension of the path to determine how to write static SlangResult writeContainer(IArtifact* artifact, const String& path); - /// If there isn't a suitable name on artifact, the filename is used to generate a name. If it's not set - /// a name may be generated. - static SlangResult writeContainer(IArtifact* artifact, const String& defaultFileName, ISlangMutableFileSystem* fileSystem); + /// If there isn't a suitable name on artifact, the filename is used to generate a name. If it's + /// not set a name may be generated. + static SlangResult writeContainer( + IArtifact* artifact, + const String& defaultFileName, + ISlangMutableFileSystem* fileSystem); - static SlangResult readContainer(ISlangFileSystemExt* fileSystem, ComPtr& outArtifact); + static SlangResult readContainer( + ISlangFileSystemExt* fileSystem, + ComPtr& outArtifact); - /// Read an artifact that represents a container as an artifact hierarchy + /// Read an artifact that represents a container as an artifact hierarchy static SlangResult readContainer(IArtifact* artifact, ComPtr& outArtifact); - /// Creates a copy of artifact where - /// * All artifacts are blobs - /// * Any generic containers that are empty are dropped - /// * Any sub artifact that can't be blobed and isn't significant is ignored - /// - /// A future improvement would be to take a function to also control what makes it to the output + /// Creates a copy of artifact where + /// * All artifacts are blobs + /// * Any generic containers that are empty are dropped + /// * Any sub artifact that can't be blobed and isn't significant is ignored + /// + /// A future improvement would be to take a function to also control what makes it to the output static SlangResult filter(IArtifact* artifact, ComPtr& outArtifact); }; diff --git a/source/compiler-core/slang-artifact-desc-util.cpp b/source/compiler-core/slang-artifact-desc-util.cpp index 9794cc90e9..c1575ba168 100644 --- a/source/compiler-core/slang-artifact-desc-util.cpp +++ b/source/compiler-core/slang-artifact-desc-util.cpp @@ -1,16 +1,16 @@ // slang-artifact-desc-util.cpp #include "slang-artifact-desc-util.h" -#include "slang-artifact-representation.h" - -#include "slang-artifact-impl.h" - -#include "../core/slang-type-text-util.h" #include "../core/slang-io.h" +#include "../core/slang-type-text-util.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation.h" -namespace Slang { +namespace Slang +{ -namespace { // anonymous +namespace +{ // anonymous struct HierarchicalEnumEntry { @@ -61,7 +61,7 @@ static bool _isHierarchicalEnumOk(ConstArrayView entries, return true; } -template +template struct HierarchicalEnumTable { HierarchicalEnumTable(ConstArrayView entries) @@ -86,7 +86,7 @@ struct HierarchicalEnumTable m_names[value] = UnownedStringSlice(entry.name); } - // TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid* + // TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid* // we would want the Parent of Base to be Base. // // Base parent should be invalid @@ -95,17 +95,10 @@ struct HierarchicalEnumTable SLANG_ASSERT(getParent(T::Invalid) == T::Invalid); } - T getParent(T kind) const - { - return (kind >= T::CountOf) ? - T::Invalid : - m_parents[Index(kind)]; - } + T getParent(T kind) const { return (kind >= T::CountOf) ? T::Invalid : m_parents[Index(kind)]; } UnownedStringSlice getName(T kind) const { - return (kind >= T::CountOf) ? - UnownedStringSlice() : - m_names[Index(kind)]; + return (kind >= T::CountOf) ? UnownedStringSlice() : m_names[Index(kind)]; } bool isDerivedFrom(T type, T base) const @@ -132,28 +125,38 @@ struct HierarchicalEnumTable UnownedStringSlice m_names[Count(T::CountOf)]; }; -} // anonymous +} // namespace // Macro utils to create "enum hierarchy" tables -#define SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_ENTRY_MACRO) \ -static ConstArrayView _getEntries##ENUM_TYPE() \ -{ \ - static const HierarchicalEnumEntry values[] = { ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO) }; \ - return makeConstArrayView(values); \ -} +#define SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_ENTRY_MACRO) \ + static ConstArrayView _getEntries##ENUM_TYPE() \ + { \ + static const HierarchicalEnumEntry values[] = {ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO)}; \ + return makeConstArrayView(values); \ + } -#define SLANG_HIERARCHICAL_ENUM(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ -SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ -\ -static const HierarchicalEnumTable g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \ -\ -ENUM_TYPE getParent(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getParent(kind); } \ -UnownedStringSlice getName(ENUM_TYPE kind) { return g_table##ENUM_TYPE.getName(kind); } \ -bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) { return g_table##ENUM_TYPE.isDerivedFrom(kind, base); } +#define SLANG_HIERARCHICAL_ENUM(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ + SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ + \ + static const HierarchicalEnumTable g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \ + \ + ENUM_TYPE getParent(ENUM_TYPE kind) \ + { \ + return g_table##ENUM_TYPE.getParent(kind); \ + } \ + UnownedStringSlice getName(ENUM_TYPE kind) \ + { \ + return g_table##ENUM_TYPE.getName(kind); \ + } \ + bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) \ + { \ + return g_table##ENUM_TYPE.isDerivedFrom(kind, base); \ + } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactKind !!!!!!!!!!!!!!!!!!!!!!! */ +// clang-format off #define SLANG_ARTIFACT_KIND(x) \ x(Invalid, Invalid) \ x(Base, Invalid) \ @@ -205,6 +208,7 @@ SLANG_HIERARCHICAL_ENUM(ArtifactKind, SLANG_ARTIFACT_KIND, SLANG_ARTIFACT_KIND_E x(PTX, KernelLike) \ x(CuBin, KernelLike) \ x(MetalAIR, KernelLike) \ + x(WGSL_SPIRV, KernelLike) \ x(CPULike, Base) \ x(UnknownCPU, CPULike) \ x(X86, CPULike) \ @@ -243,113 +247,171 @@ SLANG_HIERARCHICAL_ENUM(ArtifactPayload, SLANG_ARTIFACT_PAYLOAD, SLANG_ARTIFACT_ x(CodeLike, Base) \ x(Kernel, CodeLike) \ x(Host, CodeLike) \ - x(Obfuscated, Base) + x(Obfuscated, Base) +// clang-format on -#define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) { Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE }, +#define SLANG_ARTIFACT_STYLE_ENTRY(TYPE, PARENT) \ + {Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE}, SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYLE_ENTRY) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDescUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */ArtifactDesc ArtifactDescUtil::makeDescForCompileTarget(SlangCompileTarget target) +/* static */ ArtifactDesc ArtifactDescUtil::makeDescForCompileTarget(SlangCompileTarget target) { switch (target) { - case SLANG_TARGET_UNKNOWN: return Desc::make(Kind::Unknown, Payload::None, Style::Unknown, 0); - case SLANG_TARGET_NONE: return Desc::make(Kind::None, Payload::None, Style::Unknown, 0); - case SLANG_GLSL: + case SLANG_TARGET_UNKNOWN: + return Desc::make(Kind::Unknown, Payload::None, Style::Unknown, 0); + case SLANG_TARGET_NONE: + return Desc::make(Kind::None, Payload::None, Style::Unknown, 0); + case SLANG_GLSL: { // For the moment we Desc::make all just map to GLSL, but we could use flags // or some other mechanism to distinguish the types return Desc::make(Kind::Source, Payload::GLSL, Style::Kernel, 0); } - case SLANG_HLSL: return Desc::make(Kind::Source, Payload::HLSL, Style::Kernel, 0); - case SLANG_SPIRV: return Desc::make(Kind::Executable, Payload::SPIRV, Style::Kernel, 0); - case SLANG_SPIRV_ASM: return Desc::make(Kind::Assembly, Payload::SPIRV, Style::Kernel, 0); - case SLANG_DXBC: return Desc::make(Kind::Executable, Payload::DXBC, Style::Kernel, 0); - case SLANG_DXBC_ASM: return Desc::make(Kind::Assembly, Payload::DXBC, Style::Kernel, 0); - case SLANG_DXIL: return Desc::make(Kind::Executable, Payload::DXIL, Style::Kernel, 0); - case SLANG_DXIL_ASM: return Desc::make(Kind::Assembly, Payload::DXIL, Style::Kernel, 0); - case SLANG_C_SOURCE: return Desc::make(Kind::Source, Payload::C, Style::Kernel, 0); - case SLANG_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Kernel, 0); - case SLANG_HOST_CPP_SOURCE: return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0); - case SLANG_CPP_PYTORCH_BINDING: return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0); - case SLANG_HOST_EXECUTABLE: return Desc::make(Kind::Executable, Payload::HostCPU, Style::Host, 0); - case SLANG_HOST_SHARED_LIBRARY: return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Host, 0); - case SLANG_SHADER_SHARED_LIBRARY: return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); - case SLANG_SHADER_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Kernel, 0); - case SLANG_CUDA_SOURCE: return Desc::make(Kind::Source, Payload::CUDA, Style::Kernel, 0); - // TODO(JS): - // Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. Saying it is - // 'Executable' implies it is Binary (which PTX isn't). Executable also implies 'complete for executation', - // irrespective of it being text. - case SLANG_PTX: return Desc::make(Kind::Executable, Payload::PTX, Style::Kernel, 0); - case SLANG_OBJECT_CODE: return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); - case SLANG_HOST_HOST_CALLABLE: return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); - case SLANG_METAL: return Desc::make(Kind::Source, Payload::Metal, Style::Kernel, 0); - case SLANG_METAL_LIB: return Desc::make(Kind::Executable, Payload::MetalAIR, Style::Kernel, 0); - case SLANG_METAL_LIB_ASM: return Desc::make(Kind::Assembly, Payload::MetalAIR, Style::Kernel, 0); - case SLANG_WGSL: return Desc::make(Kind::Source, Payload::WGSL, Style::Kernel, 0); - default: break; + case SLANG_HLSL: + return Desc::make(Kind::Source, Payload::HLSL, Style::Kernel, 0); + case SLANG_SPIRV: + return Desc::make(Kind::ObjectCode, Payload::SPIRV, Style::Kernel, 0); + case SLANG_SPIRV_ASM: + return Desc::make(Kind::Assembly, Payload::SPIRV, Style::Kernel, 0); + case SLANG_DXBC: + return Desc::make(Kind::ObjectCode, Payload::DXBC, Style::Kernel, 0); + case SLANG_DXBC_ASM: + return Desc::make(Kind::Assembly, Payload::DXBC, Style::Kernel, 0); + case SLANG_DXIL: + return Desc::make(Kind::ObjectCode, Payload::DXIL, Style::Kernel, 0); + case SLANG_DXIL_ASM: + return Desc::make(Kind::Assembly, Payload::DXIL, Style::Kernel, 0); + case SLANG_C_SOURCE: + return Desc::make(Kind::Source, Payload::C, Style::Kernel, 0); + case SLANG_CPP_SOURCE: + return Desc::make(Kind::Source, Payload::Cpp, Style::Kernel, 0); + case SLANG_HOST_CPP_SOURCE: + return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0); + case SLANG_CPP_PYTORCH_BINDING: + return Desc::make(Kind::Source, Payload::Cpp, Style::Host, 0); + case SLANG_HOST_EXECUTABLE: + return Desc::make(Kind::Executable, Payload::HostCPU, Style::Host, 0); + case SLANG_HOST_SHARED_LIBRARY: + return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Host, 0); + case SLANG_SHADER_SHARED_LIBRARY: + return Desc::make(Kind::SharedLibrary, Payload::HostCPU, Style::Kernel, 0); + case SLANG_SHADER_HOST_CALLABLE: + return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Kernel, 0); + case SLANG_CUDA_SOURCE: + return Desc::make(Kind::Source, Payload::CUDA, Style::Kernel, 0); + // TODO(JS): + // Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. + // Saying it is 'Executable' implies it is Binary (which PTX isn't). Executable also + // implies 'complete for executation', irrespective of it being text. + case SLANG_PTX: + return Desc::make(Kind::ObjectCode, Payload::PTX, Style::Kernel, 0); + case SLANG_OBJECT_CODE: + return Desc::make(Kind::ObjectCode, Payload::HostCPU, Style::Kernel, 0); + case SLANG_HOST_HOST_CALLABLE: + return Desc::make(Kind::HostCallable, Payload::HostCPU, Style::Host, 0); + case SLANG_METAL: + return Desc::make(Kind::Source, Payload::Metal, Style::Kernel, 0); + case SLANG_METAL_LIB: + return Desc::make(Kind::ObjectCode, Payload::MetalAIR, Style::Kernel, 0); + case SLANG_METAL_LIB_ASM: + return Desc::make(Kind::Assembly, Payload::MetalAIR, Style::Kernel, 0); + case SLANG_WGSL: + return Desc::make(Kind::Source, Payload::WGSL, Style::Kernel, 0); + case SLANG_WGSL_SPIRV_ASM: + return Desc::make(Kind::Assembly, Payload::WGSL_SPIRV, Style::Kernel, 0); + case SLANG_WGSL_SPIRV: + return Desc::make(Kind::ObjectCode, Payload::WGSL_SPIRV, Style::Kernel, 0); + default: + break; } SLANG_UNEXPECTED("Unhandled type"); } -/* static */ArtifactPayload ArtifactDescUtil::getPayloadForSourceLanaguage(SlangSourceLanguage language) +/* static */ ArtifactPayload ArtifactDescUtil::getPayloadForSourceLanaguage( + SlangSourceLanguage language) { switch (language) { - default: - case SLANG_SOURCE_LANGUAGE_UNKNOWN: return Payload::Unknown; - case SLANG_SOURCE_LANGUAGE_SLANG: return Payload::Slang; - case SLANG_SOURCE_LANGUAGE_HLSL: return Payload::HLSL; - case SLANG_SOURCE_LANGUAGE_GLSL: return Payload::GLSL; - case SLANG_SOURCE_LANGUAGE_C: return Payload::C; - case SLANG_SOURCE_LANGUAGE_CPP: return Payload::Cpp; - case SLANG_SOURCE_LANGUAGE_CUDA: return Payload::CUDA; + default: + case SLANG_SOURCE_LANGUAGE_UNKNOWN: + return Payload::Unknown; + case SLANG_SOURCE_LANGUAGE_SLANG: + return Payload::Slang; + case SLANG_SOURCE_LANGUAGE_HLSL: + return Payload::HLSL; + case SLANG_SOURCE_LANGUAGE_GLSL: + return Payload::GLSL; + case SLANG_SOURCE_LANGUAGE_C: + return Payload::C; + case SLANG_SOURCE_LANGUAGE_CPP: + return Payload::Cpp; + case SLANG_SOURCE_LANGUAGE_CUDA: + return Payload::CUDA; } } -/* static */ArtifactDesc ArtifactDescUtil::makeDescForSourceLanguage(SlangSourceLanguage language) +/* static */ ArtifactDesc ArtifactDescUtil::makeDescForSourceLanguage(SlangSourceLanguage language) { return Desc::make(Kind::Source, getPayloadForSourceLanaguage(language), Style::Unknown, 0); } -/* static */SlangCompileTarget ArtifactDescUtil::getCompileTargetFromDesc(const ArtifactDesc& desc) +/* static */ SlangCompileTarget ArtifactDescUtil::getCompileTargetFromDesc(const ArtifactDesc& desc) { switch (desc.kind) { - case ArtifactKind::None: return SLANG_TARGET_NONE; - case ArtifactKind::Source: + case ArtifactKind::None: + return SLANG_TARGET_NONE; + case ArtifactKind::Source: { switch (desc.payload) { - case Payload::HLSL: return SLANG_HLSL; - case Payload::GLSL: return SLANG_GLSL; - case Payload::C: return SLANG_C_SOURCE; - case Payload::Cpp: return (desc.style == Style::Host) ? SLANG_HOST_CPP_SOURCE : SLANG_CPP_SOURCE; - case Payload::CUDA: return SLANG_CUDA_SOURCE; - case Payload::Metal: return SLANG_METAL; - case Payload::WGSL: return SLANG_WGSL; - default: break; + case Payload::HLSL: + return SLANG_HLSL; + case Payload::GLSL: + return SLANG_GLSL; + case Payload::C: + return SLANG_C_SOURCE; + case Payload::Cpp: + return (desc.style == Style::Host) ? SLANG_HOST_CPP_SOURCE : SLANG_CPP_SOURCE; + case Payload::CUDA: + return SLANG_CUDA_SOURCE; + case Payload::Metal: + return SLANG_METAL; + case Payload::WGSL: + return SLANG_WGSL; + default: + break; } break; } - case ArtifactKind::Assembly: + case ArtifactKind::Assembly: { switch (desc.payload) { - case Payload::SPIRV: return SLANG_SPIRV_ASM; - case Payload::DXIL: return SLANG_DXIL_ASM; - case Payload::DXBC: return SLANG_DXBC_ASM; - case Payload::PTX: return SLANG_PTX; - case Payload::MetalAIR: return SLANG_METAL_LIB_ASM; - default: break; + case Payload::SPIRV: + return SLANG_SPIRV_ASM; + case Payload::DXIL: + return SLANG_DXIL_ASM; + case Payload::DXBC: + return SLANG_DXBC_ASM; + case Payload::PTX: + return SLANG_PTX; + case Payload::MetalAIR: + return SLANG_METAL_LIB_ASM; + case Payload::WGSL_SPIRV: + return SLANG_WGSL_SPIRV_ASM; + default: + break; } } - default: break; + default: + break; } if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) @@ -358,23 +420,38 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL { switch (desc.kind) { - case Kind::Executable: return SLANG_HOST_EXECUTABLE; - case Kind::SharedLibrary: return desc.style == ArtifactStyle::Host ? SLANG_HOST_SHARED_LIBRARY : SLANG_SHADER_SHARED_LIBRARY; - case Kind::HostCallable: return desc.style == ArtifactStyle::Host ? SLANG_HOST_HOST_CALLABLE : SLANG_SHADER_HOST_CALLABLE; - case Kind::ObjectCode: return SLANG_OBJECT_CODE; - default: break; + case Kind::Executable: + return SLANG_HOST_EXECUTABLE; + case Kind::SharedLibrary: + return desc.style == ArtifactStyle::Host ? SLANG_HOST_SHARED_LIBRARY + : SLANG_SHADER_SHARED_LIBRARY; + case Kind::HostCallable: + return desc.style == ArtifactStyle::Host ? SLANG_HOST_HOST_CALLABLE + : SLANG_SHADER_HOST_CALLABLE; + case Kind::ObjectCode: + return SLANG_OBJECT_CODE; + default: + break; } } else { switch (desc.payload) { - case Payload::SPIRV: return SLANG_SPIRV; - case Payload::DXIL: return SLANG_DXIL; - case Payload::DXBC: return SLANG_DXBC; - case Payload::PTX: return SLANG_PTX; - case Payload::MetalAIR: return SLANG_METAL_LIB_ASM; - default: break; + case Payload::SPIRV: + return SLANG_SPIRV; + case Payload::DXIL: + return SLANG_DXIL; + case Payload::DXBC: + return SLANG_DXBC; + case Payload::PTX: + return SLANG_PTX; + case Payload::MetalAIR: + return SLANG_METAL_LIB_ASM; + case Payload::WGSL_SPIRV: + return SLANG_WGSL_SPIRV; + default: + break; } } } @@ -383,35 +460,31 @@ SLANG_HIERARCHICAL_ENUM(ArtifactStyle, SLANG_ARTIFACT_STYLE, SLANG_ARTIFACT_STYL } -namespace { // anonymous +namespace +{ // anonymous struct KindExtension { ArtifactKind kind; UnownedStringSlice ext; }; -} // anonymous +} // namespace -#define SLANG_KIND_EXTENSION(kind, ext) \ - { ArtifactKind::kind, toSlice(ext) }, +#define SLANG_KIND_EXTENSION(kind, ext) {ArtifactKind::kind, toSlice(ext)}, -static const KindExtension g_cpuKindExts[] = -{ +static const KindExtension g_cpuKindExts[] = { #if SLANG_WINDOWS_FAMILY - SLANG_KIND_EXTENSION(Library, "lib") - SLANG_KIND_EXTENSION(ObjectCode, "obj") - SLANG_KIND_EXTENSION(Executable, "exe") - SLANG_KIND_EXTENSION(SharedLibrary, "dll") -#else - SLANG_KIND_EXTENSION(Library, "a") - SLANG_KIND_EXTENSION(ObjectCode, "o") - SLANG_KIND_EXTENSION(Executable, "") + SLANG_KIND_EXTENSION(Library, "lib") SLANG_KIND_EXTENSION(ObjectCode, "obj") + SLANG_KIND_EXTENSION(Executable, "exe") SLANG_KIND_EXTENSION(SharedLibrary, "dll") +#else + SLANG_KIND_EXTENSION(Library, "a") SLANG_KIND_EXTENSION(ObjectCode, "o") + SLANG_KIND_EXTENSION(Executable, "") #if __CYGWIN__ - SLANG_KIND_EXTENSION(SharedLibrary, "dll") + SLANG_KIND_EXTENSION(SharedLibrary, "dll") #elif SLANG_APPLE_FAMILY - SLANG_KIND_EXTENSION(SharedLibrary, "dylib") + SLANG_KIND_EXTENSION(SharedLibrary, "dylib") #else - SLANG_KIND_EXTENSION(SharedLibrary, "so") + SLANG_KIND_EXTENSION(SharedLibrary, "so") #endif #endif @@ -419,10 +492,11 @@ static const KindExtension g_cpuKindExts[] = /* static */ bool ArtifactDescUtil::isCpuBinary(const ArtifactDesc& desc) { - return isDerivedFrom(desc.kind, ArtifactKind::CompileBinary) && isDerivedFrom(desc.payload, ArtifactPayload::CPULike); + return isDerivedFrom(desc.kind, ArtifactKind::CompileBinary) && + isDerivedFrom(desc.payload, ArtifactPayload::CPULike); } -/* static */bool ArtifactDescUtil::isText(const ArtifactDesc& desc) +/* static */ bool ArtifactDescUtil::isText(const ArtifactDesc& desc) { // If it's derived from text... if (isDerivedFrom(desc.kind, ArtifactKind::Text)) @@ -440,33 +514,34 @@ static const KindExtension g_cpuKindExts[] = return false; } -/* static */bool ArtifactDescUtil::isGpuUsable(const ArtifactDesc& desc) +/* static */ bool ArtifactDescUtil::isGpuUsable(const ArtifactDesc& desc) { if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) { return isDerivedFrom(desc.payload, ArtifactPayload::KernelLike); } - // PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be passed - // to CUDA runtime + // PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be + // passed to CUDA runtime return desc.kind == ArtifactKind::Assembly && desc.payload == ArtifactPayload::PTX; } -/* static */bool ArtifactDescUtil::isKindBinaryLinkable(Kind kind) +/* static */ bool ArtifactDescUtil::isKindBinaryLinkable(Kind kind) { switch (kind) { - case Kind::Library: - case Kind::ObjectCode: + case Kind::Library: + case Kind::ObjectCode: { return true; } - default: break; + default: + break; } return false; } -/* static */bool ArtifactDescUtil::isLinkable(const ArtifactDesc& desc) +/* static */ bool ArtifactDescUtil::isLinkable(const ArtifactDesc& desc) { // If is a container with compile results *assume* that result is linkable if (isDerivedFrom(desc.kind, ArtifactKind::Container) && @@ -476,7 +551,7 @@ static const KindExtension g_cpuKindExts[] = } // if it's a compile binary or a container - if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) + if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) { if (isDerivedFrom(desc.payload, ArtifactPayload::KernelLike)) { @@ -491,8 +566,7 @@ static const KindExtension g_cpuKindExts[] = else if (isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) { // If kind is exe or shared library, linking will arguably not work - if (desc.kind == ArtifactKind::SharedLibrary || - desc.kind == ArtifactKind::Executable) + if (desc.kind == ArtifactKind::SharedLibrary || desc.kind == ArtifactKind::Executable) { return false; } @@ -508,7 +582,7 @@ static const KindExtension g_cpuKindExts[] = return false; } -/* static */bool ArtifactDescUtil::isCpuLikeTarget(const ArtifactDesc& desc) +/* static */ bool ArtifactDescUtil::isCpuLikeTarget(const ArtifactDesc& desc) { if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary)) { @@ -523,10 +597,9 @@ static const KindExtension g_cpuKindExts[] = return false; } -/* static */ArtifactDesc ArtifactDescUtil::getDescFromExtension(const UnownedStringSlice& slice) +/* static */ ArtifactDesc ArtifactDescUtil::getDescFromExtension(const UnownedStringSlice& slice) { - if (slice == "slang-module" || - slice == "slang-lib") + if (slice == "slang-module" || slice == "slang-lib") { return ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::SlangIR); } @@ -570,7 +643,7 @@ static const KindExtension g_cpuKindExts[] = return ArtifactDesc::make(ArtifactKind::Assembly, ArtifactPayload::HostCPU); } - // TODO(JS): Unfortunately map extension is also used from output for linkage from + // TODO(JS): Unfortunately map extension is also used from output for linkage from // Visual Studio. It's used here for source map. if (slice == toSlice("map")) { @@ -597,7 +670,7 @@ static const KindExtension g_cpuKindExts[] = return makeDescForCompileTarget(target); } -/* static */ArtifactDesc ArtifactDescUtil::getDescFromPath(const UnownedStringSlice& slice) +/* static */ ArtifactDesc ArtifactDescUtil::getDescFromPath(const UnownedStringSlice& slice) { auto extension = Path::getPathExt(slice); return getDescFromExtension(extension); @@ -621,36 +694,53 @@ static UnownedStringSlice _getPayloadExtension(ArtifactPayload payload) typedef ArtifactPayload Payload; switch (payload) { - /* Source types */ - case Payload::HLSL: return toSlice("hlsl"); - case Payload::GLSL: return toSlice("glsl"); + /* Source types */ + case Payload::HLSL: + return toSlice("hlsl"); + case Payload::GLSL: + return toSlice("glsl"); - case Payload::Cpp: return toSlice("cpp"); - case Payload::C: return toSlice("c"); + case Payload::Cpp: + return toSlice("cpp"); + case Payload::C: + return toSlice("c"); - case Payload::Metal: return toSlice("metal"); + case Payload::Metal: + return toSlice("metal"); - case Payload::CUDA: return toSlice("cu"); + case Payload::CUDA: + return toSlice("cu"); - case Payload::Slang: return toSlice("slang"); + case Payload::Slang: + return toSlice("slang"); - /* Binary types */ - case Payload::DXIL: return toSlice("dxil"); - case Payload::DXBC: return toSlice("dxbc"); - case Payload::SPIRV: return toSlice("spv"); + /* Binary types */ + case Payload::DXIL: + return toSlice("dxil"); + case Payload::DXBC: + return toSlice("dxbc"); + case Payload::SPIRV: + return toSlice("spv"); - case Payload::PTX: return toSlice("ptx"); + case Payload::PTX: + return toSlice("ptx"); - case Payload::LLVMIR: return toSlice("llvm-ir"); + case Payload::LLVMIR: + return toSlice("llvm-ir"); - case Payload::SlangIR: return toSlice("slang-ir"); - - case Payload::MetalAIR: return toSlice("metallib"); + case Payload::SlangIR: + return toSlice("slang-ir"); - case Payload::PdbDebugInfo: return toSlice("pdb"); - case Payload::SourceMap: return toSlice("map"); + case Payload::MetalAIR: + return toSlice("metallib"); - default: break; + case Payload::PdbDebugInfo: + return toSlice("pdb"); + case Payload::SourceMap: + return toSlice("map"); + + default: + break; } return UnownedStringSlice(); } @@ -659,7 +749,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S { switch (desc.kind) { - case ArtifactKind::Library: + case ArtifactKind::Library: { // Special cases if (desc.payload == Payload::SlangIR) @@ -673,30 +763,30 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S out << toSlice("metallib"); return SLANG_OK; } - + break; } - case ArtifactKind::Zip: + case ArtifactKind::Zip: { out << toSlice("zip"); return SLANG_OK; } - case ArtifactKind::RiffContainer: + case ArtifactKind::RiffContainer: { out << toSlice("riff"); return SLANG_OK; } - case ArtifactKind::RiffLz4Container: + case ArtifactKind::RiffLz4Container: { out << toSlice("riff-lz4"); return SLANG_OK; } - case ArtifactKind::RiffDeflateContainer: + case ArtifactKind::RiffDeflateContainer: { out << toSlice("riff-deflate"); return SLANG_OK; } - case ArtifactKind::Assembly: + case ArtifactKind::Assembly: { // Special case PTX, because it is assembly if (desc.payload == Payload::PTX) @@ -717,7 +807,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S out << toSlice("-asm"); return SLANG_OK; } - case ArtifactKind::Source: + case ArtifactKind::Source: { auto ext = _getPayloadExtension(desc.payload); if (ext.begin() != nullptr) @@ -725,10 +815,10 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S out << ext; return SLANG_OK; } - // Don't know the extension for that + // Don't know the extension for that return SLANG_E_NOT_FOUND; } - case ArtifactKind::Json: + case ArtifactKind::Json: { auto ext = _getPayloadExtension(desc.payload); if (ext.begin() != nullptr) @@ -736,8 +826,8 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S // TODO(JS): // Do we need to alter the extension or the name if it's an // obfuscated map? - //if (isDerivedFrom(desc.style, ArtifactStyle::Obfuscated)) - //{ + // if (isDerivedFrom(desc.style, ArtifactStyle::Obfuscated)) + //{ //} out << ext; @@ -748,7 +838,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S out << "json"; return SLANG_OK; } - case ArtifactKind::CompileBinary: + case ArtifactKind::CompileBinary: { if (isDerivedFrom(desc.payload, ArtifactPayload::SlangIR) || isDerivedFrom(desc.payload, ArtifactPayload::SlangAST)) @@ -758,7 +848,8 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S } break; } - default: break; + default: + break; } if (ArtifactDescUtil::isGpuUsable(desc)) @@ -771,21 +862,26 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S } } - if (ArtifactDescUtil::isCpuLikeTarget(desc) && !isDerivedFrom(desc.payload, ArtifactPayload::Source)) + if (ArtifactDescUtil::isCpuLikeTarget(desc) && + !isDerivedFrom(desc.payload, ArtifactPayload::Source)) { return appendCpuExtensionForKind(desc.kind, out); } - + return SLANG_E_NOT_FOUND; } -/* static */String ArtifactDescUtil::getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path) +/* static */ String ArtifactDescUtil::getBaseNameFromPath( + const ArtifactDesc& desc, + const UnownedStringSlice& path) { const String name = Path::getFileName(path); return getBaseNameFromName(desc, name.getUnownedSlice()); } -/* static */String ArtifactDescUtil::getBaseNameFromName(const ArtifactDesc& desc, const UnownedStringSlice& inName) +/* static */ String ArtifactDescUtil::getBaseNameFromName( + const ArtifactDesc& desc, + const UnownedStringSlice& inName) { String name(inName); @@ -794,8 +890,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S { // Strip lib prefix if (isCpuBinary(desc) && - (desc.kind == ArtifactKind::Library || - desc.kind == ArtifactKind::SharedLibrary)) + (desc.kind == ArtifactKind::Library || desc.kind == ArtifactKind::SharedLibrary)) { // If it starts with lib strip it if (name.startsWith("lib")) @@ -809,12 +904,11 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S // Strip any extension { StringBuilder descExt; - if (SLANG_SUCCEEDED(appendDefaultExtension(desc, descExt)) && - descExt.getLength()) + if (SLANG_SUCCEEDED(appendDefaultExtension(desc, descExt)) && descExt.getLength()) { - // TODO(JS): + // TODO(JS): // It has an extension. We could check if they are the same - // but if they are not that might be fine, because of case insensitivity + // but if they are not that might be fine, because of case insensitivity // or perhaps there are multiple valid extensions. So for now we just strip // and don't bother confirming with something like.. // if (Path::getPathExt(name) == descExt)) @@ -826,19 +920,24 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S return name; } -/* static */String ArtifactDescUtil::getBaseName(const ArtifactDesc& desc, IPathArtifactRepresentation* pathRep) +/* static */ String ArtifactDescUtil::getBaseName( + const ArtifactDesc& desc, + IPathArtifactRepresentation* pathRep) { UnownedStringSlice path(pathRep->getPath()); return getBaseNameFromPath(desc, path); } -/* static */SlangResult ArtifactDescUtil::hasDefinedNameForDesc(const ArtifactDesc& desc) +/* static */ SlangResult ArtifactDescUtil::hasDefinedNameForDesc(const ArtifactDesc& desc) { StringBuilder buf; return SLANG_SUCCEEDED(appendDefaultExtension(desc, buf)); } -/* static */SlangResult ArtifactDescUtil::calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& inBaseName, StringBuilder& outName) +/* static */ SlangResult ArtifactDescUtil::calcNameForDesc( + const ArtifactDesc& desc, + const UnownedStringSlice& inBaseName, + StringBuilder& outName) { UnownedStringSlice baseName(inBaseName); @@ -850,8 +949,7 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S // Prefix if (isCpuBinary(desc) && - (desc.kind == ArtifactKind::SharedLibrary || - desc.kind == ArtifactKind::Library)) + (desc.kind == ArtifactKind::SharedLibrary || desc.kind == ArtifactKind::Library)) { const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY; if (isSharedLibraryPrefixPlatform) @@ -882,7 +980,10 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S return SLANG_OK; } -/* static */SlangResult ArtifactDescUtil::calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath) +/* static */ SlangResult ArtifactDescUtil::calcPathForDesc( + const ArtifactDesc& desc, + const UnownedStringSlice& basePath, + StringBuilder& outPath) { outPath.clear(); @@ -907,18 +1008,17 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S } } -/* static */bool ArtifactDescUtil::isDisassembly(const ArtifactDesc& from, const ArtifactDesc& to) +/* static */ bool ArtifactDescUtil::isDisassembly(const ArtifactDesc& from, const ArtifactDesc& to) { // From must be a binary like type if (!isDerivedFrom(from.kind, ArtifactKind::CompileBinary)) { return false; } - - + + // Target must be assembly, and the payload be the same type - if (!(to.kind == ArtifactKind::Assembly && - to.payload == from.payload)) + if (!(to.kind == ArtifactKind::Assembly && to.payload == from.payload)) { return false; } @@ -927,15 +1027,14 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S // Check the payload seems like something plausible to 'disassemble' if (!(isDerivedFrom(payload, ArtifactPayload::KernelLike) || - isDerivedFrom(payload, ArtifactPayload::CPULike) || - isDerivedFrom(payload, ArtifactPayload::GeneralIR))) + isDerivedFrom(payload, ArtifactPayload::CPULike) || + isDerivedFrom(payload, ArtifactPayload::GeneralIR))) { return false; } // If the flags or style are different, then it's something more than just disassembly - if (!(from.style == to.style && - from.flags == to.flags)) + if (!(from.style == to.style && from.flags == to.flags)) { return false; } @@ -943,17 +1042,17 @@ SlangResult ArtifactDescUtil::appendDefaultExtension(const ArtifactDesc& desc, S return true; } -/* static */void ArtifactDescUtil::appendText(const ArtifactDesc& desc, StringBuilder& out) +/* static */ void ArtifactDescUtil::appendText(const ArtifactDesc& desc, StringBuilder& out) { out << getName(desc.kind) << "/" << getName(desc.payload) << "/" << getName(desc.style); // TODO(JS): Output flags? None currently used } -/* static */String ArtifactDescUtil::getText(const ArtifactDesc& desc) +/* static */ String ArtifactDescUtil::getText(const ArtifactDesc& desc) { StringBuilder buf; appendText(desc, buf); - return std::move(buf); + return buf; } } // namespace Slang diff --git a/source/compiler-core/slang-artifact-desc-util.h b/source/compiler-core/slang-artifact-desc-util.h index 879732bb13..0c513474bf 100644 --- a/source/compiler-core/slang-artifact-desc-util.h +++ b/source/compiler-core/slang-artifact-desc-util.h @@ -8,25 +8,25 @@ namespace Slang { - /// Get the parent kind +/// Get the parent kind ArtifactKind getParent(ArtifactKind kind); - /// Returns true if kind is derived from base +/// Returns true if kind is derived from base bool isDerivedFrom(ArtifactKind kind, ArtifactKind base); - /// Get the name for the kind +/// Get the name for the kind UnownedStringSlice getName(ArtifactKind kind); - /// Get the parent payload -ArtifactPayload getParent(ArtifactPayload payload); - /// Returns true if payload is derived from base +/// Get the parent payload +ArtifactPayload getParent(ArtifactPayload payload); +/// Returns true if payload is derived from base bool isDerivedFrom(ArtifactPayload payload, ArtifactPayload base); - /// Get the name for the payload +/// Get the name for the payload UnownedStringSlice getName(ArtifactPayload payload); - /// Get the parent style +/// Get the parent style ArtifactStyle getParent(ArtifactStyle style); - /// Returns true if style is derived from base +/// Returns true if style is derived from base bool isDerivedFrom(ArtifactStyle style, ArtifactStyle base); - /// Get the name for the style +/// Get the name for the style UnownedStringSlice getName(ArtifactStyle style); struct ArtifactDescUtil @@ -35,89 +35,95 @@ struct ArtifactDescUtil typedef ArtifactKind Kind; typedef ArtifactStyle Style; typedef ArtifactDesc Desc; - - /// Returns true if the kind is binary linkable + + /// Returns true if the kind is binary linkable static bool isKindBinaryLinkable(Kind kind); - /// True if is a CPU target - either + /// True if is a CPU target - either static bool isCpuLikeTarget(const ArtifactDesc& desc); - /// True if is a CPU binary + /// True if is a CPU binary static bool isCpuBinary(const ArtifactDesc& desc); - /// True if is a GPU usable (can be passed to a driver/API and be used) + /// True if is a GPU usable (can be passed to a driver/API and be used) static bool isGpuUsable(const ArtifactDesc& desc); - /// True if the desc holds textual information + /// True if the desc holds textual information static bool isText(const ArtifactDesc& desc); - /// True if artifact appears to be linkable + /// True if artifact appears to be linkable static bool isLinkable(const ArtifactDesc& desc); - /// Try to determine the desc from just a file extension (passed without .) + /// Try to determine the desc from just a file extension (passed without .) static ArtifactDesc getDescFromExtension(const UnownedStringSlice& slice); - /// Try to determine the desc from a path + /// Try to determine the desc from a path static ArtifactDesc getDescFromPath(const UnownedStringSlice& slice); - /// Appends the default file extension for the artifact type. + /// Appends the default file extension for the artifact type. static SlangResult appendDefaultExtension(const ArtifactDesc& desc, StringBuilder& out); - /// Get the extension for CPU/Host for a kind + /// Get the extension for CPU/Host for a kind static SlangResult appendCpuExtensionForKind(Kind kind, StringBuilder& out); - /// Given a desc and a path returns the base name (stripped of prefix and extension) + /// Given a desc and a path returns the base name (stripped of prefix and extension) static String getBaseNameFromPath(const ArtifactDesc& desc, const UnownedStringSlice& path); - /// Given a desc and a name returns the base name (stripped of prefix and extension) + /// Given a desc and a name returns the base name (stripped of prefix and extension) static String getBaseNameFromName(const ArtifactDesc& desc, const UnownedStringSlice& path); - /// Get the base name of the fileRep - /// If no base name is found will return an empty slice + /// Get the base name of the fileRep + /// If no base name is found will return an empty slice static String getBaseName(const ArtifactDesc& desc, IPathArtifactRepresentation* fileRep); - /// Given a desc and a basePath returns a suitable path for a entity of specified desc - static SlangResult calcPathForDesc(const ArtifactDesc& desc, const UnownedStringSlice& basePath, StringBuilder& outPath); + /// Given a desc and a basePath returns a suitable path for a entity of specified desc + static SlangResult calcPathForDesc( + const ArtifactDesc& desc, + const UnownedStringSlice& basePath, + StringBuilder& outPath); - /// Given a desc and a baseName works out the the output file name - static SlangResult calcNameForDesc(const ArtifactDesc& desc, const UnownedStringSlice& baseName, StringBuilder& outName); + /// Given a desc and a baseName works out the the output file name + static SlangResult calcNameForDesc( + const ArtifactDesc& desc, + const UnownedStringSlice& baseName, + StringBuilder& outName); - /// Returns true if there is a defined name extension/type for this desc + /// Returns true if there is a defined name extension/type for this desc static SlangResult hasDefinedNameForDesc(const ArtifactDesc& desc); - /// Given a target returns the ArtifactDesc + /// Given a target returns the ArtifactDesc static ArtifactDesc makeDescForCompileTarget(SlangCompileTarget target); - /// Get the payload for the specified language + /// Get the payload for the specified language static ArtifactPayload getPayloadForSourceLanaguage(SlangSourceLanguage language); - /// Given a source language return a desc + /// Given a source language return a desc static ArtifactDesc makeDescForSourceLanguage(SlangSourceLanguage language); - /// Returns the closest compile target for desc. Will return - /// SLANG_TARGET_UNKNOWN if not known + /// Returns the closest compile target for desc. Will return + /// SLANG_TARGET_UNKNOWN if not known static SlangCompileTarget getCompileTargetFromDesc(const ArtifactDesc& desc); - /// Make ArtifactDesc from target + /// Make ArtifactDesc from target static bool isDescDerivedFrom(const ArtifactDesc& desc, const ArtifactDesc& from); - /// True if `to` is disassembly of `from` + /// True if `to` is disassembly of `from` static bool isDisassembly(const ArtifactDesc& from, const ArtifactDesc& to); - /// Append the desc as text to out + /// Append the desc as text to out static void appendText(const ArtifactDesc& desc, StringBuilder& out); - /// Given an artifact desc return a description as a string + /// Given an artifact desc return a description as a string static String getText(const ArtifactDesc& desc); - }; // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -inline /* static */bool ArtifactDescUtil::isDescDerivedFrom(const ArtifactDesc& desc, const ArtifactDesc& from) +inline /* static */ bool ArtifactDescUtil::isDescDerivedFrom( + const ArtifactDesc& desc, + const ArtifactDesc& from) { - // TODO(JS): Currently this ignores flags in desc. That may or may not be right + // TODO(JS): Currently this ignores flags in desc. That may or may not be right // long term. - return isDerivedFrom(desc.kind, from.kind) && - isDerivedFrom(desc.payload, from.payload) && - isDerivedFrom(desc.style, from.style); + return isDerivedFrom(desc.kind, from.kind) && isDerivedFrom(desc.payload, from.payload) && + isDerivedFrom(desc.style, from.style); } } // namespace Slang diff --git a/source/compiler-core/slang-artifact-diagnostic-util.cpp b/source/compiler-core/slang-artifact-diagnostic-util.cpp index 38e5c5fd81..98f8f2245c 100644 --- a/source/compiler-core/slang-artifact-diagnostic-util.cpp +++ b/source/compiler-core/slang-artifact-diagnostic-util.cpp @@ -4,22 +4,30 @@ #include "../core/slang-char-util.h" #include "../core/slang-string-util.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDiagnosticsUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */UnownedStringSlice ArtifactDiagnosticUtil::getSeverityText(Severity severity) +/* static */ UnownedStringSlice ArtifactDiagnosticUtil::getSeverityText(Severity severity) { switch (severity) { - default: return UnownedStringSlice::fromLiteral("Unknown"); - case Severity::Info: return UnownedStringSlice::fromLiteral("Info"); - case Severity::Warning: return UnownedStringSlice::fromLiteral("Warning"); - case Severity::Error: return UnownedStringSlice::fromLiteral("Error"); + default: + return UnownedStringSlice::fromLiteral("Unknown"); + case Severity::Info: + return UnownedStringSlice::fromLiteral("Info"); + case Severity::Warning: + return UnownedStringSlice::fromLiteral("Warning"); + case Severity::Error: + return UnownedStringSlice::fromLiteral("Error"); } } -/* static */SlangResult ArtifactDiagnosticUtil::splitPathLocation(SliceAllocator& allocator, const UnownedStringSlice& pathLocation, ArtifactDiagnostic& outDiagnostic) +/* static */ SlangResult ArtifactDiagnosticUtil::splitPathLocation( + SliceAllocator& allocator, + const UnownedStringSlice& pathLocation, + ArtifactDiagnostic& outDiagnostic) { const Index lineStartIndex = pathLocation.lastIndexOf('('); if (lineStartIndex >= 0) @@ -37,8 +45,8 @@ namespace Slang { UnownedStringSlice slices[2]; const Index numSlices = StringUtil::split(locationSlice, ',', 2, slices); - // NOTE! FXC actually outputs a range of columns in the form of START-END in the column position - // We don't need to parse here, because we only care about the line number + // NOTE! FXC actually outputs a range of columns in the form of START-END in the column + // position We don't need to parse here, because we only care about the line number Int lineNumber = 0; if (numSlices > 0) @@ -57,7 +65,10 @@ namespace Slang { return SLANG_OK; } -/* static */SlangResult ArtifactDiagnosticUtil::splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List& outSlices) +/* static */ SlangResult ArtifactDiagnosticUtil::splitColonDelimitedLine( + const UnownedStringSlice& line, + Int pathIndex, + List& outSlices) { StringUtil::split(line, ':', outSlices); @@ -69,7 +80,8 @@ namespace Slang { if (pathStart.getLength() == 1 && CharUtil::isAlpha(pathStart[0])) { // Splice back together - outSlices[pathIndex] = UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end()); + outSlices[pathIndex] = + UnownedStringSlice(outSlices[pathIndex].begin(), outSlices[pathIndex + 1].end()); outSlices.removeAt(pathIndex + 1); } } @@ -77,7 +89,12 @@ namespace Slang { return SLANG_OK; } -/* static */SlangResult ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(SliceAllocator& allocator, const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, IArtifactDiagnostics* diagnostics) +/* static */ SlangResult ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics( + SliceAllocator& allocator, + const UnownedStringSlice& inText, + Int pathIndex, + LineParser lineParser, + IArtifactDiagnostics* diagnostics) { List splitLine; @@ -106,7 +123,9 @@ namespace Slang { return SLANG_OK; } -/* static */void ArtifactDiagnosticUtil::maybeAddNote(const UnownedStringSlice& in, IArtifactDiagnostics* diagnostics) +/* static */ void ArtifactDiagnosticUtil::maybeAddNote( + const UnownedStringSlice& in, + IArtifactDiagnostics* diagnostics) { // Don't bother adding an empty line if (in.trim().getLength() == 0) diff --git a/source/compiler-core/slang-artifact-diagnostic-util.h b/source/compiler-core/slang-artifact-diagnostic-util.h index fe158ce384..2ccd138207 100644 --- a/source/compiler-core/slang-artifact-diagnostic-util.h +++ b/source/compiler-core/slang-artifact-diagnostic-util.h @@ -2,10 +2,8 @@ #ifndef SLANG_ARTIFACT_DIAGNOSTIC_UTIL_H #define SLANG_ARTIFACT_DIAGNOSTIC_UTIL_H -#include "slang-artifact.h" - #include "slang-artifact-associated.h" - +#include "slang-artifact.h" #include "slang-slice-allocator.h" namespace Slang @@ -18,16 +16,32 @@ struct ArtifactDiagnosticUtil /// Given severity return as text static UnownedStringSlice getSeverityText(Severity severity); - /// Given a path, that holds line number and potentially column number in () after path, writes result into outDiagnostic - static SlangResult splitPathLocation(SliceAllocator& allocator, const UnownedStringSlice& pathLocation, ArtifactDiagnostic& outDiagnostic); - - /// Split the line (separated by :), where a path is at pathIndex - static SlangResult splitColonDelimitedLine(const UnownedStringSlice& line, Int pathIndex, List& outSlices); - - typedef SlangResult(*LineParser)(SliceAllocator& allocator, const UnownedStringSlice& line, List& lineSlices, ArtifactDiagnostic& outDiagnostic); + /// Given a path, that holds line number and potentially column number in () after path, writes + /// result into outDiagnostic + static SlangResult splitPathLocation( + SliceAllocator& allocator, + const UnownedStringSlice& pathLocation, + ArtifactDiagnostic& outDiagnostic); + + /// Split the line (separated by :), where a path is at pathIndex + static SlangResult splitColonDelimitedLine( + const UnownedStringSlice& line, + Int pathIndex, + List& outSlices); + + typedef SlangResult (*LineParser)( + SliceAllocator& allocator, + const UnownedStringSlice& line, + List& lineSlices, + ArtifactDiagnostic& outDiagnostic); /// Given diagnostics in inText that are colon delimited, use lineParser to do per line parsing. - static SlangResult parseColonDelimitedDiagnostics(SliceAllocator& allocator, const UnownedStringSlice& inText, Int pathIndex, LineParser lineParser, IArtifactDiagnostics* diagnostics); + static SlangResult parseColonDelimitedDiagnostics( + SliceAllocator& allocator, + const UnownedStringSlice& inText, + Int pathIndex, + LineParser lineParser, + IArtifactDiagnostics* diagnostics); /// Maybe add a note static void maybeAddNote(const UnownedStringSlice& in, IArtifactDiagnostics* diagnostics); diff --git a/source/compiler-core/slang-artifact-handler-impl.cpp b/source/compiler-core/slang-artifact-handler-impl.cpp index 6fc96dc442..571c45c7bc 100644 --- a/source/compiler-core/slang-artifact-handler-impl.cpp +++ b/source/compiler-core/slang-artifact-handler-impl.cpp @@ -1,340 +1,370 @@ // slang-artifact-handler-impl.cpp #include "slang-artifact-handler-impl.h" -#include "slang-artifact-impl.h" -#include "slang-artifact-representation-impl.h" - -#include "slang-artifact-desc-util.h" - -#include "slang-artifact-helper.h" -#include "slang-artifact-util.h" - #include "../core/slang-castable.h" - -#include "slang-slice-allocator.h" - #include "../core/slang-file-system.h" #include "../core/slang-io.h" #include "../core/slang-shared-library.h" - -#include "slang-source-map.h" - +#include "slang-artifact-desc-util.h" +#include "slang-artifact-helper.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" +#include "slang-artifact-util.h" #include "slang-json-source-map-util.h" +#include "slang-slice-allocator.h" +#include "slang-source-map.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DefaultArtifactHandler !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */DefaultArtifactHandler DefaultArtifactHandler::g_singleton; +/* static */ DefaultArtifactHandler DefaultArtifactHandler::g_singleton; SlangResult DefaultArtifactHandler::queryInterface(SlangUUID const& uuid, void** outObject) { - if ([[maybe_unused]] auto ptr = getInterface(uuid)) - { + if ([[maybe_unused]] auto ptr = getInterface(uuid)) + { SLANG_ASSERT(ptr == this); - addRef(); - *outObject = static_cast(this); - return SLANG_OK; - } - return SLANG_E_NO_INTERFACE; + addRef(); + *outObject = static_cast(this); + return SLANG_OK; + } + return SLANG_E_NO_INTERFACE; } void* DefaultArtifactHandler::castAs(const Guid& guid) { - if (auto ptr = getInterface(guid)) - { - return ptr; - } - return getObject(guid); + if (auto ptr = getInterface(guid)) + { + return ptr; + } + return getObject(guid); } void* DefaultArtifactHandler::getInterface(const Guid& uuid) { - if (uuid == ISlangUnknown::getTypeGuid() || - uuid == ICastable::getTypeGuid() || - uuid == IArtifactHandler::getTypeGuid()) - { - return static_cast(this); - } - - return nullptr; + if (uuid == ISlangUnknown::getTypeGuid() || uuid == ICastable::getTypeGuid() || + uuid == IArtifactHandler::getTypeGuid()) + { + return static_cast(this); + } + + return nullptr; } void* DefaultArtifactHandler::getObject(const Guid& uuid) { - SLANG_UNUSED(uuid); - return nullptr; + SLANG_UNUSED(uuid); + return nullptr; } -SlangResult DefaultArtifactHandler::_addRepresentation(IArtifact* artifact, ArtifactKeep keep, ISlangUnknown* rep, ICastable** outCastable) +SlangResult DefaultArtifactHandler::_addRepresentation( + IArtifact* artifact, + ArtifactKeep keep, + ISlangUnknown* rep, + ICastable** outCastable) { - SLANG_ASSERT(rep); - - // See if it implements ICastable - { - ComPtr castable; - if (SLANG_SUCCEEDED(rep->queryInterface(SLANG_IID_PPV_ARGS(castable.writeRef()))) && castable) - { - return _addRepresentation(artifact, keep, castable, outCastable); - } - } - - // We have to wrap - ComPtr adapter(new UnknownCastableAdapter(rep)); - return _addRepresentation(artifact, keep, adapter, outCastable); + SLANG_ASSERT(rep); + + // See if it implements ICastable + { + ComPtr castable; + if (SLANG_SUCCEEDED(rep->queryInterface(SLANG_IID_PPV_ARGS(castable.writeRef()))) && + castable) + { + return _addRepresentation(artifact, keep, castable, outCastable); + } + } + + // We have to wrap + ComPtr adapter(new UnknownCastableAdapter(rep)); + return _addRepresentation(artifact, keep, adapter, outCastable); } -SlangResult DefaultArtifactHandler::_addRepresentation(IArtifact* artifact, ArtifactKeep keep, ICastable* castable, ICastable** outCastable) +SlangResult DefaultArtifactHandler::_addRepresentation( + IArtifact* artifact, + ArtifactKeep keep, + ICastable* castable, + ICastable** outCastable) { - SLANG_ASSERT(castable); + SLANG_ASSERT(castable); - if (canKeep(keep)) - { - artifact->addRepresentation(castable); - } + if (canKeep(keep)) + { + artifact->addRepresentation(castable); + } - castable->addRef(); - *outCastable = castable; - return SLANG_OK; + castable->addRef(); + *outCastable = castable; + return SLANG_OK; } SlangResult DefaultArtifactHandler::expandChildren(IArtifact* container) { - // First check if it has already been expanded - SlangResult res = container->getExpandChildrenResult(); - if (res != SLANG_E_UNINITIALIZED) - { - // It's already expanded - return res; - } - - // For the generic container type, we just expand as empty - const auto desc = container->getDesc(); + // First check if it has already been expanded + SlangResult res = container->getExpandChildrenResult(); + if (res != SLANG_E_UNINITIALIZED) + { + // It's already expanded + return res; + } + + // For the generic container type, we just expand as empty + const auto desc = container->getDesc(); if (desc.kind == ArtifactKind::Container) { // If it's just a generic container, we can assume it's expanded, and be done return SLANG_OK; } - if (isDerivedFrom(desc.kind, ArtifactKind::Container)) - { + if (isDerivedFrom(desc.kind, ArtifactKind::Container)) + { // TODO(JS): // Proper implementation should (for example) be able to expand a Zip file etc. // For now we just set that there are no children, and be done - container->setChildren(nullptr, 0); - return SLANG_E_NOT_IMPLEMENTED; - } + container->setChildren(nullptr, 0); + return SLANG_E_NOT_IMPLEMENTED; + } // We can't expand non container like types, so we just make sure it's empty container->setChildren(nullptr, 0); - return SLANG_OK; + return SLANG_OK; } -static SlangResult _loadSourceMap(IArtifact* artifact, ArtifactKeep intermediateKeep, SourceMap& outSourceMap) +static SlangResult _loadSourceMap( + IArtifact* artifact, + ArtifactKeep intermediateKeep, + SourceMap& outSourceMap) { - const auto desc = artifact->getDesc(); - if (isDerivedFrom(desc.kind, ArtifactKind::Json) && - isDerivedFrom(desc.payload, ArtifactPayload::SourceMap)) - { - ComPtr blob; - SLANG_RETURN_ON_FAIL(artifact->loadBlob(intermediateKeep, blob.writeRef())); - - SLANG_RETURN_ON_FAIL(JSONSourceMapUtil::read(blob, outSourceMap)); - return SLANG_OK; - } - - return SLANG_FAIL; + const auto desc = artifact->getDesc(); + if (isDerivedFrom(desc.kind, ArtifactKind::Json) && + isDerivedFrom(desc.payload, ArtifactPayload::SourceMap)) + { + ComPtr blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(intermediateKeep, blob.writeRef())); + + SLANG_RETURN_ON_FAIL(JSONSourceMapUtil::read(blob, outSourceMap)); + return SLANG_OK; + } + + return SLANG_FAIL; } -SlangResult DefaultArtifactHandler::getOrCreateRepresentation(IArtifact* artifact, const Guid& guid, ArtifactKeep keep, ICastable** outCastable) +SlangResult DefaultArtifactHandler::getOrCreateRepresentation( + IArtifact* artifact, + const Guid& guid, + ArtifactKeep keep, + ICastable** outCastable) { - const auto reps = artifact->getRepresentations(); - - // See if we already have a rep of this type - for (ICastable* rep : reps) - { - if (rep->castAs(guid)) - { - rep->addRef(); - *outCastable = rep; - return SLANG_OK; - } - } - - // We can ask each representation if they can do the conversion to the type, if they can we just use that - for (ICastable* castable : reps) - { - if (auto rep = as(castable)) - { - ComPtr created; - if (SLANG_SUCCEEDED(rep->createRepresentation(guid, created.writeRef()))) - { - SLANG_ASSERT(created); - // Add the rep - return _addRepresentation(artifact, keep, created, outCastable); - } - } - } - - // Special cases - if (guid == SourceMap::getTypeGuid()) - { - // Blob -> SourceMap - ComPtr> sourceMap(new BoxValue); - SLANG_RETURN_ON_FAIL(_loadSourceMap(artifact, getIntermediateKeep(keep), sourceMap->get())); - return _addRepresentation(artifact, keep, sourceMap, outCastable); - } - else if (guid == ISlangSharedLibrary::getTypeGuid()) - { - ComPtr sharedLib; - SLANG_RETURN_ON_FAIL(_loadSharedLibrary(artifact, sharedLib.writeRef())); - return _addRepresentation(artifact, keep, sharedLib, outCastable); - } - else if (guid == IOSFileArtifactRepresentation::getTypeGuid()) - { - ComPtr fileRep; - SLANG_RETURN_ON_FAIL(_createOSFile(artifact, getIntermediateKeep(keep), fileRep.writeRef())); - return _addRepresentation(artifact, keep, fileRep, outCastable); - } - - // Handle known conversion to blobs - if (guid == ISlangBlob::getTypeGuid()) - { - if (auto sourceMap = findRepresentation(artifact)) - { - // SourceMap -> Blob - ComPtr blob; - SLANG_RETURN_ON_FAIL(JSONSourceMapUtil::write(*sourceMap, blob)); - // Add the rep - return _addRepresentation(artifact, keep, blob, outCastable); - } - } - - return SLANG_E_NOT_AVAILABLE; + const auto reps = artifact->getRepresentations(); + + // See if we already have a rep of this type + for (ICastable* rep : reps) + { + if (rep->castAs(guid)) + { + rep->addRef(); + *outCastable = rep; + return SLANG_OK; + } + } + + // We can ask each representation if they can do the conversion to the type, if they can we just + // use that + for (ICastable* castable : reps) + { + if (auto rep = as(castable)) + { + ComPtr created; + if (SLANG_SUCCEEDED(rep->createRepresentation(guid, created.writeRef()))) + { + SLANG_ASSERT(created); + // Add the rep + return _addRepresentation(artifact, keep, created, outCastable); + } + } + } + + // Special cases + if (guid == SourceMap::getTypeGuid()) + { + // Blob -> SourceMap + ComPtr> sourceMap(new BoxValue); + SLANG_RETURN_ON_FAIL(_loadSourceMap(artifact, getIntermediateKeep(keep), sourceMap->get())); + return _addRepresentation(artifact, keep, sourceMap, outCastable); + } + else if (guid == ISlangSharedLibrary::getTypeGuid()) + { + ComPtr sharedLib; + SLANG_RETURN_ON_FAIL(_loadSharedLibrary(artifact, sharedLib.writeRef())); + return _addRepresentation(artifact, keep, sharedLib, outCastable); + } + else if (guid == IOSFileArtifactRepresentation::getTypeGuid()) + { + ComPtr fileRep; + SLANG_RETURN_ON_FAIL( + _createOSFile(artifact, getIntermediateKeep(keep), fileRep.writeRef())); + return _addRepresentation(artifact, keep, fileRep, outCastable); + } + + // Handle known conversion to blobs + if (guid == ISlangBlob::getTypeGuid()) + { + if (auto sourceMap = findRepresentation(artifact)) + { + // SourceMap -> Blob + ComPtr blob; + SLANG_RETURN_ON_FAIL(JSONSourceMapUtil::write(*sourceMap, blob)); + // Add the rep + return _addRepresentation(artifact, keep, blob, outCastable); + } + } + + return SLANG_E_NOT_AVAILABLE; } -SlangResult DefaultArtifactHandler::_createOSFile(IArtifact* artifact, ArtifactKeep keep, IOSFileArtifactRepresentation** outFileRep) +SlangResult DefaultArtifactHandler::_createOSFile( + IArtifact* artifact, + ArtifactKeep keep, + IOSFileArtifactRepresentation** outFileRep) { - // Look if we have an IExtFile representation, as we might already have a OS file associated with that - if (auto extRep = findRepresentation(artifact)) - { - auto system = extRep->getFileSystem(); - - String path; - switch (system->getOSPathKind()) - { - case OSPathKind::Direct: - { - path = UnownedStringSlice(extRep->getPath()); - break; - } - case OSPathKind::OperatingSystem: - { - ComPtr osPathBlob; - if (SLANG_SUCCEEDED(system->getPath(PathKind::OperatingSystem, extRep->getPath(), osPathBlob.writeRef()))) - { - path = StringUtil::getString(osPathBlob); - } - break; - } - default: break; - } - - if (path.getLength()) - { - auto fileRep = OSFileArtifactRepresentation::create(IOSFileArtifactRepresentation::Kind::Reference, path.getUnownedSlice() , nullptr); - // As a sanity check make sure it exists! - if (fileRep->exists()) - { - *outFileRep = fileRep.detach(); - return SLANG_OK; - } - } - } - - // Okay looks like we will need to generate a temporary file - auto helper = DefaultArtifactHelper::getSingleton(); - - // If we are going to access as a file we need to be able to write it, and to do that we need a blob - ComPtr blob; - SLANG_RETURN_ON_FAIL(artifact->loadBlob(getIntermediateKeep(keep), blob.writeRef())); - - // Find some name associated - auto name = ArtifactUtil::findName(artifact); - if (name.getLength() == 0) - { - name = toSlice("unknown"); - } - - // Okay we need to store as a temporary. Get a lock file. - ComPtr lockFile; - SLANG_RETURN_ON_FAIL(helper->createLockFile(asCharSlice(name), lockFile.writeRef())); - - // Now we need the appropriate name for this item - ComPtr pathBlob; - SLANG_RETURN_ON_FAIL(helper->calcArtifactPath(artifact, lockFile->getPath(), pathBlob.writeRef())); - - const auto path = StringUtil::getSlice(pathBlob); - - // Write the contents - SLANG_RETURN_ON_FAIL(File::writeAllBytes(path, blob->getBufferPointer(), blob->getBufferSize())); - if(artifact->getDesc().kind == ArtifactKind::Executable) + // Look if we have an IExtFile representation, as we might already have a OS file associated + // with that + if (auto extRep = findRepresentation(artifact)) + { + auto system = extRep->getFileSystem(); + + String path; + switch (system->getOSPathKind()) + { + case OSPathKind::Direct: + { + path = UnownedStringSlice(extRep->getPath()); + break; + } + case OSPathKind::OperatingSystem: + { + ComPtr osPathBlob; + if (SLANG_SUCCEEDED(system->getPath( + PathKind::OperatingSystem, + extRep->getPath(), + osPathBlob.writeRef()))) + { + path = StringUtil::getString(osPathBlob); + } + break; + } + default: + break; + } + + if (path.getLength()) + { + auto fileRep = OSFileArtifactRepresentation::create( + IOSFileArtifactRepresentation::Kind::Reference, + path.getUnownedSlice(), + nullptr); + // As a sanity check make sure it exists! + if (fileRep->exists()) + { + *outFileRep = fileRep.detach(); + return SLANG_OK; + } + } + } + + // Okay looks like we will need to generate a temporary file + auto helper = DefaultArtifactHelper::getSingleton(); + + // If we are going to access as a file we need to be able to write it, and to do that we need a + // blob + ComPtr blob; + SLANG_RETURN_ON_FAIL(artifact->loadBlob(getIntermediateKeep(keep), blob.writeRef())); + + // Find some name associated + auto name = ArtifactUtil::findName(artifact); + if (name.getLength() == 0) + { + name = toSlice("unknown"); + } + + // Okay we need to store as a temporary. Get a lock file. + ComPtr lockFile; + SLANG_RETURN_ON_FAIL(helper->createLockFile(asCharSlice(name), lockFile.writeRef())); + + // Now we need the appropriate name for this item + ComPtr pathBlob; + SLANG_RETURN_ON_FAIL( + helper->calcArtifactPath(artifact, lockFile->getPath(), pathBlob.writeRef())); + + const auto path = StringUtil::getSlice(pathBlob); + + // Write the contents + SLANG_RETURN_ON_FAIL( + File::writeAllBytes(path, blob->getBufferPointer(), blob->getBufferSize())); + if (artifact->getDesc().kind == ArtifactKind::Executable) { SLANG_RETURN_ON_FAIL(File::makeExecutable(path)); } - ComPtr fileRep; - - // TODO(JS): This path comparison is perhaps not perfect, in that it assumes the path is not changed - // in any way. For example an impl of calcArtifactPath that changed slashes or used a canonical path - // might mean the lock file and the rep have the same path. - // As it stands calcArtifactPath impl doesn't do that, but that is perhaps somewhatfragile - - // If the paths are identical, we can just use the lock file for the rep - if (UnownedStringSlice(lockFile->getPath()) == path) - { - fileRep.swap(lockFile); - } - else - { - // Create a new rep that references the lock file - fileRep = new OSFileArtifactRepresentation(IOSFileArtifactRepresentation::Kind::Owned, path, lockFile); - } - - // Return the file - *outFileRep = fileRep.detach(); - return SLANG_OK; + ComPtr fileRep; + + // TODO(JS): This path comparison is perhaps not perfect, in that it assumes the path is not + // changed in any way. For example an impl of calcArtifactPath that changed slashes or used a + // canonical path might mean the lock file and the rep have the same path. As it stands + // calcArtifactPath impl doesn't do that, but that is perhaps somewhatfragile + + // If the paths are identical, we can just use the lock file for the rep + if (UnownedStringSlice(lockFile->getPath()) == path) + { + fileRep.swap(lockFile); + } + else + { + // Create a new rep that references the lock file + fileRep = new OSFileArtifactRepresentation( + IOSFileArtifactRepresentation::Kind::Owned, + path, + lockFile); + } + + // Return the file + *outFileRep = fileRep.detach(); + return SLANG_OK; } -SlangResult DefaultArtifactHandler::_loadSharedLibrary(IArtifact* artifact, ISlangSharedLibrary** outSharedLibrary) +SlangResult DefaultArtifactHandler::_loadSharedLibrary( + IArtifact* artifact, + ISlangSharedLibrary** outSharedLibrary) { - // If it is 'shared library' for a CPU like thing, we can try and load it - const auto desc = artifact->getDesc(); - if ((isDerivedFrom(desc.kind, ArtifactKind::HostCallable) || - isDerivedFrom(desc.kind, ArtifactKind::SharedLibrary)) && - isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) - { - // Get as a file represenation on the OS file system - ComPtr fileRep; - - // We want to keep the file representation, otherwise every request, could produce a new file - // and that seems like a bad idea. - SLANG_RETURN_ON_FAIL(artifact->requireFile(ArtifactKeep::Yes, fileRep.writeRef())); - - // Try loading the shared library - SharedLibrary::Handle handle; - if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(fileRep->getPath(), handle))) - { - return SLANG_FAIL; - } - - // Output - *outSharedLibrary = ScopeSharedLibrary::create(handle, fileRep).detach(); - return SLANG_OK; - } - - return SLANG_FAIL; + // If it is 'shared library' for a CPU like thing, we can try and load it + const auto desc = artifact->getDesc(); + if ((isDerivedFrom(desc.kind, ArtifactKind::HostCallable) || + isDerivedFrom(desc.kind, ArtifactKind::SharedLibrary)) && + isDerivedFrom(desc.payload, ArtifactPayload::CPULike)) + { + // Get as a file represenation on the OS file system + ComPtr fileRep; + + // We want to keep the file representation, otherwise every request, could produce a new + // file and that seems like a bad idea. + SLANG_RETURN_ON_FAIL(artifact->requireFile(ArtifactKeep::Yes, fileRep.writeRef())); + + // Try loading the shared library + SharedLibrary::Handle handle; + if (SLANG_FAILED(SharedLibrary::loadWithPlatformPath(fileRep->getPath(), handle))) + { + return SLANG_FAIL; + } + + // Output + *outSharedLibrary = ScopeSharedLibrary::create(handle, fileRep).detach(); + return SLANG_OK; + } + + return SLANG_FAIL; } } // namespace Slang diff --git a/source/compiler-core/slang-artifact-handler-impl.h b/source/compiler-core/slang-artifact-handler-impl.h index c1cd259800..675dcd5f2e 100644 --- a/source/compiler-core/slang-artifact-handler-impl.h +++ b/source/compiler-core/slang-artifact-handler-impl.h @@ -2,10 +2,9 @@ #ifndef SLANG_ARTIFACT_HANDLER_IMPL_H #define SLANG_ARTIFACT_HANDLER_IMPL_H -#include "slang-artifact.h" -#include "slang-artifact-representation.h" - #include "../core/slang-com-object.h" +#include "slang-artifact-representation.h" +#include "slang-artifact.h" namespace Slang { @@ -13,30 +12,46 @@ namespace Slang class DefaultArtifactHandler : public ComBaseObject, public IArtifactHandler { public: - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE; - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // IArtifactHandler - SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren(IArtifact* container) SLANG_OVERRIDE; - SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation(IArtifact* artifact, const Guid& guid, ArtifactKeep keep, ICastable** outCastable) SLANG_OVERRIDE; - - static IArtifactHandler* getSingleton() { return &g_singleton; } -protected: + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) + SLANG_OVERRIDE; - SlangResult _loadSharedLibrary(IArtifact* artifact, ISlangSharedLibrary** outSharedLibrary); - SlangResult _createOSFile(IArtifact* artifact, ArtifactKeep intermediateKeep, IOSFileArtifactRepresentation** outFileRep); + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - void* getInterface(const Guid& uuid); - void* getObject(const Guid& uuid); + // IArtifactHandler + SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren(IArtifact* container) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation( + IArtifact* artifact, + const Guid& guid, + ArtifactKeep keep, + ICastable** outCastable) SLANG_OVERRIDE; - SlangResult _addRepresentation(IArtifact* artifact, ArtifactKeep keep, ISlangUnknown* rep, ICastable** outCastable); - SlangResult _addRepresentation(IArtifact* artifact, ArtifactKeep keep, ICastable* castable, ICastable** outCastable); - - static DefaultArtifactHandler g_singleton; + static IArtifactHandler* getSingleton() { return &g_singleton; } + +protected: + SlangResult _loadSharedLibrary(IArtifact* artifact, ISlangSharedLibrary** outSharedLibrary); + SlangResult _createOSFile( + IArtifact* artifact, + ArtifactKeep intermediateKeep, + IOSFileArtifactRepresentation** outFileRep); + + void* getInterface(const Guid& uuid); + void* getObject(const Guid& uuid); + + SlangResult _addRepresentation( + IArtifact* artifact, + ArtifactKeep keep, + ISlangUnknown* rep, + ICastable** outCastable); + SlangResult _addRepresentation( + IArtifact* artifact, + ArtifactKeep keep, + ICastable* castable, + ICastable** outCastable); + + static DefaultArtifactHandler g_singleton; }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-helper.cpp b/source/compiler-core/slang-artifact-helper.cpp index 7f1bf1ea27..dc4d6638d2 100644 --- a/source/compiler-core/slang-artifact-helper.cpp +++ b/source/compiler-core/slang-artifact-helper.cpp @@ -1,141 +1,191 @@ // slang-artifact-helper.cpp #include "slang-artifact-helper.h" -#include "slang-artifact-impl.h" -#include "slang-artifact-representation-impl.h" - -#include "slang-artifact-desc-util.h" -#include "slang-artifact-util.h" - #include "../compiler-core/slang-slice-allocator.h" - #include "../core/slang-castable.h" - #include "../core/slang-file-system.h" #include "../core/slang-io.h" #include "../core/slang-shared-library.h" +#include "slang-artifact-desc-util.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" +#include "slang-artifact-util.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! DefaultArtifactHelper !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */DefaultArtifactHelper DefaultArtifactHelper::g_singleton; +/* static */ DefaultArtifactHelper DefaultArtifactHelper::g_singleton; SlangResult DefaultArtifactHelper::queryInterface(SlangUUID const& uuid, void** outObject) { - if (auto intf = getInterface(uuid)) - { - *outObject = intf; - return SLANG_OK; - } - return SLANG_E_NO_INTERFACE; + if (auto intf = getInterface(uuid)) + { + *outObject = intf; + return SLANG_OK; + } + return SLANG_E_NO_INTERFACE; } void* DefaultArtifactHelper::castAs(const Guid& guid) { - if (auto ptr = getInterface(guid)) - { - return ptr; - } - return getObject(guid); + if (auto ptr = getInterface(guid)) + { + return ptr; + } + return getObject(guid); } void* DefaultArtifactHelper::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == IArtifactHelper::getTypeGuid()) - { - return static_cast(this); - } - return nullptr; + if (guid == ISlangUnknown::getTypeGuid() || guid == IArtifactHelper::getTypeGuid()) + { + return static_cast(this); + } + return nullptr; } void* DefaultArtifactHelper::getObject(const Guid& guid) { - SLANG_UNUSED(guid); - return nullptr; + SLANG_UNUSED(guid); + return nullptr; } -SlangResult DefaultArtifactHelper::createArtifact(const ArtifactDesc& desc, const char* inName, IArtifact** outArtifact) +SlangResult DefaultArtifactHelper::createArtifact( + const ArtifactDesc& desc, + const char* inName, + IArtifact** outArtifact) { - *outArtifact = inName ? - Artifact::create(desc, UnownedStringSlice(inName)).detach() : - Artifact::create(desc).detach(); + *outArtifact = inName ? Artifact::create(desc, UnownedStringSlice(inName)).detach() + : Artifact::create(desc).detach(); - return SLANG_OK; + return SLANG_OK; } -ArtifactKind DefaultArtifactHelper::getKindParent(ArtifactKind kind) { return getParent(kind); } -UnownedStringSlice DefaultArtifactHelper::getKindName(ArtifactKind kind) { return getName(kind); } -bool DefaultArtifactHelper::isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) { return isDerivedFrom(kind, base); } +ArtifactKind DefaultArtifactHelper::getKindParent(ArtifactKind kind) +{ + return getParent(kind); +} +UnownedStringSlice DefaultArtifactHelper::getKindName(ArtifactKind kind) +{ + return getName(kind); +} +bool DefaultArtifactHelper::isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) +{ + return isDerivedFrom(kind, base); +} -ArtifactPayload DefaultArtifactHelper::getPayloadParent(ArtifactPayload payload) { return getParent(payload); } -UnownedStringSlice DefaultArtifactHelper::getPayloadName(ArtifactPayload payload) { return getName(payload); } -bool DefaultArtifactHelper::isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) { return isDerivedFrom(payload, base); } +ArtifactPayload DefaultArtifactHelper::getPayloadParent(ArtifactPayload payload) +{ + return getParent(payload); +} +UnownedStringSlice DefaultArtifactHelper::getPayloadName(ArtifactPayload payload) +{ + return getName(payload); +} +bool DefaultArtifactHelper::isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) +{ + return isDerivedFrom(payload, base); +} -ArtifactStyle DefaultArtifactHelper::getStyleParent(ArtifactStyle style) { return getParent(style); } -UnownedStringSlice DefaultArtifactHelper::getStyleName(ArtifactStyle style) { return getName(style); } -bool DefaultArtifactHelper::isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) { return isDerivedFrom(style, base); } +ArtifactStyle DefaultArtifactHelper::getStyleParent(ArtifactStyle style) +{ + return getParent(style); +} +UnownedStringSlice DefaultArtifactHelper::getStyleName(ArtifactStyle style) +{ + return getName(style); +} +bool DefaultArtifactHelper::isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) +{ + return isDerivedFrom(style, base); +} -SlangResult DefaultArtifactHelper::createLockFile(const CharSlice& inNameBase, IOSFileArtifactRepresentation** outLockFile) +SlangResult DefaultArtifactHelper::createLockFile( + const CharSlice& inNameBase, + IOSFileArtifactRepresentation** outLockFile) { - const UnownedStringSlice nameBase = inNameBase.count ? asStringSlice(inNameBase) : UnownedStringSlice("unknown"); - String lockPath; - SLANG_RETURN_ON_FAIL(File::generateTemporary(nameBase, lockPath)); - *outLockFile = OSFileArtifactRepresentation::create(IOSFileArtifactRepresentation::Kind::Lock, lockPath.getUnownedSlice(), nullptr).detach(); - return SLANG_OK; + const UnownedStringSlice nameBase = + inNameBase.count ? asStringSlice(inNameBase) : UnownedStringSlice("unknown"); + String lockPath; + SLANG_RETURN_ON_FAIL(File::generateTemporary(nameBase, lockPath)); + *outLockFile = OSFileArtifactRepresentation::create( + IOSFileArtifactRepresentation::Kind::Lock, + lockPath.getUnownedSlice(), + nullptr) + .detach(); + return SLANG_OK; } -SlangResult DefaultArtifactHelper::calcArtifactDescPath(const ArtifactDesc& desc, const char* inBasePath, ISlangBlob** outPath) +SlangResult DefaultArtifactHelper::calcArtifactDescPath( + const ArtifactDesc& desc, + const char* inBasePath, + ISlangBlob** outPath) { - UnownedStringSlice basePath(inBasePath); - StringBuilder path; - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, basePath, path)); - *outPath = StringBlob::moveCreate(path).detach(); - return SLANG_OK; + UnownedStringSlice basePath(inBasePath); + StringBuilder path; + SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, basePath, path)); + *outPath = StringBlob::moveCreate(path).detach(); + return SLANG_OK; } -SlangResult DefaultArtifactHelper::calcArtifactPath(IArtifact* artifact, const char* inBasePath, ISlangBlob** outPath) +SlangResult DefaultArtifactHelper::calcArtifactPath( + IArtifact* artifact, + const char* inBasePath, + ISlangBlob** outPath) { - UnownedStringSlice basePath(inBasePath); - StringBuilder path; - SLANG_RETURN_ON_FAIL(ArtifactUtil::calcPath(artifact, basePath, path)); - *outPath = StringBlob::moveCreate(path).detach(); - return SLANG_OK; + UnownedStringSlice basePath(inBasePath); + StringBuilder path; + SLANG_RETURN_ON_FAIL(ArtifactUtil::calcPath(artifact, basePath, path)); + *outPath = StringBlob::moveCreate(path).detach(); + return SLANG_OK; } ArtifactDesc DefaultArtifactHelper::makeDescForCompileTarget(SlangCompileTarget target) { - return ArtifactDescUtil::makeDescForCompileTarget(target); + return ArtifactDescUtil::makeDescForCompileTarget(target); } void DefaultArtifactHelper::getCastable(ISlangUnknown* unk, ICastable** outCastable) { - *outCastable = CastableUtil::getCastable(unk).detach(); + *outCastable = CastableUtil::getCastable(unk).detach(); } SlangResult DefaultArtifactHelper::createOSFileArtifactRepresentation( - IOSFileArtifactRepresentation::Kind kind, const CharSlice& path, IOSFileArtifactRepresentation* lockFile, IOSFileArtifactRepresentation** outRep) + IOSFileArtifactRepresentation::Kind kind, + const CharSlice& path, + IOSFileArtifactRepresentation* lockFile, + IOSFileArtifactRepresentation** outRep) { - *outRep = OSFileArtifactRepresentation::create(kind, asStringSlice(path), lockFile).detach(); - return SLANG_OK; + *outRep = OSFileArtifactRepresentation::create(kind, asStringSlice(path), lockFile).detach(); + return SLANG_OK; } -SlangResult DefaultArtifactHelper::createExtFileArtifactRepresentation(const CharSlice& path, ISlangFileSystemExt* system, IExtFileArtifactRepresentation** outRep) +SlangResult DefaultArtifactHelper::createExtFileArtifactRepresentation( + const CharSlice& path, + ISlangFileSystemExt* system, + IExtFileArtifactRepresentation** outRep) { - *outRep = ExtFileArtifactRepresentation::create(asStringSlice(path), system).detach(); - return SLANG_OK; + *outRep = ExtFileArtifactRepresentation::create(asStringSlice(path), system).detach(); + return SLANG_OK; } -SlangResult DefaultArtifactHelper::createOSFileArtifact(const ArtifactDesc& desc, const CharSlice& path, IArtifact** outArtifact) +SlangResult DefaultArtifactHelper::createOSFileArtifact( + const ArtifactDesc& desc, + const CharSlice& path, + IArtifact** outArtifact) { - auto artifact = Artifact::create(desc); + auto artifact = Artifact::create(desc); + + auto fileRep = new OSFileArtifactRepresentation( + IOSFileArtifactRepresentation::Kind::Reference, + asStringSlice(path), + nullptr); + artifact->addRepresentation(fileRep); - auto fileRep = new OSFileArtifactRepresentation(IOSFileArtifactRepresentation::Kind::Reference, asStringSlice(path), nullptr); - artifact->addRepresentation(fileRep); - - *outArtifact = artifact.detach(); - return SLANG_OK; + *outArtifact = artifact.detach(); + return SLANG_OK; } } // namespace Slang diff --git a/source/compiler-core/slang-artifact-helper.h b/source/compiler-core/slang-artifact-helper.h index a0d4d6b75f..530a36de96 100644 --- a/source/compiler-core/slang-artifact-helper.h +++ b/source/compiler-core/slang-artifact-helper.h @@ -2,116 +2,165 @@ #ifndef SLANG_ARTIFACT_HELPER_H #define SLANG_ARTIFACT_HELPER_H -#include "slang-artifact.h" -#include "slang-artifact-representation.h" - #include "../core/slang-com-object.h" +#include "slang-artifact-representation.h" +#include "slang-artifact.h" namespace Slang { class IArtifactHelper : public ICastable { - SLANG_COM_INTERFACE(0x882b25d7, 0xe300, 0x4b20, { 0xbe, 0xb, 0x26, 0xd2, 0x52, 0x3e, 0x70, 0x20 }) - - /// Create an artifact - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createArtifact(const ArtifactDesc& desc, const char* name, IArtifact** outArtifact) = 0; - - /// Get the parent to a kind - virtual SLANG_NO_THROW ArtifactKind SLANG_MCALL getKindParent(ArtifactKind kind) = 0; - /// Get the name of a kind - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getKindName(ArtifactKind kind) = 0; - /// Returns true if kind is derived from base - virtual SLANG_NO_THROW bool SLANG_MCALL isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) = 0; - - /// Get the parent payload for payload - virtual SLANG_NO_THROW ArtifactPayload SLANG_MCALL getPayloadParent(ArtifactPayload payload) = 0; - /// Get the payload name text - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getPayloadName(ArtifactPayload payload) = 0; - /// Returns true if payload is derived from base - virtual SLANG_NO_THROW bool SLANG_MCALL isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) = 0; - - /// Get the parent type of a style - virtual SLANG_NO_THROW ArtifactStyle SLANG_MCALL getStyleParent(ArtifactStyle style) = 0; - /// Get text name for a style - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) = 0; - /// Returns true if style is derived from base - virtual SLANG_NO_THROW bool SLANG_MCALL isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) = 0; - - /// Create a lock file, the path of which can be used to generate other temporary files - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const CharSlice& nameBase, IOSFileArtifactRepresentation** outLockFile) = 0; - - /// Given a desc and a basePath returns a suitable name - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactDescPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; - - /// Given an artifact and a basePath returns a suitable name - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(IArtifact* , const char* basePath, ISlangBlob** outPath) = 0; - - /// Given a compile target return the equivalent desc - virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescForCompileTarget(SlangCompileTarget target) = 0; - - /// Given an interface returns as a castable interface. This might just cast unk into ICastable, or wrap it such that it uses the castable interface - virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) = 0; - - /// Create a file rep - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifactRepresentation( - IOSFileArtifactRepresentation::Kind kind, const CharSlice& path, IOSFileArtifactRepresentation* lockFile, IOSFileArtifactRepresentation** outRep) = 0; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createExtFileArtifactRepresentation(const CharSlice& path, ISlangFileSystemExt* system, IExtFileArtifactRepresentation** outRep) = 0; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifact(const ArtifactDesc& desc, const CharSlice& slice, IArtifact** outArtifact) = 0; + SLANG_COM_INTERFACE(0x882b25d7, 0xe300, 0x4b20, {0xbe, 0xb, 0x26, 0xd2, 0x52, 0x3e, 0x70, 0x20}) + + /// Create an artifact + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createArtifact(const ArtifactDesc& desc, const char* name, IArtifact** outArtifact) = 0; + + /// Get the parent to a kind + virtual SLANG_NO_THROW ArtifactKind SLANG_MCALL getKindParent(ArtifactKind kind) = 0; + /// Get the name of a kind + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getKindName(ArtifactKind kind) = 0; + /// Returns true if kind is derived from base + virtual SLANG_NO_THROW bool SLANG_MCALL + isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) = 0; + + /// Get the parent payload for payload + virtual SLANG_NO_THROW ArtifactPayload SLANG_MCALL + getPayloadParent(ArtifactPayload payload) = 0; + /// Get the payload name text + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL + getPayloadName(ArtifactPayload payload) = 0; + /// Returns true if payload is derived from base + virtual SLANG_NO_THROW bool SLANG_MCALL + isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) = 0; + + /// Get the parent type of a style + virtual SLANG_NO_THROW ArtifactStyle SLANG_MCALL getStyleParent(ArtifactStyle style) = 0; + /// Get text name for a style + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) = 0; + /// Returns true if style is derived from base + virtual SLANG_NO_THROW bool SLANG_MCALL + isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) = 0; + + /// Create a lock file, the path of which can be used to generate other temporary files + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createLockFile(const CharSlice& nameBase, IOSFileArtifactRepresentation** outLockFile) = 0; + + /// Given a desc and a basePath returns a suitable name + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + calcArtifactDescPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) = 0; + + /// Given an artifact and a basePath returns a suitable name + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + calcArtifactPath(IArtifact*, const char* basePath, ISlangBlob** outPath) = 0; + + /// Given a compile target return the equivalent desc + virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL + makeDescForCompileTarget(SlangCompileTarget target) = 0; + + /// Given an interface returns as a castable interface. This might just cast unk into ICastable, + /// or wrap it such that it uses the castable interface + virtual SLANG_NO_THROW void SLANG_MCALL + getCastable(ISlangUnknown* unk, ICastable** outCastable) = 0; + + /// Create a file rep + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifactRepresentation( + IOSFileArtifactRepresentation::Kind kind, + const CharSlice& path, + IOSFileArtifactRepresentation* lockFile, + IOSFileArtifactRepresentation** outRep) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createExtFileArtifactRepresentation( + const CharSlice& path, + ISlangFileSystemExt* system, + IExtFileArtifactRepresentation** outRep) = 0; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifact( + const ArtifactDesc& desc, + const CharSlice& slice, + IArtifact** outArtifact) = 0; }; class DefaultArtifactHelper : public IArtifactHelper { public: - // ISlangUnknown - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } - SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE; - - // ICastable - SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; - - // IArtifactHelper - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createArtifact(const ArtifactDesc& desc, const char* name, IArtifact** outArtifact) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW ArtifactKind SLANG_MCALL getKindParent(ArtifactKind kind) SLANG_OVERRIDE; - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getKindName(ArtifactKind kind) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW ArtifactPayload SLANG_MCALL getPayloadParent(ArtifactPayload payload) SLANG_OVERRIDE; - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getPayloadName(ArtifactPayload payload) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW ArtifactStyle SLANG_MCALL getStyleParent(ArtifactStyle style) SLANG_OVERRIDE; - virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile(const CharSlice& nameBase, IOSFileArtifactRepresentation** outLockFile) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactDescPath(const ArtifactDesc& desc, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactPath(IArtifact*, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL makeDescForCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifactRepresentation( - IOSFileArtifactRepresentation::Kind kind, const CharSlice& path, IOSFileArtifactRepresentation* lockFile, IOSFileArtifactRepresentation** outRep) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createExtFileArtifactRepresentation(const CharSlice& path, ISlangFileSystemExt* system, IExtFileArtifactRepresentation** outRep) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifact(const ArtifactDesc& desc, const CharSlice& slice, IArtifact** outArtifact) SLANG_OVERRIDE; - - static IArtifactHelper* getSingleton() { return &g_singleton; } + // ISlangUnknown + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) + SLANG_OVERRIDE; + + // ICastable + SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; + + // IArtifactHelper + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createArtifact( + const ArtifactDesc& desc, + const char* name, + IArtifact** outArtifact) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW ArtifactKind SLANG_MCALL getKindParent(ArtifactKind kind) SLANG_OVERRIDE; + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getKindName(ArtifactKind kind) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL isKindDerivedFrom(ArtifactKind kind, ArtifactKind base) + SLANG_OVERRIDE; + + virtual SLANG_NO_THROW ArtifactPayload SLANG_MCALL getPayloadParent(ArtifactPayload payload) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getPayloadName(ArtifactPayload payload) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + isPayloadDerivedFrom(ArtifactPayload payload, ArtifactPayload base) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW ArtifactStyle SLANG_MCALL getStyleParent(ArtifactStyle style) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW UnownedStringSlice SLANG_MCALL getStyleName(ArtifactStyle style) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + isStyleDerivedFrom(ArtifactStyle style, ArtifactStyle base) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createLockFile( + const CharSlice& nameBase, + IOSFileArtifactRepresentation** outLockFile) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL calcArtifactDescPath( + const ArtifactDesc& desc, + const char* basePath, + ISlangBlob** outPath) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + calcArtifactPath(IArtifact*, const char* basePath, ISlangBlob** outPath) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW ArtifactDesc SLANG_MCALL + makeDescForCompileTarget(SlangCompileTarget target) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW void SLANG_MCALL getCastable(ISlangUnknown* unk, ICastable** outCastable) + SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifactRepresentation( + IOSFileArtifactRepresentation::Kind kind, + const CharSlice& path, + IOSFileArtifactRepresentation* lockFile, + IOSFileArtifactRepresentation** outRep) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createExtFileArtifactRepresentation( + const CharSlice& path, + ISlangFileSystemExt* system, + IExtFileArtifactRepresentation** outRep) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL createOSFileArtifact( + const ArtifactDesc& desc, + const CharSlice& slice, + IArtifact** outArtifact) SLANG_OVERRIDE; + + static IArtifactHelper* getSingleton() { return &g_singleton; } protected: - void* getInterface(const Guid& guid); - void* getObject(const Guid& guid); + void* getInterface(const Guid& guid); + void* getObject(const Guid& guid); - static DefaultArtifactHelper g_singleton; + static DefaultArtifactHelper g_singleton; }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-impl.cpp b/source/compiler-core/slang-artifact-impl.cpp index d13421880b..31c01f1dee 100644 --- a/source/compiler-core/slang-artifact-impl.cpp +++ b/source/compiler-core/slang-artifact-impl.cpp @@ -1,29 +1,27 @@ // slang-artifact-impl.cpp #include "slang-artifact-impl.h" -#include "slang-artifact-representation.h" - -#include "slang-artifact-util.h" +#include "../core/slang-castable.h" #include "slang-artifact-desc-util.h" - #include "slang-artifact-handler-impl.h" - +#include "slang-artifact-representation.h" +#include "slang-artifact-util.h" #include "slang-slice-allocator.h" -#include "../core/slang-castable.h" - -namespace Slang { +namespace Slang +{ -namespace { // anonymous +namespace +{ // anonymous /* Get a view as a slice of *raw* pointers */ -template +template SLANG_FORCE_INLINE ConstArrayView _getRawView(const List>& in) { - return makeConstArrayView((T*const*)in.getBuffer(), in.getCount()); + return makeConstArrayView((T* const*)in.getBuffer(), in.getCount()); } -} // anonymous +} // namespace /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Artifact !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -38,8 +36,7 @@ void* Artifact::castAs(const Guid& guid) void* Artifact::getInterface(const Guid& uuid) { - if (uuid == ISlangUnknown::getTypeGuid() || - uuid == ICastable::getTypeGuid() || + if (uuid == ISlangUnknown::getTypeGuid() || uuid == ICastable::getTypeGuid() || uuid == IArtifact::getTypeGuid()) { return static_cast(this); @@ -96,7 +93,11 @@ SlangResult Artifact::requireFile(Keep keep, IOSFileArtifactRepresentation** out auto handler = _getHandler(); ComPtr castable; - SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation(this, IOSFileArtifactRepresentation::getTypeGuid(), keep, castable.writeRef())); + SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation( + this, + IOSFileArtifactRepresentation::getTypeGuid(), + keep, + castable.writeRef())); auto fileRep = as(castable); fileRep->addRef(); @@ -110,8 +111,12 @@ SlangResult Artifact::loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** auto handler = _getHandler(); ComPtr castable; - SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation(this, ISlangSharedLibrary::getTypeGuid(), keep, castable.writeRef())); - + SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation( + this, + ISlangSharedLibrary::getTypeGuid(), + keep, + castable.writeRef())); + auto lib = as(castable); lib->addRef(); @@ -133,10 +138,17 @@ void Artifact::clear(IArtifact::ContainedKind kind) { switch (kind) { - case ContainedKind::Associated: m_associated.clear(); break; - case ContainedKind::Representation: m_representations.clear(); break; - case ContainedKind::Children: m_children.clear(); break; - default: break; + case ContainedKind::Associated: + m_associated.clear(); + break; + case ContainedKind::Representation: + m_representations.clear(); + break; + case ContainedKind::Children: + m_children.clear(); + break; + default: + break; } } @@ -144,14 +156,24 @@ void Artifact::removeAt(ContainedKind kind, Index i) { switch (kind) { - case ContainedKind::Associated: m_associated.removeAt(i); break; - case ContainedKind::Representation: m_representations.removeAt(i); break; - case ContainedKind::Children: m_children.removeAt(i); break; - default: break; + case ContainedKind::Associated: + m_associated.removeAt(i); + break; + case ContainedKind::Representation: + m_representations.removeAt(i); + break; + case ContainedKind::Children: + m_children.removeAt(i); + break; + default: + break; } } -SlangResult Artifact::getOrCreateRepresentation(const Guid& typeGuid, ArtifactKeep keep, ICastable** outCastable) +SlangResult Artifact::getOrCreateRepresentation( + const Guid& typeGuid, + ArtifactKeep keep, + ICastable** outCastable) { auto handler = _getHandler(); return handler->getOrCreateRepresentation(this, typeGuid, keep, outCastable); @@ -162,7 +184,11 @@ SlangResult Artifact::loadBlob(Keep keep, ISlangBlob** outBlob) auto handler = _getHandler(); ComPtr castable; - SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation(this, ISlangBlob::getTypeGuid(), keep, castable.writeRef())); + SLANG_RETURN_ON_FAIL(handler->getOrCreateRepresentation( + this, + ISlangBlob::getTypeGuid(), + keep, + castable.writeRef())); ISlangBlob* blob = as(castable); blob->addRef(); @@ -205,9 +231,11 @@ void* Artifact::findRepresentation(ContainedKind kind, const Guid& guid) { switch (kind) { - case ContainedKind::Associated: return _findRepresentation(_getRawView(m_associated), guid); - case ContainedKind::Representation: return _findRepresentation(_getRawView(m_representations), guid); - case ContainedKind::Children: + case ContainedKind::Associated: + return _findRepresentation(_getRawView(m_associated), guid); + case ContainedKind::Representation: + return _findRepresentation(_getRawView(m_representations), guid); + case ContainedKind::Children: { _requireChildren(); return _findRepresentation(_getRawView(m_children), guid); @@ -240,7 +268,9 @@ void Artifact::addRepresentationUnknown(ISlangUnknown* unk) SLANG_ASSERT(unk); { - const auto view = makeConstArrayView((ISlangUnknown*const*)m_representations.getBuffer(), m_representations.getCount()); + const auto view = makeConstArrayView( + (ISlangUnknown* const*)m_representations.getBuffer(), + m_representations.getCount()); if (view.indexOf(unk) >= 0) { SLANG_ASSERT_FAILURE("Already have this representation"); @@ -270,7 +300,7 @@ Slice Artifact::getRepresentations() return SliceUtil::asSlice(m_representations); } -void Artifact::setChildren(IArtifact*const* children, Count count) +void Artifact::setChildren(IArtifact* const* children, Count count) { m_expandResult = SLANG_OK; diff --git a/source/compiler-core/slang-artifact-impl.h b/source/compiler-core/slang-artifact-impl.h index 22547d3ef9..a307a9d6d9 100644 --- a/source/compiler-core/slang-artifact-impl.h +++ b/source/compiler-core/slang-artifact-impl.h @@ -2,34 +2,36 @@ #ifndef SLANG_ARTIFACT_IMPL_H #define SLANG_ARTIFACT_IMPL_H +#include "../core/slang-com-object.h" #include "slang-artifact.h" - #include "slang-com-helper.h" #include "slang-com-ptr.h" -#include "../core/slang-com-object.h" - namespace Slang { /* Discussion: -Another issue occurs around wanting to hold multiple kernels within a container. The problem here is that although through the desc -we can identify what target a kernel is for, there is no way of telling what stage it is for. +Another issue occurs around wanting to hold multiple kernels within a container. The problem here is +that although through the desc we can identify what target a kernel is for, there is no way of +telling what stage it is for. -When discussing the idea of a shader cache, one idea was to use a ISlangFileSystem (which could actually be a zip, or directory or in memory rep) -as the main structure. Within this it can contain kernels, and then a json manifest can describe what each of these actually are. +When discussing the idea of a shader cache, one idea was to use a ISlangFileSystem (which could +actually be a zip, or directory or in memory rep) as the main structure. Within this it can contain +kernels, and then a json manifest can describe what each of these actually are. -This all 'works', in that we can add an element of ISlangFileSystem with a desc of Container. Code that uses this can then go through the process -of finding, and getting the blob, and find from the manifest what it means. That does sound a little tedious though. Perhaps we just have an interface -that handles this detail, such that we search for that first. That interface is just attached to the artifact as an element. +This all 'works', in that we can add an element of ISlangFileSystem with a desc of Container. Code +that uses this can then go through the process of finding, and getting the blob, and find from the +manifest what it means. That does sound a little tedious though. Perhaps we just have an interface +that handles this detail, such that we search for that first. That interface is just attached to the +artifact as an element. */ class Artifact : public ComBaseObject, public IArtifact { public: SLANG_COM_BASE_IUNKNOWN_ALL - + /// ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; @@ -37,47 +39,71 @@ class Artifact : public ComBaseObject, public IArtifact virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc() SLANG_OVERRIDE { return m_desc; } virtual SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob(Keep keep, ISlangBlob** outBlob) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFile(Keep keep, IOSFileArtifactRepresentation** outFileRep) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary) SLANG_OVERRIDE; - - virtual SLANG_NO_THROW const char* SLANG_MCALL getName() SLANG_OVERRIDE { return m_name.getBuffer(); } - virtual SLANG_NO_THROW void SLANG_MCALL setName(const char* name) SLANG_OVERRIDE { m_name = name; } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob(Keep keep, ISlangBlob** outBlob) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + requireFile(Keep keep, IOSFileArtifactRepresentation** outFileRep) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW const char* SLANG_MCALL getName() SLANG_OVERRIDE + { + return m_name.getBuffer(); + } + virtual SLANG_NO_THROW void SLANG_MCALL setName(const char* name) SLANG_OVERRIDE + { + m_name = name; + } virtual SLANG_NO_THROW void SLANG_MCALL addAssociated(IArtifact* artifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW Slice SLANG_MCALL getAssociated() SLANG_OVERRIDE; - + virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(ICastable* castable) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown(ISlangUnknown* rep) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown(ISlangUnknown* rep) + SLANG_OVERRIDE; virtual SLANG_NO_THROW Slice SLANG_MCALL getRepresentations() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation(const Guid& typeGuid, ArtifactKeep keep, ICastable** outCastable) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation( + const Guid& typeGuid, + ArtifactKeep keep, + ICastable** outCastable) SLANG_OVERRIDE; virtual SLANG_NO_THROW IArtifactHandler* SLANG_MCALL getHandler() SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL setHandler(IArtifactHandler* handler) SLANG_OVERRIDE; virtual SLANG_NO_THROW Slice SLANG_MCALL getChildren() SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getExpandChildrenResult() SLANG_OVERRIDE { return m_expandResult; } - virtual SLANG_NO_THROW void SLANG_MCALL setChildren(IArtifact*const* children, Count count) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getExpandChildrenResult() SLANG_OVERRIDE + { + return m_expandResult; + } + virtual SLANG_NO_THROW void SLANG_MCALL setChildren(IArtifact* const* children, Count count) + SLANG_OVERRIDE; virtual SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren() SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL addChild(IArtifact* artifact) SLANG_OVERRIDE; - virtual SLANG_NO_THROW void* SLANG_MCALL findRepresentation(ContainedKind kind, const Guid& unk) SLANG_OVERRIDE; + virtual SLANG_NO_THROW void* SLANG_MCALL findRepresentation(ContainedKind kind, const Guid& unk) + SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL clear(ContainedKind kind) SLANG_OVERRIDE; virtual SLANG_NO_THROW void SLANG_MCALL removeAt(ContainedKind kind, Index i) SLANG_OVERRIDE; - static ComPtr create(const Desc& desc) { return ComPtr(new Artifact(desc)); } - static ComPtr create(const Desc& desc, const UnownedStringSlice& name) { return ComPtr(new Artifact(desc, name)); } - -protected: + static ComPtr create(const Desc& desc) + { + return ComPtr(new Artifact(desc)); + } + static ComPtr create(const Desc& desc, const UnownedStringSlice& name) + { + return ComPtr(new Artifact(desc, name)); + } +protected: /// Ctor - Artifact(const Desc& desc, const UnownedStringSlice& name) : - m_desc(desc), - m_name(name) - {} - Artifact(const Desc& desc) : - m_desc(desc) - {} + Artifact(const Desc& desc, const UnownedStringSlice& name) + : m_desc(desc), m_name(name) + { + } + Artifact(const Desc& desc) + : m_desc(desc) + { + } IArtifactHandler* _getHandler(); void _requireChildren(); @@ -85,15 +111,16 @@ class Artifact : public ComBaseObject, public IArtifact void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); - Desc m_desc; ///< Description of the artifact - String m_name; ///< Name of this artifact + Desc m_desc; ///< Description of the artifact + String m_name; ///< Name of this artifact SlangResult m_expandResult = SLANG_E_UNINITIALIZED; - ComPtr m_handler; ///< The handler. Can be nullptr and then default handler is used. + ComPtr + m_handler; ///< The handler. Can be nullptr and then default handler is used. - List> m_representations; ///< All the representation of this artifact - List> m_associated; ///< All the items associated with this artifact - List> m_children; ///< All the child artifacts owned + List> m_representations; ///< All the representation of this artifact + List> m_associated; ///< All the items associated with this artifact + List> m_children; ///< All the child artifacts owned }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-representation-impl.cpp b/source/compiler-core/slang-artifact-representation-impl.cpp index 85563fe612..648e4d8c19 100644 --- a/source/compiler-core/slang-artifact-representation-impl.cpp +++ b/source/compiler-core/slang-artifact-representation-impl.cpp @@ -1,24 +1,21 @@ // slang-artifact-representation-impl.cpp #include "slang-artifact-representation-impl.h" +#include "../core/slang-array-view.h" +#include "../core/slang-castable.h" #include "../core/slang-file-system.h" - -#include "../core/slang-type-text-util.h" #include "../core/slang-io.h" -#include "../core/slang-array-view.h" - +#include "../core/slang-type-text-util.h" #include "slang-artifact-util.h" -#include "../core/slang-castable.h" - -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExtFileArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ void* ExtFileArtifactRepresentation::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IArtifactRepresentation::getTypeGuid() || guid == IPathArtifactRepresentation::getTypeGuid() || guid == IExtFileArtifactRepresentation::getTypeGuid()) @@ -43,7 +40,9 @@ void* ExtFileArtifactRepresentation::castAs(const Guid& guid) return getObject(guid); } -SlangResult ExtFileArtifactRepresentation::createRepresentation(const Guid& typeGuid, ICastable** outCastable) +SlangResult ExtFileArtifactRepresentation::createRepresentation( + const Guid& typeGuid, + ICastable** outCastable) { // We can convert into a blob only, and only if we have a path // If it's referenced by a name only, it's a file that *can't* be loaded as a blob in general. @@ -72,7 +71,9 @@ const char* ExtFileArtifactRepresentation::getUniqueIdentity() if (m_uniqueIdentity.getLength() == 0) { ComPtr uniqueIdentityBlob; - if (SLANG_FAILED(m_fileSystem->getFileUniqueIdentity(m_path.getBuffer(), uniqueIdentityBlob.writeRef()))) + if (SLANG_FAILED(m_fileSystem->getFileUniqueIdentity( + m_path.getBuffer(), + uniqueIdentityBlob.writeRef()))) { return nullptr; } @@ -82,12 +83,12 @@ const char* ExtFileArtifactRepresentation::getUniqueIdentity() return m_uniqueIdentity.getLength() ? m_uniqueIdentity.getBuffer() : nullptr; } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SourceBlobWithPathArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SourceBlobWithPathArtifactRepresentation + * !!!!!!!!!!!!!!!!!!!!!!!!!!! */ void* SourceBlobWithPathInfoArtifactRepresentation::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IArtifactRepresentation::getTypeGuid() || guid == IPathArtifactRepresentation::getTypeGuid()) { @@ -111,7 +112,9 @@ void* SourceBlobWithPathInfoArtifactRepresentation::castAs(const Guid& guid) return getObject(guid); } -SlangResult SourceBlobWithPathInfoArtifactRepresentation::createRepresentation(const Guid& typeGuid, ICastable** outCastable) +SlangResult SourceBlobWithPathInfoArtifactRepresentation::createRepresentation( + const Guid& typeGuid, + ICastable** outCastable) { // We can convert into a blob only. if (typeGuid != ISlangBlob::getTypeGuid()) @@ -132,8 +135,7 @@ SlangResult SourceBlobWithPathInfoArtifactRepresentation::createRepresentation(c void* OSFileArtifactRepresentation::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IArtifactRepresentation::getTypeGuid() || guid == IPathArtifactRepresentation::getTypeGuid() || guid == IOSFileArtifactRepresentation::getTypeGuid()) @@ -149,7 +151,7 @@ void* OSFileArtifactRepresentation::getObject(const Guid& guid) return nullptr; } -/* static */ISlangMutableFileSystem* OSFileArtifactRepresentation::_getFileSystem() +/* static */ ISlangMutableFileSystem* OSFileArtifactRepresentation::_getFileSystem() { return OSFileSystem::getMutableSingleton(); } @@ -163,12 +165,13 @@ void* OSFileArtifactRepresentation::castAs(const Guid& guid) return getObject(guid); } -SlangResult OSFileArtifactRepresentation::createRepresentation(const Guid& typeGuid, ICastable** outCastable) +SlangResult OSFileArtifactRepresentation::createRepresentation( + const Guid& typeGuid, + ICastable** outCastable) { // We can convert into a blob only, and only if we have a path // If it's referenced by a name only, it's a file that *can't* be loaded as a blob in general. - if (typeGuid != ISlangBlob::getTypeGuid() || - m_kind == Kind::NameOnly) + if (typeGuid != ISlangBlob::getTypeGuid() || m_kind == Kind::NameOnly) { return SLANG_E_NOT_AVAILABLE; } @@ -185,9 +188,9 @@ SlangResult OSFileArtifactRepresentation::createRepresentation(const Guid& typeG bool OSFileArtifactRepresentation::exists() { // TODO(JS): - // If it's a name only it's hard to know what exists should do. It can't *check* because it relies on the 'system' doing - // the actual location. We could ask the IArtifactUtil, and that could change the behavior. - // For now we just assume it does. + // If it's a name only it's hard to know what exists should do. It can't *check* because it + // relies on the 'system' doing the actual location. We could ask the IArtifactUtil, and that + // could change the behavior. For now we just assume it does. if (m_kind == Kind::NameOnly) { return true; @@ -209,7 +212,9 @@ const char* OSFileArtifactRepresentation::getUniqueIdentity() auto fileSystem = _getFileSystem(); ComPtr uniqueIdentityBlob; - if (SLANG_FAILED(fileSystem->getFileUniqueIdentity(m_path.getBuffer(), uniqueIdentityBlob.writeRef()))) + if (SLANG_FAILED(fileSystem->getFileUniqueIdentity( + m_path.getBuffer(), + uniqueIdentityBlob.writeRef()))) { return nullptr; } @@ -236,11 +241,12 @@ OSFileArtifactRepresentation::~OSFileArtifactRepresentation() } } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! PostEmitMetadataArtifactRepresentation !!!!!!!!!!!!!!!!!!!!!!!!!!! + */ void* ObjectArtifactRepresentation::castAs(const Guid& guid) { - + if (auto ptr = getInterface(guid)) { return ptr; @@ -250,8 +256,7 @@ void* ObjectArtifactRepresentation::castAs(const Guid& guid) void* ObjectArtifactRepresentation::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IArtifactRepresentation::getTypeGuid()) { return static_cast(this); diff --git a/source/compiler-core/slang-artifact-representation-impl.h b/source/compiler-core/slang-artifact-representation-impl.h index 034084950a..5e28d42f38 100644 --- a/source/compiler-core/slang-artifact-representation-impl.h +++ b/source/compiler-core/slang-artifact-representation-impl.h @@ -2,14 +2,11 @@ #ifndef SLANG_ARTIFACT_REPRESENTATION_IMPL_H #define SLANG_ARTIFACT_REPRESENTATION_IMPL_H +#include "../core/slang-com-object.h" +#include "../core/slang-memory-arena.h" #include "slang-artifact-representation.h" - #include "slang-com-helper.h" #include "slang-com-ptr.h" - -#include "../core/slang-com-object.h" -#include "../core/slang-memory-arena.h" - #include "slang-source-loc.h" namespace Slang @@ -27,29 +24,43 @@ class OSFileArtifactRepresentation : public ComBaseObject, public IOSFileArtifac SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL + createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; // IPathArtifactRepresentation - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_path.getBuffer(); } - virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE { return SLANG_PATH_TYPE_FILE; } + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE + { + return m_path.getBuffer(); + } + virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE + { + return SLANG_PATH_TYPE_FILE; + } virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() SLANG_OVERRIDE; // IOSFileArtifactRepresentation virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() SLANG_OVERRIDE { return m_kind; } virtual SLANG_NO_THROW void SLANG_MCALL disown() SLANG_OVERRIDE; - virtual SLANG_NO_THROW IOSFileArtifactRepresentation* SLANG_MCALL getLockFile() SLANG_OVERRIDE { return m_lockFile; } + virtual SLANG_NO_THROW IOSFileArtifactRepresentation* SLANG_MCALL getLockFile() SLANG_OVERRIDE + { + return m_lockFile; + } - OSFileArtifactRepresentation(Kind kind, const UnownedStringSlice& path, IOSFileArtifactRepresentation* lockFile): - m_kind(kind), - m_lockFile(lockFile), - m_path(path) + OSFileArtifactRepresentation( + Kind kind, + const UnownedStringSlice& path, + IOSFileArtifactRepresentation* lockFile) + : m_kind(kind), m_lockFile(lockFile), m_path(path) { } ~OSFileArtifactRepresentation(); - static ComPtr create(Kind kind, const UnownedStringSlice& path, IOSFileArtifactRepresentation* lockFile) + static ComPtr create( + Kind kind, + const UnownedStringSlice& path, + IOSFileArtifactRepresentation* lockFile) { return ComPtr(new ThisType(kind, path, lockFile)); } @@ -58,7 +69,7 @@ class OSFileArtifactRepresentation : public ComBaseObject, public IOSFileArtifac void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); - /// True if the file is owned + /// True if the file is owned bool _isOwned() const { return Index(m_kind) >= Index(Kind::Owned); } static ISlangMutableFileSystem* _getFileSystem(); @@ -82,24 +93,35 @@ class ExtFileArtifactRepresentation : public ComBaseObject, public IExtFileArtif SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL + createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE; // IPathArtifactRepresentation - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_path.getBuffer(); } - virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE { return SLANG_PATH_TYPE_FILE; } + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE + { + return m_path.getBuffer(); + } + virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE + { + return SLANG_PATH_TYPE_FILE; + } virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() SLANG_OVERRIDE; - + // IExtFileArtifactRepresentation - virtual SLANG_NO_THROW ISlangFileSystemExt* SLANG_MCALL getFileSystem() SLANG_OVERRIDE { return m_fileSystem; } + virtual SLANG_NO_THROW ISlangFileSystemExt* SLANG_MCALL getFileSystem() SLANG_OVERRIDE + { + return m_fileSystem; + } - ExtFileArtifactRepresentation(const UnownedStringSlice& path, ISlangFileSystemExt* fileSystem) : - m_path(path), - m_fileSystem(fileSystem) + ExtFileArtifactRepresentation(const UnownedStringSlice& path, ISlangFileSystemExt* fileSystem) + : m_path(path), m_fileSystem(fileSystem) { } - static ComPtr create(const UnownedStringSlice& path, ISlangFileSystemExt* fileSystem) + static ComPtr create( + const UnownedStringSlice& path, + ISlangFileSystemExt* fileSystem) { return ComPtr(new ThisType(path, fileSystem)); } @@ -113,7 +135,8 @@ class ExtFileArtifactRepresentation : public ComBaseObject, public IExtFileArtif ComPtr m_fileSystem; }; -class SourceBlobWithPathInfoArtifactRepresentation : public ComBaseObject, public IPathArtifactRepresentation +class SourceBlobWithPathInfoArtifactRepresentation : public ComBaseObject, + public IPathArtifactRepresentation { public: typedef SourceBlobWithPathInfoArtifactRepresentation ThisType; @@ -124,21 +147,32 @@ class SourceBlobWithPathInfoArtifactRepresentation : public ComBaseObject, publi SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL + createRepresentation(const Guid& typeGuid, ICastable** outCastable) SLANG_OVERRIDE; SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return false; } // IPathArtifactRepresentation - virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE { return m_pathInfo.getName().getBuffer(); } - virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE { return SLANG_PATH_TYPE_FILE; } - virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() SLANG_OVERRIDE { return m_pathInfo.hasUniqueIdentity() ? m_pathInfo.uniqueIdentity.getBuffer() : nullptr; } + virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() SLANG_OVERRIDE + { + return m_pathInfo.getName().getBuffer(); + } + virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() SLANG_OVERRIDE + { + return SLANG_PATH_TYPE_FILE; + } + virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() SLANG_OVERRIDE + { + return m_pathInfo.hasUniqueIdentity() ? m_pathInfo.uniqueIdentity.getBuffer() : nullptr; + } - SourceBlobWithPathInfoArtifactRepresentation(const PathInfo& pathInfo, ISlangBlob* sourceBlob) : - m_pathInfo(pathInfo), - m_blob(sourceBlob) + SourceBlobWithPathInfoArtifactRepresentation(const PathInfo& pathInfo, ISlangBlob* sourceBlob) + : m_pathInfo(pathInfo), m_blob(sourceBlob) { } - static ComPtr create(const PathInfo& pathInfo, ISlangBlob* sourceBlob) + static ComPtr create( + const PathInfo& pathInfo, + ISlangBlob* sourceBlob) { return ComPtr(new ThisType(pathInfo, sourceBlob)); } @@ -151,34 +185,40 @@ class SourceBlobWithPathInfoArtifactRepresentation : public ComBaseObject, publi ComPtr m_blob; }; -/* This allows wrapping any object to be an artifact representation. +/* This allows wrapping any object to be an artifact representation. -NOTE! Only allows casting from a single guid. Passing a RefObject across an ABI boundary remains risky! +NOTE! Only allows casting from a single guid. Passing a RefObject across an ABI boundary remains +risky! */ class ObjectArtifactRepresentation : public ComBaseObject, public IArtifactRepresentation { public: - SLANG_CLASS_GUID(0xb9d5af57, 0x725b, 0x45f8, { 0xac, 0xed, 0x18, 0xf4, 0xa8, 0x4b, 0xf4, 0x73 }) + SLANG_CLASS_GUID(0xb9d5af57, 0x725b, 0x45f8, {0xac, 0xed, 0x18, 0xf4, 0xa8, 0x4b, 0xf4, 0x73}) SLANG_COM_BASE_IUNKNOWN_ALL // ICastable SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IArtifactRepresentation - SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& guid, ICastable** outCastable) SLANG_OVERRIDE { SLANG_UNUSED(guid); SLANG_UNUSED(outCastable); return SLANG_E_NOT_AVAILABLE; } + SLANG_NO_THROW SlangResult SLANG_MCALL + createRepresentation(const Guid& guid, ICastable** outCastable) SLANG_OVERRIDE + { + SLANG_UNUSED(guid); + SLANG_UNUSED(outCastable); + return SLANG_E_NOT_AVAILABLE; + } SLANG_NO_THROW bool SLANG_MCALL exists() SLANG_OVERRIDE { return m_object; } - ObjectArtifactRepresentation(const Guid& typeGuid, RefObject* obj): - m_typeGuid(typeGuid), - m_object(obj) + ObjectArtifactRepresentation(const Guid& typeGuid, RefObject* obj) + : m_typeGuid(typeGuid), m_object(obj) { } void* getInterface(const Guid& uuid); void* getObject(const Guid& uuid); - - Guid m_typeGuid; ///< Will return m_object if a cast to m_typeGuid is given - RefPtr m_object; ///< The object + + Guid m_typeGuid; ///< Will return m_object if a cast to m_typeGuid is given + RefPtr m_object; ///< The object }; } // namespace Slang diff --git a/source/compiler-core/slang-artifact-representation.h b/source/compiler-core/slang-artifact-representation.h index 3e76590581..7195718066 100644 --- a/source/compiler-core/slang-artifact-representation.h +++ b/source/compiler-core/slang-artifact-representation.h @@ -10,49 +10,65 @@ namespace Slang /* Base interface for types that have a path. */ class IPathArtifactRepresentation : public IArtifactRepresentation { - SLANG_COM_INTERFACE(0xcb1c188c, 0x7e48, 0x43eb, { 0xb0, 0x9a, 0xa1, 0x6e, 0xef, 0xd4, 0x9b, 0xef }); + SLANG_COM_INTERFACE( + 0xcb1c188c, + 0x7e48, + 0x43eb, + {0xb0, 0x9a, 0xa1, 0x6e, 0xef, 0xd4, 0x9b, 0xef}); - /// The path + /// The path virtual SLANG_NO_THROW const char* SLANG_MCALL getPath() = 0; - /// Get type + /// Get type virtual SLANG_NO_THROW SlangPathType SLANG_MCALL getPathType() = 0; - /// Returns the unique identity. If a unique identity is not supported - /// or available will return nullptr. + /// Returns the unique identity. If a unique identity is not supported + /// or available will return nullptr. virtual SLANG_NO_THROW const char* SLANG_MCALL getUniqueIdentity() = 0; }; /* Represents a path to a file held on an ISlangFileSystem. */ class IExtFileArtifactRepresentation : public IPathArtifactRepresentation { - SLANG_COM_INTERFACE(0xacd65576, 0xb09d, 0x4ac9, { 0xa5, 0x93, 0xeb, 0xf8, 0x9b, 0xd7, 0x11, 0xfd }); + SLANG_COM_INTERFACE( + 0xacd65576, + 0xb09d, + 0x4ac9, + {0xa5, 0x93, 0xeb, 0xf8, 0x9b, 0xd7, 0x11, 0xfd}); - /// File system that holds the item along the path. + /// File system that holds the item along the path. virtual SLANG_NO_THROW ISlangFileSystemExt* SLANG_MCALL getFileSystem() = 0; }; -/* +/* A representation as a file on the OS file system. */ class IOSFileArtifactRepresentation : public IPathArtifactRepresentation { public: - SLANG_COM_INTERFACE(0xc7d7d3a4, 0x8683, 0x44b5, { 0x87, 0x96, 0xdf, 0xba, 0x9b, 0xc3, 0xf1, 0x7b }); + SLANG_COM_INTERFACE( + 0xc7d7d3a4, + 0x8683, + 0x44b5, + {0x87, 0x96, 0xdf, 0xba, 0x9b, 0xc3, 0xf1, 0x7b}); /* Determines ownership and other characteristics of the OS 'file' */ enum class Kind { - Reference, ///< References a file on the file system - NameOnly, ///< Typically used for items that can be found by the 'system'. The path is just a name, and cannot typically be loaded as a blob. - Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope - Lock, ///< An owned type, indicates potentially in part may only exist to 'lock' a path for a temporary file. Other files might exists based on the 'lock' path. + Reference, ///< References a file on the file system + NameOnly, ///< Typically used for items that can be found by the 'system'. The path is just + ///< a name, and cannot typically be loaded as a blob. + Owned, ///< File is *owned* by this instance and will be deleted when goes out of scope + Lock, ///< An owned type, indicates potentially in part may only exist to 'lock' a path for + ///< a temporary file. Other files might exists based on the 'lock' path. CountOf, }; - /// The the kind of file. - virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() = 0; - /// Makes the file no longer owned. Only applicable for Owned/Lock and they will become 'Reference' + /// The the kind of file. + virtual SLANG_NO_THROW Kind SLANG_MCALL getKind() = 0; + /// Makes the file no longer owned. Only applicable for Owned/Lock and they will become + /// 'Reference' virtual SLANG_NO_THROW void SLANG_MCALL disown() = 0; - /// Gets the 'lock file' if any associated with this file. Returns nullptr if there isn't one. - /// If this file is based on a 'lock file', the lock file must stay in scope at least as long as this does. + /// Gets the 'lock file' if any associated with this file. Returns nullptr if there isn't one. + /// If this file is based on a 'lock file', the lock file must stay in scope at least as long as + /// this does. virtual SLANG_NO_THROW IOSFileArtifactRepresentation* SLANG_MCALL getLockFile() = 0; }; diff --git a/source/compiler-core/slang-artifact-util.cpp b/source/compiler-core/slang-artifact-util.cpp index e03f02e1e1..703f8fddb2 100644 --- a/source/compiler-core/slang-artifact-util.cpp +++ b/source/compiler-core/slang-artifact-util.cpp @@ -1,15 +1,14 @@ // slang-artifact-util.cpp #include "slang-artifact-util.h" -#include "slang-artifact-impl.h" -#include "slang-artifact-representation-impl.h" - -#include "slang-artifact-desc-util.h" - #include "../core/slang-castable.h" #include "../core/slang-io.h" +#include "slang-artifact-desc-util.h" +#include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" -namespace Slang { +namespace Slang +{ static bool _checkSelf(ArtifactUtil::FindStyle findStyle) { @@ -23,36 +22,39 @@ static bool _checkChildren(ArtifactUtil::FindStyle findStyle) static bool _checkRecursive(ArtifactUtil::FindStyle findStyle) { - return findStyle == ArtifactUtil::FindStyle::Recursive || - findStyle == ArtifactUtil::FindStyle::ChildrenRecursive; + return findStyle == ArtifactUtil::FindStyle::Recursive || + findStyle == ArtifactUtil::FindStyle::ChildrenRecursive; } - + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */ComPtr ArtifactUtil::createArtifact(const ArtifactDesc& desc, const char* name) +/* static */ ComPtr ArtifactUtil::createArtifact( + const ArtifactDesc& desc, + const char* name) { auto artifact = createArtifact(desc); artifact->setName(name); return artifact; } -/* static */ComPtr ArtifactUtil::createArtifact(const ArtifactDesc& desc) +/* static */ ComPtr ArtifactUtil::createArtifact(const ArtifactDesc& desc) { return Artifact::create(desc); } -/* static */ComPtr ArtifactUtil::createArtifactForCompileTarget(SlangCompileTarget target) +/* static */ ComPtr ArtifactUtil::createArtifactForCompileTarget( + SlangCompileTarget target) { auto desc = ArtifactDescUtil::makeDescForCompileTarget(target); return createArtifact(desc); } -/* static */bool ArtifactUtil::isSignificant(IArtifact* artifact) +/* static */ bool ArtifactUtil::isSignificant(IArtifact* artifact) { return isSignificant(artifact->getDesc()); } -/* static */bool ArtifactUtil::isSignificant(const ArtifactDesc& desc) +/* static */ bool ArtifactUtil::isSignificant(const ArtifactDesc& desc) { // Containers are not significant as of themselves, they may contain something tho if (isDerivedFrom(desc.kind, ArtifactKind::Container)) @@ -61,16 +63,14 @@ static bool _checkRecursive(ArtifactUtil::FindStyle findStyle) } // If it has no payload.. we are done - if (desc.payload == ArtifactPayload::None || - desc.payload == ArtifactPayload::Invalid) + if (desc.payload == ArtifactPayload::None || desc.payload == ArtifactPayload::Invalid) { return false; } // If it's binary like or assembly/source we it's significant if (isDerivedFrom(desc.kind, ArtifactKind::CompileBinary) || - desc.kind == ArtifactKind::Assembly || - desc.kind == ArtifactKind::Source) + desc.kind == ArtifactKind::Assembly || desc.kind == ArtifactKind::Source) { return true; } @@ -93,15 +93,19 @@ static bool _checkRecursive(ArtifactUtil::FindStyle findStyle) } -/* static */bool ArtifactUtil::isSignificant(IArtifact* artifact, void* data) +/* static */ bool ArtifactUtil::isSignificant(IArtifact* artifact, void* data) { SLANG_UNUSED(data); return isSignificant(artifact->getDesc()); } -/* static */IArtifact* ArtifactUtil::findSignificant(IArtifact* artifact) -{ - return findArtifactByPredicate(artifact, FindStyle::SelfOrChildren, &ArtifactUtil::isSignificant, nullptr); +/* static */ IArtifact* ArtifactUtil::findSignificant(IArtifact* artifact) +{ + return findArtifactByPredicate( + artifact, + FindStyle::SelfOrChildren, + &ArtifactUtil::isSignificant, + nullptr); } UnownedStringSlice ArtifactUtil::findPath(IArtifact* artifact) @@ -122,7 +126,7 @@ UnownedStringSlice ArtifactUtil::findPath(IArtifact* artifact) { if (auto pathRep = as(rep)) { - if (pathRep->getPathType() == SLANG_PATH_TYPE_FILE && + if (pathRep->getPathType() == SLANG_PATH_TYPE_FILE && (bestRep == nullptr || as(rep))) { bestRep = pathRep; @@ -130,11 +134,12 @@ UnownedStringSlice ArtifactUtil::findPath(IArtifact* artifact) } } - const UnownedStringSlice name = bestRep ? UnownedStringSlice(bestRep->getPath()) : UnownedStringSlice(); + const UnownedStringSlice name = + bestRep ? UnownedStringSlice(bestRep->getPath()) : UnownedStringSlice(); return name.getLength() ? name : UnownedStringSlice(); } -/* static */UnownedStringSlice ArtifactUtil::inferExtension(IArtifact* artifact) +/* static */ UnownedStringSlice ArtifactUtil::inferExtension(IArtifact* artifact) { const UnownedStringSlice path = findPath(artifact); if (path.getLength()) @@ -148,14 +153,17 @@ UnownedStringSlice ArtifactUtil::findPath(IArtifact* artifact) return UnownedStringSlice(); } -/* static */UnownedStringSlice ArtifactUtil::findName(IArtifact* artifact) +/* static */ UnownedStringSlice ArtifactUtil::findName(IArtifact* artifact) { const UnownedStringSlice path = findPath(artifact); const Index pos = Path::findLastSeparatorIndex(path); return (pos >= 0) ? path.tail(pos + 1) : path; } -static SlangResult _calcInferred(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath) +static SlangResult _calcInferred( + IArtifact* artifact, + const UnownedStringSlice& basePath, + StringBuilder& outPath) { auto ext = ArtifactUtil::inferExtension(artifact); @@ -175,7 +183,10 @@ static SlangResult _calcInferred(IArtifact* artifact, const UnownedStringSlice& return SLANG_OK; } -/* static */SlangResult ArtifactUtil::calcPath(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath) +/* static */ SlangResult ArtifactUtil::calcPath( + IArtifact* artifact, + const UnownedStringSlice& basePath, + StringBuilder& outPath) { if (ArtifactDescUtil::hasDefinedNameForDesc(artifact->getDesc())) { @@ -187,7 +198,10 @@ static SlangResult _calcInferred(IArtifact* artifact, const UnownedStringSlice& } } -/* static */SlangResult ArtifactUtil::calcName(IArtifact* artifact, const UnownedStringSlice& baseName, StringBuilder& outName) +/* static */ SlangResult ArtifactUtil::calcName( + IArtifact* artifact, + const UnownedStringSlice& baseName, + StringBuilder& outName) { if (ArtifactDescUtil::hasDefinedNameForDesc(artifact->getDesc())) { @@ -223,22 +237,39 @@ static bool _isName(IArtifact* artifact, void* data) return ::strcmp(name, artifactName) == 0; } -/* static */IArtifact* ArtifactUtil::findArtifactByDerivedDesc(IArtifact* artifact, FindStyle findStyle, const ArtifactDesc& desc) +/* static */ IArtifact* ArtifactUtil::findArtifactByDerivedDesc( + IArtifact* artifact, + FindStyle findStyle, + const ArtifactDesc& desc) { - return findArtifactByPredicate(artifact, findStyle, _isByDerivedDesc, &const_cast(desc)); + return findArtifactByPredicate( + artifact, + findStyle, + _isByDerivedDesc, + &const_cast(desc)); } -/* static */IArtifact* ArtifactUtil::findArtifactByName(IArtifact* artifact, FindStyle findStyle, const char* name) +/* static */ IArtifact* ArtifactUtil::findArtifactByName( + IArtifact* artifact, + FindStyle findStyle, + const char* name) { return findArtifactByPredicate(artifact, findStyle, _isName, const_cast(name)); } -/* static */IArtifact* ArtifactUtil::findArtifactByDesc(IArtifact* artifact, FindStyle findStyle, const ArtifactDesc& desc) +/* static */ IArtifact* ArtifactUtil::findArtifactByDesc( + IArtifact* artifact, + FindStyle findStyle, + const ArtifactDesc& desc) { return findArtifactByPredicate(artifact, findStyle, _isDesc, &const_cast(desc)); } -/* static */IArtifact* ArtifactUtil::findArtifactByPredicate(IArtifact* artifact, FindStyle findStyle, FindFunc func, void* data) +/* static */ IArtifact* ArtifactUtil::findArtifactByPredicate( + IArtifact* artifact, + FindStyle findStyle, + FindFunc func, + void* data) { if (_checkSelf(findStyle) && func(artifact, data)) { @@ -250,7 +281,7 @@ static bool _isName(IArtifact* artifact, void* data) return nullptr; } - // Expand the children so we can search them + // Expand the children so we can search them artifact->expandChildren(); auto children = artifact->getChildren(); @@ -268,38 +299,45 @@ static bool _isName(IArtifact* artifact, void* data) } } - // If it's recursive, we check all the children of children + // If it's recursive, we check all the children of children if (_checkRecursive(findStyle)) { for (auto child : children) { - if (auto found = findArtifactByPredicate(child, FindStyle::ChildrenRecursive, func, data)) + if (auto found = + findArtifactByPredicate(child, FindStyle::ChildrenRecursive, func, data)) { return found; } } } - + return nullptr; } -/* static */void ArtifactUtil::addAssociated(IArtifact* artifact, IArtifactPostEmitMetadata* metadata) +/* static */ void ArtifactUtil::addAssociated( + IArtifact* artifact, + IArtifactPostEmitMetadata* metadata) { if (metadata) { - auto metadataArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Instance, ArtifactPayload::PostEmitMetadata)); + auto metadataArtifact = ArtifactUtil::createArtifact( + ArtifactDesc::make(ArtifactKind::Instance, ArtifactPayload::PostEmitMetadata)); metadataArtifact->addRepresentation(metadata); artifact->addAssociated(metadataArtifact); } } -/* static */void ArtifactUtil::addAssociated(IArtifact* artifact, IArtifactDiagnostics* diagnostics) +/* static */ void ArtifactUtil::addAssociated( + IArtifact* artifact, + IArtifactDiagnostics* diagnostics) { if (diagnostics) { - auto diagnosticsArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Instance, ArtifactPayload::Diagnostics)); + auto diagnosticsArtifact = ArtifactUtil::createArtifact( + ArtifactDesc::make(ArtifactKind::Instance, ArtifactPayload::Diagnostics)); diagnosticsArtifact->addRepresentation(diagnostics); - artifact->addAssociated(diagnosticsArtifact); + artifact->addAssociated(diagnosticsArtifact); } } diff --git a/source/compiler-core/slang-artifact-util.h b/source/compiler-core/slang-artifact-util.h index 5341f309b5..538affcdb3 100644 --- a/source/compiler-core/slang-artifact-util.h +++ b/source/compiler-core/slang-artifact-util.h @@ -2,10 +2,9 @@ #ifndef SLANG_ARTIFACT_UTIL_H #define SLANG_ARTIFACT_UTIL_H -#include "slang-artifact.h" -#include "slang-artifact-representation.h" #include "slang-artifact-associated.h" - +#include "slang-artifact-representation.h" +#include "slang-artifact.h" #include "slang-com-ptr.h" namespace Slang @@ -17,63 +16,86 @@ struct ArtifactUtil enum class FindStyle : uint8_t { - Self, ///< Just on self - SelfOrChildren, ///< Self, or if container just the children - Recursive, ///< On self plus any children recursively - Children, ///< Only on children - ChildrenRecursive, ///< Only on children recursively + Self, ///< Just on self + SelfOrChildren, ///< Self, or if container just the children + Recursive, ///< On self plus any children recursively + Children, ///< Only on children + ChildrenRecursive, ///< Only on children recursively }; - /// Find an artifact that matches desc allowing derivations. Flags is ignored - static IArtifact* findArtifactByDerivedDesc(IArtifact* artifact, FindStyle findStyle, const ArtifactDesc& desc); - /// Find an artifact that predicate matches - static IArtifact* findArtifactByPredicate(IArtifact* artifact, FindStyle findStyle, FindFunc func, void* data); - /// Find by name - static IArtifact* findArtifactByName(IArtifact* artifact, FindStyle findStyle, const char* name); - /// Find by desc exactly - static IArtifact* findArtifactByDesc(IArtifact* artifact, FindStyle findStyle, const ArtifactDesc& desc); - - /// Creates an empty artifact for a type + /// Find an artifact that matches desc allowing derivations. Flags is ignored + static IArtifact* findArtifactByDerivedDesc( + IArtifact* artifact, + FindStyle findStyle, + const ArtifactDesc& desc); + /// Find an artifact that predicate matches + static IArtifact* findArtifactByPredicate( + IArtifact* artifact, + FindStyle findStyle, + FindFunc func, + void* data); + /// Find by name + static IArtifact* findArtifactByName( + IArtifact* artifact, + FindStyle findStyle, + const char* name); + /// Find by desc exactly + static IArtifact* findArtifactByDesc( + IArtifact* artifact, + FindStyle findStyle, + const ArtifactDesc& desc); + + /// Creates an empty artifact for a type static ComPtr createArtifactForCompileTarget(SlangCompileTarget target); - /// Create an artifact + /// Create an artifact static ComPtr createArtifact(const ArtifactDesc& desc, const char* name); static ComPtr createArtifact(const ArtifactDesc& desc); - /// True if is significant + /// True if is significant static bool isSignificant(IArtifact* artifact); - /// True if is significant + /// True if is significant static bool isSignificant(const ArtifactDesc& desc); - /// Returns true if an artifact is 'significant'. - /// The data parameter is unused and just used to make work as FindFunc + /// Returns true if an artifact is 'significant'. + /// The data parameter is unused and just used to make work as FindFunc static bool isSignificant(IArtifact* artifact, void* data); - /// Find a significant artifact + /// Find a significant artifact static IArtifact* findSignificant(IArtifact* artifact); - /// Find the path/name associated with the artifact. - /// The path is *not* necessarily the path on the file system. The order of search is - /// * If the artifact has a name return that - /// * If the artifact has a IPathFileArtifactRepresentation (that isn't temporary) return it's path - /// * If not found return an empty slice + /// Find the path/name associated with the artifact. + /// The path is *not* necessarily the path on the file system. The order of search is + /// * If the artifact has a name return that + /// * If the artifact has a IPathFileArtifactRepresentation (that isn't temporary) return it's + /// path + /// * If not found return an empty slice static UnownedStringSlice findPath(IArtifact* artifact); - /// Find a name + /// Find a name static UnownedStringSlice findName(IArtifact* artifact); - /// Sometimes we have artifacts that don't specify a payload type - perhaps because they can be interpretted in different ways - /// This function uses the associated name and file representations to infer a extension. If none is found returns an empty slice. + /// Sometimes we have artifacts that don't specify a payload type - perhaps because they can be + /// interpretted in different ways This function uses the associated name and file + /// representations to infer a extension. If none is found returns an empty slice. static UnownedStringSlice inferExtension(IArtifact* artifact); - /// Given a desc and a basePath returns a suitable path for a entity of specified desc - static SlangResult calcPath(IArtifact* artifact, const UnownedStringSlice& basePath, StringBuilder& outPath); + /// Given a desc and a basePath returns a suitable path for a entity of specified desc + static SlangResult calcPath( + IArtifact* artifact, + const UnownedStringSlice& basePath, + StringBuilder& outPath); - /// Given a desc and a baseName works out the the output file name - static SlangResult calcName(IArtifact* artifact, const UnownedStringSlice& baseName, StringBuilder& outName); + /// Given a desc and a baseName works out the the output file name + static SlangResult calcName( + IArtifact* artifact, + const UnownedStringSlice& baseName, + StringBuilder& outName); - /// Convenience function that adds metadata to artifact. If metadata is nullptr nothing is added. + /// Convenience function that adds metadata to artifact. If metadata is nullptr nothing is + /// added. static void addAssociated(IArtifact* artifact, IArtifactPostEmitMetadata* metadata); - /// Convenience function that adds diagnostics to artifact. If diagnostics is nullptr nothing is added. + /// Convenience function that adds diagnostics to artifact. If diagnostics is nullptr nothing is + /// added. static void addAssociated(IArtifact* artifact, IArtifactDiagnostics* diagnostics); }; diff --git a/source/compiler-core/slang-artifact.h b/source/compiler-core/slang-artifact.h index 6d65aafba4..46e8831fff 100644 --- a/source/compiler-core/slang-artifact.h +++ b/source/compiler-core/slang-artifact.h @@ -10,32 +10,39 @@ namespace Slang { -/* Simplest slice types. We can't use UnownedStringSlice etc, because they implement functionality in libraries, -and we want to use these types in headers. -If we wanted a C implementation it would be easy to use a macro to generate the functionality */ +/* Simplest slice types. We can't use UnownedStringSlice etc, because they implement functionality +in libraries, and we want to use these types in headers. If we wanted a C implementation it would be +easy to use a macro to generate the functionality */ -template +template struct Slice { const T* begin() const { return data; } const T* end() const { return data + count; } - const T& operator[](Index index) const { SLANG_ASSERT(index >= 0 && index < count); return data[index]; } + const T& operator[](Index index) const + { + SLANG_ASSERT(index >= 0 && index < count); + return data[index]; + } - Slice() :count(0), data(nullptr) {} - Slice(const T* inData, Count inCount) : - data(inData), - count(inCount) - {} + Slice() + : count(0), data(nullptr) + { + } + Slice(const T* inData, Count inCount) + : data(inData), count(inCount) + { + } const T* data; Count count; }; -template -SLANG_FORCE_INLINE Slice makeSlice(const T* inData, Count inCount) -{ - return Slice(inData, inCount); +template +SLANG_FORCE_INLINE Slice makeSlice(const T* inData, Count inCount) +{ + return Slice(inData, inCount); } struct CharSlice : public Slice @@ -43,13 +50,26 @@ struct CharSlice : public Slice typedef CharSlice ThisType; typedef Slice Super; - bool operator==(const ThisType& rhs) const { return count == rhs.count && (data == rhs.data || ::memcmp(data, rhs.data, count) == 0); } + bool operator==(const ThisType& rhs) const + { + return count == rhs.count && (data == rhs.data || ::memcmp(data, rhs.data, count) == 0); + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - explicit CharSlice(const char* in) :Super(in, ::strlen(in)) {} - CharSlice(const char* in, Count inCount) :Super(in, inCount) {} - CharSlice() :Super(nullptr, 0) {} - explicit CharSlice(const String& s) :CharSlice(s.begin(), s.getLength()){}; + explicit CharSlice(const char* in) + : Super(in, ::strlen(in)) + { + } + CharSlice(const char* in, Count inCount) + : Super(in, inCount) + { + } + CharSlice() + : Super(nullptr, 0) + { + } + explicit CharSlice(const String& s) + : CharSlice(s.begin(), s.getLength()){}; }; static_assert(std::is_trivially_copyable_v); @@ -61,17 +81,28 @@ struct TerminatedCharSlice : public CharSlice SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return Super::operator==(rhs); } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Make convertable to char* - SLANG_FORCE_INLINE operator const char* () const { return data; } + /// Make convertable to char* + SLANG_FORCE_INLINE operator const char*() const { return data; } - explicit TerminatedCharSlice(const char* in) :Super(in) {} - TerminatedCharSlice(const char* in, Count inCount) :Super(in, inCount) { SLANG_ASSERT(in[inCount] == 0); } - TerminatedCharSlice() :Super("", 0) {} + explicit TerminatedCharSlice(const char* in) + : Super(in) + { + } + TerminatedCharSlice(const char* in, Count inCount) + : Super(in, inCount) + { + SLANG_ASSERT(in[inCount] == 0); + } + TerminatedCharSlice() + : Super("", 0) + { + } }; static_assert(std::is_trivially_copyable_v); -/* As a rule of thumb, if we can define some aspect in a hierarchy then we should do so at the highest level. -If some aspect can apply to multiple items identically we move that to a separate enum. +/* As a rule of thumb, if we can define some aspect in a hierarchy then we should do so at the +highest level. If some aspect can apply to multiple items identically we move that to a separate +enum. NOTE! New Kinds must be added at the end. Values can be deprecated, or disabled @@ -80,43 +111,43 @@ but never removed, without breaking binary compatability. Any change requires a change to SLANG_ARTIFACT_KIND */ enum class ArtifactKind : uint8_t -{ - Invalid, ///< Invalid - Base, ///< Base kind of all valid kinds - - None, ///< Doesn't contain anything - Unknown, ///< Unknown - - BinaryFormat, ///< A generic binary format. - - Container, ///< Container like types - Zip, ///< Zip container - RiffContainer, ///< Riff container - RiffLz4Container, ///< Riff container using Lz4 compression - RiffDeflateContainer, ///< Riff container using deflate compression - - Text, ///< Representation is text. Encoding is utf8, unless prefixed with 'encoding'. - - Source, ///< Source (Source type is in payload) - Assembly, ///< Assembly (Type is in payload) - HumanText, ///< Text for human consumption - - CompileBinary, ///< Kinds which are 'binary like' - can be executed, linked with and so forth. - - ObjectCode, ///< Object file - Library, ///< Library (collection of object code) - Executable, ///< Executable - SharedLibrary, ///< Shared library - can be dynamically linked - HostCallable, ///< Code can be executed directly on the host - - Instance, ///< Primary representation is an interface/class instance - - Json, ///< It's JSON +{ + Invalid, ///< Invalid + Base, ///< Base kind of all valid kinds + + None, ///< Doesn't contain anything + Unknown, ///< Unknown + + BinaryFormat, ///< A generic binary format. + + Container, ///< Container like types + Zip, ///< Zip container + RiffContainer, ///< Riff container + RiffLz4Container, ///< Riff container using Lz4 compression + RiffDeflateContainer, ///< Riff container using deflate compression + + Text, ///< Representation is text. Encoding is utf8, unless prefixed with 'encoding'. + + Source, ///< Source (Source type is in payload) + Assembly, ///< Assembly (Type is in payload) + HumanText, ///< Text for human consumption + + CompileBinary, ///< Kinds which are 'binary like' - can be executed, linked with and so forth. + + ObjectCode, ///< Object file + Library, ///< Library (collection of object code) + Executable, ///< Executable + SharedLibrary, ///< Shared library - can be dynamically linked + HostCallable, ///< Code can be executed directly on the host + + Instance, ///< Primary representation is an interface/class instance + + Json, ///< It's JSON CountOf, }; -/* Payload. +/* Payload. SlangIR and LLVMIR can be GPU or CPU orientated, so put in own category. @@ -128,68 +159,69 @@ Any change requires a change to SLANG_ARTIFACT_PAYLOAD */ enum class ArtifactPayload : uint8_t { - Invalid, ///< Is invalid - indicates some kind of problem - Base, ///< The base of the hierarchy - - None, ///< Doesn't have a payload - Unknown, ///< Unknown but probably valid - - Source, ///< Source code - - C, ///< C source - Cpp, ///< C++ source - HLSL, ///< HLSL source - GLSL, ///< GLSL source - CUDA, ///< CUDA source - Metal, ///< Metal source - Slang, ///< Slang source - WGSL, ///< WGSL source - - KernelLike, ///< GPU Kernel like - - DXIL, ///< DXIL - DXBC, ///< DXBC - SPIRV, ///< SPIR-V - PTX, ///< PTX. NOTE! PTX is a text format, but is handable to CUDA API. - MetalAIR, ///< Metal AIR - CuBin, ///< CUDA binary - - CPULike, ///< CPU code - - UnknownCPU, ///< CPU code for unknown/undetermined type - X86, ///< X86 - X86_64, ///< X86_64 - Aarch, ///< 32 bit arm - Aarch64, ///< Aarch64 - HostCPU, ///< HostCPU - UniversalCPU, ///< CPU code for multiple CPU types - - GeneralIR, ///< General purpose IR representation (IR) - - SlangIR, ///< Slang IR - LLVMIR, ///< LLVM IR - - AST, ///< Abstract syntax tree (AST) - - SlangAST, ///< Slang AST + Invalid, ///< Is invalid - indicates some kind of problem + Base, ///< The base of the hierarchy + + None, ///< Doesn't have a payload + Unknown, ///< Unknown but probably valid + + Source, ///< Source code + + C, ///< C source + Cpp, ///< C++ source + HLSL, ///< HLSL source + GLSL, ///< GLSL source + CUDA, ///< CUDA source + Metal, ///< Metal source + Slang, ///< Slang source + WGSL, ///< WGSL source + + KernelLike, ///< GPU Kernel like + + DXIL, ///< DXIL + DXBC, ///< DXBC + SPIRV, ///< SPIR-V + PTX, ///< PTX. NOTE! PTX is a text format, but is handable to CUDA API. + MetalAIR, ///< Metal AIR + CuBin, ///< CUDA binary + WGSL_SPIRV, ///< SPIR-V derived via WebGPU shading language + + CPULike, ///< CPU code + + UnknownCPU, ///< CPU code for unknown/undetermined type + X86, ///< X86 + X86_64, ///< X86_64 + Aarch, ///< 32 bit arm + Aarch64, ///< Aarch64 + HostCPU, ///< HostCPU + UniversalCPU, ///< CPU code for multiple CPU types + + GeneralIR, ///< General purpose IR representation (IR) + + SlangIR, ///< Slang IR + LLVMIR, ///< LLVM IR + + AST, ///< Abstract syntax tree (AST) + + SlangAST, ///< Slang AST CompileResults, ///< Payload is a collection of compilation results - Metadata, ///< Metadata + Metadata, ///< Metadata - DebugInfo, ///< Debugging information - Diagnostics, ///< Diagnostics information + DebugInfo, ///< Debugging information + Diagnostics, ///< Diagnostics information - Miscellaneous, ///< Category for miscellaneous payloads (like Log/Lock) + Miscellaneous, ///< Category for miscellaneous payloads (like Log/Lock) - Log, ///< Log file - Lock, ///< Typically some kind of 'lock' file. Contents is typically not important. + Log, ///< Log file + Lock, ///< Typically some kind of 'lock' file. Contents is typically not important. - PdbDebugInfo, ///< PDB debug info + PdbDebugInfo, ///< PDB debug info - SourceMap, ///< A source map + SourceMap, ///< A source map - PostEmitMetadata, ///< Metadata from post emit (binding information) + PostEmitMetadata, ///< Metadata from post emit (binding information) CountOf, }; @@ -204,18 +236,18 @@ Any change requires a change to SLANG_ARTIFACT_STYLE */ enum class ArtifactStyle : uint8_t { - Invalid, ///< Invalid style (indicating an error) + Invalid, ///< Invalid style (indicating an error) Base, - - None, ///< A style is not applicable - Unknown, ///< Unknown + None, ///< A style is not applicable + + Unknown, ///< Unknown - CodeLike, ///< For styles that are 'code like' such as 'kernel' or 'host'. + CodeLike, ///< For styles that are 'code like' such as 'kernel' or 'host'. - Kernel, ///< Compiled as `GPU kernel` style. - Host, ///< Compiled in `host` style - Obfuscated, ///< Holds something specific to obfuscation, such as an obfuscated source map + Kernel, ///< Compiled as `GPU kernel` style. + Host, ///< Compiled in `host` style + Obfuscated, ///< Holds something specific to obfuscation, such as an obfuscated source map CountOf, }; @@ -241,21 +273,35 @@ struct ArtifactDesc typedef ArtifactPayload Payload; typedef ArtifactStyle Style; typedef ArtifactFlags Flags; - + typedef uint32_t PackedBacking; enum class Packed : PackedBacking; - - /// Get in packed format + + /// Get in packed format inline Packed getPacked() const; - bool operator==(const ThisType& rhs) const { return kind == rhs.kind && payload == rhs.payload && style == rhs.style && flags == rhs.flags; } + bool operator==(const ThisType& rhs) const + { + return kind == rhs.kind && payload == rhs.payload && style == rhs.style && + flags == rhs.flags; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Construct from the elements - static ThisType make(Kind inKind, Payload inPayload, Style inStyle = Style::Unknown, Flags flags = 0) { return ThisType{ inKind, inPayload, inStyle, flags }; } - static ThisType make(Kind inKind, Payload inPayload, const ThisType& base) { return ThisType{ inKind, inPayload, base.style, base.flags }; } + /// Construct from the elements + static ThisType make( + Kind inKind, + Payload inPayload, + Style inStyle = Style::Unknown, + Flags flags = 0) + { + return ThisType{inKind, inPayload, inStyle, flags}; + } + static ThisType make(Kind inKind, Payload inPayload, const ThisType& base) + { + return ThisType{inKind, inPayload, base.style, base.flags}; + } - /// Construct from the packed format + /// Construct from the packed format inline static ThisType make(Packed inPacked); Kind kind; @@ -268,14 +314,11 @@ struct ArtifactDesc inline ArtifactDesc::Packed ArtifactDesc::getPacked() const { typedef PackedBacking IntType; - return Packed((IntType(kind) << 24) | - (IntType(payload) << 16) | - (IntType(style) << 8) | - flags); + return Packed((IntType(kind) << 24) | (IntType(payload) << 16) | (IntType(style) << 8) | flags); } // -------------------------------------------------------------------------- -inline /* static */ArtifactDesc ArtifactDesc::make(Packed inPacked) +inline /* static */ ArtifactDesc ArtifactDesc::make(Packed inPacked) { const PackedBacking packed = PackedBacking(inPacked); @@ -294,43 +337,53 @@ class IPathArtifactRepresentation; class IArtifactRepresentation; -// Controls what items can be kept. +// Controls what items can be kept. enum class ArtifactKeep { - No, ///< Don't keep the item - Yes, ///< Yes keep the final item - All, ///< Keep the final item and any intermediataries + No, ///< Don't keep the item + Yes, ///< Yes keep the final item + All, ///< Keep the final item and any intermediataries }; /// True if can keep an intermediate item -SLANG_INLINE bool canKeepIntermediate(ArtifactKeep keep) { return keep == ArtifactKeep::All; } +SLANG_INLINE bool canKeepIntermediate(ArtifactKeep keep) +{ + return keep == ArtifactKeep::All; +} /// True if can keep -SLANG_INLINE bool canKeep(ArtifactKeep keep) { return Index(keep) >= Index(ArtifactKeep::Yes); } +SLANG_INLINE bool canKeep(ArtifactKeep keep) +{ + return Index(keep) >= Index(ArtifactKeep::Yes); +} /// Returns the keep type for an intermediate -SLANG_INLINE ArtifactKeep getIntermediateKeep(ArtifactKeep keep) { return (keep == ArtifactKeep::All) ? ArtifactKeep::All : ArtifactKeep::No; } +SLANG_INLINE ArtifactKeep getIntermediateKeep(ArtifactKeep keep) +{ + return (keep == ArtifactKeep::All) ? ArtifactKeep::All : ArtifactKeep::No; +} /* Forward define */ class IArtifactHandler; -/* The IArtifact interface is designed to represent some Artifact of compilation. It could be input to or output from a compilation. +/* The IArtifact interface is designed to represent some Artifact of compilation. It could be input +to or output from a compilation. An abstraction is desirable here, because depending on the compiler the artifact/s could be * A file on the file system * A blob * Multiple files -* Some other (perhaps multiple) in memory representations -* A name +* Some other (perhaps multiple) in memory representations +* A name -The artifact uses the Blob as the canonical in memory representation. +The artifact uses the Blob as the canonical in memory representation. Some downstream compilers require the artifact to be available as a file system file, or to produce artifacts that are files. The IArtifact type allows to abstract away this difference, including the -ability to turn an in memory representation into a temporary file on the file system. +ability to turn an in memory representation into a temporary file on the file system. -The mechanism also allows for 'Containers' which allow for Artifacts to contain other Artifacts (amongst other things). -Those artifacts may be other files. For example a downstream compilation that produces results as well as temporary -files could be a Container containing artifacts for +The mechanism also allows for 'Containers' which allow for Artifacts to contain other Artifacts +(amongst other things). Those artifacts may be other files. For example a downstream compilation +that produces results as well as temporary files could be a Container containing artifacts for * Diagnostics * Temporary files (of known and unknown types) @@ -343,20 +396,26 @@ There are several types of ways to associate data with an artifact: * An associated artifact * A child artifact -A `representation` has to wholly represent the artifact. That representation could be a blob, a file on the file system, -an in memory representation. There are two classes of `Representation` - ones that can be turned into blobs (and therefore -derive from IArtifactRepresentation) and ones that are in of themselves a representation (such as a blob or or ISlangSharedLibrary). +A `representation` has to wholly represent the artifact. That representation could be a blob, a file +on the file system, an in memory representation. There are two classes of `Representation` - ones +that can be turned into blobs (and therefore derive from IArtifactRepresentation) and ones that are +in of themselves a representation (such as a blob or or ISlangSharedLibrary). -`Associated artifacts` hold information that is associated with the artifact. It could be part -of the representation, or useful for the implementation of a representation. Could also be considered as a kind of side channel -to associate arbitrary data including temporary data with an artifact. +`Associated artifacts` hold information that is associated with the artifact. It could be part +of the representation, or useful for the implementation of a representation. Could also be +considered as a kind of side channel to associate arbitrary data including temporary data with an +artifact. A `child artifact` belongs to the artifact, within the hierarchy of artifacts. */ class IArtifact : public ICastable { public: - SLANG_COM_INTERFACE(0xf90acdb0, 0x9a4a, 0x414e, { 0x85, 0x45, 0x8b, 0x26, 0xc9, 0x2d, 0x94, 0x42 }) + SLANG_COM_INTERFACE( + 0xf90acdb0, + 0x9a4a, + 0x414e, + {0x85, 0x45, 0x8b, 0x26, 0xc9, 0x2d, 0x94, 0x42}) enum class ContainedKind { @@ -373,90 +432,100 @@ class IArtifact : public ICastable typedef ArtifactFlags Flags; typedef ArtifactKeep Keep; - - /// Get the Desc defining the contents of the artifact + + /// Get the Desc defining the contents of the artifact virtual SLANG_NO_THROW Desc SLANG_MCALL getDesc() = 0; - /// Returns true if the artifact in principal exists + /// Returns true if the artifact in principal exists virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; - /// Load as a blob + /// Load as a blob virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadBlob(Keep keep, ISlangBlob** outBlob) = 0; - - /// Require artifact is available as a file. - /// NOTE! May need to serialize and write as a temporary file. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL requireFile(Keep keep, IOSFileArtifactRepresentation** outFileRep) = 0; - /// Load the artifact as a shared library - virtual SLANG_NO_THROW SlangResult SLANG_MCALL loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary) = 0; + /// Require artifact is available as a file. + /// NOTE! May need to serialize and write as a temporary file. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + requireFile(Keep keep, IOSFileArtifactRepresentation** outFileRep) = 0; - /// Get the name of the artifact. This can be empty. + /// Load the artifact as a shared library + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + loadSharedLibrary(ArtifactKeep keep, ISlangSharedLibrary** outSharedLibrary) = 0; + + /// Get the name of the artifact. This can be empty. virtual SLANG_NO_THROW const char* SLANG_MCALL getName() = 0; - /// Set the name associated with the artifact + /// Set the name associated with the artifact virtual SLANG_NO_THROW void SLANG_MCALL setName(const char* name) = 0; - /// Add associated artifacts with this artifact + /// Add associated artifacts with this artifact virtual SLANG_NO_THROW void SLANG_MCALL addAssociated(IArtifact* artifact) = 0; - /// Get the list of associated items + /// Get the list of associated items virtual SLANG_NO_THROW Slice SLANG_MCALL getAssociated() = 0; - - /// Add a representation + + /// Add a representation virtual SLANG_NO_THROW void SLANG_MCALL addRepresentation(ICastable* castable) = 0; - /// Add a representation that doesn't derive from IArtifactRepresentation + /// Add a representation that doesn't derive from IArtifactRepresentation virtual SLANG_NO_THROW void SLANG_MCALL addRepresentationUnknown(ISlangUnknown* rep) = 0; - /// Get all the representations + /// Get all the representations virtual SLANG_NO_THROW Slice SLANG_MCALL getRepresentations() = 0; - /// Given a typeGuid representing the desired type get or create the representation. - /// If found outCastable holds an entity that *must* be castable to typeGuid - /// Use the keep parameter to determine if the representation should be cached on the artifact/s or not. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation(const Guid& typeGuid, ArtifactKeep keep, ICastable** outCastable) = 0; - - /// Get the handler used for this artifact. If nullptr means the default handler will be used. + /// Given a typeGuid representing the desired type get or create the representation. + /// If found outCastable holds an entity that *must* be castable to typeGuid + /// Use the keep parameter to determine if the representation should be cached on the artifact/s + /// or not. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getOrCreateRepresentation(const Guid& typeGuid, ArtifactKeep keep, ICastable** outCastable) = 0; + + /// Get the handler used for this artifact. If nullptr means the default handler will be used. virtual SLANG_NO_THROW IArtifactHandler* SLANG_MCALL getHandler() = 0; - /// Set the handler associated with this artifact. Setting nullptr will use the default handler. + /// Set the handler associated with this artifact. Setting nullptr will use the default handler. virtual SLANG_NO_THROW void SLANG_MCALL setHandler(IArtifactHandler* handler) = 0; - /// Returns the result of expansion. Will return SLANG_E_UNINITIALIZED if expansion hasn't happened + /// Returns the result of expansion. Will return SLANG_E_UNINITIALIZED if expansion hasn't + /// happened virtual SLANG_NO_THROW SlangResult SLANG_MCALL getExpandChildrenResult() = 0; - /// Sets all of the children, will set the expansion state to SLANG_OK - virtual SLANG_NO_THROW void SLANG_MCALL setChildren(IArtifact*const* children, Count count) = 0; - /// Will be called implicitly on access to children + /// Sets all of the children, will set the expansion state to SLANG_OK + virtual SLANG_NO_THROW void SLANG_MCALL + setChildren(IArtifact* const* children, Count count) = 0; + /// Will be called implicitly on access to children virtual SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren() = 0; - /// Add the artifact to the list + /// Add the artifact to the list virtual SLANG_NO_THROW void SLANG_MCALL addChild(IArtifact* artifact) = 0; - /// Get the children, will only remain valid if no mutation of children list + /// Get the children, will only remain valid if no mutation of children list virtual SLANG_NO_THROW Slice SLANG_MCALL getChildren() = 0; - /// Find a represention from the specified list - virtual SLANG_NO_THROW void* SLANG_MCALL findRepresentation(ContainedKind kind, const Guid& guid) = 0; - /// Clear all of the contained kind + /// Find a represention from the specified list + virtual SLANG_NO_THROW void* SLANG_MCALL + findRepresentation(ContainedKind kind, const Guid& guid) = 0; + /// Clear all of the contained kind virtual SLANG_NO_THROW void SLANG_MCALL clear(ContainedKind kind) = 0; - /// Remove entry at index for the specified kind + /// Remove entry at index for the specified kind virtual SLANG_NO_THROW void SLANG_MCALL removeAt(ContainedKind kind, Index i) = 0; }; -template +template SLANG_FORCE_INLINE T* findRepresentation(IArtifact* artifact) { - return reinterpret_cast(artifact->findRepresentation(IArtifact::ContainedKind::Representation, T::getTypeGuid())); + return reinterpret_cast( + artifact->findRepresentation(IArtifact::ContainedKind::Representation, T::getTypeGuid())); } -template +template SLANG_FORCE_INLINE T* findAssociatedRepresentation(IArtifact* artifact) { - return reinterpret_cast(artifact->findRepresentation(IArtifact::ContainedKind::Associated, T::getTypeGuid())); + return reinterpret_cast( + artifact->findRepresentation(IArtifact::ContainedKind::Associated, T::getTypeGuid())); } -template +template SLANG_FORCE_INLINE T* findChildRepresentation(IArtifact* artifact) { - return reinterpret_cast(artifact->findRepresentation(IArtifact::ContainedKind::Children, T::getTypeGuid())); + return reinterpret_cast( + artifact->findRepresentation(IArtifact::ContainedKind::Children, T::getTypeGuid())); } -/* The IArtifactRepresentation interface represents a single representation that can be part of an artifact. It's special in so far -as +/* The IArtifactRepresentation interface represents a single representation that can be part of an +artifact. It's special in so far as * IArtifactRepresentation can be queried for it's underlying object class * Can determine if the representation exists (for example if it's on the file system) @@ -464,26 +533,35 @@ as */ class IArtifactRepresentation : public ICastable { - SLANG_COM_INTERFACE(0xa3790eb, 0x22b9, 0x430e, { 0xbf, 0xc6, 0x24, 0x6c, 0x5b, 0x5c, 0xcd, 0x0 }) + SLANG_COM_INTERFACE(0xa3790eb, 0x22b9, 0x430e, {0xbf, 0xc6, 0x24, 0x6c, 0x5b, 0x5c, 0xcd, 0x0}) - /// Create a representation of the specified typeGuid interface. - /// Calling castAs on the castable will return the specific type - /// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement - virtual SLANG_NO_THROW SlangResult SLANG_MCALL createRepresentation(const Guid& typeGuid, ICastable** outCastable) = 0; + /// Create a representation of the specified typeGuid interface. + /// Calling castAs on the castable will return the specific type + /// Returns SLANG_E_NOT_IMPLEMENTED if an implementation doesn't implement + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + createRepresentation(const Guid& typeGuid, ICastable** outCastable) = 0; - /// Returns true if this representation exists and is available for use. + /// Returns true if this representation exists and is available for use. virtual SLANG_NO_THROW bool SLANG_MCALL exists() = 0; }; /* Handler provides functionality external to the artifact */ class IArtifactHandler : public ICastable { - SLANG_COM_INTERFACE(0x6a646f57, 0xb3ac, 0x4c6a, { 0xb6, 0xf1, 0x33, 0xb6, 0xef, 0x60, 0xa6, 0xae }); + SLANG_COM_INTERFACE( + 0x6a646f57, + 0xb3ac, + 0x4c6a, + {0xb6, 0xf1, 0x33, 0xb6, 0xef, 0x60, 0xa6, 0xae}); - /// Given an artifact expands children + /// Given an artifact expands children virtual SLANG_NO_THROW SlangResult SLANG_MCALL expandChildren(IArtifact* container) = 0; - /// Given an artifact gets or creates a representation. - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation(IArtifact* artifact, const Guid& guid, ArtifactKeep keep, ICastable** outCastable) = 0; + /// Given an artifact gets or creates a representation. + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getOrCreateRepresentation( + IArtifact* artifact, + const Guid& guid, + ArtifactKeep keep, + ICastable** outCastable) = 0; }; } // namespace Slang diff --git a/source/compiler-core/slang-command-line-args.cpp b/source/compiler-core/slang-command-line-args.cpp index b698360302..451ea406c5 100644 --- a/source/compiler-core/slang-command-line-args.cpp +++ b/source/compiler-core/slang-command-line-args.cpp @@ -6,9 +6,10 @@ #include "../core/slang-type-text-util.h" #include "slang-core-diagnostics.h" -namespace Slang { +namespace Slang +{ -void CommandLineArgs::setArgs(const char*const* args, size_t argCount) +void CommandLineArgs::setArgs(const char* const* args, size_t argCount) { m_args.clear(); @@ -17,7 +18,7 @@ void CommandLineArgs::setArgs(const char*const* args, size_t argCount) const SourceLoc startLoc = sourceManager->getNextRangeStart(); StringBuilder buf; - + auto escapeHandler = Process::getEscapeHandler(); for (size_t i = 0; i < argCount; ++i) @@ -39,14 +40,16 @@ void CommandLineArgs::setArgs(const char*const* args, size_t argCount) buf << " "; } - SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), buf.produceString()); - SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0)); + SourceFile* sourceFile = + sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), buf.produceString()); + SourceView* sourceView = + sourceManager->createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0)); SLANG_UNUSED(sourceView); SLANG_ASSERT(sourceView->getRange().begin == startLoc); } -bool CommandLineArgs::hasArgs(const char*const* args, Index count) const +bool CommandLineArgs::hasArgs(const char* const* args, Index count) const { if (m_args.getCount() != count) { @@ -164,12 +167,16 @@ Index DownstreamArgs::addName(const String& name) if (index < 0) { index = m_entries.getCount(); - m_entries.add(Entry{name, CommandLineArgs(m_context) }); + m_entries.add(Entry{name, CommandLineArgs(m_context)}); } return index; } -Index DownstreamArgs::_findOrAddName(SourceLoc loc, const UnownedStringSlice& name, Flags flags, DiagnosticSink* sink) +Index DownstreamArgs::_findOrAddName( + SourceLoc loc, + const UnownedStringSlice& name, + Flags flags, + DiagnosticSink* sink) { if (name.getLength() <= 0) { @@ -225,7 +232,10 @@ const CommandLineArgs& DownstreamArgs::getArgsByName(const char* name) const return m_entries[index].args; } -SlangResult DownstreamArgs::stripDownstreamArgs(CommandLineArgs& ioArgs, Flags flags, DiagnosticSink* sink) +SlangResult DownstreamArgs::stripDownstreamArgs( + CommandLineArgs& ioArgs, + Flags flags, + DiagnosticSink* sink) { CommandLineReader reader(&ioArgs, sink); @@ -237,7 +247,8 @@ SlangResult DownstreamArgs::stripDownstreamArgs(CommandLineArgs& ioArgs, Flags f { if (arg.value.endsWith("...")) { - const UnownedStringSlice name = arg.value.getUnownedSlice().subString(2, arg.value.getLength() - 5); + const UnownedStringSlice name = + arg.value.getUnownedSlice().subString(2, arg.value.getLength() - 5); const Index nameIndex = _findOrAddName(arg.loc, name, flags, sink); if (nameIndex < 0) { @@ -283,7 +294,9 @@ SlangResult DownstreamArgs::stripDownstreamArgs(CommandLineArgs& ioArgs, Flags f CommandLineArgs& args = getArgsAt(nameIndex); // Copy the values in the range - args.m_args.addRange(ioArgs.m_args.getBuffer() + startIndex + 1, index - (startIndex + 1)); + args.m_args.addRange( + ioArgs.m_args.getBuffer() + startIndex + 1, + index - (startIndex + 1)); // If we aren't at the end, we must be pointing to -X., so skip that index += Index(index < count); diff --git a/source/compiler-core/slang-command-line-args.h b/source/compiler-core/slang-command-line-args.h index 0c11a3c464..388847f5c9 100644 --- a/source/compiler-core/slang-command-line-args.h +++ b/source/compiler-core/slang-command-line-args.h @@ -5,33 +5,34 @@ // the name of types, variables, etc. in the AST. #include "../core/slang-basic.h" - -#include "slang-source-loc.h" #include "slang-diagnostic-sink.h" +#include "slang-source-loc.h" -namespace Slang { +namespace Slang +{ struct CommandLineArg { - String value; ///< The value of the arg - SourceLoc loc; ///< The location of the arg + String value; ///< The value of the arg + SourceLoc loc; ///< The location of the arg }; -/* This type ends up being really just a container for the sourceManager that has the CommandLine specific SourceLocs. -That it would perhaps be better to just have SourceManager derive from RefObject, and then we could remove this -type. */ +/* This type ends up being really just a container for the sourceManager that has the CommandLine +specific SourceLocs. That it would perhaps be better to just have SourceManager derive from +RefObject, and then we could remove this type. */ class CommandLineContext : public RefObject { -public: - /// Get the source manager +public: + /// Get the source manager SourceManager* getSourceManager() { return &m_sourceManager; } CommandLineContext(ISlangFileSystemExt* fileSystemExt = nullptr) { m_sourceManager.initialize(nullptr, fileSystemExt); // Make range start from high value, so can be differentiated from other uses - // That this doesn't not assume exclusive use of this range - just that in normal use scenarios - // there is no confusion, and using the wrong source manager, will typically report nothing is found. + // That this doesn't not assume exclusive use of this range - just that in normal use + // scenarios there is no confusion, and using the wrong source manager, will typically + // report nothing is found. m_sourceManager.allocateSourceRange(~(~SourceLoc::RawValue(0) >> 1)); } @@ -49,26 +50,26 @@ struct CommandLineArgs const Arg* begin() const { return m_args.begin(); } const Arg* end() const { return m_args.end(); } - /// NOTE! Should NOT include the executable name - void setArgs(const char*const* args, size_t argCount); + /// NOTE! Should NOT include the executable name + void setArgs(const char* const* args, size_t argCount); - /// True if has args in same order - bool hasArgs(const char*const* args, Index count) const; + /// True if has args in same order + bool hasArgs(const char* const* args, Index count) const; - /// Add an arg + /// Add an arg void add(const Arg& arg) { m_args.add(arg); } - /// Ctor with a context - CommandLineArgs(CommandLineContext* context): - m_context(context) + /// Ctor with a context + CommandLineArgs(CommandLineContext* context) + : m_context(context) { } - /// Default Ctor + /// Default Ctor CommandLineArgs() {} - //String m_executablePath; ///< Can be optionally be set - List m_args; ///< The args - RefPtr m_context; ///< The context, which mainly has source manager + // String m_executablePath; ///< Can be optionally be set + List m_args; ///< The args + RefPtr m_context; ///< The context, which mainly has source manager String serialize(); void deserialize(String content); @@ -76,45 +77,83 @@ struct CommandLineArgs struct CommandLineReader { - /// Peek the current location - SourceLoc peekLoc() const { return m_index < m_args->getArgCount() ? (*m_args)[m_index].loc : SourceLoc(); } - /// Peek the current arg - const CommandLineArg& peekArg() const { SLANG_ASSERT(hasArg()); return (*m_args)[m_index]; } + /// Peek the current location + SourceLoc peekLoc() const + { + return m_index < m_args->getArgCount() ? (*m_args)[m_index].loc : SourceLoc(); + } + /// Peek the current arg + const CommandLineArg& peekArg() const + { + SLANG_ASSERT(hasArg()); + return (*m_args)[m_index]; + } - /// Peek the string value at that position - const String& peekValue() const { SLANG_ASSERT(hasArg()); return (*m_args)[m_index].value; } + /// Peek the string value at that position + const String& peekValue() const + { + SLANG_ASSERT(hasArg()); + return (*m_args)[m_index].value; + } - /// Get the arg and advance - CommandLineArg getArgAndAdvance() { CommandLineArg arg(peekArg()); advance(); return arg; } + /// Get the arg and advance + CommandLineArg getArgAndAdvance() + { + CommandLineArg arg(peekArg()); + advance(); + return arg; + } - const String& getValueAndAdvance() { const String& value = peekValue(); advance(); return value; } + const String& getValueAndAdvance() + { + const String& value = peekValue(); + advance(); + return value; + } - /// True if at end + /// True if at end bool atEnd() const { return m_index >= m_args->getArgCount(); } - /// True if has a current arg + /// True if has a current arg bool hasArg() const { return !atEnd(); } - /// Advance to next arg - void advance() { SLANG_ASSERT(m_index < m_args->getArgCount()); m_index++; } - /// Removes arg at current position - void removeArg() { SLANG_ASSERT(hasArg()); m_args->m_args.removeAt(m_index); } + /// Advance to next arg + void advance() + { + SLANG_ASSERT(m_index < m_args->getArgCount()); + m_index++; + } + /// Removes arg at current position + void removeArg() + { + SLANG_ASSERT(hasArg()); + m_args->m_args.removeAt(m_index); + } - /// Get the value from the arg previous to the current position. Will assert if there isn't one. - String getPreviousValue() const; + /// Get the value from the arg previous to the current position. Will assert if there isn't one. + String getPreviousValue() const; - /// If there is an arg outArg is set and advanced - /// Note, this *assumes* the previous arg is the option that initated this + /// If there is an arg outArg is set and advanced + /// Note, this *assumes* the previous arg is the option that initated this SlangResult expectArg(String& outArg); SlangResult expectArg(CommandLineArg& outArg); - /// Get the current index + /// Get the current index Index getIndex() const { return m_index; } - /// Set the current index - void setIndex(Index index) { SLANG_ASSERT(index >= 0 && index <= m_args->getArgCount()); m_index = index; } + /// Set the current index + void setIndex(Index index) + { + SLANG_ASSERT(index >= 0 && index <= m_args->getArgCount()); + m_index = index; + } - void init(CommandLineArgs* args, DiagnosticSink* sink) { m_args = args; m_sink = sink; m_index = 0; } + void init(CommandLineArgs* args, DiagnosticSink* sink) + { + m_args = args; + m_sink = sink; + m_index = 0; + } - /// Set up reader with args + /// Set up reader with args CommandLineReader(CommandLineArgs* args, DiagnosticSink* sink) { init(args, sink); } CommandLineReader() = default; @@ -136,39 +175,48 @@ struct DownstreamArgs struct Entry { - String name; ///< The name of the 'tool' that these args are associated with - CommandLineArgs args; ///< The args to be passed to the tool + String name; ///< The name of the 'tool' that these args are associated with + CommandLineArgs args; ///< The args to be passed to the tool }; - /// Add a name, returns the index + /// Add a name, returns the index Index addName(const String& name); - /// Find the index of a name. Returns < 0 if not found. - Index findName(const String& name) const { return m_entries.findFirstIndex([&](const Entry& entry) -> bool { return entry.name == name; }); } + /// Find the index of a name. Returns < 0 if not found. + Index findName(const String& name) const + { + return m_entries.findFirstIndex( + [&](const Entry& entry) -> bool { return entry.name == name; }); + } - /// Get the args at the nameIndex + /// Get the args at the nameIndex CommandLineArgs& getArgsAt(Index nameIndex) { return m_entries[nameIndex].args; } - /// Get args by name - will assert if name isn't found + /// Get args by name - will assert if name isn't found CommandLineArgs& getArgsByName(const char* name); const CommandLineArgs& getArgsByName(const char* name) const; - /// Looks for '-X' expressions, removing them from ioArgs and putting in appropriate args + /// Looks for '-X' expressions, removing them from ioArgs and putting in appropriate args SlangResult stripDownstreamArgs(CommandLineArgs& ioArgs, Flags flags, DiagnosticSink* sink); - /// Get the context used + /// Get the context used CommandLineContext* getContext() const { return m_context; } - /// Ctor + /// Ctor DownstreamArgs(CommandLineContext* context); - /// Default ctor - for convenience, should really use with context normally + /// Default ctor - for convenience, should really use with context normally DownstreamArgs() {} - List m_entries; ///< All of the entries + List m_entries; ///< All of the entries protected: - Index _findOrAddName(SourceLoc loc, const UnownedStringSlice& name, Flags flags, DiagnosticSink* sink); - - RefPtr m_context; ///< The context that is being used (primarily for loc tracking) across all entries/args + Index _findOrAddName( + SourceLoc loc, + const UnownedStringSlice& name, + Flags flags, + DiagnosticSink* sink); + + RefPtr m_context; ///< The context that is being used (primarily for loc + ///< tracking) across all entries/args }; diff --git a/source/compiler-core/slang-core-diagnostics.cpp b/source/compiler-core/slang-core-diagnostics.cpp index 7aa6c5c14d..4fbae6873e 100644 --- a/source/compiler-core/slang-core-diagnostics.cpp +++ b/source/compiler-core/slang-core-diagnostics.cpp @@ -1,18 +1,19 @@ // slang-core-diagnostics.cpp #include "slang-core-diagnostics.h" -namespace Slang { +namespace Slang +{ namespace MiscDiagnostics { -#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, #name, messageFormat }; +#define DIAGNOSTIC(id, severity, name, messageFormat) \ + const DiagnosticInfo name = {id, Severity::severity, #name, messageFormat}; #include "slang-misc-diagnostic-defs.h" #undef DIAGNOSTIC -} +} // namespace MiscDiagnostics -static const DiagnosticInfo* const kMiscDiagnostics[] = -{ -#define DIAGNOSTIC(id, severity, name, messageFormat) &MiscDiagnostics::name, +static const DiagnosticInfo* const kMiscDiagnostics[] = { +#define DIAGNOSTIC(id, severity, name, messageFormat) &MiscDiagnostics::name, #include "slang-misc-diagnostic-defs.h" #undef DIAGNOSTIC }; @@ -20,14 +21,14 @@ static const DiagnosticInfo* const kMiscDiagnostics[] = namespace LexerDiagnostics { -#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, #name, messageFormat }; +#define DIAGNOSTIC(id, severity, name, messageFormat) \ + const DiagnosticInfo name = {id, Severity::severity, #name, messageFormat}; #include "slang-lexer-diagnostic-defs.h" #undef DIAGNOSTIC -} +} // namespace LexerDiagnostics -static const DiagnosticInfo* const kLexerDiagnostics[] = -{ -#define DIAGNOSTIC(id, severity, name, messageFormat) &LexerDiagnostics::name, +static const DiagnosticInfo* const kLexerDiagnostics[] = { +#define DIAGNOSTIC(id, severity, name, messageFormat) &LexerDiagnostics::name, #include "slang-lexer-diagnostic-defs.h" #undef DIAGNOSTIC }; diff --git a/source/compiler-core/slang-core-diagnostics.h b/source/compiler-core/slang-core-diagnostics.h index fd1906fae2..815a042c0f 100644 --- a/source/compiler-core/slang-core-diagnostics.h +++ b/source/compiler-core/slang-core-diagnostics.h @@ -3,11 +3,9 @@ #include "../core/slang-basic.h" #include "../core/slang-writer.h" - -#include "slang-source-loc.h" #include "slang-diagnostic-sink.h" +#include "slang-source-loc.h" #include "slang-token.h" - #include "slang.h" namespace Slang @@ -19,14 +17,14 @@ namespace MiscDiagnostics { #define DIAGNOSTIC(id, severity, name, messageFormat) extern const DiagnosticInfo name; #include "slang-misc-diagnostic-defs.h" -} +} // namespace MiscDiagnostics namespace LexerDiagnostics { #define DIAGNOSTIC(id, severity, name, messageFormat) extern const DiagnosticInfo name; #include "slang-lexer-diagnostic-defs.h" -} +} // namespace LexerDiagnostics -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-diagnostic-sink.cpp b/source/compiler-core/slang-diagnostic-sink.cpp index 7e3c286eb2..f9a7d9c88d 100644 --- a/source/compiler-core/slang-diagnostic-sink.cpp +++ b/source/compiler-core/slang-diagnostic-sink.cpp @@ -1,16 +1,16 @@ // slang-diagnostic-sink.cpp #include "slang-diagnostic-sink.h" -#include "slang-name.h" -#include "slang-core-diagnostics.h" -#include "slang-name-convention-util.h" - -#include "../core/slang-memory-arena.h" +#include "../core/slang-char-util.h" #include "../core/slang-dictionary.h" +#include "../core/slang-memory-arena.h" #include "../core/slang-string-util.h" -#include "../core/slang-char-util.h" +#include "slang-core-diagnostics.h" +#include "slang-name-convention-util.h" +#include "slang-name.h" -namespace Slang { +namespace Slang +{ void printDiagnosticArg(StringBuilder& sb, char const* str) { @@ -75,10 +75,14 @@ SourceLoc getDiagnosticPos(Token const& token) } // Take the format string for a diagnostic message, along with its arguments, and turn it into a -static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int argCount, DiagnosticArg const* args) +static void formatDiagnosticMessage( + StringBuilder& sb, + char const* format, + int argCount, + DiagnosticArg const* args) { char const* spanBegin = format; - for(;;) + for (;;) { char const* spanEnd = spanBegin; while (int c = *spanEnd) @@ -97,7 +101,7 @@ static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int a int d = *spanEnd++; switch (d) { - // A double dollar sign `$$` is used to emit a single `$` + // A double dollar sign `$$` is used to emit a single `$` case '$': sb.append('$'); break; @@ -105,13 +109,22 @@ static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int a // A single digit means to emit the corresponding argument. // TODO: support more than 10 arguments, and add options // to control formatting, etc. - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { int index = d - '0'; if (index >= argCount) { - // TODO(tfoley): figure out what a good policy will be for "panic" situations like this + // TODO(tfoley): figure out what a good policy will be for "panic" situations + // like this SLANG_INVALID_OPERATION("too few arguments for diagnostic message"); } else @@ -131,7 +144,11 @@ static void formatDiagnosticMessage(StringBuilder& sb, char const* format, int a } } -static void formatDiagnostic(const HumaneSourceLoc& humaneLoc, Diagnostic const& diagnostic, DiagnosticSink::Flags flags, StringBuilder& outBuilder) +static void formatDiagnostic( + const HumaneSourceLoc& humaneLoc, + Diagnostic const& diagnostic, + DiagnosticSink::Flags flags, + StringBuilder& outBuilder) { if (flags & DiagnosticSink::Flag::HumaneLoc) { @@ -161,7 +178,7 @@ static void formatDiagnostic(const HumaneSourceLoc& humaneLoc, Diagnostic const& static void _replaceTabWithSpaces(const UnownedStringSlice& slice, Int tabSize, StringBuilder& out) { const char* start = slice.begin(); - const char*const end = slice.end(); + const char* const end = slice.end(); const Index startLength = out.getLength(); @@ -211,12 +228,14 @@ static void _replaceTabWithSpaces(const UnownedStringSlice& slice, Int tabSize, // Given multi-line text, and a position within the text (as a pointer into the memory of text) // extract the line that contains pos -static UnownedStringSlice _extractLineContainingPosition(const UnownedStringSlice& text, const char* pos) +static UnownedStringSlice _extractLineContainingPosition( + const UnownedStringSlice& text, + const char* pos) { SLANG_ASSERT(text.isMemoryContained(pos)); - const char*const contentStart = text.begin(); - const char*const contentEnd = text.end(); + const char* const contentStart = text.begin(); + const char* const contentEnd = text.end(); // We want to determine the start of the line, and the end of the line const char* start = pos; @@ -251,7 +270,11 @@ static void _reduceLength(Index startIndex, const UnownedStringSlice& prefix, St ioBuf = buf; } -static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sourceView, SourceLoc sourceLoc, StringBuilder& sb) +static void _sourceLocationNoteDiagnostic( + DiagnosticSink* sink, + SourceView* sourceView, + SourceLoc sourceLoc, + StringBuilder& sb) { SourceFile* sourceFile = sourceView->getSourceFile(); if (!sourceFile) @@ -262,8 +285,9 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour UnownedStringSlice content = sourceFile->getContent(); // Make sure the offset is within content. - // This is important because it's possible to have a 'SourceFile' that doesn't contain any content - // (for example when reconstructed via serialization with just line offsets, the actual source text 'content' isn't available). + // This is important because it's possible to have a 'SourceFile' that doesn't contain any + // content (for example when reconstructed via serialization with just line offsets, the actual + // source text 'content' isn't available). const int offset = sourceView->getRange().getOffset(sourceLoc); if (offset < 0 || offset >= content.getLength()) { @@ -271,7 +295,7 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour } // Work out the position of the SourceLoc in the source - const char*const pos = content.begin() + offset; + const char* const pos = content.begin() + offset; UnownedStringSlice line = _extractLineContainingPosition(content, pos); @@ -287,7 +311,7 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour // First work out the sourceLine _replaceTabWithSpaces(line, tabSize, sourceLine); - + // Now the caretLine which appears underneath the sourceLine { // Produce the text up to the caret position (at pos), taking into account tabs @@ -321,9 +345,9 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour const UnownedStringSlice spaces = UnownedStringSlice::fromLiteral(" "); SLANG_ASSERT(ellipsis.getLength() == spaces.getLength()); - // We use the caretLine length if we have a lexer, because it will have underscores such that it's end is the end of - // the item at issue. - // If we don't have the lexer, we guesstimate using 1/4 of the maximum length + // We use the caretLine length if we have a lexer, because it will have underscores such + // that it's end is the end of the item at issue. If we don't have the lexer, we + // guesstimate using 1/4 of the maximum length const Index endIndex = lexer ? caretLine.getLength() : (caretIndex + (maxLength / 4)); if (endIndex > maxLength) @@ -344,9 +368,8 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour } } - // We could have handling here for if the line is too long, that we surround the important section - // will ellipsis for example. - // For now we just output. + // We could have handling here for if the line is too long, that we surround the important + // section will ellipsis for example. For now we just output. sb << sourceLine << "\n"; sb << caretLine << "\n"; @@ -354,7 +377,10 @@ static void _sourceLocationNoteDiagnostic(DiagnosticSink* sink, SourceView* sour // Output the length of the token at `sourceLoc`. This is used by language server. static void _tokenLengthNoteDiagnostic( - DiagnosticSink* sink, SourceView* sourceView, SourceLoc sourceLoc, StringBuilder& sb) + DiagnosticSink* sink, + SourceView* sourceView, + SourceLoc sourceLoc, + StringBuilder& sb) { SourceFile* sourceFile = sourceView->getSourceFile(); if (!sourceFile) @@ -394,10 +420,7 @@ static void _tokenLengthNoteDiagnostic( } } -static void formatDiagnostic( - DiagnosticSink* sink, - Diagnostic const& diagnostic, - StringBuilder& sb) +static void formatDiagnostic(DiagnosticSink* sink, Diagnostic const& diagnostic, StringBuilder& sb) { auto sourceManager = sink->getSourceManager(); @@ -413,15 +436,19 @@ static void formatDiagnostic( humaneLoc = sourceView->getHumaneLoc(sourceLoc); } } - + formatDiagnostic(humaneLoc, diagnostic, sink->getFlags(), sb); { SourceView* currentView = sourceView; - while (currentView && currentView->getInitiatingSourceLoc().isValid() && currentView->getSourceFile()->getPathInfo().type == PathInfo::Type::TokenPaste) + while (currentView && currentView->getInitiatingSourceLoc().isValid() && + currentView->getSourceFile()->getPathInfo().type == PathInfo::Type::TokenPaste) { - SourceView* initiatingView = sourceManager ? sourceManager->findSourceView(currentView->getInitiatingSourceLoc()) : nullptr; + SourceView* initiatingView = + sourceManager + ? sourceManager->findSourceView(currentView->getInitiatingSourceLoc()) + : nullptr; if (initiatingView == nullptr) { break; @@ -441,8 +468,10 @@ static void formatDiagnostic( initiationDiagnostic.severity = diagnosticInfo.severity; // TODO(JS): - // Not 100% clear what the best sourceLoc type is most useful here - we will go with default for now - HumaneSourceLoc pasteHumaneLoc = initiatingView->getHumaneLoc(sourceView->getInitiatingSourceLoc()); + // Not 100% clear what the best sourceLoc type is most useful here - we will go + // with default for now + HumaneSourceLoc pasteHumaneLoc = + initiatingView->getHumaneLoc(sourceView->getInitiatingSourceLoc()); // Okay we should output where the token paste took place formatDiagnostic(pasteHumaneLoc, initiationDiagnostic, sink->getFlags(), sb); @@ -459,7 +488,8 @@ static void formatDiagnostic( _tokenLengthNoteDiagnostic(sink, sourceView, sourceLoc, sb); } - if (sourceView && sink->isFlagSet(DiagnosticSink::Flag::SourceLocationLine) && diagnostic.loc.isValid()) + if (sourceView && sink->isFlagSet(DiagnosticSink::Flag::SourceLocationLine) && + diagnostic.loc.isValid()) { _sourceLocationNoteDiagnostic(sink, sourceView, sourceLoc, sb); } @@ -473,9 +503,8 @@ static void formatDiagnostic( // Only output if it's actually different if (actualHumaneLoc.pathInfo.foundPath != humaneLoc.pathInfo.foundPath || - actualHumaneLoc.line != humaneLoc.line || - actualHumaneLoc.column != humaneLoc.column) - { + actualHumaneLoc.line != humaneLoc.line || actualHumaneLoc.column != humaneLoc.column) + { formatDiagnostic(actualHumaneLoc, diagnostic, sink->getFlags(), sb); } } @@ -533,7 +562,8 @@ SlangResult DiagnosticSink::getBlobIfNeeded(ISlangBlob** outBlob) { // If the client doesn't want an output blob, there is nothing to do. // - if (!outBlob) return SLANG_OK; + if (!outBlob) + return SLANG_OK; // For outputBuffer to be valid and hold diagnostics, writer must not be set SLANG_ASSERT(writer == nullptr); @@ -550,7 +580,9 @@ SlangResult DiagnosticSink::getBlobIfNeeded(ISlangBlob** outBlob) return SLANG_OK; } -bool DiagnosticSink::diagnoseImpl(DiagnosticInfo const& info, const UnownedStringSlice& formattedMessage) +bool DiagnosticSink::diagnoseImpl( + DiagnosticInfo const& info, + const UnownedStringSlice& formattedMessage) { if (info.severity >= Severity::Error) { @@ -574,7 +606,8 @@ bool DiagnosticSink::diagnoseImpl(DiagnosticInfo const& info, const UnownedStrin if (info.severity >= Severity::Fatal) { // TODO: figure out a better policy for aborting compilation - SLANG_ABORT_COMPILATION(""); + std::string message(formattedMessage.begin(), formattedMessage.end()); + SLANG_ABORT_COMPILATION(message.c_str()); } return true; } @@ -599,7 +632,11 @@ Severity DiagnosticSink::getEffectiveMessageSeverity(DiagnosticInfo const& info) return effectiveSeverity; } -bool DiagnosticSink::diagnoseImpl(SourceLoc const& pos, DiagnosticInfo info, int argCount, DiagnosticArg const* args) +bool DiagnosticSink::diagnoseImpl( + SourceLoc const& pos, + DiagnosticInfo info, + int argCount, + DiagnosticArg const* args) { // Override the severity in the 'info' structure to pass it further into formatDiagnostics info.severity = getEffectiveMessageSeverity(info); @@ -625,16 +662,12 @@ bool DiagnosticSink::diagnoseImpl(SourceLoc const& pos, DiagnosticInfo info, int return diagnoseImpl(info, messageBuilder.getUnownedSlice()); } -void DiagnosticSink::diagnoseRaw( - Severity severity, - char const* message) +void DiagnosticSink::diagnoseRaw(Severity severity, char const* message) { return diagnoseRaw(severity, UnownedStringSlice(message)); } -void DiagnosticSink::diagnoseRaw( - Severity severity, - const UnownedStringSlice& message) +void DiagnosticSink::diagnoseRaw(Severity severity, const UnownedStringSlice& message) { if (severity >= Severity::Error) { @@ -642,7 +675,7 @@ void DiagnosticSink::diagnoseRaw( } // Did the client supply a callback for us to use? - if(writer) + if (writer) { // If so, pass the error string along to them. writer->write(message.begin(), message.getLength()); @@ -666,7 +699,10 @@ void DiagnosticSink::diagnoseRaw( } } -void DiagnosticSink::overrideDiagnosticSeverity(int diagnosticId, Severity overrideSeverity, const DiagnosticInfo* info) +void DiagnosticSink::overrideDiagnosticSeverity( + int diagnosticId, + Severity overrideSeverity, + const DiagnosticInfo* info) { if (info) { @@ -684,7 +720,8 @@ void DiagnosticSink::overrideDiagnosticSeverity(int diagnosticId, Severity overr m_severityOverrides[diagnosticId] = overrideSeverity; } -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DiagnosticLookup !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DiagnosticLookup + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ Index DiagnosticsLookup::_findDiagnosticIndexByExactName(const UnownedStringSlice& slice) const { @@ -714,7 +751,8 @@ const DiagnosticInfo* DiagnosticsLookup::getDiagnosticById(Int id) const return indexPtr ? m_diagnostics[*indexPtr] : nullptr; } -const DiagnosticInfo* DiagnosticsLookup::findDiagnosticByExactName(const UnownedStringSlice& slice) const +const DiagnosticInfo* DiagnosticsLookup::findDiagnosticByExactName( + const UnownedStringSlice& slice) const { const Index* indexPtr = m_nameMap.tryGetValue(slice); return indexPtr ? m_diagnostics[*indexPtr] : nullptr; @@ -725,9 +763,12 @@ const DiagnosticInfo* DiagnosticsLookup::findDiagnosticByName(const UnownedStrin const auto convention = NameConventionUtil::inferConventionFromText(slice); switch (convention) { - case NameConvention::Invalid: return nullptr; - case NameConvention::LowerCamel: return findDiagnosticByExactName(slice); - default: break; + case NameConvention::Invalid: + return nullptr; + case NameConvention::LowerCamel: + return findDiagnosticByExactName(slice); + default: + break; } StringBuilder buf; @@ -746,11 +787,11 @@ Index DiagnosticsLookup::add(const DiagnosticInfo* info) _addName(info->name, diagnosticIndex); m_idMap.addIfNotExists(info->id, diagnosticIndex); - + return diagnosticIndex; } -void DiagnosticsLookup::add(const DiagnosticInfo*const* infos, Index infosCount) +void DiagnosticsLookup::add(const DiagnosticInfo* const* infos, Index infosCount) { for (Index i = 0; i < infosCount; ++i) { @@ -758,19 +799,21 @@ void DiagnosticsLookup::add(const DiagnosticInfo*const* infos, Index infosCount) } } -DiagnosticsLookup::DiagnosticsLookup(): - m_arena(kArenaInitialSize) +DiagnosticsLookup::DiagnosticsLookup() + : m_arena(kArenaInitialSize) { } -DiagnosticsLookup::DiagnosticsLookup(const DiagnosticInfo*const* diagnostics, Index diagnosticsCount) : - m_arena(kArenaInitialSize) +DiagnosticsLookup::DiagnosticsLookup( + const DiagnosticInfo* const* diagnostics, + Index diagnosticsCount) + : m_arena(kArenaInitialSize) { // TODO: We should eventually have a more formal system for associating individual // diagnostics, or groups of diagnostics, with user-exposed names for use when // enabling/disabling warnings (or turning warnings into errors, etc.). // - // For now we build a map from diagnostic name to it's entry. + // For now we build a map from diagnostic name to it's entry. add(diagnostics, diagnosticsCount); } diff --git a/source/compiler-core/slang-diagnostic-sink.h b/source/compiler-core/slang-diagnostic-sink.h index 38a31752f9..90f1bfccf1 100644 --- a/source/compiler-core/slang-diagnostic-sink.h +++ b/source/compiler-core/slang-diagnostic-sink.h @@ -2,12 +2,10 @@ #define SLANG_DIAGNOSTIC_SINK_H #include "../core/slang-basic.h" -#include "../core/slang-writer.h" #include "../core/slang-memory-arena.h" - +#include "../core/slang-writer.h" #include "slang-source-loc.h" #include "slang-token.h" - #include "slang.h" namespace Slang @@ -24,25 +22,34 @@ enum class Severity }; // Make sure that the slang.h severity constants match those defined here -static_assert(SLANG_SEVERITY_DISABLED == int(Severity::Disable), "mismatched Severity enum values"); -static_assert(SLANG_SEVERITY_NOTE == int(Severity::Note), "mismatched Severity enum values"); -static_assert(SLANG_SEVERITY_WARNING == int(Severity::Warning), "mismatched Severity enum values"); -static_assert(SLANG_SEVERITY_ERROR == int(Severity::Error), "mismatched Severity enum values"); -static_assert(SLANG_SEVERITY_FATAL == int(Severity::Fatal), "mismatched Severity enum values"); -static_assert(SLANG_SEVERITY_INTERNAL == int(Severity::Internal), "mismatched Severity enum values"); +static_assert(SLANG_SEVERITY_DISABLED == int(Severity::Disable), "mismatched Severity enum values"); +static_assert(SLANG_SEVERITY_NOTE == int(Severity::Note), "mismatched Severity enum values"); +static_assert(SLANG_SEVERITY_WARNING == int(Severity::Warning), "mismatched Severity enum values"); +static_assert(SLANG_SEVERITY_ERROR == int(Severity::Error), "mismatched Severity enum values"); +static_assert(SLANG_SEVERITY_FATAL == int(Severity::Fatal), "mismatched Severity enum values"); +static_assert( + SLANG_SEVERITY_INTERNAL == int(Severity::Internal), + "mismatched Severity enum values"); // TODO(tfoley): move this into a source file... inline const char* getSeverityName(Severity severity) { switch (severity) { - case Severity::Disable: return "ignored"; - case Severity::Note: return "note"; - case Severity::Warning: return "warning"; - case Severity::Error: return "error"; - case Severity::Fatal: return "fatal error"; - case Severity::Internal: return "internal error"; - default: return "unknown error"; + case Severity::Disable: + return "ignored"; + case Severity::Note: + return "note"; + case Severity::Warning: + return "warning"; + case Severity::Error: + return "error"; + case Severity::Fatal: + return "fatal error"; + case Severity::Internal: + return "internal error"; + default: + return "unknown error"; } } @@ -52,7 +59,7 @@ struct DiagnosticInfo { int id; Severity severity; - char const* name; ///< Unique name + char const* name; ///< Unique name char const* messageFormat; }; @@ -64,15 +71,8 @@ class Diagnostic int ErrorID; Severity severity; - Diagnostic() - { - ErrorID = -1; - } - Diagnostic( - const String & msg, - int id, - const SourceLoc & pos, - Severity severity) + Diagnostic() { ErrorID = -1; } + Diagnostic(const String& msg, int id, const SourceLoc& pos, Severity severity) : severity(severity) { Message = msg; @@ -105,14 +105,17 @@ void printDiagnosticArg(StringBuilder& sb, IRInst* irObject); class Modifier; void printDiagnosticArg(StringBuilder& sb, Modifier* modifier); - + template void printDiagnosticArg(StringBuilder& sb, RefPtr ptr) { printDiagnosticArg(sb, ptr.Ptr()); } -inline SourceLoc getDiagnosticPos(SourceLoc const& pos) { return pos; } +inline SourceLoc getDiagnosticPos(SourceLoc const& pos) +{ + return pos; +} SourceLoc getDiagnosticPos(Token const& token); @@ -136,39 +139,43 @@ struct DiagnosticArg template DiagnosticArg(T const& arg) - : data((void*)&arg) - , printFunc(&Helper::printFunc) - {} + : data((void*)&arg), printFunc(&Helper::printFunc) + { + } }; class DiagnosticSink { public: - /// Flags to control some aspects of Diagnostic sink behavior + /// Flags to control some aspects of Diagnostic sink behavior typedef uint32_t Flags; - struct Flag + struct Flag { - enum Enum: Flags + enum Enum : Flags { - VerbosePath = 0x1, ///< Will display a more verbose path (if available) - such as a canonical or absolute path - SourceLocationLine = 0x2, ///< If set will display the location line if source is available - HumaneLoc = 0x4, ///< If set will display humane locs (filename/line number) information - TreatWarningsAsErrors = 0x8, ///< If set will turn all Warning type messages (after overrides) into Error type messages - LanguageServer = 0x10, ///< If set will format message in a way that is suitable for language server + VerbosePath = 0x1, ///< Will display a more verbose path (if available) - such as a + ///< canonical or absolute path + SourceLocationLine = + 0x2, ///< If set will display the location line if source is available + HumaneLoc = 0x4, ///< If set will display humane locs (filename/line number) information + TreatWarningsAsErrors = 0x8, ///< If set will turn all Warning type messages (after + ///< overrides) into Error type messages + LanguageServer = + 0x10, ///< If set will format message in a way that is suitable for language server }; }; - /// Used by diagnostic sink to be able to underline tokens. If not defined on the DiagnosticSink, - /// will only display a caret at the SourceLoc - typedef UnownedStringSlice(*SourceLocationLexer)(const UnownedStringSlice& text); + /// Used by diagnostic sink to be able to underline tokens. If not defined on the + /// DiagnosticSink, will only display a caret at the SourceLoc + typedef UnownedStringSlice (*SourceLocationLexer)(const UnownedStringSlice& text); - /// Get the total amount of errors that have taken place on this DiagnosticSink + /// Get the total amount of errors that have taken place on this DiagnosticSink SLANG_FORCE_INLINE int getErrorCount() { return m_errorCount; } template - bool diagnose(P const& pos, DiagnosticInfo const& info, Args const&... args ) + bool diagnose(P const& pos, DiagnosticInfo const& info, Args const&... args) { - DiagnosticArg as[] = { DiagnosticArg(args)... }; + DiagnosticArg as[] = {DiagnosticArg(args)...}; return diagnoseImpl(getDiagnosticPos(pos), info, sizeof...(args), as); } @@ -179,10 +186,10 @@ class DiagnosticSink return diagnoseImpl(getDiagnosticPos(pos), info, 0, nullptr); } - // Useful for notes on existing diagnostics, where it would be redundant to display the same line again. - // (Ideally we would print the error/warning and notes in one call...) + // Useful for notes on existing diagnostics, where it would be redundant to display the same + // line again. (Ideally we would print the error/warning and notes in one call...) template - bool diagnoseWithoutSourceView(P const& pos, DiagnosticInfo const& info, Args const&... args ) + bool diagnoseWithoutSourceView(P const& pos, DiagnosticInfo const& info, Args const&... args) { const auto fs = this->getFlags(); this->resetFlag(Flag::SourceLocationLine); @@ -193,83 +200,92 @@ class DiagnosticSink return result; } - // Add a diagnostic with raw text - // (used when we get errors from a downstream compiler) + // Add a diagnostic with raw text + // (used when we get errors from a downstream compiler) void diagnoseRaw(Severity severity, char const* message); void diagnoseRaw(Severity severity, const UnownedStringSlice& message); - /// During propagation of an exception for an internal - /// error, note that this source location was involved + /// During propagation of an exception for an internal + /// error, note that this source location was involved void noteInternalErrorLoc(SourceLoc const& loc); - /// Create a blob containing diagnostics if there were any errors. - /// *note* only works if writer is not set, the blob is created from outputBuffer + /// Create a blob containing diagnostics if there were any errors. + /// *note* only works if writer is not set, the blob is created from outputBuffer SlangResult getBlobIfNeeded(ISlangBlob** outBlob); - /// Get the source manager used + /// Get the source manager used SourceManager* getSourceManager() const { return m_sourceManager; } - /// Set the source manager used for lookup of source locs + /// Set the source manager used for lookup of source locs void setSourceManager(SourceManager* inSourceManager) { m_sourceManager = inSourceManager; } - /// Set the flags - void setFlags(Flags flags) { m_flags = flags; } - /// Get the flags + /// Set the flags + void setFlags(Flags flags) { m_flags = flags; } + /// Get the flags Flags getFlags() const { return m_flags; } - /// Set a flag + /// Set a flag void setFlag(Flag::Enum flag) { m_flags |= Flags(flag); } - /// Reset a flag + /// Reset a flag void resetFlag(Flag::Enum flag) { m_flags &= ~Flags(flag); } - /// Test if flag is set + /// Test if flag is set bool isFlagSet(Flag::Enum flag) { return (m_flags & Flags(flag)) != 0; } - /// Sets an override on the severity of a specific diagnostic message (by numeric identifier) - /// info can be set to nullptr if only to override - void overrideDiagnosticSeverity(int diagnosticId, Severity overrideSeverity, const DiagnosticInfo* info = nullptr); + /// Sets an override on the severity of a specific diagnostic message (by numeric identifier) + /// info can be set to nullptr if only to override + void overrideDiagnosticSeverity( + int diagnosticId, + Severity overrideSeverity, + const DiagnosticInfo* info = nullptr); - /// Get the (optional) diagnostic sink lexer. This is used to - /// improve quality of highlighting a locations token. If not set, will just have a single - /// character caret at location + /// Get the (optional) diagnostic sink lexer. This is used to + /// improve quality of highlighting a locations token. If not set, will just have a single + /// character caret at location SourceLocationLexer getSourceLocationLexer() const { return m_sourceLocationLexer; } - /// Set the maximum length (in chars) of a source line displayed. Set to 0 for no limit + /// Set the maximum length (in chars) of a source line displayed. Set to 0 for no limit void setSourceLineMaxLength(Index length) { m_sourceLineMaxLength = length; } Index getSourceLineMaxLength() const { return m_sourceLineMaxLength; } - /// The parent sink is another sink that will receive diagnostics from this sink. + /// The parent sink is another sink that will receive diagnostics from this sink. void setParentSink(DiagnosticSink* parentSink) { m_parentSink = parentSink; } DiagnosticSink* getParentSink() const { return m_parentSink; } - /// Reset state. - /// Resets error counts. Resets the output buffer. + /// Reset state. + /// Resets error counts. Resets the output buffer. void reset(); - /// Initialize state. + /// Initialize state. void init(SourceManager* sourceManager, SourceLocationLexer sourceLocationLexer); - /// Ctor - DiagnosticSink(SourceManager* sourceManager, SourceLocationLexer sourceLocationLexer) { init(sourceManager, sourceLocationLexer); } - /// Default Ctor - DiagnosticSink(): - m_sourceManager(nullptr), - m_sourceLocationLexer(nullptr) + /// Ctor + DiagnosticSink(SourceManager* sourceManager, SourceLocationLexer sourceLocationLexer) + { + init(sourceManager, sourceLocationLexer); + } + /// Default Ctor + DiagnosticSink() + : m_sourceManager(nullptr), m_sourceLocationLexer(nullptr) { } // Public members - /// The outputBuffer will contain any diagnostics *iff* the writer is *not* set + /// The outputBuffer will contain any diagnostics *iff* the writer is *not* set StringBuilder outputBuffer; - /// If a writer is set output will *not* be written to the outputBuffer + /// If a writer is set output will *not* be written to the outputBuffer ISlangWriter* writer = nullptr; protected: // Returns true if a diagnostic is actually written. - bool diagnoseImpl(SourceLoc const& pos, DiagnosticInfo info, int argCount, DiagnosticArg const* args); + bool diagnoseImpl( + SourceLoc const& pos, + DiagnosticInfo info, + int argCount, + DiagnosticArg const* args); bool diagnoseImpl(DiagnosticInfo const& info, const UnownedStringSlice& formattedMessage); Severity getEffectiveMessageSeverity(DiagnosticInfo const& info); - /// If set all diagnostics (as formatted by *this* sink, will be routed to the parent). + /// If set all diagnostics (as formatted by *this* sink, will be routed to the parent). DiagnosticSink* m_parentSink = nullptr; int m_errorCount = 0; @@ -277,7 +293,7 @@ class DiagnosticSink /// If 0, then there is no limit, otherwise max amount of chars of the source line location /// We don't know the size of a terminal in general, but for now we'll guess 120. - Index m_sourceLineMaxLength = 120; + Index m_sourceLineMaxLength = 120; Flags m_flags = 0; @@ -285,26 +301,27 @@ class DiagnosticSink SourceManager* m_sourceManager = nullptr; SourceLocationLexer m_sourceLocationLexer; - + // Configuration that allows the user to control the severity of certain diagnostic messages Dictionary m_severityOverrides; }; - /// An `ISlangWriter` that writes directly to a diagnostic sink. +/// An `ISlangWriter` that writes directly to a diagnostic sink. class DiagnosticSinkWriter : public AppendBufferWriter { public: typedef AppendBufferWriter Super; DiagnosticSinkWriter(DiagnosticSink* sink) - : Super(WriterFlag::IsStatic) - , m_sink(sink) - {} + : Super(WriterFlag::IsStatic), m_sink(sink) + { + } // ISlangWriter - SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) SLANG_OVERRIDE + SLANG_NO_THROW virtual SlangResult SLANG_MCALL write(const char* chars, size_t numChars) + SLANG_OVERRIDE { - m_sink->diagnoseRaw(Severity::Note, UnownedStringSlice(chars, chars+numChars)); + m_sink->diagnoseRaw(Severity::Note, UnownedStringSlice(chars, chars + numChars)); return SLANG_OK; } @@ -317,36 +334,36 @@ class DiagnosticsLookup : public RefObject public: static const Index kArenaInitialSize = 65536; - /// Will take into account the slice name could be using different conventions + /// Will take into account the slice name could be using different conventions const DiagnosticInfo* findDiagnosticByName(const UnownedStringSlice& slice) const; - /// The name must be as defined in the diagnostics exactly, typically lower camel + /// The name must be as defined in the diagnostics exactly, typically lower camel const DiagnosticInfo* findDiagnosticByExactName(const UnownedStringSlice& slice) const; - /// Get a diagnostic by it's id. - /// NOTE! That it is possible for multiple diagnostics to have the same id. This will return - /// the first added + /// Get a diagnostic by it's id. + /// NOTE! That it is possible for multiple diagnostics to have the same id. This will return + /// the first added const DiagnosticInfo* getDiagnosticById(Int id) const; - /// info must stay in scope + /// info must stay in scope Index add(const DiagnosticInfo* info); - /// Infos referenced must remain in scope - void add(const DiagnosticInfo*const* infos, Index infosCount); + /// Infos referenced must remain in scope + void add(const DiagnosticInfo* const* infos, Index infosCount); - /// NOTE! Name must stay in scope as long as the diagnostics lookup. - /// If not possible add it to the arena to keep in scope. + /// NOTE! Name must stay in scope as long as the diagnostics lookup. + /// If not possible add it to the arena to keep in scope. void addAlias(const char* name, const char* diagnosticName); - /// Get the diagnostics held in this lookup + /// Get the diagnostics held in this lookup const List& getDiagnostics() const { return m_diagnostics; } - /// Get the associated arena + /// Get the associated arena MemoryArena& getArena() { return m_arena; } - /// NOTE! diagnostics must stay in scope for lifetime of lookup - DiagnosticsLookup(const DiagnosticInfo*const* diagnostics, Index diagnosticsCount); + /// NOTE! diagnostics must stay in scope for lifetime of lookup + DiagnosticsLookup(const DiagnosticInfo* const* diagnostics, Index diagnosticsCount); DiagnosticsLookup(); -protected: +protected: void _addName(const char* name, Index diagnosticIndex); Index _findDiagnosticIndexByExactName(const UnownedStringSlice& slice) const; @@ -360,6 +377,6 @@ class DiagnosticsLookup : public RefObject MemoryArena m_arena; }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-doc-extractor.cpp b/source/compiler-core/slang-doc-extractor.cpp index 9a625f3e08..f2f4775fad 100644 --- a/source/compiler-core/slang-doc-extractor.cpp +++ b/source/compiler-core/slang-doc-extractor.cpp @@ -3,23 +3,28 @@ #include "../core/slang-string-util.h" -namespace Slang { +namespace Slang +{ /* TODO(JS): -* If Decls hand SourceRange, then we could use the range to simplify getting the Post markup, as will be trivial to get to the 'end' +* If Decls hand SourceRange, then we could use the range to simplify getting the Post markup, as +will be trivial to get to the 'end' * Need to handle preceeding * in some markup styles -* If we want to be able to disable markup we need a mechanism to do this. Probably define source ranges. +* If we want to be able to disable markup we need a mechanism to do this. Probably define source +ranges. * Need a way to take the extracted markup and produce suitable markdown ** This will need to display the decoration appropriately */ -/* static */UnownedStringSlice DocMarkupExtractor::removeStart(MarkupType type, const UnownedStringSlice& comment) +/* static */ UnownedStringSlice DocMarkupExtractor::removeStart( + MarkupType type, + const UnownedStringSlice& comment) { switch (type) { - case MarkupType::BlockBefore: + case MarkupType::BlockBefore: { if (comment.startsWith(UnownedStringSlice::fromLiteral("/**")) || comment.startsWith(UnownedStringSlice::fromLiteral("/*!"))) @@ -28,10 +33,10 @@ namespace Slang { return comment.tail(3); } return comment; - } - case MarkupType::BlockAfter: + } + case MarkupType::BlockAfter: { - + if (comment.startsWith(UnownedStringSlice::fromLiteral("/**<")) || comment.startsWith(UnownedStringSlice::fromLiteral("/*!<"))) { @@ -40,7 +45,7 @@ namespace Slang { } return comment; } - case MarkupType::OrdinaryBlockBefore: + case MarkupType::OrdinaryBlockBefore: { if (comment.startsWith(UnownedStringSlice::fromLiteral("/*"))) { @@ -49,29 +54,35 @@ namespace Slang { } return comment; } - case MarkupType::LineBangBefore: + case MarkupType::LineBangBefore: { - return comment.startsWith(UnownedStringSlice::fromLiteral("//!")) ? comment.tail(3) : comment; + return comment.startsWith(UnownedStringSlice::fromLiteral("//!")) ? comment.tail(3) + : comment; } - case MarkupType::LineSlashBefore: + case MarkupType::LineSlashBefore: { - return comment.startsWith(UnownedStringSlice::fromLiteral("///")) ? comment.tail(3) : comment; + return comment.startsWith(UnownedStringSlice::fromLiteral("///")) ? comment.tail(3) + : comment; } - case MarkupType::OrdinaryLineBefore: - case MarkupType::OrdinaryLineAfter: + case MarkupType::OrdinaryLineBefore: + case MarkupType::OrdinaryLineAfter: { - return comment.startsWith(UnownedStringSlice::fromLiteral("//")) ? comment.tail(2) : comment; + return comment.startsWith(UnownedStringSlice::fromLiteral("//")) ? comment.tail(2) + : comment; } - case MarkupType::LineBangAfter: + case MarkupType::LineBangAfter: { /// //!< Can be multiple lines - return comment.startsWith(UnownedStringSlice::fromLiteral("//!<")) ? comment.tail(4) : comment; + return comment.startsWith(UnownedStringSlice::fromLiteral("//!<")) ? comment.tail(4) + : comment; } - case MarkupType::LineSlashAfter: + case MarkupType::LineSlashAfter: { - return comment.startsWith(UnownedStringSlice::fromLiteral("///<")) ? comment.tail(4) : comment; + return comment.startsWith(UnownedStringSlice::fromLiteral("///<")) ? comment.tail(4) + : comment; } - default: break; + default: + break; } return comment; } @@ -106,37 +117,47 @@ static Index _findTokenIndex(SourceLoc loc, const Token* toks, Index numToks) return -1; } -/* static */DocMarkupExtractor::MarkupFlags DocMarkupExtractor::getFlags(MarkupType type) +/* static */ DocMarkupExtractor::MarkupFlags DocMarkupExtractor::getFlags(MarkupType type) { switch (type) { - default: - case MarkupType::None: return 0; - case MarkupType::BlockBefore: return MarkupFlag::Before | MarkupFlag::IsBlock; - case MarkupType::BlockAfter: return MarkupFlag::After | MarkupFlag::IsBlock; - case MarkupType::OrdinaryBlockBefore: return MarkupFlag::Before | MarkupFlag::IsBlock; - - case MarkupType::LineBangBefore: return MarkupFlag::Before | MarkupFlag::IsMultiToken; - case MarkupType::LineSlashBefore: return MarkupFlag::Before | MarkupFlag::IsMultiToken; - case MarkupType::OrdinaryLineBefore: return MarkupFlag::Before | MarkupFlag::IsMultiToken; - - case MarkupType::LineBangAfter: return MarkupFlag::After | MarkupFlag::IsMultiToken; - case MarkupType::LineSlashAfter: return MarkupFlag::After | MarkupFlag::IsMultiToken; - case MarkupType::OrdinaryLineAfter: return MarkupFlag::After | MarkupFlag::IsMultiToken; - + default: + case MarkupType::None: + return 0; + case MarkupType::BlockBefore: + return MarkupFlag::Before | MarkupFlag::IsBlock; + case MarkupType::BlockAfter: + return MarkupFlag::After | MarkupFlag::IsBlock; + case MarkupType::OrdinaryBlockBefore: + return MarkupFlag::Before | MarkupFlag::IsBlock; + + case MarkupType::LineBangBefore: + return MarkupFlag::Before | MarkupFlag::IsMultiToken; + case MarkupType::LineSlashBefore: + return MarkupFlag::Before | MarkupFlag::IsMultiToken; + case MarkupType::OrdinaryLineBefore: + return MarkupFlag::Before | MarkupFlag::IsMultiToken; + + case MarkupType::LineBangAfter: + return MarkupFlag::After | MarkupFlag::IsMultiToken; + case MarkupType::LineSlashAfter: + return MarkupFlag::After | MarkupFlag::IsMultiToken; + case MarkupType::OrdinaryLineAfter: + return MarkupFlag::After | MarkupFlag::IsMultiToken; } } -/* static */DocMarkupExtractor::MarkupType DocMarkupExtractor::findMarkupType(const Token& tok) +/* static */ DocMarkupExtractor::MarkupType DocMarkupExtractor::findMarkupType(const Token& tok) { switch (tok.type) { - case TokenType::BlockComment: + case TokenType::BlockComment: { UnownedStringSlice slice = tok.getContent(); if (slice.getLength() >= 3 && (slice[2] == '!' || slice[2] == '*')) { - return (slice.getLength() >= 4 && slice[3] == '<') ? MarkupType::BlockAfter : MarkupType::BlockBefore; + return (slice.getLength() >= 4 && slice[3] == '<') ? MarkupType::BlockAfter + : MarkupType::BlockBefore; } else { @@ -144,25 +165,29 @@ static Index _findTokenIndex(SourceLoc loc, const Token* toks, Index numToks) } break; } - case TokenType::LineComment: + case TokenType::LineComment: { UnownedStringSlice slice = tok.getContent(); if (slice.getLength() >= 3) { if (slice[2] == '!') { - return (slice.getLength() >= 4 && slice[3] == '<') ? MarkupType::LineBangAfter : MarkupType::LineBangBefore; + return (slice.getLength() >= 4 && slice[3] == '<') ? MarkupType::LineBangAfter + : MarkupType::LineBangBefore; } else if (slice[2] == '/') { - return (slice.getLength() >= 4 && slice[3] == '<') ? MarkupType::LineSlashAfter : MarkupType::LineSlashBefore; + return (slice.getLength() >= 4 && slice[3] == '<') + ? MarkupType::LineSlashAfter + : MarkupType::LineSlashBefore; } } return (tok.flags & TokenFlag::AtStartOfLine) != 0 ? MarkupType::OrdinaryLineBefore : MarkupType::OrdinaryLineAfter; break; } - default: break; + default: + break; } return MarkupType::None; } @@ -172,7 +197,8 @@ static Index _calcWhitespaceIndent(const UnownedStringSlice& line) // TODO(JS): For now we ignore tabs and just work out indentation based on spaces/assume ASCII Index indent = 0; const Index count = line.getLength(); - for (; indent < count && line[indent] == ' '; indent++); + for (; indent < count && line[indent] == ' '; indent++) + ; return indent; } @@ -182,7 +208,10 @@ static Index _calcIndent(const UnownedStringSlice& line) return line.getLength(); } -static void _appendUnindenttedLine(const UnownedStringSlice& line, Index maxIndent, StringBuilder& out) +static void _appendUnindenttedLine( + const UnownedStringSlice& line, + Index maxIndent, + StringBuilder& out) { Index indent = _calcWhitespaceIndent(line); @@ -196,19 +225,22 @@ static void _appendUnindenttedLine(const UnownedStringSlice& line, Index maxInde out.append(line.tail(indent)); } -SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const FoundMarkup& foundMarkup, StringBuilder& out) +SlangResult DocMarkupExtractor::_extractMarkup( + const FindInfo& info, + const FoundMarkup& foundMarkup, + StringBuilder& out) { SourceView* sourceView = info.sourceView; SourceFile* sourceFile = sourceView->getSourceFile(); // Here we want to produce the text that is implied by the markup tokens. // We want to removing surrounding markup, and to also keep appropriate indentation - + switch (foundMarkup.type) { - case MarkupType::BlockBefore: - case MarkupType::BlockAfter: - case MarkupType::OrdinaryBlockBefore: + case MarkupType::BlockBefore: + case MarkupType::BlockAfter: + case MarkupType::OrdinaryBlockBefore: { // We should only have a single line SLANG_ASSERT(foundMarkup.range.getCount() == 1); @@ -239,9 +271,10 @@ SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const Found { if (startLine.isMemoryContained(line.begin())) { - // For now we'll ignore tabs, and that the indent amount is, the amount of *byte* - // NOTE! This is only appropriate for ASCII without tabs. - maxIndent = _calcIndent(UnownedStringSlice(startLine.begin(), line.begin())); + // For now we'll ignore tabs, and that the indent amount is, the amount of + // *byte* NOTE! This is only appropriate for ASCII without tabs. + maxIndent = + _calcIndent(UnownedStringSlice(startLine.begin(), line.begin())); // Let's strip the start stuff line = removeStart(foundMarkup.type, line); @@ -250,7 +283,8 @@ SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const Found if (i == linesCount - 1) { - SLANG_ASSERT(line.tail(line.getLength() - 2) == UnownedStringSlice::fromLiteral("*/")); + SLANG_ASSERT( + line.tail(line.getLength() - 2) == UnownedStringSlice::fromLiteral("*/")); // Remove the */ at the end of the line line = line.head(line.getLength() - 2); } @@ -263,9 +297,10 @@ SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const Found { unindentedLine.append(line); } - + // If the first or last line are all white space, just ignore them - if ((i == linesCount - 1 || i == 0) && unindentedLine.getUnownedSlice().trim().getLength() == 0) + if ((i == linesCount - 1 || i == 0) && + unindentedLine.getUnownedSlice().trim().getLength() == 0) { continue; } @@ -276,18 +311,19 @@ SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const Found break; } - case MarkupType::OrdinaryLineBefore: - case MarkupType::OrdinaryLineAfter: - case MarkupType::LineBangBefore: - case MarkupType::LineSlashBefore: - case MarkupType::LineBangAfter: - case MarkupType::LineSlashAfter: + case MarkupType::OrdinaryLineBefore: + case MarkupType::OrdinaryLineAfter: + case MarkupType::LineBangBefore: + case MarkupType::LineSlashBefore: + case MarkupType::LineBangAfter: + case MarkupType::LineSlashAfter: { - // Holds the lines extracted, they may have some white space indenting (like the space at the start of //) + // Holds the lines extracted, they may have some white space indenting (like the space + // at the start of //) List lines; const auto& range = foundMarkup.range; - for (Index i = range.start; i < range.end; ++ i) + for (Index i = range.start; i < range.end; ++i) { const auto& tok = info.tokenList->m_tokens[i]; UnownedStringSlice line = tok.getContent(); @@ -322,7 +358,8 @@ SlangResult DocMarkupExtractor::_extractMarkup(const FindInfo& info, const Found break; } - default: return SLANG_FAIL; + default: + return SLANG_FAIL; } return SLANG_OK; @@ -344,22 +381,24 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio switch (tok.type) { - case TokenType::LBrace: - case TokenType::LBracket: - case TokenType::LParent: - case TokenType::OpLess: + case TokenType::LBrace: + case TokenType::LBracket: + case TokenType::LParent: + case TokenType::OpLess: { openCount += direction; - if (openCount < 0) return -1; + if (openCount < 0) + return -1; break; } - case TokenType::RBracket: + case TokenType::RBracket: { openCount -= direction; - if (openCount < 0) return -1; + if (openCount < 0) + return -1; break; } - case TokenType::OpGreater: + case TokenType::OpGreater: { if (location == Location::AfterGenericParam && openCount == 0) { @@ -367,11 +406,12 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } openCount -= direction; - if (openCount < 0) return -1; + if (openCount < 0) + return -1; break; } - case TokenType::RParent: + case TokenType::RParent: { if (openCount == 0 && location == Location::AfterParam) { @@ -379,10 +419,11 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } openCount -= direction; - if (openCount < 0) return -1; + if (openCount < 0) + return -1; break; } - case TokenType::RBrace: + case TokenType::RBrace: { // If we haven't hit a candidate yet before hitting } it's not going to work if (location == Location::Before || location == Location::AfterEnumCase) @@ -391,8 +432,8 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } break; } - case TokenType::BlockComment: - case TokenType::LineComment: + case TokenType::BlockComment: + case TokenType::LineComment: { if (openCount == 0) { @@ -407,7 +448,8 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio { return i; } - // If we are looking for enum cases, and the markup is after, we'll assume this is it + // If we are looking for enum cases, and the markup is after, we'll assume this + // is it if (isAfter(location) && isAfter(markupType)) { return i; @@ -415,11 +457,12 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } break; } - case TokenType::Comma: + case TokenType::Comma: { if (openCount == 0) - { - if (location == Location::AfterParam || location == Location::AfterEnumCase || location == Location::AfterGenericParam) + { + if (location == Location::AfterParam || location == Location::AfterEnumCase || + location == Location::AfterGenericParam) { return i + 1; } @@ -432,7 +475,7 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio break; } - case TokenType::Semicolon: + case TokenType::Semicolon: { // If we haven't hit a candidate yet it's not going to work if (location == Location::Before) @@ -445,14 +488,19 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } break; } - default: break; + default: + break; } } return -1; } -/* static */bool DocMarkupExtractor::_isTokenOnLineIndex(SourceView* sourceView, MarkupType type, const Token& tok, Index lineIndex) +/* static */ bool DocMarkupExtractor::_isTokenOnLineIndex( + SourceView* sourceView, + MarkupType type, + const Token& tok, + Index lineIndex) { SourceFile* sourceFile = sourceView->getSourceFile(); const int offset = sourceView->getRange().getOffset(tok.loc); @@ -462,7 +510,8 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio if (flags & MarkupFlag::IsBlock) { // Either the start or the end of the block have to be on the specified line - return sourceFile->isOffsetOnLine(offset, lineIndex) || sourceFile->isOffsetOnLine(offset + tok.charsCount, lineIndex); + return sourceFile->isOffsetOnLine(offset, lineIndex) || + sourceFile->isOffsetOnLine(offset + tok.charsCount, lineIndex); } else { @@ -471,12 +520,15 @@ Index DocMarkupExtractor::_findStartIndex(const FindInfo& info, Location locatio } } -SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Location location, FoundMarkup& out) +SlangResult DocMarkupExtractor::_findMarkup( + const FindInfo& info, + Location location, + FoundMarkup& out) { out.reset(); const auto& toks = info.tokenList->m_tokens; - + // The starting token index Index startIndex = _findStartIndex(info, location); if (startIndex <= 0) @@ -490,7 +542,7 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Location locat // Let's lookup the line index where this occurred const int startOffset = sourceView->getRange().getOffset(toks[startIndex].loc); - // The line index that the markoff starts from + // The line index that the markoff starts from Index lineIndex = sourceFile->calcLineIndexFromOffset(startOffset); if (lineIndex < 0) { @@ -498,12 +550,13 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Location locat } const Index searchDirection = isBefore(location) ? -1 : 1; - + // Get the type and flags const MarkupType type = findMarkupType(toks[startIndex]); const MarkupFlags flags = getFlags(type); - const MarkupFlag::Enum requiredFlag = isBefore(location) ? MarkupFlag::Before : MarkupFlag::After; + const MarkupFlag::Enum requiredFlag = + isBefore(location) ? MarkupFlag::Before : MarkupFlag::After; if ((flags & requiredFlag) == 0) { return SLANG_E_NOT_FOUND; @@ -567,14 +620,19 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, Location locat // Okay we've found the markup out.type = type; out.location = location; - out.range = IndexRange{ startIndex, endIndex }; + out.range = IndexRange{startIndex, endIndex}; SLANG_ASSERT(out.range.getCount() > 0); return SLANG_OK; } -SlangResult DocMarkupExtractor::_findFirstMarkup(const FindInfo& info, const Location* locs, Index locCount, FoundMarkup& out, Index& outIndex) +SlangResult DocMarkupExtractor::_findFirstMarkup( + const FindInfo& info, + const Location* locs, + Index locCount, + FoundMarkup& out, + Index& outIndex) { Index i = 0; for (; i < locCount; ++i) @@ -589,7 +647,11 @@ SlangResult DocMarkupExtractor::_findFirstMarkup(const FindInfo& info, const Loc return SLANG_E_NOT_FOUND; } -SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, const Location* locs, Index locCount, FoundMarkup& out) +SlangResult DocMarkupExtractor::_findMarkup( + const FindInfo& info, + const Location* locs, + Index locCount, + FoundMarkup& out) { Index foundIndex; SLANG_RETURN_ON_FAIL(_findFirstMarkup(info, locs, locCount, out, foundIndex)); @@ -611,53 +673,59 @@ SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, const Location } -SlangResult DocMarkupExtractor::_findMarkup(const FindInfo& info, SearchStyle searchStyle, FoundMarkup& out) +SlangResult DocMarkupExtractor::_findMarkup( + const FindInfo& info, + SearchStyle searchStyle, + FoundMarkup& out) { switch (searchStyle) { - default: - case SearchStyle::None: + default: + case SearchStyle::None: { return SLANG_E_NOT_FOUND; } - case SearchStyle::EnumCase: + case SearchStyle::EnumCase: { - Location locs[] = { Location::Before, Location::AfterEnumCase }; + Location locs[] = {Location::Before, Location::AfterEnumCase}; return _findMarkup(info, locs, SLANG_COUNT_OF(locs), out); } - case SearchStyle::Param: + case SearchStyle::Param: { - Location locs[] = { Location::Before, Location::AfterParam }; + Location locs[] = {Location::Before, Location::AfterParam}; return _findMarkup(info, locs, SLANG_COUNT_OF(locs), out); } - case SearchStyle::Before: + case SearchStyle::Before: { return _findMarkup(info, Location::Before, out); } - case SearchStyle::Function: + case SearchStyle::Function: { return _findMarkup(info, Location::Before, out); } - case SearchStyle::Attribute: + case SearchStyle::Attribute: { FindInfo newInfo = info; newInfo.tokenIndex -= 2; return _findMarkup(newInfo, Location::Before, out); } - case SearchStyle::Variable: + case SearchStyle::Variable: { - Location locs[] = { Location::Before, Location::AfterSemicolon }; + Location locs[] = {Location::Before, Location::AfterSemicolon}; return _findMarkup(info, locs, SLANG_COUNT_OF(locs), out); } - case SearchStyle::GenericParam: + case SearchStyle::GenericParam: { - Location locs[] = { Location::Before, Location::AfterGenericParam }; + Location locs[] = {Location::Before, Location::AfterGenericParam}; return _findMarkup(info, locs, SLANG_COUNT_OF(locs), out); } } } -static void _calcLineVisibility(SourceView* sourceView, const TokenList& toks, List& outLineVisibility) +static void _calcLineVisibility( + SourceView* sourceView, + const TokenList& toks, + List& outLineVisibility) { SourceFile* sourceFile = sourceView->getSourceFile(); const auto& lineOffsets = sourceFile->getLineBreakOffsets(); @@ -713,21 +781,27 @@ static void _calcLineVisibility(SourceView* sourceView, const TokenList& toks, L } // Fill in the remaining - for (Index i = lastLine; i < outLineVisibility.getCount(); ++ i) + for (Index i = lastLine; i < outLineVisibility.getCount(); ++i) { outLineVisibility[i] = lastVisibility; } } -SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inputCount, SourceManager* sourceManager, DiagnosticSink* sink, List& outViews, List& out) +SlangResult DocMarkupExtractor::extract( + const SearchItemInput* inputs, + Index inputCount, + SourceManager* sourceManager, + DiagnosticSink* sink, + List& outViews, + List& out) { struct Entry { - Index viewIndex; ///< The view/file index this loc is found in - SourceLoc::RawValue locOrOffset; ///< Can be a loc or an offset into the file + Index viewIndex; ///< The view/file index this loc is found in + SourceLoc::RawValue locOrOffset; ///< Can be a loc or an offset into the file - SearchStyle searchStyle; ///< The search style when looking for an item - Index inputIndex; ///< The index to this item in the input + SearchStyle searchStyle; ///< The search style when looking for an item + Index inputIndex; ///< The index to this item in the input }; List entries; @@ -739,14 +813,15 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp const auto& input = inputs[i]; Entry& entry = entries[i]; entry.inputIndex = i; - entry.viewIndex = -1; //< We don't know what file/view it's in + entry.viewIndex = -1; //< We don't know what file/view it's in entry.locOrOffset = input.sourceLoc.getRaw(); entry.searchStyle = input.searchStyle; } } // Sort them into loc order - entries.sort([](const Entry& a, const Entry& b) -> bool { return a.locOrOffset < b.locOrOffset; }); + entries.sort( + [](const Entry& a, const Entry& b) -> bool { return a.locOrOffset < b.locOrOffset; }); { SourceView* sourceView = nullptr; @@ -774,8 +849,10 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp // We want only one view per SourceFile SourceFile* sourceFile = sourceView->getSourceFile(); - // NOTE! The view found might be different than sourceView. - viewIndex = outViews.findFirstIndex([&](SourceView* currentView) -> bool { return currentView->getSourceFile() == sourceFile; }); + // NOTE! The view found might be different than sourceView. + viewIndex = outViews.findFirstIndex( + [&](SourceView* currentView) -> bool + { return currentView->getSourceFile() == sourceFile; }); if (viewIndex < 0) { @@ -789,12 +866,17 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp // Set the file index entry.viewIndex = viewIndex; - // Set as the offset within the file + // Set as the offset within the file entry.locOrOffset = sourceView->getRange().getOffset(loc); } // Sort into view/file and then offset order - entries.sort([](const Entry& a, const Entry& b) -> bool { return (a.viewIndex < b.viewIndex) || ((a.viewIndex == b.viewIndex) && a.locOrOffset < b.locOrOffset); }); + entries.sort( + [](const Entry& a, const Entry& b) -> bool + { + return (a.viewIndex < b.viewIndex) || + ((a.viewIndex == b.viewIndex) && a.locOrOffset < b.locOrOffset); + }); } { @@ -854,7 +936,8 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp // Get the offset within the source file const uint32_t offset = entry.locOrOffset; - // We need to get the loc in the source views space, so we look up appropriately in the list of tokens (which uses the views loc range) + // We need to get the loc in the source views space, so we look up appropriately in the + // list of tokens (which uses the views loc range) const SourceLoc loc = sourceView->getRange().getSourceLocFromOffset(offset); // Work out the line number @@ -864,7 +947,8 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp dst.visibilty = lineVisibility[lineIndex]; // Okay, lets find the token index with a binary chop - Index tokenIndex = _findTokenIndex(loc, tokens.m_tokens.getBuffer(), tokens.m_tokens.getCount()); + Index tokenIndex = + _findTokenIndex(loc, tokens.m_tokens.getBuffer(), tokens.m_tokens.getCount()); if (tokenIndex >= 0 && lineIndex >= 0) { FindInfo findInfo; @@ -885,7 +969,6 @@ SlangResult DocMarkupExtractor::extract(const SearchItemInput* inputs, Index inp // Save the extracted text in the output dst.text = buf; - } else if (res != SLANG_E_NOT_FOUND) { diff --git a/source/compiler-core/slang-doc-extractor.h b/source/compiler-core/slang-doc-extractor.h index 30346ce6fa..45575126fc 100644 --- a/source/compiler-core/slang-doc-extractor.h +++ b/source/compiler-core/slang-doc-extractor.h @@ -3,25 +3,25 @@ #define SLANG_DOC_EXTRACTOR_H #include "../core/slang-basic.h" - -#include "slang-source-loc.h" #include "slang-lexer.h" +#include "slang-source-loc.h" -namespace Slang { +namespace Slang +{ enum class MarkupVisibility : uint8_t { - Public, ///< Always available - Internal, ///< Can be available in more verbose 'internal' documentation - Hidden, ///< Not generally available + Public, ///< Always available + Internal, ///< Can be available in more verbose 'internal' documentation + Hidden, ///< Not generally available }; -/* Extracts 'markup' from comments in Slang source core. The comments are extracted and associated in declarations. The association -is held in DocMarkup type. The comment style follows the doxygen style */ +/* Extracts 'markup' from comments in Slang source core. The comments are extracted and associated +in declarations. The association is held in DocMarkup type. The comment style follows the doxygen +style */ class DocMarkupExtractor { public: - typedef uint32_t MarkupFlags; struct MarkupFlag { @@ -29,8 +29,8 @@ class DocMarkupExtractor { Before = 0x1, After = 0x2, - IsMultiToken = 0x4, ///< Can use more than one token - IsBlock = 0x8, ///< + IsMultiToken = 0x4, ///< Can use more than one token + IsBlock = 0x8, ///< }; }; @@ -39,20 +39,23 @@ class DocMarkupExtractor { None, - BlockBefore, /// /** */ or /*! */. - LineBangBefore, /// //! Can be multiple lines - LineSlashBefore, /// /// Can be multiple lines + BlockBefore, /// /** */ or /*! */. + LineBangBefore, /// //! Can be multiple lines + LineSlashBefore, /// /// Can be multiple lines OrdinaryBlockBefore, OrdinaryLineBefore, - BlockAfter, /// /*!< */ or /**< */ - LineBangAfter, /// //!< Can be multiple lines - LineSlashAfter, /// ///< Can be multiple lines + BlockAfter, /// /*!< */ or /**< */ + LineBangAfter, /// //!< Can be multiple lines + LineSlashAfter, /// ///< Can be multiple lines OrdinaryLineAfter, - }; - static bool isBefore(MarkupType type) { return Index(type) >= Index(MarkupType::BlockBefore) && Index(type) <= Index(MarkupType::OrdinaryLineBefore); } + static bool isBefore(MarkupType type) + { + return Index(type) >= Index(MarkupType::BlockBefore) && + Index(type) <= Index(MarkupType::OrdinaryLineBefore); + } static bool isAfter(MarkupType type) { return Index(type) >= Index(MarkupType::BlockAfter); } struct IndexRange @@ -65,15 +68,18 @@ class DocMarkupExtractor enum class Location { - None, ///< No defined location + None, ///< No defined location Before, - AfterParam, ///< Can have trailing , or ) - AfterSemicolon, ///< Can have a trailing ; - AfterEnumCase, ///< Can have a , or before } - AfterGenericParam, ///< Can have trailing , or > + AfterParam, ///< Can have trailing , or ) + AfterSemicolon, ///< Can have a trailing ; + AfterEnumCase, ///< Can have a , or before } + AfterGenericParam, ///< Can have trailing , or > }; - static bool isAfter(Location location) { return Index(location) >= Index(Location::AfterParam); } + static bool isAfter(Location location) + { + return Index(location) >= Index(Location::AfterParam); + } static bool isBefore(Location location) { return location == Location::Before; } struct FoundMarkup @@ -82,7 +88,7 @@ class DocMarkupExtractor { location = Location::None; type = MarkupType::None; - range = IndexRange{ 0, 0 }; + range = IndexRange{0, 0}; } Location location = Location::None; @@ -92,50 +98,54 @@ class DocMarkupExtractor enum SearchStyle { - None, ///< Cannot be searched for - EnumCase, ///< An enum case - Param, ///< A parameter in a function/method - Variable, ///< A variable-like declaration - Before, ///< Only allows before - Function, ///< Function/method - GenericParam, ///< Generic parameter - Attribute, ///< Attribute definition + None, ///< Cannot be searched for + EnumCase, ///< An enum case + Param, ///< A parameter in a function/method + Variable, ///< A variable-like declaration + Before, ///< Only allows before + Function, ///< Function/method + GenericParam, ///< Generic parameter + Attribute, ///< Attribute definition }; - /// An input search item + /// An input search item struct SearchItemInput { SourceLoc sourceLoc; - SearchStyle searchStyle; ///< The search style when looking for an item + SearchStyle searchStyle; ///< The search style when looking for an item }; - /// The items will be in source order + /// The items will be in source order struct SearchItemOutput { - Index viewIndex; ///< Index into the array of views on the output - Index inputIndex; ///< The index to this item in the input - String text; ///< The found text - MarkupVisibility visibilty; ///< Visibility of the item + Index viewIndex; ///< Index into the array of views on the output + Index inputIndex; ///< The index to this item in the input + String text; ///< The found text + MarkupVisibility visibilty; ///< Visibility of the item }; struct FindInfo { - SourceView* sourceView; ///< The source view the tokens were generated from - TokenList* tokenList; ///< The token list - Index tokenIndex; ///< The token index location (where searches start from) - Index lineIndex; ///< The line number for the decl + SourceView* sourceView; ///< The source view the tokens were generated from + TokenList* tokenList; ///< The token list + Index tokenIndex; ///< The token index location (where searches start from) + Index lineIndex; ///< The line number for the decl }; - void setSearchInOrdinaryComments(bool val) - { - m_searchInOrindaryComments = val; - } - - /// Extracts 'markup' doc information for the specified input items - /// The output is placed in out - with the items now in the source order *not* the order of the input items - /// The inputIndex on the output holds the input item index - /// The outViews holds the views specified in viewIndex in the output, which may be useful for determining where the documentation was placed in source - SlangResult extract(const SearchItemInput* inputItems, Index inputCount, SourceManager* sourceManager, DiagnosticSink* sink, List& outViews, List& out); + void setSearchInOrdinaryComments(bool val) { m_searchInOrindaryComments = val; } + + /// Extracts 'markup' doc information for the specified input items + /// The output is placed in out - with the items now in the source order *not* the order of the + /// input items The inputIndex on the output holds the input item index The outViews holds the + /// views specified in viewIndex in the output, which may be useful for determining where the + /// documentation was placed in source + SlangResult extract( + const SearchItemInput* inputItems, + Index inputCount, + SourceManager* sourceManager, + DiagnosticSink* sink, + List& outViews, + List& out); static MarkupFlags getFlags(MarkupType type); static MarkupType findMarkupType(const Token& tok); @@ -145,24 +155,42 @@ class DocMarkupExtractor /// returns SLANG_E_NOT_FOUND if not found, SLANG_OK on success else an error SlangResult _findMarkup(const FindInfo& info, Location location, FoundMarkup& out); - /// Locations are processed in order, and the first successful used. If found in another location will issue a warning. - /// returns SLANG_E_NOT_FOUND if not found, SLANG_OK on success else an error - SlangResult _findFirstMarkup(const FindInfo& info, const Location* locs, Index locCount, FoundMarkup& out, Index& outIndex); - - SlangResult _findMarkup(const FindInfo& info, const Location* locs, Index locCount, FoundMarkup& out); - - /// Given the decl, the token stream, and the decls tokenIndex, try to find some associated markup + /// Locations are processed in order, and the first successful used. If found in another + /// location will issue a warning. returns SLANG_E_NOT_FOUND if not found, SLANG_OK on success + /// else an error + SlangResult _findFirstMarkup( + const FindInfo& info, + const Location* locs, + Index locCount, + FoundMarkup& out, + Index& outIndex); + + SlangResult _findMarkup( + const FindInfo& info, + const Location* locs, + Index locCount, + FoundMarkup& out); + + /// Given the decl, the token stream, and the decls tokenIndex, try to find some associated + /// markup SlangResult _findMarkup(const FindInfo& info, SearchStyle searchStyle, FoundMarkup& out); /// Given a found markup location extracts the contents of the tokens into out - SlangResult _extractMarkup(const FindInfo& info, const FoundMarkup& foundMarkup, StringBuilder& out); + SlangResult _extractMarkup( + const FindInfo& info, + const FoundMarkup& foundMarkup, + StringBuilder& out); /// Given a location, try to find the first token index that could potentially be markup /// Will return -1 if not found Index _findStartIndex(const FindInfo& info, Location location); /// True if the tok is 'on' lineIndex. Interpretation of 'on' depends on the markup type. - static bool _isTokenOnLineIndex(SourceView* sourceView, MarkupType type, const Token& tok, Index lineIndex); + static bool _isTokenOnLineIndex( + SourceView* sourceView, + MarkupType type, + const Token& tok, + Index lineIndex); DiagnosticSink* m_sink; diff --git a/source/compiler-core/slang-downstream-compiler-set.cpp b/source/compiler-core/slang-downstream-compiler-set.cpp index ee09b994cf..151c74b3e9 100644 --- a/source/compiler-core/slang-downstream-compiler-set.cpp +++ b/source/compiler-core/slang-downstream-compiler-set.cpp @@ -19,7 +19,7 @@ Index DownstreamCompilerSet::_findIndex(const DownstreamCompilerDesc& desc) cons { const Index count = m_compilers.getCount(); for (Index i = 0; i < count; ++i) - { + { if (m_compilers[i]->getDesc() == desc) { return i; @@ -28,7 +28,8 @@ Index DownstreamCompilerSet::_findIndex(const DownstreamCompilerDesc& desc) cons return -1; } -IDownstreamCompiler* DownstreamCompilerSet::getCompiler(const DownstreamCompilerDesc& compilerDesc) const +IDownstreamCompiler* DownstreamCompilerSet::getCompiler( + const DownstreamCompilerDesc& compilerDesc) const { const Index index = _findIndex(compilerDesc); return index >= 0 ? m_compilers[index] : nullptr; @@ -37,13 +38,14 @@ IDownstreamCompiler* DownstreamCompilerSet::getCompiler(const DownstreamCompiler void DownstreamCompilerSet::getCompilers(List& outCompilers) const { outCompilers.clear(); - outCompilers.addRange((IDownstreamCompiler*const*)m_compilers.begin(), m_compilers.getCount()); + outCompilers.addRange((IDownstreamCompiler* const*)m_compilers.begin(), m_compilers.getCount()); } bool DownstreamCompilerSet::hasSharedLibrary(ISlangSharedLibrary* lib) { - const Index foundIndex = m_sharedLibraries.findFirstIndex([lib](ISlangSharedLibrary* inLib) -> bool { return lib == inLib; }); - return(foundIndex >= 0); + const Index foundIndex = m_sharedLibraries.findFirstIndex( + [lib](ISlangSharedLibrary* inLib) -> bool { return lib == inLib; }); + return (foundIndex >= 0); } void DownstreamCompilerSet::addSharedLibrary(ISlangSharedLibrary* lib) @@ -94,4 +96,4 @@ void DownstreamCompilerSet::addCompiler(IDownstreamCompiler* compiler) } } -} +} // namespace Slang diff --git a/source/compiler-core/slang-downstream-compiler-set.h b/source/compiler-core/slang-downstream-compiler-set.h index 2a3d1ac01c..042fcc9f63 100644 --- a/source/compiler-core/slang-downstream-compiler-set.h +++ b/source/compiler-core/slang-downstream-compiler-set.h @@ -11,23 +11,29 @@ class DownstreamCompilerSet : public RefObject public: typedef RefObject Super; - /// Find all the available compilers + /// Find all the available compilers void getCompilerDescs(List& outCompilerDescs) const; - /// Returns list of all compilers + /// Returns list of all compilers void getCompilers(List& outCompilers) const; - /// Get a compiler + /// Get a compiler IDownstreamCompiler* getCompiler(const DownstreamCompilerDesc& compilerDesc) const; - - /// Will replace if there is one with same desc + + /// Will replace if there is one with same desc void addCompiler(IDownstreamCompiler* compiler); - /// Get a default compiler - IDownstreamCompiler* getDefaultCompiler(SlangSourceLanguage sourceLanguage) const { return m_defaultCompilers[int(sourceLanguage)]; } - /// Set the default compiler - void setDefaultCompiler(SlangSourceLanguage sourceLanguage, IDownstreamCompiler* compiler) { m_defaultCompilers[int(sourceLanguage)] = compiler; } + /// Get a default compiler + IDownstreamCompiler* getDefaultCompiler(SlangSourceLanguage sourceLanguage) const + { + return m_defaultCompilers[int(sourceLanguage)]; + } + /// Set the default compiler + void setDefaultCompiler(SlangSourceLanguage sourceLanguage, IDownstreamCompiler* compiler) + { + m_defaultCompilers[int(sourceLanguage)] = compiler; + } - /// True if has a compiler of the specified type + /// True if has a compiler of the specified type bool hasCompiler(SlangPassThrough compilerType) const; void remove(SlangPassThrough compilerType); @@ -51,7 +57,6 @@ class DownstreamCompilerSet : public RefObject } protected: - Index _findIndex(const DownstreamCompilerDesc& desc) const; @@ -63,6 +68,6 @@ class DownstreamCompilerSet : public RefObject List> m_sharedLibraries; }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-downstream-compiler-util.cpp b/source/compiler-core/slang-downstream-compiler-util.cpp index 70063b772e..68fc241b9c 100644 --- a/source/compiler-core/slang-downstream-compiler-util.cpp +++ b/source/compiler-core/slang-downstream-compiler-util.cpp @@ -1,29 +1,28 @@ // slang-downstream-compiler.cpp #include "slang-downstream-compiler-util.h" +#include "../core/slang-blob.h" +#include "../core/slang-char-util.h" #include "../core/slang-common.h" -#include "slang-com-helper.h" -#include "../core/slang-string-util.h" - -#include "../core/slang-type-text-util.h" - #include "../core/slang-io.h" #include "../core/slang-shared-library.h" -#include "../core/slang-blob.h" -#include "../core/slang-char-util.h" +#include "../core/slang-string-util.h" +#include "../core/slang-type-text-util.h" +#include "slang-com-helper.h" #ifdef SLANG_VC -# include "windows/slang-win-visual-studio-util.h" +#include "windows/slang-win-visual-studio-util.h" #endif -#include "slang-visual-studio-compiler-util.h" -#include "slang-gcc-compiler-util.h" -#include "slang-nvrtc-compiler.h" -#include "slang-fxc-compiler.h" #include "slang-dxc-compiler.h" +#include "slang-fxc-compiler.h" +#include "slang-gcc-compiler-util.h" #include "slang-glslang-compiler.h" #include "slang-llvm-compiler.h" #include "slang-metal-compiler.h" +#include "slang-nvrtc-compiler.h" +#include "slang-tint-compiler.h" +#include "slang-visual-studio-compiler-util.h" namespace Slang { @@ -45,10 +44,14 @@ struct DownstreamCompilerInfos DownstreamCompilerInfos infos; - infos.infos[int(SLANG_PASS_THROUGH_CLANG)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); - infos.infos[int(SLANG_PASS_THROUGH_VISUAL_STUDIO)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); - infos.infos[int(SLANG_PASS_THROUGH_GCC)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); - infos.infos[int(SLANG_PASS_THROUGH_LLVM)] = Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_CLANG)] = + Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_VISUAL_STUDIO)] = + Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_GCC)] = + Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); + infos.infos[int(SLANG_PASS_THROUGH_LLVM)] = + Info(SourceLanguageFlag::CPP | SourceLanguageFlag::C); infos.infos[int(SLANG_PASS_THROUGH_NVRTC)] = Info(SourceLanguageFlag::CUDA); @@ -60,16 +63,20 @@ struct DownstreamCompilerInfos return infos; } -/* static */DownstreamCompilerInfos DownstreamCompilerInfos::s_infos = DownstreamCompilerInfos::_calcInfos(); +/* static */ DownstreamCompilerInfos DownstreamCompilerInfos::s_infos = + DownstreamCompilerInfos::_calcInfos(); /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerInfo !!!!!!!!!!!!!!!!!!!!!!*/ -/* static */const DownstreamCompilerInfo& DownstreamCompilerInfo::getInfo(SlangPassThrough compiler) +/* static */ const DownstreamCompilerInfo& DownstreamCompilerInfo::getInfo( + SlangPassThrough compiler) { return DownstreamCompilerInfos::s_infos.infos[int(compiler)]; } -/* static */bool DownstreamCompilerInfo::canCompile(SlangPassThrough compiler, SlangSourceLanguage sourceLanguage) +/* static */ bool DownstreamCompilerInfo::canCompile( + SlangPassThrough compiler, + SlangSourceLanguage sourceLanguage) { const auto& info = getInfo(compiler); return (info.sourceLanguageFlags & (SourceLanguageFlags(1) << int(sourceLanguage))) != 0; @@ -90,7 +97,8 @@ static DownstreamCompilerMatchVersion _calcCompiledVersion() matchVersion.type = SLANG_PASS_THROUGH_GCC; matchVersion.matchVersion.set(Index(__GNUC__), Index(__GNUC_MINOR__)); #else - // TODO(JS): Hmmm None is not quite the same as unknown. It works for now, but we might want to have a distinct enum for unknown. + // TODO(JS): Hmmm None is not quite the same as unknown. It works for now, but we might want to + // have a distinct enum for unknown. matchVersion.type = SLANG_PASS_THROUGH_NONE; #endif @@ -104,14 +112,20 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() return s_version; } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompilerDesc& desc) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findCompiler( + const DownstreamCompilerSet* set, + MatchType matchType, + const DownstreamCompilerDesc& desc) { List compilers; set->getCompilers(compilers); return findCompiler(compilers, matchType, desc); } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List& compilers, MatchType matchType, const DownstreamCompilerDesc& desc) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findCompiler( + const List& compilers, + MatchType matchType, + const DownstreamCompilerDesc& desc) { if (compilers.getCount() <= 0) { @@ -144,7 +158,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() const Int versionValue = compilerDesc.getVersionValue(); switch (matchType) { - case MatchType::MinGreaterEqual: + case MatchType::MinGreaterEqual: { auto diff = descVersionValue - versionValue; if (diff >= 0 && diff < minVersionDiff) @@ -154,7 +168,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } break; } - case MatchType::MinAbsolute: + case MatchType::MinAbsolute: { auto diff = descVersionValue - versionValue; diff = (diff >= 0) ? diff : -diff; @@ -165,7 +179,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } break; } - case MatchType::Newest: + case MatchType::Newest: { if (versionValue > maxVersionValue) { @@ -181,7 +195,9 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() return (bestIndex >= 0) ? compilers[bestIndex] : nullptr; } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List& compilers, const DownstreamCompilerDesc& desc) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findCompiler( + const List& compilers, + const DownstreamCompilerDesc& desc) { for (auto compiler : compilers) { @@ -193,15 +209,21 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() return nullptr; } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findCompiler(const List& compilers, SlangPassThrough type, const SemanticVersion& version) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findCompiler( + const List& compilers, + SlangPassThrough type, + const SemanticVersion& version) { DownstreamCompilerDesc desc; desc.type = type; - desc.version = version; + desc.version = version; return findCompiler(compilers, desc); } -/* static */void DownstreamCompilerUtil::findVersions(const List& compilers, SlangPassThrough type, List& outVersions) +/* static */ void DownstreamCompilerUtil::findVersions( + const List& compilers, + SlangPassThrough type, + List& outVersions) { for (auto compiler : compilers) { @@ -214,7 +236,9 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const List& compilers, const DownstreamCompilerMatchVersion& matchVersion) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler( + const List& compilers, + const DownstreamCompilerMatchVersion& matchVersion) { List versions; @@ -229,7 +253,10 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } // Okay lets find the best one - auto bestVersion = MatchSemanticVersion::findAnyBest(versions.getBuffer(), versions.getCount(), matchVersion.matchVersion); + auto bestVersion = MatchSemanticVersion::findAnyBest( + versions.getBuffer(), + versions.getCount(), + matchVersion.matchVersion); // If one is found use it if (bestVersion.isSet()) @@ -240,14 +267,13 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() { // TODO(JS): - // NOTE! This may not really be appropriate, because LLVM is *not* interchangable with + // NOTE! This may not really be appropriate, because LLVM is *not* interchangable with // a 'normal' C++ compiler as cannot access standard libraries/headers. // So `slang-llvm` can't be used for 'host' code. - // These compilers should be usable interchangably. The order is important, as the first one that matches will - // be used, so LLVM is used before CLANG or GCC if appropriate - const SlangPassThrough compatiblePassThroughs[] = - { + // These compilers should be usable interchangably. The order is important, as the first one + // that matches will be used, so LLVM is used before CLANG or GCC if appropriate + const SlangPassThrough compatiblePassThroughs[] = { SLANG_PASS_THROUGH_LLVM, SLANG_PASS_THROUGH_CLANG, SLANG_PASS_THROUGH_GCC, @@ -265,7 +291,8 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() if (versions.getCount() > 0) { // Get the latest version (as we have no way to really compare) - auto latestVersion = SemanticVersion::getLatest(versions.getBuffer(), versions.getCount()); + auto latestVersion = + SemanticVersion::getLatest(versions.getBuffer(), versions.getCount()); return findCompiler(compilers, matchVersion.type, latestVersion); } } @@ -275,21 +302,25 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() return nullptr; } -/* static */IDownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompilerMatchVersion& matchVersion) +/* static */ IDownstreamCompiler* DownstreamCompilerUtil::findClosestCompiler( + const DownstreamCompilerSet* set, + const DownstreamCompilerMatchVersion& matchVersion) { List compilers; set->getCompilers(compilers); return findClosestCompiler(compilers, matchVersion); } -/* static */void DownstreamCompilerUtil::updateDefault(DownstreamCompilerSet* set, SlangSourceLanguage sourceLanguage) +/* static */ void DownstreamCompilerUtil::updateDefault( + DownstreamCompilerSet* set, + SlangSourceLanguage sourceLanguage) { IDownstreamCompiler* compiler = nullptr; switch (sourceLanguage) { - case SLANG_SOURCE_LANGUAGE_CPP: - case SLANG_SOURCE_LANGUAGE_C: + case SLANG_SOURCE_LANGUAGE_CPP: + case SLANG_SOURCE_LANGUAGE_C: { // Find the compiler closest to the compiler this was compiled with if (!compiler) @@ -298,20 +329,21 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } break; } - case SLANG_SOURCE_LANGUAGE_CUDA: + case SLANG_SOURCE_LANGUAGE_CUDA: { DownstreamCompilerDesc desc; desc.type = SLANG_PASS_THROUGH_NVRTC; compiler = findCompiler(set, MatchType::Newest, desc); break; } - default: break; + default: + break; } set->setDefaultCompiler(sourceLanguage, compiler); } -/* static */void DownstreamCompilerUtil::updateDefaults(DownstreamCompilerSet* set) +/* static */ void DownstreamCompilerUtil::updateDefaults(DownstreamCompilerSet* set) { for (Index i = 0; i < Index(SLANG_SOURCE_LANGUAGE_COUNT_OF); ++i) { @@ -319,7 +351,8 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() } } -/* static */void DownstreamCompilerUtil::setDefaultLocators(DownstreamCompilerLocatorFunc outFuncs[int(SLANG_PASS_THROUGH_COUNT_OF)]) +/* static */ void DownstreamCompilerUtil::setDefaultLocators( + DownstreamCompilerLocatorFunc outFuncs[int(SLANG_PASS_THROUGH_COUNT_OF)]) { outFuncs[int(SLANG_PASS_THROUGH_VISUAL_STUDIO)] = &VisualStudioCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_CLANG)] = &GCCDownstreamCompilerUtil::locateClangCompilers; @@ -332,6 +365,7 @@ DownstreamCompilerMatchVersion DownstreamCompilerUtil::getCompiledVersion() outFuncs[int(SLANG_PASS_THROUGH_LLVM)] = &LLVMDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_SPIRV_DIS)] = &SpirvDisDownstreamCompilerUtil::locateCompilers; outFuncs[int(SLANG_PASS_THROUGH_METAL)] = &MetalDownstreamCompilerUtil::locateCompilers; + outFuncs[int(SLANG_PASS_THROUGH_TINT)] = &TintDownstreamCompilerUtil::locateCompilers; } static String _getParentPath(const String& path) @@ -348,7 +382,11 @@ static String _getParentPath(const String& path) } } -static SlangResult _findPaths(const String& path, const char* libraryName, String& outParentPath, String& outLibraryPath) +static SlangResult _findPaths( + const String& path, + const char* libraryName, + String& outParentPath, + String& outLibraryPath) { // Try to determine what the path is by looking up the path type SlangPathType pathType; @@ -370,14 +408,17 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin return SLANG_OK; } - // If this failed the path could be to a shared library, but we may need to convert to the shared library filename first + // If this failed the path could be to a shared library, but we may need to convert to the + // shared library filename first const String sharedLibraryFilePath = SharedLibrary::calcPlatformPath(path.getUnownedSlice()); - if (SLANG_SUCCEEDED(Path::getPathType(sharedLibraryFilePath, &pathType)) && pathType == SLANG_PATH_TYPE_FILE) + if (SLANG_SUCCEEDED(Path::getPathType(sharedLibraryFilePath, &pathType)) && + pathType == SLANG_PATH_TYPE_FILE) { - // We pass in the shared library path, as canonical paths can sometimes only apply to pre-existing objects. + // We pass in the shared library path, as canonical paths can sometimes only apply to + // pre-existing objects. outParentPath = _getParentPath(sharedLibraryFilePath); - // The original path should work as is for the SharedLibrary load. Notably we don't use the sharedLibraryFilePath - // as this is the wrong name to do a SharedLibrary load with. + // The original path should work as is for the SharedLibrary load. Notably we don't use the + // sharedLibraryFilePath as this is the wrong name to do a SharedLibrary load with. outLibraryPath = path; return SLANG_OK; @@ -386,7 +427,12 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin return SLANG_FAIL; } -/* static */SlangResult DownstreamCompilerUtil::loadSharedLibrary(const String& path, ISlangSharedLibraryLoader* loader, const char*const* dependentNames, const char* inLibraryName, ComPtr& outSharedLib) +/* static */ SlangResult DownstreamCompilerUtil::loadSharedLibrary( + const String& path, + ISlangSharedLibraryLoader* loader, + const char* const* dependentNames, + const char* inLibraryName, + ComPtr& outSharedLib) { String parentPath; String libraryPath; @@ -397,19 +443,21 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin if (SLANG_FAILED(_findPaths(path, inLibraryName, parentPath, libraryPath))) { // We have a few scenarios here. - // 1) The path could be the shared library/dll filename, that will be found through some operating system mechanism - // 2) That the shared library is *NOT* on the filesystem directly (the loader does something different) - // 3) Permissions or some other mechanism stops the lookup from working + // 1) The path could be the shared library/dll filename, that will be found through some + // operating system mechanism 2) That the shared library is *NOT* on the filesystem + // directly (the loader does something different) 3) Permissions or some other mechanism + // stops the lookup from working // We should probably assume that the path means something, else why set it. - // It's probably less likely that it is a directory that we can't detect - as if it's a directory as part of an app - // it's permissions should allow detection, or be made to allow it. + // It's probably less likely that it is a directory that we can't detect - as if it's a + // directory as part of an app it's permissions should allow detection, or be made to + // allow it. // All this being the case we should probably assume that it is the shared library name. libraryPath = path; - // Attempt to get a parent. If there isn't one this will be empty, which will mean it will be ignored, which is probably - // what we want if path is just a shared library name + // Attempt to get a parent. If there isn't one this will be empty, which will mean it + // will be ignored, which is probably what we want if path is just a shared library name parentPath = Path::getParentDirectory(libraryPath); } } @@ -420,7 +468,7 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin // Try to load any dependent libs from the parent path if (dependentNames) { - for (const char*const* cur = dependentNames; *cur; ++cur) + for (const char* const* cur = dependentNames; *cur; ++cur) { const char* dependentName = *cur; ComPtr lib; @@ -453,7 +501,9 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin } } -/* static */void DownstreamCompilerUtil::appendAsText(const DownstreamCompilerDesc& desc, StringBuilder& out) +/* static */ void DownstreamCompilerUtil::appendAsText( + const DownstreamCompilerDesc& desc, + StringBuilder& out) { out << TypeTextUtil::getPassThroughAsHumanText(desc.type); @@ -467,4 +517,4 @@ static SlangResult _findPaths(const String& path, const char* libraryName, Strin } } -} +} // namespace Slang diff --git a/source/compiler-core/slang-downstream-compiler-util.h b/source/compiler-core/slang-downstream-compiler-util.h index 84b8edccac..b6efb2e4f6 100644 --- a/source/compiler-core/slang-downstream-compiler-util.h +++ b/source/compiler-core/slang-downstream-compiler-util.h @@ -1,13 +1,16 @@ #ifndef SLANG_DOWNSTREAM_COMPILER_UTIL_H #define SLANG_DOWNSTREAM_COMPILER_UTIL_H -#include "slang-downstream-compiler.h" #include "slang-downstream-compiler-set.h" +#include "slang-downstream-compiler.h" namespace Slang { -typedef SlangResult (*DownstreamCompilerLocatorFunc)(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); +typedef SlangResult (*DownstreamCompilerLocatorFunc)( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); struct DownstreamCompilerInfo { @@ -33,31 +36,38 @@ struct DownstreamCompilerInfo /// True if this compiler can compile the specified language static bool canCompile(SlangPassThrough compiler, SlangSourceLanguage sourceLanguage); - DownstreamCompilerInfo() : sourceLanguageFlags(0) {} + DownstreamCompilerInfo() + : sourceLanguageFlags(0) + { + } - DownstreamCompilerInfo(SourceLanguageFlags inSourceLanguageFlags) : - sourceLanguageFlags(inSourceLanguageFlags) - {} + DownstreamCompilerInfo(SourceLanguageFlags inSourceLanguageFlags) + : sourceLanguageFlags(inSourceLanguageFlags) + { + } SourceLanguageFlags sourceLanguageFlags; }; -// Combination of a downstream compiler type (pass through) and +// Combination of a downstream compiler type (pass through) and // a match version. struct DownstreamCompilerMatchVersion { - DownstreamCompilerMatchVersion(SlangPassThrough inType, MatchSemanticVersion inMatchVersion) : - type(inType), - matchVersion(inMatchVersion) - {} + DownstreamCompilerMatchVersion(SlangPassThrough inType, MatchSemanticVersion inMatchVersion) + : type(inType), matchVersion(inMatchVersion) + { + } - DownstreamCompilerMatchVersion() :type(SLANG_PASS_THROUGH_NONE) {} + DownstreamCompilerMatchVersion() + : type(SLANG_PASS_THROUGH_NONE) + { + } - SlangPassThrough type; ///< The type of the compiler - MatchSemanticVersion matchVersion; ///< The match version + SlangPassThrough type; ///< The type of the compiler + MatchSemanticVersion matchVersion; ///< The match version }; -struct DownstreamCompilerUtil: public DownstreamCompilerUtilBase +struct DownstreamCompilerUtil : public DownstreamCompilerUtilBase { enum class MatchType { @@ -66,40 +76,66 @@ struct DownstreamCompilerUtil: public DownstreamCompilerUtilBase Newest, }; - /// Find a compiler - static IDownstreamCompiler* findCompiler(const DownstreamCompilerSet* set, MatchType matchType, const DownstreamCompilerDesc& desc); - static IDownstreamCompiler* findCompiler(const List& compilers, MatchType matchType, const DownstreamCompilerDesc& desc); - - static IDownstreamCompiler* findCompiler(const List& compilers, SlangPassThrough type, const SemanticVersion& version); - static IDownstreamCompiler* findCompiler(const List& compilers, const DownstreamCompilerDesc& desc); - - /// Find all the compilers with the version - static void findVersions(const List& compilers, SlangPassThrough compiler, List& versions); - - - /// Find the compiler closest to the desc - static IDownstreamCompiler* findClosestCompiler(const List& compilers, const DownstreamCompilerMatchVersion& version); - static IDownstreamCompiler* findClosestCompiler(const DownstreamCompilerSet* set, const DownstreamCompilerMatchVersion& version); - - /// Get the information on the compiler used to compile this source + /// Find a compiler + static IDownstreamCompiler* findCompiler( + const DownstreamCompilerSet* set, + MatchType matchType, + const DownstreamCompilerDesc& desc); + static IDownstreamCompiler* findCompiler( + const List& compilers, + MatchType matchType, + const DownstreamCompilerDesc& desc); + + static IDownstreamCompiler* findCompiler( + const List& compilers, + SlangPassThrough type, + const SemanticVersion& version); + static IDownstreamCompiler* findCompiler( + const List& compilers, + const DownstreamCompilerDesc& desc); + + /// Find all the compilers with the version + static void findVersions( + const List& compilers, + SlangPassThrough compiler, + List& versions); + + + /// Find the compiler closest to the desc + static IDownstreamCompiler* findClosestCompiler( + const List& compilers, + const DownstreamCompilerMatchVersion& version); + static IDownstreamCompiler* findClosestCompiler( + const DownstreamCompilerSet* set, + const DownstreamCompilerMatchVersion& version); + + /// Get the information on the compiler used to compile this source static DownstreamCompilerMatchVersion getCompiledVersion(); static void updateDefault(DownstreamCompilerSet* set, SlangSourceLanguage sourceLanguage); static void updateDefaults(DownstreamCompilerSet* set); - static void setDefaultLocators(DownstreamCompilerLocatorFunc outFuncs[int(SLANG_PASS_THROUGH_COUNT_OF)]); - - /// Attempts to determine what 'path' is and load appropriately. Is it a path to a shared library? Is it a directory holding the libraries? - /// Some downstream shared libraries need other shared libraries to be loaded before the main shared library, such that they are in the same directory - /// otherwise the shared library could come from some unwanted location. - /// dependentNames names shared libraries which should be attempted to be loaded in the path of the main shared library. - /// The list is optional (nullptr can be passed in), and the list is terminated by nullptr. - static SlangResult loadSharedLibrary(const String& path, ISlangSharedLibraryLoader* loader, const char*const* dependantNames, const char* libraryName, ComPtr& outSharedLib); - - /// Append the desc as text + static void setDefaultLocators( + DownstreamCompilerLocatorFunc outFuncs[int(SLANG_PASS_THROUGH_COUNT_OF)]); + + /// Attempts to determine what 'path' is and load appropriately. Is it a path to a shared + /// library? Is it a directory holding the libraries? Some downstream shared libraries need + /// other shared libraries to be loaded before the main shared library, such that they are in + /// the same directory otherwise the shared library could come from some unwanted location. + /// dependentNames names shared libraries which should be attempted to be loaded in the path of + /// the main shared library. The list is optional (nullptr can be passed in), and the list is + /// terminated by nullptr. + static SlangResult loadSharedLibrary( + const String& path, + ISlangSharedLibraryLoader* loader, + const char* const* dependantNames, + const char* libraryName, + ComPtr& outSharedLib); + + /// Append the desc as text static void appendAsText(const DownstreamCompilerDesc& desc, StringBuilder& out); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-downstream-compiler.cpp b/source/compiler-core/slang-downstream-compiler.cpp index 8553191768..190400f55a 100644 --- a/source/compiler-core/slang-downstream-compiler.cpp +++ b/source/compiler-core/slang-downstream-compiler.cpp @@ -1,37 +1,36 @@ // slang-downstream-compiler.cpp #include "slang-downstream-compiler.h" +#include "../core/slang-blob.h" +#include "../core/slang-castable.h" +#include "../core/slang-char-util.h" #include "../core/slang-common.h" -#include "slang-com-helper.h" -#include "../core/slang-string-util.h" - -#include "../core/slang-type-text-util.h" - #include "../core/slang-io.h" #include "../core/slang-shared-library.h" -#include "../core/slang-blob.h" -#include "../core/slang-char-util.h" - -#include "../core/slang-castable.h" - +#include "../core/slang-string-util.h" +#include "../core/slang-type-text-util.h" +#include "slang-artifact-associated-impl.h" +#include "slang-artifact-desc-util.h" +#include "slang-artifact-helper.h" #include "slang-artifact-impl.h" #include "slang-artifact-representation-impl.h" -#include "slang-artifact-associated-impl.h" #include "slang-artifact-util.h" -#include "slang-artifact-helper.h" -#include "slang-artifact-desc-util.h" +#include "slang-com-helper.h" namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! DownstreamCompilerBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ -SlangResult DownstreamCompilerBase::convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) +SlangResult DownstreamCompilerBase::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) { SLANG_UNUSED(from); SLANG_UNUSED(to); SLANG_UNUSED(outArtifact); - + return SLANG_E_NOT_AVAILABLE; } @@ -46,8 +45,7 @@ void* DownstreamCompilerBase::castAs(const Guid& guid) void* DownstreamCompilerBase::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IDownstreamCompiler::getTypeGuid()) { return static_cast(this); @@ -64,7 +62,9 @@ void* DownstreamCompilerBase::getObject(const Guid& guid) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CommandLineDownstreamCompiler !!!!!!!!!!!!!!!!!!!!!!*/ -SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact** outArtifact) +SlangResult CommandLineDownstreamCompiler::compile( + const CompileOptions& inOptions, + IArtifact** outArtifact) { if (!isVersionCompatible(inOptions)) { @@ -77,11 +77,11 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio // Copy the command line options CommandLine cmdLine(m_cmdLine); - // Work out the ArtifactDesc + // Work out the ArtifactDesc const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); auto helper = DefaultArtifactHelper::getSingleton(); - + List> artifactList; // It may be necessary to produce a temporary file 'lock file'. @@ -93,11 +93,13 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio // If no module path is set we will need to generate one if (options.modulePath.count == 0) { - // We could use the path to the source, or use the source name/paths as defined on the artifact - // For now we just go with a lock file based on "slang-generated". - SLANG_RETURN_ON_FAIL(helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef())); + // We could use the path to the source, or use the source name/paths as defined on the + // artifact For now we just go with a lock file based on "slang-generated". + SLANG_RETURN_ON_FAIL( + helper->createLockFile(asCharSlice(toSlice("slang-generated")), lockFile.writeRef())); - auto lockArtifact = Artifact::create(ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); + auto lockArtifact = Artifact::create( + ArtifactDesc::make(ArtifactKind::Base, ArtifactPayload::Lock, ArtifactStyle::None)); lockArtifact->addRepresentation(lockFile); artifactList.add(lockArtifact); @@ -108,14 +110,17 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio options.modulePath = SliceUtil::asTerminatedCharSlice(modulePath); } - // Append command line args to the end of cmdLine using the target specific function for the specified options + // Append command line args to the end of cmdLine using the target specific function for the + // specified options SLANG_RETURN_ON_FAIL(calcArgs(options, cmdLine)); - // The 'productArtifact' is the main product produced from the compilation - the executable/sharedlibrary/object etc + // The 'productArtifact' is the main product produced from the compilation - the + // executable/sharedlibrary/object etc ComPtr productArtifact; { List> artifacts; - SLANG_RETURN_ON_FAIL(calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts)); + SLANG_RETURN_ON_FAIL( + calcCompileProducts(options, DownstreamProductFlag::All, lockFile, artifacts)); for (IArtifact* artifact : artifacts) { @@ -129,7 +134,7 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio artifactList.add(ComPtr(artifact)); } } - + SLANG_ASSERT(productArtifact); // Somethings gone wrong if we don't find the main artifact if (!productArtifact) @@ -155,21 +160,22 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio } #endif - // Go through the list of artifacts in the artifactList and check if they exist. - // - // This is useful because `calcCompileProducts` is conservative and may produce artifacts for products that aren't actually - // produced, by the compilation. + // Go through the list of artifacts in the artifactList and check if they exist. + // + // This is useful because `calcCompileProducts` is conservative and may produce artifacts for + // products that aren't actually produced, by the compilation. { - + Count count = artifactList.getCount(); for (Index i = 0; i < count; ++i) { IArtifact* artifact = artifactList[i]; - + if (!artifact->exists()) { // We should find a file rep and if we do we can disown it. Disowning will mean - // when scope is lost the rep won't try and delete the (apparently non existing) backing file. + // when scope is lost the rep won't try and delete the (apparently non existing) + // backing file. if (auto fileRep = findRepresentation(artifact)) { fileRep->disown(); @@ -189,7 +195,8 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio } } - // Add all of the source artifacts, that are temporary on the file system, such that they can stay in scope for debugging + // Add all of the source artifacts, that are temporary on the file system, such that they can + // stay in scope for debugging for (auto sourceArtifact : options.sourceArtifacts) { if (auto fileRep = findRepresentation(sourceArtifact)) @@ -205,16 +212,18 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio // Create the result artifact auto artifact = ArtifactUtil::createArtifact(targetDesc); - // Createa the diagnostics + // Createa the diagnostics auto diagnostics = ArtifactDiagnostics::create(); SLANG_RETURN_ON_FAIL(parseOutput(exeRes, diagnostics)); ArtifactUtil::addAssociated(artifact, diagnostics); - // Find the rep from the 'main' artifact, we'll just use the same representation on the output + // Find the rep from the 'main' artifact, we'll just use the same representation on the output // artifact. Sharing is desirable, because the rep owns the file. - if (auto fileRep = productArtifact ? findRepresentation(productArtifact) : nullptr) + if (auto fileRep = productArtifact + ? findRepresentation(productArtifact) + : nullptr) { artifact->addRepresentation(fileRep); } @@ -222,13 +231,17 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio // Add the artifact list if there is anything in it if (artifactList.getCount()) { - // Holds all of the artifacts that are relatated to the final artifact - such as debug files, ancillary file and lock files - auto artifactContainer = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactKind::Container, ArtifactPayload::Unknown, ArtifactStyle::Unknown)); + // Holds all of the artifacts that are relatated to the final artifact - such as debug + // files, ancillary file and lock files + auto artifactContainer = ArtifactUtil::createArtifact(ArtifactDesc::make( + ArtifactKind::Container, + ArtifactPayload::Unknown, + ArtifactStyle::Unknown)); auto slice = SliceUtil::asSlice(artifactList); artifactContainer->setChildren(slice.data, slice.count); - + artifact->addAssociated(artifactContainer); } @@ -236,4 +249,4 @@ SlangResult CommandLineDownstreamCompiler::compile(const CompileOptions& inOptio return SLANG_OK; } -} +} // namespace Slang diff --git a/source/compiler-core/slang-downstream-compiler.h b/source/compiler-core/slang-downstream-compiler.h index 95793eaa35..c0cc868d10 100644 --- a/source/compiler-core/slang-downstream-compiler.h +++ b/source/compiler-core/slang-downstream-compiler.h @@ -2,19 +2,14 @@ #define SLANG_DOWNSTREAM_COMPILER_H #include "../core/slang-common.h" -#include "../core/slang-string.h" - -#include "../core/slang-process-util.h" - +#include "../core/slang-io.h" #include "../core/slang-platform.h" +#include "../core/slang-process-util.h" #include "../core/slang-semantic-version.h" - -#include "../core/slang-io.h" - -#include "slang-com-ptr.h" - -#include "slang-artifact.h" +#include "../core/slang-string.h" #include "slang-artifact-associated.h" +#include "slang-artifact.h" +#include "slang-com-ptr.h" #include @@ -29,43 +24,58 @@ struct DownstreamCompilerDesc typedef DownstreamCompilerDesc ThisType; HashCode getHashCode() const { return combineHash(HashCode(type), version.getHashCode()); } - bool operator==(const ThisType& rhs) const { return type == rhs.type && version == rhs.version; } + bool operator==(const ThisType& rhs) const + { + return type == rhs.type && version == rhs.version; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Get the version as a value + /// Get the version as a value Int getVersionValue() const { return version.m_major * 100 + version.m_minor; } - /// true if has a version set + /// true if has a version set bool hasVersion() const { return version.isSet(); } /// Ctor - explicit DownstreamCompilerDesc(SlangPassThrough inType = SLANG_PASS_THROUGH_NONE, Int inMajorVersion = 0, Int inMinorVersion = 0) :type(inType), version(int(inMajorVersion), int(inMinorVersion)) {} - explicit DownstreamCompilerDesc(SlangPassThrough inType, const SemanticVersion& inVersion) : type(inType), version(inVersion) {} + explicit DownstreamCompilerDesc( + SlangPassThrough inType = SLANG_PASS_THROUGH_NONE, + Int inMajorVersion = 0, + Int inMinorVersion = 0) + : type(inType), version(int(inMajorVersion), int(inMinorVersion)) + { + } + explicit DownstreamCompilerDesc(SlangPassThrough inType, const SemanticVersion& inVersion) + : type(inType), version(inVersion) + { + } - SlangPassThrough type; ///< The type of the compiler - SemanticVersion version; ///< The version of the compiler + SlangPassThrough type; ///< The type of the compiler + SemanticVersion version; ///< The version of the compiler }; -/* Placed at the start of structs that are versioned. -The id uniquely identifies a compatible set of versions. +/* Placed at the start of structs that are versioned. +The id uniquely identifies a compatible set of versions. The size indicates the struct size. It should be considered as a kind of version number. The larger the number for the target the newer the *compatible* version (assuming the identifiers match). -Note that size versioning *only* works, if adding a field *doesn't* use any existing unused "pad" bytes. -This implies that any new members *must* take into account padding/alignment. Any additions that have alignment -*less* than the alignment of struct may need padding. +Note that size versioning *only* works, if adding a field *doesn't* use any existing unused "pad" +bytes. This implies that any new members *must* take into account padding/alignment. Any additions +that have alignment *less* than the alignment of struct may need padding. */ struct VersionedStruct { typedef VersionedStruct ThisType; - VersionedStruct(uint32_t inIdentifier, size_t inSize): - identifier(inIdentifier), - size(uint32_t(inSize)) - {} + VersionedStruct(uint32_t inIdentifier, size_t inSize) + : identifier(inIdentifier), size(uint32_t(inSize)) + { + } - /// True if the versions are identical - bool operator==(const ThisType& rhs) const { return identifier == rhs.identifier && size == rhs.size; } + /// True if the versions are identical + bool operator==(const ThisType& rhs) const + { + return identifier == rhs.identifier && size == rhs.size; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } VersionedStruct(const ThisType& rhs) = default; @@ -75,7 +85,7 @@ struct VersionedStruct uint32_t size; }; -template +template T getCompatibleVersion(const T* inT) { const VersionedStruct* in = &inT->version; @@ -85,7 +95,7 @@ T getCompatibleVersion(const T* inT) // Note that the struct is passed in by pointer rather than reference, because // we must ensure that it is not sliced. - + // Must match SLANG_ASSERT(T::kVersionIdentifier == in->identifier); @@ -118,13 +128,13 @@ T getCompatibleVersion(const T* inT) return t; } -template +template bool isVersionCompatible(const VersionedStruct& ver) { return ver.identifier == T::kVersionIdentifier; } -template +template bool isVersionCompatible(const T& in) { return isVersionCompatible(in.version); @@ -132,20 +142,21 @@ bool isVersionCompatible(const T& in) /* Downstream compile options -NOTE! This type is trafficed across shared library boundaries and *versioned*. +NOTE! This type is trafficed across shared library boundaries and *versioned*. In particular * The struct can only contain types that can be trivially memcpyd (checked by static_assert); -* New fields can only be added to the end of the struct -* New fields must take into account alignment/padding such that they do not share bytes in previous version sizes +* New fields can only be added to the end of the struct +* New fields must take into account alignment/padding such that they do not share bytes in previous +version sizes */ struct DownstreamCompileOptions { typedef DownstreamCompileOptions ThisType; - // A unique identifer for this particular struct kind. If the struct become incompatible + // A unique identifer for this particular struct kind. If the struct become incompatible // a new id should be used to identify a specific style. If the change is only to add members - // to the end, this should be handled via the version size at use sites. + // to the end, this should be handled via the version size at use sites. static const uint32_t kVersionIdentifier = 0x34296897; typedef uint32_t Flags; @@ -153,27 +164,31 @@ struct DownstreamCompileOptions { enum Enum : Flags { - EnableExceptionHandling = 0x01, ///< Enables exception handling support (say as optionally supported by C++) - Verbose = 0x02, ///< Give more verbose diagnostics - EnableSecurityChecks = 0x04, ///< Enable runtime security checks (such as for buffer overruns) - enabling typically decreases performance - EnableFloat16 = 0x08, ///< If set compiles with support for float16/half + EnableExceptionHandling = + 0x01, ///< Enables exception handling support (say as optionally supported by C++) + Verbose = 0x02, ///< Give more verbose diagnostics + EnableSecurityChecks = 0x04, ///< Enable runtime security checks (such as for buffer + ///< overruns) - enabling typically decreases performance + EnableFloat16 = 0x08, ///< If set compiles with support for float16/half }; }; enum class OptimizationLevel : uint8_t { - None, ///< Don't optimize at all. - Default, ///< Default optimization level: balance code quality and compilation time. - High, ///< Optimize aggressively. - Maximal, ///< Include optimizations that may take a very long time, or may involve severe space-vs-speed tradeoffs + None, ///< Don't optimize at all. + Default, ///< Default optimization level: balance code quality and compilation time. + High, ///< Optimize aggressively. + Maximal, ///< Include optimizations that may take a very long time, or may involve severe + ///< space-vs-speed tradeoffs }; enum class DebugInfoType : uint8_t { - None, ///< Don't emit debug information at all. - Minimal, ///< Emit as little debug information as possible, while still supporting stack traces. - Standard, ///< Emit whatever is the standard level of debug information for each target. - Maximal, ///< Emit as much debug information as possible for each target. + None, ///< Don't emit debug information at all. + Minimal, ///< Emit as little debug information as possible, while still supporting stack + ///< traces. + Standard, ///< Emit whatever is the standard level of debug information for each target. + Maximal, ///< Emit as much debug information as possible for each target. }; enum class FloatingPointMode : uint8_t { @@ -192,7 +207,7 @@ struct DownstreamCompileOptions struct Define { - TerminatedCharSlice nameWithSig; ///< If macro takes parameters include in brackets + TerminatedCharSlice nameWithSig; ///< If macro takes parameters include in brackets TerminatedCharSlice value; }; @@ -200,7 +215,7 @@ struct DownstreamCompileOptions { enum class Kind : uint8_t { - CUDASM, ///< What the version is for + CUDASM, ///< What the version is for SPIRV, }; Kind kind; @@ -222,8 +237,9 @@ struct DownstreamCompileOptions PlatformKind platform = PlatformKind::Unknown; - /// The path/name of the output module. Should not have the extension, as that will be added for each of the target types. - /// If not set a module path will be internally generated internally on a command line based compiler + /// The path/name of the output module. Should not have the extension, as that will be added for + /// each of the target types. If not set a module path will be internally generated internally + /// on a command line based compiler TerminatedCharSlice modulePath; Slice defines; @@ -241,31 +257,32 @@ struct DownstreamCompileOptions /// For compilers/compiles that require an entry point name, else can be empty TerminatedCharSlice entryPointName; - /// Profile name to use, only required for compiles that need to compile against a a specific profiles. - /// Profile names are tied to compilers and targets. + /// Profile name to use, only required for compiles that need to compile against a a specific + /// profiles. Profile names are tied to compilers and targets. TerminatedCharSlice profileName; - /// The stage being compiled for + /// The stage being compiled for SlangStage stage = SLANG_STAGE_NONE; /// Arguments that are specific to a particular compiler implementation. Slice compilerSpecificArguments; - /// NOTE! Not all downstream compilers can use the fileSystemExt/sourceManager. This option will be ignored in those scenarios. + /// NOTE! Not all downstream compilers can use the fileSystemExt/sourceManager. This option will + /// be ignored in those scenarios. ISlangFileSystemExt* fileSystemExt = nullptr; SourceManager* sourceManager = nullptr; - // The debug info format to use. + // The debug info format to use. SlangDebugInfoFormat m_debugInfoFormat = SLANG_DEBUG_INFO_FORMAT_DEFAULT; }; static_assert(std::is_trivially_copyable_v); -#define SLANG_ALIAS_DEPRECATED_VERSION(name, id, firstField, lastField) \ -struct name##_AliasDeprecated##id \ -{ \ - static const ptrdiff_t kStart = SLANG_OFFSET_OF(name, firstField); \ - static const ptrdiff_t kEnd = SLANG_OFFSET_OF(name, lastField) + sizeof(name::lastField); \ -}; +#define SLANG_ALIAS_DEPRECATED_VERSION(name, id, firstField, lastField) \ + struct name##_AliasDeprecated##id \ + { \ + static const ptrdiff_t kStart = SLANG_OFFSET_OF(name, firstField); \ + static const ptrdiff_t kEnd = SLANG_OFFSET_OF(name, lastField) + sizeof(name::lastField); \ + }; /* Used to indicate what kind of products are expected to be produced for a compilation. */ typedef uint32_t DownstreamProductFlags; @@ -273,25 +290,29 @@ struct DownstreamProductFlag { enum Enum : DownstreamProductFlags { - Debug = 0x1, ///< Used by debugger during execution - Execution = 0x2, ///< Required for execution - Compile = 0x4, ///< A product *required* for compilation - Miscellaneous = 0x8, ///< Anything else + Debug = 0x1, ///< Used by debugger during execution + Execution = 0x2, ///< Required for execution + Compile = 0x4, ///< A product *required* for compilation + Miscellaneous = 0x8, ///< Anything else }; enum Mask : DownstreamProductFlags { - All = 0xf, ///< All the flags + All = 0xf, ///< All the flags }; }; class IDownstreamCompiler : public ICastable { public: - SLANG_COM_INTERFACE(0x167b8ba7, 0xbd41, 0x469a, { 0x92, 0x28, 0xb8, 0x53, 0xc8, 0xea, 0x56, 0x6d }) + SLANG_COM_INTERFACE( + 0x167b8ba7, + 0xbd41, + 0x469a, + {0x92, 0x28, 0xb8, 0x53, 0xc8, 0xea, 0x56, 0x6d}) typedef DownstreamCompilerDesc Desc; typedef DownstreamCompileOptions CompileOptions; - + typedef CompileOptions::OptimizationLevel OptimizationLevel; typedef CompileOptions::DebugInfoType DebugInfoType; typedef CompileOptions::FloatingPointMode FloatingPointMode; @@ -299,40 +320,63 @@ class IDownstreamCompiler : public ICastable typedef CompileOptions::Define Define; typedef CompileOptions::CapabilityVersion CapabilityVersion; - /// Get the desc of this compiler + /// Get the desc of this compiler virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() = 0; - /// Compile using the specified options. The result is in resOut - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) = 0; - /// Returns true if compiler can do a transformation of `from` to `to` Artifact types - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) = 0; - /// Converts an artifact `from` to a desc of `to` and puts the result in outArtifact - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) = 0; - /// Get the version of this compiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) = 0; - /// Validate and return the result - virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) = 0; - - /// True if underlying compiler uses file system to communicate source + /// Compile using the specified options. The result is in resOut + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) = 0; + /// Returns true if compiler can do a transformation of `from` to `to` Artifact types + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) = 0; + /// Converts an artifact `from` to a desc of `to` and puts the result in outArtifact + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) = 0; + /// Get the version of this compiler + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + getVersionString(slang::IBlob** outVersionString) = 0; + /// Validate and return the result + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + validate(const uint32_t* contents, int contentsSize) = 0; + + /// True if underlying compiler uses file system to communicate source virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() = 0; }; class DownstreamCompilerBase : public ComBaseObject, public IDownstreamCompiler { public: - SLANG_COM_BASE_IUNKNOWN_ALL + SLANG_COM_BASE_IUNKNOWN_ALL // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IDownstreamCompiler virtual SLANG_NO_THROW const Desc& SLANG_MCALL getDesc() SLANG_OVERRIDE { return m_desc; } - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE { SLANG_UNUSED(from); SLANG_UNUSED(to); return false; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE { *outVersionString = nullptr; return SLANG_FAIL; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE { SLANG_UNUSED(contents); SLANG_UNUSED(contentsSize); return SLANG_FAIL; } + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE + { + SLANG_UNUSED(from); + SLANG_UNUSED(to); + return false; + } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) + SLANG_OVERRIDE + { + *outVersionString = nullptr; + return SLANG_FAIL; + } + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE + { + SLANG_UNUSED(contents); + SLANG_UNUSED(contentsSize); + return SLANG_FAIL; + } - DownstreamCompilerBase(const Desc& desc): - m_desc(desc) + DownstreamCompilerBase(const Desc& desc) + : m_desc(desc) { } DownstreamCompilerBase() {} @@ -349,36 +393,47 @@ class CommandLineDownstreamCompiler : public DownstreamCompilerBase typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return true; } // Functions to be implemented for a specific CommandLine - /// Given options determines the paths to products produced (including the 'moduleFilePath'). - /// Note that does *not* guarentee all products were or should be produced. Just aims to include all that could - /// be produced, such that can be removed on completion. - virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) = 0; + /// Given options determines the paths to products produced (including the 'moduleFilePath'). + /// Note that does *not* guarentee all products were or should be produced. Just aims to include + /// all that could be produced, such that can be removed on completion. + virtual SlangResult calcCompileProducts( + const CompileOptions& options, + DownstreamProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) = 0; virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) = 0; - virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) = 0; + virtual SlangResult parseOutput( + const ExecuteResult& exeResult, + IArtifactDiagnostics* diagnostics) = 0; - CommandLineDownstreamCompiler(const Desc& desc, const ExecutableLocation& exe) : - Super(desc) + CommandLineDownstreamCompiler(const Desc& desc, const ExecutableLocation& exe) + : Super(desc) { m_cmdLine.setExecutableLocation(exe); } - CommandLineDownstreamCompiler(const Desc& desc, const CommandLine& cmdLine) : - Super(desc), - m_cmdLine(cmdLine) - {} + CommandLineDownstreamCompiler(const Desc& desc, const CommandLine& cmdLine) + : Super(desc), m_cmdLine(cmdLine) + { + } - CommandLineDownstreamCompiler(const Desc& desc):Super(desc) {} + CommandLineDownstreamCompiler(const Desc& desc) + : Super(desc) + { + } CommandLine m_cmdLine; }; -/* Only purpose of having base-class here is to make all the DownstreamCompiler types available directly in derived Utils */ +/* Only purpose of having base-class here is to make all the DownstreamCompiler types available + * directly in derived Utils */ struct DownstreamCompilerUtilBase { typedef DownstreamCompileOptions CompileOptions; @@ -392,6 +447,6 @@ struct DownstreamCompilerUtilBase typedef DownstreamProductFlags ProductFlags; }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-dxc-compiler.cpp b/source/compiler-core/slang-dxc-compiler.cpp index 3a949b3bd3..cfc4771e6f 100644 --- a/source/compiler-core/slang-dxc-compiler.cpp +++ b/source/compiler-core/slang-dxc-compiler.cpp @@ -1,35 +1,28 @@ // slang-dxc-compiler.cpp #include "slang-dxc-compiler.h" -#include "../core/slang-common.h" -#include "slang-com-helper.h" - #include "../core/slang-blob.h" - -#include "../core/slang-string-util.h" -#include "../core/slang-string-slice-pool.h" - +#include "../core/slang-char-util.h" +#include "../core/slang-common.h" #include "../core/slang-io.h" -#include "../core/slang-shared-library.h" #include "../core/slang-semantic-version.h" -#include "../core/slang-char-util.h" - -#include "slang-include-system.h" -#include "slang-source-loc.h" - #include "../core/slang-shared-library.h" - +#include "../core/slang-string-slice-pool.h" +#include "../core/slang-string-util.h" #include "slang-artifact-associated-impl.h" -#include "slang-artifact-util.h" -#include "slang-artifact-diagnostic-util.h" #include "slang-artifact-desc-util.h" +#include "slang-artifact-diagnostic-util.h" +#include "slang-artifact-util.h" +#include "slang-com-helper.h" +#include "slang-include-system.h" +#include "slang-source-loc.h" // Enable DXIL by default unless told not to #ifndef SLANG_ENABLE_DXIL_SUPPORT #if SLANG_APPLE_FAMILY -# define SLANG_ENABLE_DXIL_SUPPORT 0 +#define SLANG_ENABLE_DXIL_SUPPORT 0 #else -# define SLANG_ENABLE_DXIL_SUPPORT 1 +#define SLANG_ENABLE_DXIL_SUPPORT 1 #endif #endif @@ -37,26 +30,32 @@ // generate code on Windows. #if SLANG_ENABLE_DXIL_SUPPORT -# ifdef _WIN32 -# include -# include -# include "../../external/dxc/dxcapi.h" -# else -# include "../../external/dxc/dxcapi.h" - -# ifdef __uuidof - // DXC's WinAdapter.h defines __uuidof(T) over types, but the existing - // usage in this file is over values (both are accepted on MSVC.) - // We also need to decay through Slang::ComPtr, hence the helper struct - template - struct StripSlangComPtr { using type = T; }; - template - struct StripSlangComPtr> { using type = T; }; -# undef __uuidof -# define __uuidof(x) __emulated_uuidof>::type>() -# endif -# endif +#ifdef _WIN32 +#include +#include +#endif + +#include "../../external/dxc/dxcapi.h" +#ifndef _WIN32 +#ifdef __uuidof +// DXC's WinAdapter.h defines __uuidof(T) over types, but the existing +// usage in this file is over values (both are accepted on MSVC.) +// We also need to decay through Slang::ComPtr, hence the helper struct +template +struct StripSlangComPtr +{ + using type = T; +}; +template +struct StripSlangComPtr> +{ + using type = T; +}; +#undef __uuidof +#define __uuidof(x) __emulated_uuidof>::type>() +#endif +#endif #endif namespace Slang @@ -64,11 +63,15 @@ namespace Slang #if SLANG_ENABLE_DXIL_SUPPORT -static UnownedStringSlice _getSlice(IDxcBlob* blob) { return StringUtil::getSlice((ISlangBlob*)blob); } +static UnownedStringSlice _getSlice(IDxcBlob* blob) +{ + return StringUtil::getSlice((ISlangBlob*)blob); +} // IDxcIncludeHandler // 7f61fc7d-950d-467f-b3e3-3c02fb49187c -static const Guid IID_IDxcIncludeHandler = { 0x7f61fc7d, 0x950d, 0x467f, { 0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c } }; +static const Guid IID_IDxcIncludeHandler = + {0x7f61fc7d, 0x950d, 0x467f, {0x3c, 0x02, 0xfb, 0x49, 0x18, 0x7c}}; static UnownedStringSlice _addName(const UnownedStringSlice& inSlice, StringSlicePool& pool) { @@ -82,10 +85,10 @@ static UnownedStringSlice _addName(const UnownedStringSlice& inSlice, StringSlic const Index length = slice.getLength(); buf << slice; - for (Index i = 0; ; ++i) + for (Index i = 0;; ++i) { buf.reduceLength(length); - + if (i > 0) { buf << "_" << i; @@ -124,8 +127,8 @@ class DxcIncludeHandler : public IDxcIncludeHandler // Implement IDxcIncludeHandler virtual HRESULT SLANG_MCALL LoadSource(LPCWSTR inFilename, IDxcBlob** outSource) SLANG_OVERRIDE { - // Hmm DXC does something a bit odd - when it sees a path, it just passes that in with ./ in front!! - // NOTE! It doesn't make any difference if it is "" or <> quoted. + // Hmm DXC does something a bit odd - when it sees a path, it just passes that in with ./ in + // front!! NOTE! It doesn't make any difference if it is "" or <> quoted. // So we just do a work around where we strip if we see a path starting with ./ String filePath = String::fromWString(inFilename); @@ -134,9 +137,9 @@ class DxcIncludeHandler : public IDxcIncludeHandler if (filePath.startsWith("./")) { const String remaining = filePath.getUnownedSlice().tail(2); - - // Okay if we strip ./ and what we have is absolute, then it's the absolute path that we care about, - // otherwise we just leave as is. + + // Okay if we strip ./ and what we have is absolute, then it's the absolute path that we + // care about, otherwise we just leave as is. if (Path::isAbsolute(remaining)) { filePath = remaining; @@ -153,13 +156,15 @@ class DxcIncludeHandler : public IDxcIncludeHandler return res; } - DxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr) : - m_system(searchDirectories, fileSystemExt, sourceManager) + DxcIncludeHandler( + SearchDirectoryList* searchDirectories, + ISlangFileSystemExt* fileSystemExt, + SourceManager* sourceManager = nullptr) + : m_system(searchDirectories, fileSystemExt, sourceManager) { } protected: - // Used by QueryInterface for casting ISlangUnknown* getInterface(const Guid& guid) { @@ -169,7 +174,7 @@ class DxcIncludeHandler : public IDxcIncludeHandler } return nullptr; } - + IncludeSystem m_system; }; @@ -179,11 +184,15 @@ class DXCDownstreamCompiler : public DownstreamCompilerBase typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) + SLANG_OVERRIDE; /// Must be called before use SlangResult init(ISlangSharedLibrary* library); @@ -191,13 +200,12 @@ class DXCDownstreamCompiler : public DownstreamCompilerBase DXCDownstreamCompiler() {} protected: - DxcCreateInstanceProc m_createInstance = nullptr; - /// The commit hash associated with the DXC dll used - /// If 0 length, no hash was found - String m_commitHash; - /// The commit count. 0 if not set + /// The commit hash associated with the DXC dll used + /// If 0 length, no hash was found + String m_commitHash; + /// The commit count. 0 if not set uint32_t m_commitCount = 0; ComPtr m_sharedLibrary; @@ -224,10 +232,13 @@ SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_FAIL; } - // Must be able to create the compiler. We inly do this here, because we want to get the compiler - // version. + // Must be able to create the compiler. We inly do this here, because we want to get the + // compiler version. ComPtr dxcCompiler; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef())); + SLANG_RETURN_ON_FAIL(m_createInstance( + CLSID_DxcCompiler, + __uuidof(dxcCompiler), + (LPVOID*)dxcCompiler.writeRef())); uint32_t major = 0; uint32_t minor = 0; @@ -270,12 +281,13 @@ SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library) StringBuilder buf; semanticVersion.append(buf); - if (customVersionString.startsWith(buf) && + if (customVersionString.startsWith(buf) && customVersionString.getLength() > buf.getLength() + 2 && customVersionString[buf.getLength()] == '.') { // Get the patch slice - UnownedStringSlice patchSlice = StringUtil::getAtInSplit(customVersionString.getUnownedSlice(), '.', 2); + UnownedStringSlice patchSlice = + StringUtil::getAtInSplit(customVersionString.getUnownedSlice(), '.', 2); Int patchValue; if (SLANG_SUCCEEDED(StringUtil::parseInt(patchSlice, patchValue)) && patchValue > 0) @@ -291,7 +303,11 @@ SlangResult DXCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const UnownedStringSlice& line, List& lineSlices, IArtifactDiagnostics::Diagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + List& lineSlices, + IArtifactDiagnostics::Diagnostic& outDiagnostic) { /* tests/diagnostics/syntax-error-intrinsic.slang:14:2: error: expected expression */ if (lineSlices.getCount() < 5) @@ -303,8 +319,8 @@ static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const Unowned SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[1], outDiagnostic.location.line)); - //Int lineCol; - //SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], lineCol)); + // Int lineCol; + // SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineSlices[2], lineCol)); UnownedStringSlice severitySlice = lineSlices[3].trim(); @@ -319,7 +335,10 @@ static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const Unowned return SLANG_OK; } -static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtifactDiagnostics* diagnostics, ComPtr& outBlob) +static SlangResult _handleOperationResult( + IDxcOperationResult* dxcResult, + IArtifactDiagnostics* diagnostics, + ComPtr& outBlob) { // Retrieve result. HRESULT resultCode = S_OK; @@ -348,7 +367,12 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtif SliceAllocator allocator; List parsedDiagnostics; - SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticsSlice, 0, _parseDiagnosticLine, diagnostics); + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics( + allocator, + diagnosticsSlice, + 0, + _parseDiagnosticLine, + diagnostics); SLANG_UNUSED(diagnosticParseRes); SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); @@ -358,7 +382,8 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtif // If it failed, make sure we have an error in the diagnostics if (SLANG_FAILED(resultCode)) { - // In case the parsing failed, we still have an error -> so require there is one in the diagnostics + // In case the parsing failed, we still have an error -> so require there is one in the + // diagnostics diagnostics->requireErrorDiagnostic(); } else @@ -373,7 +398,7 @@ static SlangResult _handleOperationResult(IDxcOperationResult* dxcResult, IArtif SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact** outArtifact) { - if (!isVersionCompatible(inOptions)) + if (!isVersionCompatible(inOptions)) { // Not possible to compile with this version of the interface. return SLANG_E_NOT_IMPLEMENTED; @@ -382,7 +407,8 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt CompileOptions options = getCompatibleVersion(&inOptions); // This compiler can only deal at most, a single source code artifact - // Should be okay to link together multiple libraries without any source artifacts (assuming that means source code) + // Should be okay to link together multiple libraries without any source artifacts (assuming + // that means source code) if (options.sourceArtifacts.count > 1) { return SLANG_FAIL; @@ -394,7 +420,8 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt if (hasSource) { - if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || options.targetType != SLANG_DXIL) + if (options.sourceLanguage != SLANG_SOURCE_LANGUAGE_HLSL || + options.targetType != SLANG_DXIL) { SLANG_ASSERT(!"Can only compile HLSL to DXIL"); return SLANG_FAIL; @@ -418,9 +445,13 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt } ComPtr dxcCompiler; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef())); + SLANG_RETURN_ON_FAIL(m_createInstance( + CLSID_DxcCompiler, + __uuidof(dxcCompiler), + (LPVOID*)dxcCompiler.writeRef())); ComPtr dxcLibrary; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef())); + SLANG_RETURN_ON_FAIL( + m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef())); ComPtr dxcSourceBlob = nullptr; ComPtr sourceBlob; @@ -457,45 +488,52 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt switch (options.matrixLayout) { - default: - break; + default: + break; - case SLANG_MATRIX_LAYOUT_ROW_MAJOR: - args.add(L"-Zpr"); - break; + case SLANG_MATRIX_LAYOUT_ROW_MAJOR: + args.add(L"-Zpr"); + break; } switch (options.floatingPointMode) { - default: - break; + default: + break; - case FloatingPointMode::Precise: - args.add(L"-Gis"); // "force IEEE strictness" - break; + case FloatingPointMode::Precise: + args.add(L"-Gis"); // "force IEEE strictness" + break; } - switch (options.optimizationLevel) { - default: - break; + default: + break; - case OptimizationLevel::None: args.add(L"-Od"); break; - case OptimizationLevel::Default: args.add(L"-O1"); break; - case OptimizationLevel::High: args.add(L"-O2"); break; - case OptimizationLevel::Maximal: args.add(L"-O3"); break; + case OptimizationLevel::None: + args.add(L"-Od"); + break; + case OptimizationLevel::Default: + args.add(L"-O1"); + break; + case OptimizationLevel::High: + args.add(L"-O2"); + break; + case OptimizationLevel::Maximal: + args.add(L"-O3"); + break; } switch (options.debugInfoType) { - case DebugInfoType::None: - break; + case DebugInfoType::None: + break; - default: - args.add(L"-Zi"); - break; + default: + args.add(L"-Zi"); + break; } // Slang strives to produce correct code, and by default @@ -549,9 +587,9 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt searchDirectories.searchDirectories.add(asString(includePath)); } - // TODO(JS): - // We don't want to enable HLSL2021 on DXC by default even if it's available because it has - // changes that break things. Such as with operator ?:. So for now we disable. +// TODO(JS): +// We don't want to enable HLSL2021 on DXC by default even if it's available because it has +// changes that break things. Such as with operator ?:. So for now we disable. #if 0 // TODO(JS): Enable in a better way perhaps? { @@ -579,27 +617,33 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt sourcePath = ArtifactUtil::findPath(sourceArtifact); OSString wideSourcePath = sourcePath.toWString(); - DxcIncludeHandler includeHandler(&searchDirectories, options.fileSystemExt, options.sourceManager); + DxcIncludeHandler includeHandler( + &searchDirectories, + options.fileSystemExt, + options.sourceManager); - SLANG_RETURN_ON_FAIL(dxcCompiler->Compile(dxcSourceBlob, + SLANG_RETURN_ON_FAIL(dxcCompiler->Compile( + dxcSourceBlob, wideSourcePath.begin(), wideEntryPointName.begin(), wideProfileName.begin(), args.getBuffer(), UINT32(args.getCount()), - nullptr, // `#define`s - 0, // `#define` count - &includeHandler, // `#include` handler + nullptr, // `#define`s + 0, // `#define` count + &includeHandler, // `#include` handler dxcOperationResult.writeRef())); - SLANG_RETURN_ON_FAIL(_handleOperationResult(dxcOperationResult, diagnostics, dxcResultBlob)); + SLANG_RETURN_ON_FAIL( + _handleOperationResult(dxcOperationResult, diagnostics, dxcResultBlob)); } // If we have libraries then we need to link... if (libraries.getCount()) { ComPtr linker; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLinker, __uuidof(linker), (void**)linker.writeRef())); + SLANG_RETURN_ON_FAIL( + m_createInstance(CLSID_DxcLinker, __uuidof(linker), (void**)linker.writeRef())); StringSlicePool pool(StringSlicePool::Style::Default); @@ -641,22 +685,30 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt SLANG_ASSERT(libraryNames.getCount() == librariesCount); List linkLibraryNames; - + linkLibraryNames.setCount(librariesCount); - + for (Index i = 0; i < librariesCount; ++i) { linkLibraryNames[i] = libraryNames[i].begin(); // Register the library - SLANG_RETURN_ON_FAIL(linker->RegisterLibrary(linkLibraryNames[i], (IDxcBlob*)libraryBlobs[i].get())); + SLANG_RETURN_ON_FAIL( + linker->RegisterLibrary(linkLibraryNames[i], (IDxcBlob*)libraryBlobs[i].get())); } // Use the original profile name wideProfileName = asString(options.profileName).toWString(); ComPtr linkDxcResult; - SLANG_RETURN_ON_FAIL(linker->Link(wideEntryPointName.begin(), wideProfileName.begin(), linkLibraryNames.getBuffer(), UINT32(librariesCount), nullptr, 0, linkDxcResult.writeRef())); + SLANG_RETURN_ON_FAIL(linker->Link( + wideEntryPointName.begin(), + wideProfileName.begin(), + linkLibraryNames.getBuffer(), + UINT32(librariesCount), + nullptr, + 0, + linkDxcResult.writeRef())); ComPtr linkedBlob; SLANG_RETURN_ON_FAIL(_handleOperationResult(linkDxcResult, diagnostics, linkedBlob)); @@ -689,9 +741,15 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt ComPtr pdbBlob; ComPtr nameBlob; - if (SLANG_SUCCEEDED(dxcResult->GetOutput(DXC_OUT_PDB, __uuidof(pdbBlob), (void**)pdbBlob.writeRef(), nameBlob.writeRef()))) + if (SLANG_SUCCEEDED(dxcResult->GetOutput( + DXC_OUT_PDB, + __uuidof(pdbBlob), + (void**)pdbBlob.writeRef(), + nameBlob.writeRef()))) { - auto pdbArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make(ArtifactDesc::Kind::BinaryFormat, ArtifactDesc::Payload::PdbDebugInfo)); + auto pdbArtifact = ArtifactUtil::createArtifact(ArtifactDesc::make( + ArtifactDesc::Kind::BinaryFormat, + ArtifactDesc::Payload::PdbDebugInfo)); if (nameBlob) { @@ -700,7 +758,8 @@ SlangResult DXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt const auto name = String::fromWString(wideName); if (name.getLength()) { - // Set the name on the artifact. This is the name that must be used for the PDB to be loadable as a file by other tooling. + // Set the name on the artifact. This is the name that must be used for + // the PDB to be loadable as a file by other tooling. pdbArtifact->setName(name.getBuffer()); } } @@ -723,7 +782,10 @@ bool DXCDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactD return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::DXIL; } -SlangResult DXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) +SlangResult DXCDownstreamCompiler::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) { // Can only disassemble blobs that are DXIL if (!canConvert(from->getDesc(), to)) @@ -735,13 +797,21 @@ SlangResult DXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& SLANG_RETURN_ON_FAIL(from->loadBlob(ArtifactKeep::No, dxilBlob.writeRef())); ComPtr dxcCompiler; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcCompiler, __uuidof(dxcCompiler), (LPVOID*)dxcCompiler.writeRef())); + SLANG_RETURN_ON_FAIL(m_createInstance( + CLSID_DxcCompiler, + __uuidof(dxcCompiler), + (LPVOID*)dxcCompiler.writeRef())); ComPtr dxcLibrary; - SLANG_RETURN_ON_FAIL(m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef())); + SLANG_RETURN_ON_FAIL( + m_createInstance(CLSID_DxcLibrary, __uuidof(dxcLibrary), (LPVOID*)dxcLibrary.writeRef())); // Create blob from the input data ComPtr dxcSourceBlob; - SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned((LPBYTE)dxilBlob->getBufferPointer(), (UINT32)dxilBlob->getBufferSize(), 0, dxcSourceBlob.writeRef())); + SLANG_RETURN_ON_FAIL(dxcLibrary->CreateBlobWithEncodingFromPinned( + (LPBYTE)dxilBlob->getBufferPointer(), + (UINT32)dxilBlob->getBufferSize(), + 0, + dxcSourceBlob.writeRef())); ComPtr dxcResultBlob; SLANG_RETURN_ON_FAIL(dxcCompiler->Disassemble(dxcSourceBlob, dxcResultBlob.writeRef())); @@ -763,26 +833,36 @@ SlangResult DXCDownstreamCompiler::getVersionString(slang::IBlob** outVersionStr m_desc.version.append(versionString); if (m_commitHash.getLength()) - { + { versionString << "#" << m_commitHash; } else { // If we don't have the commitHash, we use the library timestamp, to uniquely identify. - versionString << " " << SharedLibraryUtils::getSharedLibraryTimestamp(reinterpret_cast(m_createInstance)); + versionString << " " + << SharedLibraryUtils::getSharedLibraryTimestamp( + reinterpret_cast(m_createInstance)); } *outVersionString = StringBlob::moveCreate(versionString).detach(); return SLANG_OK; } -/* static */SlangResult DXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult DXCDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { ComPtr library; - const char* dependentNames[] = {"dxil", nullptr } ; - SLANG_RETURN_ON_FAIL(DownstreamCompilerUtil::loadSharedLibrary(path, loader, dependentNames, "dxcompiler", library)); - + const char* dependentNames[] = {"dxil", nullptr}; + SLANG_RETURN_ON_FAIL(DownstreamCompilerUtil::loadSharedLibrary( + path, + loader, + dependentNames, + "dxcompiler", + library)); + SLANG_ASSERT(library); if (!library) { @@ -799,7 +879,10 @@ SlangResult DXCDownstreamCompiler::getVersionString(slang::IBlob** outVersionStr #else // SLANG_ENABLE_DXIL_SUPPORT -/* static */SlangResult DXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult DXCDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { SLANG_UNUSED(path); SLANG_UNUSED(loader); @@ -809,4 +892,4 @@ SlangResult DXCDownstreamCompiler::getVersionString(slang::IBlob** outVersionStr #endif // SLANG_ENABLE_DXIL_SUPPORT -} +} // namespace Slang diff --git a/source/compiler-core/slang-dxc-compiler.h b/source/compiler-core/slang-dxc-compiler.h index 4c915fb195..ee1d93c486 100644 --- a/source/compiler-core/slang-dxc-compiler.h +++ b/source/compiler-core/slang-dxc-compiler.h @@ -1,18 +1,20 @@ #ifndef SLANG_DXC_COMPILER_UTIL_H #define SLANG_DXC_COMPILER_UTIL_H -#include "slang-downstream-compiler-util.h" - #include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" namespace Slang { struct DXCDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-fxc-compiler.cpp b/source/compiler-core/slang-fxc-compiler.cpp index e4a9f25c78..c42516399a 100644 --- a/source/compiler-core/slang-fxc-compiler.cpp +++ b/source/compiler-core/slang-fxc-compiler.cpp @@ -3,43 +3,36 @@ #if SLANG_ENABLE_DXBC_SUPPORT -#include "../core/slang-common.h" -#include "slang-com-helper.h" - #include "../core/slang-blob.h" - -#include "../core/slang-string-util.h" -#include "../core/slang-string-slice-pool.h" - +#include "../core/slang-char-util.h" +#include "../core/slang-common.h" #include "../core/slang-io.h" -#include "../core/slang-shared-library.h" #include "../core/slang-semantic-version.h" -#include "../core/slang-char-util.h" - -#include "slang-include-system.h" -#include "slang-source-loc.h" - +#include "../core/slang-shared-library.h" +#include "../core/slang-string-slice-pool.h" +#include "../core/slang-string-util.h" #include "slang-artifact-associated-impl.h" #include "slang-artifact-desc-util.h" #include "slang-artifact-diagnostic-util.h" - -#include "../core/slang-shared-library.h" +#include "slang-com-helper.h" +#include "slang-include-system.h" +#include "slang-source-loc.h" // Enable calling through to `fxc` or `dxc` to // generate code on Windows. #ifdef _WIN32 -# include -# include +#include +#include #endif // Some of the `D3DCOMPILE_*` constants aren't available in all // versions of `d3dcompiler.h`, so we define them here just in case #ifndef D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES -# define D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES (1 << 20) +#define D3DCOMPILE_ENABLE_UNBOUNDED_DESCRIPTOR_TABLES (1 << 20) #endif #ifndef D3DCOMPILE_ALL_RESOURCES_BOUND -# define D3DCOMPILE_ALL_RESOURCES_BOUND (1 << 21) +#define D3DCOMPILE_ALL_RESOURCES_BOUND (1 << 21) #endif #endif // SLANG_ENABLE_DXBC_SUPPORT @@ -49,25 +42,35 @@ namespace Slang #if SLANG_ENABLE_DXBC_SUPPORT -static UnownedStringSlice _getSlice(ID3DBlob* blob) { return StringUtil::getSlice((ISlangBlob*)blob); } +static UnownedStringSlice _getSlice(ID3DBlob* blob) +{ + return StringUtil::getSlice((ISlangBlob*)blob); +} struct FxcIncludeHandler : ID3DInclude { - STDMETHOD(Open)(D3D_INCLUDE_TYPE includeType, LPCSTR fileName, LPCVOID parentData, LPCVOID* outData, UINT* outSize) override + STDMETHOD(Open) + (D3D_INCLUDE_TYPE includeType, + LPCSTR fileName, + LPCVOID parentData, + LPCVOID* outData, + UINT* outSize) override { SLANG_UNUSED(includeType); // NOTE! The pParentData means the *text* of any previous include. - // In order to work out what *path* that came from, we need to seach which source file it came from, and - // use it's path + // In order to work out what *path* that came from, we need to seach which source file it + // came from, and use it's path - // Assume the root pathInfo initially + // Assume the root pathInfo initially PathInfo includedFromPathInfo = m_rootPathInfo; // Lets try and find the parent source if there is any if (parentData) { - SourceFile* foundSourceFile = m_system.getSourceManager()->findSourceFileByContentRecursively((const char*)parentData); + SourceFile* foundSourceFile = + m_system.getSourceManager()->findSourceFileByContentRecursively( + (const char*)parentData); if (foundSourceFile) { includedFromPathInfo = foundSourceFile->getPathInfo(); @@ -78,7 +81,8 @@ struct FxcIncludeHandler : ID3DInclude PathInfo pathInfo; ComPtr blob; - SLANG_RETURN_ON_FAIL(m_system.findAndLoadFile(path, includedFromPathInfo.foundPath, pathInfo, blob)); + SLANG_RETURN_ON_FAIL( + m_system.findAndLoadFile(path, includedFromPathInfo.foundPath, pathInfo, blob)); // Return the data *outData = blob->getBufferPointer(); @@ -92,8 +96,11 @@ struct FxcIncludeHandler : ID3DInclude SLANG_UNUSED(pData); return S_OK; } - FxcIncludeHandler(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager) : - m_system(searchDirectories, fileSystemExt, sourceManager) + FxcIncludeHandler( + SearchDirectoryList* searchDirectories, + ISlangFileSystemExt* fileSystemExt, + SourceManager* sourceManager) + : m_system(searchDirectories, fileSystemExt, sourceManager) { } @@ -107,22 +114,24 @@ class FXCDownstreamCompiler : public DownstreamCompilerBase typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } - /// Must be called before use + /// Must be called before use SlangResult init(ISlangSharedLibrary* library); FXCDownstreamCompiler() {} - -protected: +protected: pD3DCompile m_compile = nullptr; pD3DDisassemble m_disassemble = nullptr; - ComPtr m_sharedLibrary; + ComPtr m_sharedLibrary; }; SlangResult FXCDownstreamCompiler::init(ISlangSharedLibrary* library) @@ -143,21 +152,29 @@ SlangResult FXCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const UnownedStringSlice& line, List& lineSlices, ArtifactDiagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + List& lineSlices, + ArtifactDiagnostic& outDiagnostic) { - /* tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected token '@' */ + /* tests/diagnostics/syntax-error-intrinsic.slang(14,2): error X3000: syntax error: unexpected + * token '@' */ if (lineSlices.getCount() < 3) { return SLANG_FAIL; } - SLANG_RETURN_ON_FAIL(ArtifactDiagnosticUtil::splitPathLocation(allocator, lineSlices[0], outDiagnostic)); + SLANG_RETURN_ON_FAIL( + ArtifactDiagnosticUtil::splitPathLocation(allocator, lineSlices[0], outDiagnostic)); { const UnownedStringSlice severityAndCodeSlice = lineSlices[1].trim(); - const UnownedStringSlice severitySlice = StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 0); + const UnownedStringSlice severitySlice = + StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 0); - outDiagnostic.code = allocator.allocate(StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1)); + outDiagnostic.code = + allocator.allocate(StringUtil::getAtInSplit(severityAndCodeSlice, ' ', 1)); outDiagnostic.severity = ArtifactDiagnostic::Severity::Error; if (severitySlice == "warning") @@ -212,10 +229,13 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt // Use the default fileSystemExt is not set ID3DInclude* includeHandler = nullptr; - FxcIncludeHandler fxcIncludeHandlerStorage(&searchDirectories, options.fileSystemExt, options.sourceManager); + FxcIncludeHandler fxcIncludeHandlerStorage( + &searchDirectories, + options.fileSystemExt, + options.sourceManager); if (options.fileSystemExt) { - + if (sourcePath.getLength() > 0) { fxcIncludeHandlerStorage.m_rootPathInfo = PathInfo::makePath(sourcePath); @@ -235,7 +255,7 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt dxMacro.Definition = define.value; dxMacrosStorage.add(dxMacro); } - D3D_SHADER_MACRO nullTerminator = { 0, 0 }; + D3D_SHADER_MACRO nullTerminator = {0, 0}; dxMacrosStorage.add(nullTerminator); dxMacros = dxMacrosStorage.getBuffer(); @@ -245,12 +265,12 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt switch (options.floatingPointMode) { - default: - break; + default: + break; - case FloatingPointMode::Precise: - flags |= D3DCOMPILE_IEEE_STRICTNESS; - break; + case FloatingPointMode::Precise: + flags |= D3DCOMPILE_IEEE_STRICTNESS; + break; } flags |= D3DCOMPILE_ENABLE_STRICTNESS; @@ -258,23 +278,31 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt switch (options.optimizationLevel) { - default: - break; - - case OptimizationLevel::None: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0; break; - case OptimizationLevel::Default: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL1; break; - case OptimizationLevel::High: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL2; break; - case OptimizationLevel::Maximal: flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; break; + default: + break; + + case OptimizationLevel::None: + flags |= D3DCOMPILE_OPTIMIZATION_LEVEL0; + break; + case OptimizationLevel::Default: + flags |= D3DCOMPILE_OPTIMIZATION_LEVEL1; + break; + case OptimizationLevel::High: + flags |= D3DCOMPILE_OPTIMIZATION_LEVEL2; + break; + case OptimizationLevel::Maximal: + flags |= D3DCOMPILE_OPTIMIZATION_LEVEL3; + break; } switch (options.debugInfoType) { - case DebugInfoType::None: - break; + case DebugInfoType::None: + break; - default: - flags |= D3DCOMPILE_DEBUG; - break; + default: + flags |= D3DCOMPILE_DEBUG; + break; } ComPtr sourceBlob; @@ -307,7 +335,12 @@ SlangResult FXCDownstreamCompiler::compile(const CompileOptions& inOptions, IArt UnownedStringSlice diagnosticText = _getSlice(diagnosticsBlob); diagnostics->setRaw(asCharSlice(diagnosticText)); - SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticText, 0, _parseDiagnosticLine, diagnostics); + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics( + allocator, + diagnosticText, + 0, + _parseDiagnosticLine, + diagnostics); SLANG_UNUSED(diagnosticParseRes); SLANG_ASSERT(SLANG_SUCCEEDED(diagnosticParseRes)); } @@ -338,7 +371,10 @@ bool FXCDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactD return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::DXBC; } -SlangResult FXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) +SlangResult FXCDownstreamCompiler::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) { if (!canConvert(from->getDesc(), to)) { @@ -349,22 +385,31 @@ SlangResult FXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& SLANG_RETURN_ON_FAIL(from->loadBlob(ArtifactKeep::No, dxbcBlob.writeRef())); ComPtr disassemblyBlob; - SLANG_RETURN_ON_FAIL(m_disassemble(dxbcBlob->getBufferPointer(), dxbcBlob->getBufferSize(), 0, nullptr, disassemblyBlob.writeRef())); + SLANG_RETURN_ON_FAIL(m_disassemble( + dxbcBlob->getBufferPointer(), + dxbcBlob->getBufferSize(), + 0, + nullptr, + disassemblyBlob.writeRef())); auto artifact = ArtifactUtil::createArtifact(to); // ISlangBlob is compatible with ID3DBlob artifact->addRepresentationUnknown((ISlangBlob*)disassemblyBlob.get()); - *outArtifact= artifact.detach(); + *outArtifact = artifact.detach(); return SLANG_OK; } -/* static */SlangResult FXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult FXCDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { ComPtr library; const char* const libName = "d3dcompiler_47"; - SLANG_RETURN_ON_FAIL(DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, libName, library)); + SLANG_RETURN_ON_FAIL( + DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, libName, library)); SLANG_ASSERT(library); if (!library) @@ -383,7 +428,10 @@ SlangResult FXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& #else // SLANG_ENABLE_DXBC_SUPPORT -/* static */SlangResult FXCDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult FXCDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { SLANG_UNUSED(path); SLANG_UNUSED(loader); @@ -393,4 +441,4 @@ SlangResult FXCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& #endif // else SLANG_ENABLE_DXBC_SUPPORT -} +} // namespace Slang diff --git a/source/compiler-core/slang-fxc-compiler.h b/source/compiler-core/slang-fxc-compiler.h index 856d2fc0e5..9ab072de07 100644 --- a/source/compiler-core/slang-fxc-compiler.h +++ b/source/compiler-core/slang-fxc-compiler.h @@ -1,18 +1,20 @@ #ifndef SLANG_FXC_COMPILER_UTIL_H #define SLANG_FXC_COMPILER_UTIL_H -#include "slang-downstream-compiler-util.h" - #include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" namespace Slang { struct FXCDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-gcc-compiler-util.cpp b/source/compiler-core/slang-gcc-compiler-util.cpp index 875f7bea1a..f12f44338b 100644 --- a/source/compiler-core/slang-gcc-compiler-util.cpp +++ b/source/compiler-core/slang-gcc-compiler-util.cpp @@ -1,19 +1,17 @@ // slang-gcc-compiler-util.cpp #include "slang-gcc-compiler-util.h" +#include "../core/slang-char-util.h" #include "../core/slang-common.h" -#include "slang-com-helper.h" -#include "../core/slang-string-util.h" - #include "../core/slang-io.h" #include "../core/slang-shared-library.h" -#include "../core/slang-char-util.h" #include "../core/slang-string-slice-pool.h" - +#include "../core/slang-string-util.h" #include "slang-artifact-desc-util.h" #include "slang-artifact-diagnostic-util.h" -#include "slang-artifact-util.h" #include "slang-artifact-representation-impl.h" +#include "slang-artifact-util.h" +#include "slang-com-helper.h" namespace Slang { @@ -44,7 +42,10 @@ static Index _findVersionEnd(const UnownedStringSlice& in) return len; } -/* static */SlangResult GCCDownstreamCompilerUtil::parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, DownstreamCompilerDesc& outDesc) +/* static */ SlangResult GCCDownstreamCompilerUtil::parseVersion( + const UnownedStringSlice& text, + const UnownedStringSlice& prefix, + DownstreamCompilerDesc& outDesc) { List lines; StringUtil::calcLines(text, lines); @@ -57,7 +58,8 @@ static Index _findVersionEnd(const UnownedStringSlice& in) continue; } - const UnownedStringSlice remainingSlice = UnownedStringSlice(line.begin() + prefixIndex + prefix.getLength(), line.end()).trim(); + const UnownedStringSlice remainingSlice = + UnownedStringSlice(line.begin() + prefixIndex + prefix.getLength(), line.end()).trim(); const Index versionEndIndex = _findVersionEnd(remainingSlice); if (versionEndIndex < 0) @@ -65,9 +67,11 @@ static Index _findVersionEnd(const UnownedStringSlice& in) return SLANG_FAIL; } - const UnownedStringSlice versionSlice(remainingSlice.begin(), remainingSlice.begin() + versionEndIndex); + const UnownedStringSlice versionSlice( + remainingSlice.begin(), + remainingSlice.begin() + versionEndIndex); - // Version is in format 0.0.0 + // Version is in format 0.0.0 List split; StringUtil::split(versionSlice, '.', split); List digits; @@ -91,7 +95,9 @@ static Index _findVersionEnd(const UnownedStringSlice& in) return SLANG_FAIL; } -SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe, DownstreamCompilerDesc& outDesc) +SlangResult GCCDownstreamCompilerUtil::calcVersion( + const ExecutableLocation& exe, + DownstreamCompilerDesc& outDesc) { CommandLine cmdLine; cmdLine.setExecutableLocation(exe); @@ -102,16 +108,14 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe // Note we now have builds that add other words in front of the version // such as "Ubuntu clang version" - const UnownedStringSlice prefixes[] = - { + const UnownedStringSlice prefixes[] = { UnownedStringSlice::fromLiteral("clang version"), UnownedStringSlice::fromLiteral("gcc version"), UnownedStringSlice::fromLiteral("Apple LLVM version"), UnownedStringSlice::fromLiteral("Apple metal version"), }; - const SlangPassThrough types[] = - { + const SlangPassThrough types[] = { SLANG_PASS_THROUGH_CLANG, SLANG_PASS_THROUGH_GCC, SLANG_PASS_THROUGH_CLANG, @@ -125,7 +129,8 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe // Set the type outDesc.type = types[i]; // Extract the version - if (SLANG_SUCCEEDED(parseVersion(exeRes.standardError.getUnownedSlice(), prefixes[i], outDesc))) + if (SLANG_SUCCEEDED( + parseVersion(exeRes.standardError.getUnownedSlice(), prefixes[i], outDesc))) { return SLANG_OK; } @@ -134,7 +139,9 @@ SlangResult GCCDownstreamCompilerUtil::calcVersion(const ExecutableLocation& exe return SLANG_FAIL; } -static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnostic::Severity& outSeverity) +static SlangResult _parseSeverity( + const UnownedStringSlice& in, + ArtifactDiagnostic::Severity& outSeverity) { typedef ArtifactDiagnostic::Severity Severity; @@ -157,28 +164,33 @@ static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnost return SLANG_OK; } -namespace { // anonymous +namespace +{ // anonymous enum class LineParseResult { - Single, ///< It's a single line - Start, ///< Line was the start of a message - Continuation, ///< Not totally clear, add to previous line if nothing else hit - Ignore, ///< Ignore the line + Single, ///< It's a single line + Start, ///< Line was the start of a message + Continuation, ///< Not totally clear, add to previous line if nothing else hit + Ignore, ///< Ignore the line }; - -} // anonymous - -static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedStringSlice& line, LineParseResult& outLineParseResult, ArtifactDiagnostic& outDiagnostic) + +} // namespace + +static SlangResult _parseGCCFamilyLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + LineParseResult& outLineParseResult, + ArtifactDiagnostic& outDiagnostic) { typedef ArtifactDiagnostic Diagnostic; typedef Diagnostic::Severity Severity; - + // Set to default case outLineParseResult = LineParseResult::Ignore; /* example error output from different scenarios */ - + /* tests/cpp-compiler/c-compile-error.c: In function 'int main(int, char**)': tests/cpp-compiler/c-compile-error.c:8:13: error: 'b' was not declared in this scope @@ -189,25 +201,26 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS ^ */ - /* /tmp/ccS0JCWe.o:c-compile-link-error.c:(.rdata$.refptr.thing[.refptr.thing]+0x0): undefined reference to `thing' - collect2: error: ld returned 1 exit status*/ + /* /tmp/ccS0JCWe.o:c-compile-link-error.c:(.rdata$.refptr.thing[.refptr.thing]+0x0): undefined + reference to `thing' collect2: error: ld returned 1 exit status*/ /* - clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated] - Undefined symbols for architecture x86_64: + clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated + [-Wdeprecated] Undefined symbols for architecture x86_64: "_thing", referenced from: _main in c-compile-link-error-a83ace.o ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) */ - /* /tmp/c-compile-link-error-ccf151.o: In function `main': - c-compile-link-error.c:(.text+0x19): undefined reference to `thing' - clang: error: linker command failed with exit code 1 (use -v to see invocation) - */ + /* /tmp/c-compile-link-error-ccf151.o: In function `main': + c-compile-link-error.c:(.text+0x19): undefined reference to `thing' + clang: error: linker command failed with exit code 1 (use -v to see invocation) + */ - /* /tmp/c-compile-link-error-301c8c.o: In function `main': - /home/travis/build/shader-slang/slang/tests/cpp-compiler/c-compile-link-error.c:10: undefined reference to `thing' - clang-7: error: linker command failed with exit code 1 (use -v to see invocation)*/ + /* /tmp/c-compile-link-error-301c8c.o: In function `main': + /home/travis/build/shader-slang/slang/tests/cpp-compiler/c-compile-link-error.c:10: undefined + reference to `thing' clang-7: error: linker command failed with exit code 1 (use -v to see + invocation)*/ /* /path/slang-cpp-prelude.h:4:10: fatal error: ../slang.h: No such file or directory #include "slang.h" @@ -221,7 +234,8 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS List split; StringUtil::split(line, ':', split); - // On windows we can have paths that are a: etc... if we detect this we can combine 0 - 1 to be 1. + // On windows we can have paths that are a: etc... if we detect this we can combine 0 - 1 to + // be 1. if (split.getCount() > 1 && split[0].getLength() == 1) { const char c = split[0][0]; @@ -328,7 +342,7 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS outDiagnostic.severity = Diagnostic::Severity::Error; outDiagnostic.stage = Diagnostic::Stage::Link; outDiagnostic.text = allocator.allocate(split[3]); - + outLineParseResult = LineParseResult::Start; return SLANG_OK; } @@ -353,55 +367,60 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics) +/* static */ SlangResult GCCDownstreamCompilerUtil::parseOutput( + const ExecuteResult& exeRes, + IArtifactDiagnostics* diagnostics) { LineParseResult prevLineResult = LineParseResult::Ignore; - + SliceAllocator allocator; diagnostics->reset(); diagnostics->setRaw(SliceUtil::asCharSlice(exeRes.standardError)); - // We hold in workDiagnostics so as it is more convenient to append to the last with a continuation - // also means we don't hold the allocations of building up continuations, just the results when finally allocated at the end + // We hold in workDiagnostics so as it is more convenient to append to the last with a + // continuation also means we don't hold the allocations of building up continuations, just the + // results when finally allocated at the end List workDiagnostics; for (auto line : LineParser(exeRes.standardError.getUnownedSlice())) { ArtifactDiagnostic diagnostic; - + LineParseResult lineRes; - + SLANG_RETURN_ON_FAIL(_parseGCCFamilyLine(allocator, line, lineRes, diagnostic)); - + switch (lineRes) { - case LineParseResult::Start: + case LineParseResult::Start: { // It's start of a new message workDiagnostics.add(diagnostic); prevLineResult = LineParseResult::Start; break; } - case LineParseResult::Single: + case LineParseResult::Single: { // It's a single message, without anything following workDiagnostics.add(diagnostic); prevLineResult = LineParseResult::Ignore; break; } - case LineParseResult::Continuation: + case LineParseResult::Continuation: { - if (prevLineResult == LineParseResult::Start || prevLineResult == LineParseResult::Continuation) + if (prevLineResult == LineParseResult::Start || + prevLineResult == LineParseResult::Continuation) { if (workDiagnostics.getCount() > 0) { auto& last = workDiagnostics.getLast(); - // TODO(JS): Note that this is somewhat wasteful as every time we append we just allocate more memory - // to hold the result. - // If we had an allocator dedicated to 'text' we could perhaps just append to the end of the last allocation - // + // TODO(JS): Note that this is somewhat wasteful as every time we append we + // just allocate more memory to hold the result. If we had an allocator + // dedicated to 'text' we could perhaps just append to the end of the last + // allocation + // // We are now in a continuation, add to the last StringBuilder buf; buf.append(asStringSlice(last.text)); @@ -414,12 +433,13 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS } break; } - case LineParseResult::Ignore: + case LineParseResult::Ignore: { prevLineResult = lineRes; break; } - default: return SLANG_FAIL; + default: + return SLANG_FAIL; } } @@ -428,7 +448,8 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS diagnostics->add(diagnostic); } - if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error) || exeRes.resultCode != 0) + if (diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error) || + exeRes.resultCode != 0) { diagnostics->setResult(SLANG_FAIL); } @@ -436,7 +457,11 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) +/* static */ SlangResult GCCDownstreamCompilerUtil::calcCompileProducts( + const CompileOptions& options, + ProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) { SLANG_ASSERT(options.modulePath.count); @@ -446,9 +471,13 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS { StringBuilder builder; const auto desc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, asStringSlice(options.modulePath), builder)); + SLANG_RETURN_ON_FAIL( + ArtifactDescUtil::calcPathForDesc(desc, asStringSlice(options.modulePath), builder)); - auto fileRep = OSFileArtifactRepresentation::create(IOSFileArtifactRepresentation::Kind::Owned, builder.getUnownedSlice(), lockFile); + auto fileRep = OSFileArtifactRepresentation::create( + IOSFileArtifactRepresentation::Kind::Owned, + builder.getUnownedSlice(), + lockFile); auto artifact = ArtifactUtil::createArtifact(desc); artifact->addRepresentation(fileRep); @@ -458,12 +487,16 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) +/* static */ SlangResult GCCDownstreamCompilerUtil::calcArgs( + const CompileOptions& options, + CommandLine& cmdLine) { SLANG_ASSERT(options.modulePath.count); - PlatformKind platformKind = (options.platform == PlatformKind::Unknown) ? PlatformUtil::getPlatformKind() : options.platform; - + PlatformKind platformKind = (options.platform == PlatformKind::Unknown) + ? PlatformUtil::getPlatformKind() + : options.platform; + const auto targetDesc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP) @@ -473,7 +506,7 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS // C++17 since we share headers with slang itself (which uses c++17) cmdLine.addArg("-std=c++17"); } - + if (targetDesc.payload == ArtifactDesc::Payload::MetalAIR) { cmdLine.addArg("-std=metal3.1"); @@ -484,44 +517,45 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS // speaking UB, and GCC 10+ is happy to take advantage of this, stop it. cmdLine.addArg("-fno-strict-aliasing"); - // TODO(JS): Here we always set -m32 on x86. It could be argued it is only necessary when creating a shared library - // but if we create an object file, we don't know what to choose because we don't know what final usage is. - // It could also be argued that the platformKind could define the actual desired target - but as it stands - // we only have a target of 'Linux' (as opposed to Win32/64). Really it implies we need an arch enumeration too. + // TODO(JS): Here we always set -m32 on x86. It could be argued it is only necessary when + // creating a shared library but if we create an object file, we don't know what to choose + // because we don't know what final usage is. It could also be argued that the platformKind + // could define the actual desired target - but as it stands we only have a target of 'Linux' + // (as opposed to Win32/64). Really it implies we need an arch enumeration too. // - // For now we just make X86 binaries try and produce x86 compatible binaries as fixes the immediate problems. + // For now we just make X86 binaries try and produce x86 compatible binaries as fixes the + // immediate problems. #if SLANG_PROCESSOR_X86 - /* Used to specify the processor more broadly. For a x86 binary we need to make sure we build x86 builds - even when on an x64 system. - -m32 - -m64*/ + /* Used to specify the processor more broadly. For a x86 binary we need to make sure we build + x86 builds even when on an x64 system. -m32 -m64*/ cmdLine.addArg("-m32"); #endif switch (options.optimizationLevel) { - case OptimizationLevel::None: + case OptimizationLevel::None: { // No optimization cmdLine.addArg("-O0"); break; } - case OptimizationLevel::Default: + case OptimizationLevel::Default: { cmdLine.addArg("-Os"); break; } - case OptimizationLevel::High: + case OptimizationLevel::High: { cmdLine.addArg("-O2"); break; } - case OptimizationLevel::Maximal: + case OptimizationLevel::Maximal: { cmdLine.addArg("-O4"); break; } - default: break; + default: + break; } if (options.debugInfoType != DebugInfoType::None) @@ -536,31 +570,36 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS switch (options.floatingPointMode) { - case FloatingPointMode::Default: break; - case FloatingPointMode::Precise: + case FloatingPointMode::Default: + break; + case FloatingPointMode::Precise: { - //cmdLine.addArg("-fno-unsafe-math-optimizations"); + // cmdLine.addArg("-fno-unsafe-math-optimizations"); break; } - case FloatingPointMode::Fast: + case FloatingPointMode::Fast: { // We could enable SSE with -mfpmath=sse - // But that would only make sense on a x64/x86 type processor and only if that feature is present (it is on all x64) + // But that would only make sense on a x64/x86 type processor and only if that feature + // is present (it is on all x64) cmdLine.addArg("-ffast-math"); break; } } - StringBuilder moduleFilePath; - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(targetDesc, asStringSlice(options.modulePath), moduleFilePath)); - + StringBuilder moduleFilePath; + SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc( + targetDesc, + asStringSlice(options.modulePath), + moduleFilePath)); + cmdLine.addArg("-o"); cmdLine.addArg(moduleFilePath); switch (options.targetType) { - case SLANG_SHADER_SHARED_LIBRARY: - case SLANG_HOST_SHARED_LIBRARY: + case SLANG_SHADER_SHARED_LIBRARY: + case SLANG_HOST_SHARED_LIBRARY: { // Shared library cmdLine.addArg("-shared"); @@ -572,18 +611,19 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS } break; } - case SLANG_HOST_EXECUTABLE: + case SLANG_HOST_EXECUTABLE: { cmdLine.addArg("-rdynamic"); break; } - case SLANG_OBJECT_CODE: + case SLANG_OBJECT_CODE: { // Don't link, just produce object file cmdLine.addArg("-c"); break; } - default: break; + default: + break; } // Add defines @@ -611,8 +651,8 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS // Link options if (0) // && options.targetType != TargetType::Object) { - //linkOptions << "-Wl,"; - //cmdLine.addArg(linkOptions); + // linkOptions << "-Wl,"; + // cmdLine.addArg(linkOptions); } if (options.targetType == SLANG_SHADER_SHARED_LIBRARY) @@ -632,7 +672,7 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS { ComPtr fileRep; - // TODO(JS): + // TODO(JS): // Do we want to keep the file on the file system? It's probably reasonable to do so. SLANG_RETURN_ON_FAIL(sourceArtifact->requireFile(ArtifactKeep::Yes, fileRep.writeRef())); cmdLine.addArg(fileRep->getPath()); @@ -640,10 +680,9 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS // Add the library paths - if (options.libraryPaths.count && - (options.targetType == SLANG_HOST_EXECUTABLE)) + if (options.libraryPaths.count && (options.targetType == SLANG_HOST_EXECUTABLE)) { - if(PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) + if (PlatformUtil::isFamily(PlatformFamily::Apple, platformKind)) cmdLine.addArg("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib"); else cmdLine.addArg("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib"); @@ -661,7 +700,8 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS { const auto artifactDesc = artifact->getDesc(); // If it's a library for CPU types, try and use it - if (ArtifactDescUtil::isCpuBinary(artifactDesc) && artifactDesc.kind == ArtifactKind::Library) + if (ArtifactDescUtil::isCpuBinary(artifactDesc) && + artifactDesc.kind == ArtifactKind::Library) { ComPtr fileRep; @@ -670,12 +710,15 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS const UnownedStringSlice path(fileRep->getPath()); libPathPool.add(Path::getParentDirectory(path)); - - cmdLine.addPrefixPathArg("-l", ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); + + cmdLine.addPrefixPathArg( + "-l", + ArtifactDescUtil::getBaseNameFromPath(artifact->getDesc(), path)); } } - if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind)) + if (options.sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && + !PlatformUtil::isFamily(PlatformFamily::Windows, platformKind)) { // Make STD libs available cmdLine.addArg("-lstdc++"); @@ -695,7 +738,9 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::createCompiler(const ExecutableLocation& exe, ComPtr& outCompiler) +/* static */ SlangResult GCCDownstreamCompilerUtil::createCompiler( + const ExecutableLocation& exe, + ComPtr& outCompiler) { DownstreamCompilerDesc desc; SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::calcVersion(exe, desc)); @@ -708,7 +753,10 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::locateGCCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult GCCDownstreamCompilerUtil::locateGCCCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { SLANG_UNUSED(loader); @@ -717,10 +765,10 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS { // A downstream compiler for Slang must currently support C++17 - such that // the prelude and generated code works. - // + // // The first version of gcc that supports stable `-std=c++17` is 9.0 // https://gcc.gnu.org/projects/cxx-status.html - + auto desc = compiler->getDesc(); if (desc.version.m_major < 9) { @@ -733,7 +781,10 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -/* static */SlangResult GCCDownstreamCompilerUtil::locateClangCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult GCCDownstreamCompilerUtil::locateClangCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { SLANG_UNUSED(loader); @@ -745,4 +796,4 @@ static SlangResult _parseGCCFamilyLine(SliceAllocator& allocator, const UnownedS return SLANG_OK; } -} +} // namespace Slang diff --git a/source/compiler-core/slang-gcc-compiler-util.h b/source/compiler-core/slang-gcc-compiler-util.h index 6afb39ec6f..e15701f94a 100644 --- a/source/compiler-core/slang-gcc-compiler-util.h +++ b/source/compiler-core/slang-gcc-compiler-util.h @@ -9,30 +9,46 @@ namespace Slang /* Utility for processing input and output of gcc-like compilers, including clang */ struct GCCDownstreamCompilerUtil : public DownstreamCompilerUtilBase { - /// Extracts version number into desc from text (assumes gcc/clang -v layout with a line with version) - static SlangResult parseVersion(const UnownedStringSlice& text, const UnownedStringSlice& prefix, DownstreamCompilerDesc& outDesc); + /// Extracts version number into desc from text (assumes gcc/clang -v layout with a line with + /// version) + static SlangResult parseVersion( + const UnownedStringSlice& text, + const UnownedStringSlice& prefix, + DownstreamCompilerDesc& outDesc); - /// Runs the exe, and extracts the version info into outDesc + /// Runs the exe, and extracts the version info into outDesc static SlangResult calcVersion(const ExecutableLocation& exe, DownstreamCompilerDesc& outDesc); - /// Calculate gcc family compilers (including clang) cmdLine arguments from options + /// Calculate gcc family compilers (including clang) cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); - /// Parse ExecuteResult into diagnostics + /// Parse ExecuteResult into diagnostics static SlangResult parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics); - /// Given options, calculate paths to products/files produced for a compilation - static SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts); + /// Given options, calculate paths to products/files produced for a compilation + static SlangResult calcCompileProducts( + const CompileOptions& options, + ProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts); - /// Given the exe location, creates a DownstreamCompiler. - /// Note! Invoke/s the compiler to determine the compiler version number. - static SlangResult createCompiler(const ExecutableLocation& exe, ComPtr& outCompiler); + /// Given the exe location, creates a DownstreamCompiler. + /// Note! Invoke/s the compiler to determine the compiler version number. + static SlangResult createCompiler( + const ExecutableLocation& exe, + ComPtr& outCompiler); - /// Finds GCC compiler/s and adds them to the set - static SlangResult locateGCCCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + /// Finds GCC compiler/s and adds them to the set + static SlangResult locateGCCCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); - /// Finds clang compiler/s and adds them to the set - static SlangResult locateClangCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + /// Finds clang compiler/s and adds them to the set + static SlangResult locateClangCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; class GCCDownstreamCompiler : public CommandLineDownstreamCompiler @@ -42,13 +58,31 @@ class GCCDownstreamCompiler : public CommandLineDownstreamCompiler typedef GCCDownstreamCompilerUtil Util; // CommandLineCPPCompiler impl - just forwards to the Util - virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE { return Util::parseOutput(exeResult, diagnostics); } - virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) SLANG_OVERRIDE { return Util::calcCompileProducts(options, flags, lockFile, outArtifacts); } + virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE + { + return Util::calcArgs(options, cmdLine); + } + virtual SlangResult parseOutput( + const ExecuteResult& exeResult, + IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE + { + return Util::parseOutput(exeResult, diagnostics); + } + virtual SlangResult calcCompileProducts( + const CompileOptions& options, + DownstreamProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) SLANG_OVERRIDE + { + return Util::calcCompileProducts(options, flags, lockFile, outArtifacts); + } - GCCDownstreamCompiler(const Desc& desc):Super(desc) {} + GCCDownstreamCompiler(const Desc& desc) + : Super(desc) + { + } }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-glslang-compiler.cpp b/source/compiler-core/slang-glslang-compiler.cpp index 9ef8e7fb4c..5550ac8ade 100644 --- a/source/compiler-core/slang-glslang-compiler.cpp +++ b/source/compiler-core/slang-glslang-compiler.cpp @@ -1,35 +1,28 @@ // slang-glslang-compiler.cpp #include "slang-glslang-compiler.h" -#include "../core/slang-common.h" -#include "slang-com-helper.h" - #include "../core/slang-blob.h" - -#include "../core/slang-string-util.h" -#include "../core/slang-string-slice-pool.h" - +#include "../core/slang-char-util.h" +#include "../core/slang-common.h" #include "../core/slang-io.h" -#include "../core/slang-shared-library.h" #include "../core/slang-semantic-version.h" -#include "../core/slang-char-util.h" - +#include "../core/slang-shared-library.h" +#include "../core/slang-string-slice-pool.h" +#include "../core/slang-string-util.h" #include "slang-artifact-associated-impl.h" #include "slang-artifact-desc-util.h" - +#include "slang-com-helper.h" #include "slang-include-system.h" #include "slang-source-loc.h" -#include "../core/slang-shared-library.h" - // Enable calling through to `glslang` on // all platforms. #ifndef SLANG_ENABLE_GLSLANG_SUPPORT -# define SLANG_ENABLE_GLSLANG_SUPPORT 1 +#define SLANG_ENABLE_GLSLANG_SUPPORT 1 #endif #if SLANG_ENABLE_GLSLANG_SUPPORT -# include "../slang-glslang/slang-glslang.h" +#include "../slang-glslang/slang-glslang.h" #endif namespace Slang @@ -43,24 +36,31 @@ class GlslangDownstreamCompiler : public DownstreamCompilerBase typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outResult) SLANG_OVERRIDE; - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outResult) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } - virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) + SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + validate(const uint32_t* contents, int contentsSize) SLANG_OVERRIDE; - /// Must be called before use + /// Must be called before use SlangResult init(ISlangSharedLibrary* library); - GlslangDownstreamCompiler(SlangPassThrough compilerType) : m_compilerType(compilerType) {} - -protected: + GlslangDownstreamCompiler(SlangPassThrough compilerType) + : m_compilerType(compilerType) + { + } +protected: SlangResult _invoke(glslang_CompileRequest_1_2& request); - glslang_CompileFunc_1_0 m_compile_1_0 = nullptr; - glslang_CompileFunc_1_1 m_compile_1_1 = nullptr; + glslang_CompileFunc_1_0 m_compile_1_0 = nullptr; + glslang_CompileFunc_1_1 m_compile_1_1 = nullptr; glslang_CompileFunc_1_2 m_compile_1_2 = nullptr; glslang_ValidateSPIRVFunc m_validate = nullptr; @@ -135,7 +135,11 @@ SlangResult GlslangDownstreamCompiler::_invoke(glslang_CompileRequest_1_2& reque return err ? SLANG_FAIL : SLANG_OK; } -static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const UnownedStringSlice& line, List& lineSlices, ArtifactDiagnostic& outDiagnostic) +static SlangResult _parseDiagnosticLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + List& lineSlices, + ArtifactDiagnostic& outDiagnostic) { /* ERROR: tests/diagnostics/syntax-error-intrinsic.slang:13: '@' : unexpected token */ @@ -160,7 +164,9 @@ static SlangResult _parseDiagnosticLine(SliceAllocator& allocator, const Unowned return SLANG_OK; } -SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, IArtifact** outArtifact) +SlangResult GlslangDownstreamCompiler::compile( + const CompileOptions& inOptions, + IArtifact** outArtifact) { if (!isVersionCompatible(inOptions)) { @@ -186,14 +192,10 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, StringBuilder diagnosticOutput; auto diagnosticOutputFunc = [](void const* data, size_t size, void* userData) - { - (*(StringBuilder*)userData).append((char const*)data, (char const*)data + size); - }; + { (*(StringBuilder*)userData).append((char const*)data, (char const*)data + size); }; List spirv; auto outputFunc = [](void const* data, size_t size, void* userData) - { - ((List*)userData)->addRange((uint8_t*)data, size); - }; + { ((List*)userData)->addRange((uint8_t*)data, size); }; ComPtr sourceBlob; SLANG_RETURN_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); @@ -270,7 +272,12 @@ SlangResult GlslangDownstreamCompiler::compile(const CompileOptions& inOptions, SliceAllocator allocator; - SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics(allocator, diagnosticOutput.getUnownedSlice(), 1, _parseDiagnosticLine, diagnostics); + SlangResult diagnosticParseRes = ArtifactDiagnosticUtil::parseColonDelimitedDiagnostics( + allocator, + diagnosticOutput.getUnownedSlice(), + 1, + _parseDiagnosticLine, + diagnostics); SLANG_UNUSED(diagnosticParseRes); diagnostics->requireErrorDiagnostic(); @@ -301,10 +308,15 @@ SlangResult GlslangDownstreamCompiler::validate(const uint32_t* contents, int co bool GlslangDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to) { // Can only disassemble blobs that are SPIR-V - return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::SPIRV; + return ArtifactDescUtil::isDisassembly(from, to) && + ((from.payload == ArtifactPayload::SPIRV) || + (from.payload == ArtifactPayload::WGSL_SPIRV)); } -SlangResult GlslangDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) +SlangResult GlslangDownstreamCompiler::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) { if (!canConvert(from->getDesc(), to)) { @@ -315,11 +327,9 @@ SlangResult GlslangDownstreamCompiler::convert(IArtifact* from, const ArtifactDe SLANG_RETURN_ON_FAIL(from->loadBlob(ArtifactKeep::No, blob.writeRef())); StringBuilder builder; - + auto outputFunc = [](void const* data, size_t size, void* userData) - { - (*(StringBuilder*)userData).append((char const*)data, (char const*)data + size); - }; + { (*(StringBuilder*)userData).append((char const*)data, (char const*)data + size); }; glslang_CompileRequest_1_2 request; memset(&request, 0, sizeof(request)); @@ -364,14 +374,18 @@ SlangResult GlslangDownstreamCompiler::getVersionString(slang::IBlob** outVersio { return SLANG_FAIL; } - + auto timestampString = String(timestamp); ComPtr version = StringBlob::create(timestampString.getBuffer()); *outVersionString = version.detach(); return SLANG_OK; } -static SlangResult locateGlslangSpirvDownstreamCompiler(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set, SlangPassThrough compilerType) +static SlangResult locateGlslangSpirvDownstreamCompiler( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set, + SlangPassThrough compilerType) { ComPtr library; @@ -379,18 +393,23 @@ static SlangResult locateGlslangSpirvDownstreamCompiler(const String& path, ISla // On unix systems we need to ensure pthread is loaded first. // TODO(JS): // There is an argument that this should be performed through the loader.... - // NOTE! We don't currently load through a dependent library, as it is *assumed* something as core as 'ptheads' - // isn't going to be distributed with the shader compiler. + // NOTE! We don't currently load through a dependent library, as it is *assumed* something as + // core as 'ptheads' isn't going to be distributed with the shader compiler. ComPtr pthreadLibrary; DefaultSharedLibraryLoader::load(loader, path, "pthread", pthreadLibrary.writeRef()); if (!pthreadLibrary.get()) { - DefaultSharedLibraryLoader::load(loader, path, "libpthread.so.0", pthreadLibrary.writeRef()); + DefaultSharedLibraryLoader::load( + loader, + path, + "libpthread.so.0", + pthreadLibrary.writeRef()); } #endif - SLANG_RETURN_ON_FAIL(DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-glslang", library)); + SLANG_RETURN_ON_FAIL( + DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-glslang", library)); SLANG_ASSERT(library); if (!library) @@ -406,24 +425,36 @@ static SlangResult locateGlslangSpirvDownstreamCompiler(const String& path, ISla return SLANG_OK; } -SlangResult GlslangDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +SlangResult GlslangDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_GLSLANG); } -SlangResult SpirvOptDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +SlangResult SpirvOptDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_OPT); } -SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { return locateGlslangSpirvDownstreamCompiler(path, loader, set, SLANG_PASS_THROUGH_SPIRV_DIS); } #else // SLANG_ENABLE_GLSLANG_SUPPORT -/* static */SlangResult GlslangDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult GlslangDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { SLANG_UNUSED(path); SLANG_UNUSED(loader); @@ -433,4 +464,4 @@ SlangResult SpirvDisDownstreamCompilerUtil::locateCompilers(const String& path, #endif // SLANG_ENABLE_GLSLANG_SUPPORT -} +} // namespace Slang diff --git a/source/compiler-core/slang-glslang-compiler.h b/source/compiler-core/slang-glslang-compiler.h index 577bcaacca..73cc611357 100644 --- a/source/compiler-core/slang-glslang-compiler.h +++ b/source/compiler-core/slang-glslang-compiler.h @@ -1,29 +1,37 @@ #ifndef SLANG_GLSLANG_COMPILER_UTIL_H #define SLANG_GLSLANG_COMPILER_UTIL_H -#include "slang-downstream-compiler-util.h" - #include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" namespace Slang { struct GlslangDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; struct SpirvOptDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; struct SpirvDisDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-include-system.cpp b/source/compiler-core/slang-include-system.cpp index 1b768d506d..4ee742136a 100644 --- a/source/compiler-core/slang-include-system.cpp +++ b/source/compiler-core/slang-include-system.cpp @@ -1,26 +1,31 @@ // slang-include-system.cpp #include "slang-include-system.h" +#include "../core/slang-file-system.h" #include "../core/slang-io.h" #include "../core/slang-string-util.h" - -#include "../core/slang-file-system.h" - -#include "slang-slice-allocator.h" #include "slang-artifact-impl.h" #include "slang-artifact-representation-impl.h" +#include "slang-slice-allocator.h" namespace Slang { -IncludeSystem::IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager) : - m_searchDirectories(searchDirectories), - m_fileSystemExt(fileSystemExt), - m_sourceManager(sourceManager) +IncludeSystem::IncludeSystem( + SearchDirectoryList* searchDirectories, + ISlangFileSystemExt* fileSystemExt, + SourceManager* sourceManager) + : m_searchDirectories(searchDirectories) + , m_fileSystemExt(fileSystemExt) + , m_sourceManager(sourceManager) { } -SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo) +SlangResult IncludeSystem::findFile( + SlangPathType fromPathType, + const String& fromPath, + const String& path, + PathInfo& outPathInfo) { String combinedPath; @@ -33,7 +38,11 @@ SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fr { // Get relative path ComPtr combinedPathBlob; - SLANG_RETURN_ON_FAIL(m_fileSystemExt->calcCombinedPath(fromPathType, fromPath.begin(), path.begin(), combinedPathBlob.writeRef())); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->calcCombinedPath( + fromPathType, + fromPath.begin(), + path.begin(), + combinedPathBlob.writeRef())); combinedPath = StringUtil::getString(combinedPathBlob); if (combinedPath.getLength() <= 0) { @@ -51,7 +60,9 @@ SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fr // Get the uniqueIdentity ComPtr uniqueIdentityBlob; - SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity(combinedPath.begin(), uniqueIdentityBlob.writeRef())); + SLANG_RETURN_ON_FAIL(m_fileSystemExt->getFileUniqueIdentity( + combinedPath.begin(), + uniqueIdentityBlob.writeRef())); // If the rel path exists -> a uniqueIdentity MUST exists too String uniqueIdentity(StringUtil::getString(uniqueIdentityBlob)); @@ -68,14 +79,20 @@ SlangResult IncludeSystem::findFile(SlangPathType fromPathType, const String& fr String IncludeSystem::simplifyPath(const String& path) { ComPtr simplifiedPath; - if (SLANG_FAILED(m_fileSystemExt->getPath(PathKind::Simplified, path.getBuffer(), simplifiedPath.writeRef()))) + if (SLANG_FAILED(m_fileSystemExt->getPath( + PathKind::Simplified, + path.getBuffer(), + simplifiedPath.writeRef()))) { return path; } return StringUtil::getString(simplifiedPath); } -SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& pathIncludedFrom, PathInfo& outPathInfo) +SlangResult IncludeSystem::findFile( + String const& pathToInclude, + String const& pathIncludedFrom, + PathInfo& outPathInfo) { outPathInfo.type = PathInfo::Type::Unknown; @@ -84,12 +101,17 @@ SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& p { // We pass in "" as the from path, so ensure no from path is taken into account // and to allow easy identification that this is in effect absolute - return findFile(SLANG_PATH_TYPE_DIRECTORY, UnownedStringSlice::fromLiteral(""), pathToInclude, outPathInfo); + return findFile( + SLANG_PATH_TYPE_DIRECTORY, + UnownedStringSlice::fromLiteral(""), + pathToInclude, + outPathInfo); } // Try just relative to current path { - SlangResult res = findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, outPathInfo); + SlangResult res = + findFile(SLANG_PATH_TYPE_FILE, pathIncludedFrom, pathToInclude, outPathInfo); // It either succeeded or wasn't found, anything else is a failure passed back if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND) { @@ -102,7 +124,8 @@ SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& p { for (auto& dir : sd->searchDirectories) { - SlangResult res = findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, outPathInfo); + SlangResult res = + findFile(SLANG_PATH_TYPE_DIRECTORY, dir.path, pathToInclude, outPathInfo); if (SLANG_SUCCEEDED(res) || res != SLANG_E_NOT_FOUND) { return res; @@ -113,7 +136,10 @@ SlangResult IncludeSystem::findFile(String const& pathToInclude, String const& p return SLANG_E_NOT_FOUND; } -SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr& outBlob, SourceFile*& outSourceFile) +SlangResult IncludeSystem::loadFile( + const PathInfo& pathInfo, + ComPtr& outBlob, + SourceFile*& outSourceFile) { if (m_sourceManager) { @@ -124,7 +150,9 @@ SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr if (!outSourceFile) { ComPtr foundSourceBlob; - if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef()))) + if (SLANG_FAILED(m_fileSystemExt->loadFile( + pathInfo.foundPath.getBuffer(), + foundSourceBlob.writeRef()))) { return SLANG_E_CANNOT_OPEN; } @@ -144,7 +172,9 @@ SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr } ComPtr foundSourceBlob; - if (SLANG_FAILED(m_fileSystemExt->loadFile(pathInfo.foundPath.getBuffer(), foundSourceBlob.writeRef()))) + if (SLANG_FAILED(m_fileSystemExt->loadFile( + pathInfo.foundPath.getBuffer(), + foundSourceBlob.writeRef()))) { return SLANG_E_CANNOT_OPEN; } @@ -163,7 +193,11 @@ SlangResult IncludeSystem::loadFile(const PathInfo& pathInfo, ComPtr } } -SlangResult IncludeSystem::findAndLoadFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo, ComPtr& outBlob) +SlangResult IncludeSystem::findAndLoadFile( + const String& pathToInclude, + const String& pathIncludedFrom, + PathInfo& outPathInfo, + ComPtr& outBlob) { SLANG_RETURN_ON_FAIL(findFile(pathToInclude, pathIncludedFrom, outPathInfo)); SLANG_RETURN_ON_FAIL(loadFile(outPathInfo, outBlob)); diff --git a/source/compiler-core/slang-include-system.h b/source/compiler-core/slang-include-system.h index cc89985dd3..dbe3793bf7 100644 --- a/source/compiler-core/slang-include-system.h +++ b/source/compiler-core/slang-include-system.h @@ -14,7 +14,8 @@ struct SearchDirectory SearchDirectory(SearchDirectory const& other) = default; SearchDirectory(String const& path) : path(path) - {} + { + } SearchDirectory& operator=(SearchDirectory const& other) = default; String path; @@ -24,42 +25,60 @@ struct SearchDirectory struct SearchDirectoryList { // A parent list that should also be searched - SearchDirectoryList* parent = nullptr; + SearchDirectoryList* parent = nullptr; // Directories to be searched - List searchDirectories; + List searchDirectories; }; -/* A helper class that builds basic include handling on top of searchDirectories/fileSystemExt and optionally a sourceManager */ +/* A helper class that builds basic include handling on top of searchDirectories/fileSystemExt and + * optionally a sourceManager */ struct IncludeSystem { - SlangResult findFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo); - SlangResult findFile(SlangPathType fromPathType, const String& fromPath, const String& path, PathInfo& outPathInfo); + SlangResult findFile( + const String& pathToInclude, + const String& pathIncludedFrom, + PathInfo& outPathInfo); + SlangResult findFile( + SlangPathType fromPathType, + const String& fromPath, + const String& path, + PathInfo& outPathInfo); String simplifyPath(const String& path); - SlangResult loadFile(const PathInfo& pathInfo, ComPtr& outBlob, SourceFile*& outSourceFile); + SlangResult loadFile( + const PathInfo& pathInfo, + ComPtr& outBlob, + SourceFile*& outSourceFile); inline SlangResult loadFile(const PathInfo& pathInfo, ComPtr& outBlob) { SourceFile* sourceFile; return loadFile(pathInfo, outBlob, sourceFile); } - SlangResult findAndLoadFile(const String& pathToInclude, const String& pathIncludedFrom, PathInfo& outPathInfo, ComPtr& outBlob); + SlangResult findAndLoadFile( + const String& pathToInclude, + const String& pathIncludedFrom, + PathInfo& outPathInfo, + ComPtr& outBlob); SearchDirectoryList* getSearchDirectoryList() const { return m_searchDirectories; } ISlangFileSystemExt* getFileSystem() const { return m_fileSystemExt; } SourceManager* getSourceManager() const { return m_sourceManager; } - /// Ctor + /// Ctor IncludeSystem() = default; - IncludeSystem(SearchDirectoryList* searchDirectories, ISlangFileSystemExt* fileSystemExt, SourceManager* sourceManager = nullptr); + IncludeSystem( + SearchDirectoryList* searchDirectories, + ISlangFileSystemExt* fileSystemExt, + SourceManager* sourceManager = nullptr); protected: - SearchDirectoryList* m_searchDirectories; ISlangFileSystemExt* m_fileSystemExt; - SourceManager* m_sourceManager; ///< If not set, will not look up the content in the source manager + SourceManager* + m_sourceManager; ///< If not set, will not look up the content in the source manager }; -} +} // namespace Slang -#endif // SLANG_INCLUDE_HANDLER_H +#endif // SLANG_INCLUDE_HANDLER_H diff --git a/source/compiler-core/slang-json-diagnostic-defs.h b/source/compiler-core/slang-json-diagnostic-defs.h index 576f14beb6..2bc4c6a81b 100644 --- a/source/compiler-core/slang-json-diagnostic-defs.h +++ b/source/compiler-core/slang-json-diagnostic-defs.h @@ -14,7 +14,7 @@ // for any arguments. #ifndef DIAGNOSTIC -#error Need to #define DIAGNOSTIC(...) before including +#error Need to #define DIAGNOSTIC(...) before including #define DIAGNOSTIC(id, severity, name, messageFormat) /* */ #endif @@ -40,7 +40,11 @@ DIAGNOSTIC(20009, Error, unableToConvertField, "unable to convert field '$0' in DIAGNOSTIC(20010, Error, fieldNotFound, "field '$0' not found in type '$1'") DIAGNOSTIC(20011, Error, fieldNotDefinedOnType, "field '$0' not defined on type '$1'") DIAGNOSTIC(20011, Error, fieldRequiredOnType, "field '$0' required on '$1'") -DIAGNOSTIC(20012, Error, tooManyElementsForArray, "too many elements ($0) for array array. Max allowed is $1") +DIAGNOSTIC( + 20012, + Error, + tooManyElementsForArray, + "too many elements ($0) for array array. Max allowed is $1") // // 3xxxx JSON-RPC diff --git a/source/compiler-core/slang-json-diagnostics.cpp b/source/compiler-core/slang-json-diagnostics.cpp index 1d35e8faff..1dc30572e8 100644 --- a/source/compiler-core/slang-json-diagnostics.cpp +++ b/source/compiler-core/slang-json-diagnostics.cpp @@ -1,18 +1,19 @@ // slang-json-diagnostics.cpp #include "slang-json-diagnostics.h" -namespace Slang { +namespace Slang +{ namespace JSONDiagnostics { -#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, #name, messageFormat }; +#define DIAGNOSTIC(id, severity, name, messageFormat) \ + const DiagnosticInfo name = {id, Severity::severity, #name, messageFormat}; #include "slang-json-diagnostic-defs.h" #undef DIAGNOSTIC -} +} // namespace JSONDiagnostics -static const DiagnosticInfo* const kJSONDiagnostics[] = -{ -#define DIAGNOSTIC(id, severity, name, messageFormat) &JSONDiagnostics::name, +static const DiagnosticInfo* const kJSONDiagnostics[] = { +#define DIAGNOSTIC(id, severity, name, messageFormat) &JSONDiagnostics::name, #include "slang-json-diagnostic-defs.h" #undef DIAGNOSTIC }; diff --git a/source/compiler-core/slang-json-diagnostics.h b/source/compiler-core/slang-json-diagnostics.h index d819d89476..183178d2be 100644 --- a/source/compiler-core/slang-json-diagnostics.h +++ b/source/compiler-core/slang-json-diagnostics.h @@ -3,11 +3,9 @@ #include "../core/slang-basic.h" #include "../core/slang-writer.h" - -#include "slang-source-loc.h" #include "slang-diagnostic-sink.h" +#include "slang-source-loc.h" #include "slang-token.h" - #include "slang.h" namespace Slang @@ -19,8 +17,8 @@ namespace JSONDiagnostics { #define DIAGNOSTIC(id, severity, name, messageFormat) extern const DiagnosticInfo name; #include "slang-json-diagnostic-defs.h" -} +} // namespace JSONDiagnostics -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-json-lexer.cpp b/source/compiler-core/slang-json-lexer.cpp index a335403e1b..7f1499a216 100644 --- a/source/compiler-core/slang-json-lexer.cpp +++ b/source/compiler-core/slang-json-lexer.cpp @@ -1,16 +1,17 @@ // slang-json-lexer.cpp #include "slang-json-lexer.h" -#include "slang-json-diagnostics.h" #include "../core/slang-char-util.h" +#include "slang-json-diagnostics.h" /* https://www.json.org/json-en.html */ -namespace Slang { +namespace Slang +{ -/* static */UnownedStringSlice JSONLexer::calcLexemeLocation(const UnownedStringSlice& text) +/* static */ UnownedStringSlice JSONLexer::calcLexemeLocation(const UnownedStringSlice& text) { SourceManager sourceManager; sourceManager.initialize(nullptr, nullptr); @@ -18,7 +19,8 @@ namespace Slang { sink.init(&sourceManager, nullptr); String contents(text); - SourceFile* sourceFile = sourceManager.createSourceFileWithString(PathInfo::makeUnknown(), contents); + SourceFile* sourceFile = + sourceManager.createSourceFileWithString(PathInfo::makeUnknown(), contents); SourceView* sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc()); JSONLexer lexer; @@ -38,7 +40,7 @@ namespace Slang { } } -SlangResult JSONLexer::init(SourceView* sourceView, DiagnosticSink* sink) +SlangResult JSONLexer::init(SourceView* sourceView, DiagnosticSink* sink) { m_sourceView = sourceView; m_sink = sink; @@ -77,7 +79,11 @@ SlangResult JSONLexer::expect(JSONTokenType type) { if (type != peekType()) { - m_sink->diagnose(m_token.loc, JSONDiagnostics::unexpectedTokenExpectedTokenType, getJSONTokenAsText(peekType()), getJSONTokenAsText(type)); + m_sink->diagnose( + m_token.loc, + JSONDiagnostics::unexpectedTokenExpectedTokenType, + getJSONTokenAsText(peekType()), + getJSONTokenAsText(type)); return SLANG_FAIL; } @@ -89,7 +95,11 @@ SlangResult JSONLexer::expect(JSONTokenType type, JSONToken& out) { if (type != peekType()) { - m_sink->diagnose(m_token.loc, JSONDiagnostics::unexpectedTokenExpectedTokenType, getJSONTokenAsText(peekType()), getJSONTokenAsText(type)); + m_sink->diagnose( + m_token.loc, + JSONDiagnostics::unexpectedTokenExpectedTokenType, + getJSONTokenAsText(peekType()), + getJSONTokenAsText(type)); return SLANG_FAIL; } @@ -137,8 +147,9 @@ JSONTokenType JSONLexer::advance() switch (c) { - case 0: return _setToken(JSONTokenType::EndOfFile, cursor - 1); - case '"': + case 0: + return _setToken(JSONTokenType::EndOfFile, cursor - 1); + case '"': { cursor = _lexString(cursor); if (cursor == nullptr) @@ -147,7 +158,7 @@ JSONTokenType JSONLexer::advance() } return _setToken(JSONTokenType::StringLiteral, cursor); } - case '/': + case '/': { // We allow comments const char nextChar = *m_cursor; @@ -160,7 +171,7 @@ JSONTokenType JSONLexer::advance() else if (nextChar == '*') { cursor = _lexBlockComment(cursor); - // Can fail... + // Can fail... if (cursor == nullptr) { return _setInvalidToken(); @@ -172,32 +183,38 @@ JSONTokenType JSONLexer::advance() } break; } - case ' ': - case '\t': - case '\n': - case '\r': + case ' ': + case '\t': + case '\n': + case '\r': { cursor = _lexWhitespace(cursor); break; } - case ':': return _setToken(JSONTokenType::Colon, cursor); - case ',': return _setToken(JSONTokenType::Comma, cursor); - case '[': return _setToken(JSONTokenType::LBracket, cursor); - case ']': return _setToken(JSONTokenType::RBracket, cursor); - case '{': return _setToken(JSONTokenType::LBrace, cursor); - case '}': return _setToken(JSONTokenType::RBrace, cursor); - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': + case ':': + return _setToken(JSONTokenType::Colon, cursor); + case ',': + return _setToken(JSONTokenType::Comma, cursor); + case '[': + return _setToken(JSONTokenType::LBracket, cursor); + case ']': + return _setToken(JSONTokenType::RBracket, cursor); + case '{': + return _setToken(JSONTokenType::LBrace, cursor); + case '}': + return _setToken(JSONTokenType::RBrace, cursor); + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': { LexResult res = _lexNumber(cursor - 1); if (res.cursor == nullptr) @@ -206,7 +223,7 @@ JSONTokenType JSONLexer::advance() } return _setToken(res.type, res.cursor); } - case 't': + case 't': { if (cursor[0] == 'r' && cursor[1] == 'u' && cursor[2] == 'e') { @@ -215,7 +232,7 @@ JSONTokenType JSONLexer::advance() m_sink->diagnose(_getLoc(m_lexemeStart), JSONDiagnostics::expectingValueName); return _setInvalidToken(); } - case 'f': + case 'f': { if (cursor[0] == 'a' && cursor[1] == 'l' && cursor[2] == 's' && cursor[3] == 'e') { @@ -224,7 +241,7 @@ JSONTokenType JSONLexer::advance() m_sink->diagnose(_getLoc(m_lexemeStart), JSONDiagnostics::expectingValueName); return _setInvalidToken(); } - case 'n': + case 'n': { if (cursor[0] == 'u' && cursor[1] == 'l' && cursor[2] == 'l') { @@ -233,7 +250,7 @@ JSONTokenType JSONLexer::advance() m_sink->diagnose(_getLoc(m_lexemeStart), JSONDiagnostics::expectingValueName); return _setInvalidToken(); } - default: + default: { StringBuilder buf; if (c <= ' ' || c >= 0x7e) @@ -241,7 +258,7 @@ JSONTokenType JSONLexer::advance() static const char s_hex[] = "0123456789abcdef"; char hexBuf[5] = "0x"; - + uint32_t value = c; hexBuf[2] = s_hex[((value >> 4) & 0xf)]; hexBuf[3] = s_hex[(value & 0xf)]; @@ -294,12 +311,13 @@ JSONLexer::LexResult JSONLexer::_lexNumber(const char* cursor) if (!CharUtil::isDigit(*cursor)) { m_sink->diagnose(_getLoc(cursor), JSONDiagnostics::expectingADigit); - return LexResult{ JSONTokenType::Invalid, nullptr }; + return LexResult{JSONTokenType::Invalid, nullptr}; } // Skip the digit cursor++; // Skip any more digits - while (CharUtil::isDigit(*cursor)) cursor++; + while (CharUtil::isDigit(*cursor)) + cursor++; } // Theres an exponent @@ -320,13 +338,14 @@ JSONLexer::LexResult JSONLexer::_lexNumber(const char* cursor) if (!CharUtil::isDigit(*cursor)) { m_sink->diagnose(_getLoc(cursor), JSONDiagnostics::expectingADigit); - return LexResult{ JSONTokenType::Invalid, nullptr }; + return LexResult{JSONTokenType::Invalid, nullptr}; } // Skip the digit cursor++; // Skip any more digits - while (CharUtil::isDigit(*cursor)) cursor++; + while (CharUtil::isDigit(*cursor)) + cursor++; } return LexResult{tokenType, cursor}; @@ -341,40 +360,42 @@ const char* JSONLexer::_lexString(const char* cursor) switch (c) { - case 0: + case 0: { m_sink->diagnose(_getLoc(cursor - 1), JSONDiagnostics::endOfFileInLiteral); return nullptr; } - case '"': + case '"': { return cursor; } - case '\\': + case '\\': { const char nextC = *cursor; switch (nextC) { - case '"': - case '\\': - case '/': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': + case '"': + case '\\': + case '/': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': { ++cursor; break; } - case 'u': + case 'u': { cursor++; for (Index i = 0; i < 4; ++i) { if (!CharUtil::isHexDigit(cursor[i])) { - m_sink->diagnose(_getLoc(cursor), JSONDiagnostics::expectingAHexDigit); + m_sink->diagnose( + _getLoc(cursor), + JSONDiagnostics::expectingAHexDigit); return nullptr; } } @@ -382,10 +403,10 @@ const char* JSONLexer::_lexString(const char* cursor) break; } } - } - // Somewhat surprisingly it appears it's valid to have \r\n inside of quotes. - default: break; + // Somewhat surprisingly it appears it's valid to have \r\n inside of quotes. + default: + break; } } } @@ -398,13 +419,13 @@ const char* JSONLexer::_lexLineComment(const char* cursor) switch (c) { - case '\n': - case '\r': + case '\n': + case '\r': { // We need to skip to the next line return _handleEndOfLine(c, cursor); } - case 0: + case 0: { return cursor - 1; } @@ -419,12 +440,12 @@ const char* JSONLexer::_lexBlockComment(const char* cursor) const char c = *cursor++; switch (c) { - case 0: + case 0: { m_sink->diagnose(_getLoc(cursor), JSONDiagnostics::endOfFileInComment); return nullptr; } - case '*': + case '*': { if (*cursor == '/') { @@ -432,7 +453,8 @@ const char* JSONLexer::_lexBlockComment(const char* cursor) } break; } - default: break; + default: + break; } } } @@ -447,21 +469,20 @@ const char* JSONLexer::_lexWhitespace(const char* cursor) switch (c) { - case ' ': - case '\n': - case '\r': - case '\t': + case ' ': + case '\n': + case '\r': + case '\t': { cursor++; break; } - default: + default: { // Hit non white space return cursor; } } - } } @@ -469,21 +490,36 @@ UnownedStringSlice getJSONTokenAsText(JSONTokenType type) { switch (type) { - case JSONTokenType::Invalid: return UnownedStringSlice::fromLiteral("invalid"); - case JSONTokenType::IntegerLiteral: return UnownedStringSlice::fromLiteral("integer literal"); - case JSONTokenType::FloatLiteral: return UnownedStringSlice::fromLiteral("float literal"); - case JSONTokenType::StringLiteral: return UnownedStringSlice::fromLiteral("string literal"); - case JSONTokenType::LBracket: return UnownedStringSlice::fromLiteral("["); - case JSONTokenType::RBracket: return UnownedStringSlice::fromLiteral("]"); - case JSONTokenType::LBrace: return UnownedStringSlice::fromLiteral("{"); - case JSONTokenType::RBrace: return UnownedStringSlice::fromLiteral("}"); - case JSONTokenType::Comma: return UnownedStringSlice::fromLiteral(","); - case JSONTokenType::Colon: return UnownedStringSlice::fromLiteral(":"); - case JSONTokenType::True: return UnownedStringSlice::fromLiteral("true"); - case JSONTokenType::False: return UnownedStringSlice::fromLiteral("false"); - case JSONTokenType::Null: return UnownedStringSlice::fromLiteral("null"); - case JSONTokenType::EndOfFile: return UnownedStringSlice::fromLiteral("end of file"); - default: break; + case JSONTokenType::Invalid: + return UnownedStringSlice::fromLiteral("invalid"); + case JSONTokenType::IntegerLiteral: + return UnownedStringSlice::fromLiteral("integer literal"); + case JSONTokenType::FloatLiteral: + return UnownedStringSlice::fromLiteral("float literal"); + case JSONTokenType::StringLiteral: + return UnownedStringSlice::fromLiteral("string literal"); + case JSONTokenType::LBracket: + return UnownedStringSlice::fromLiteral("["); + case JSONTokenType::RBracket: + return UnownedStringSlice::fromLiteral("]"); + case JSONTokenType::LBrace: + return UnownedStringSlice::fromLiteral("{"); + case JSONTokenType::RBrace: + return UnownedStringSlice::fromLiteral("}"); + case JSONTokenType::Comma: + return UnownedStringSlice::fromLiteral(","); + case JSONTokenType::Colon: + return UnownedStringSlice::fromLiteral(":"); + case JSONTokenType::True: + return UnownedStringSlice::fromLiteral("true"); + case JSONTokenType::False: + return UnownedStringSlice::fromLiteral("false"); + case JSONTokenType::Null: + return UnownedStringSlice::fromLiteral("null"); + case JSONTokenType::EndOfFile: + return UnownedStringSlice::fromLiteral("end of file"); + default: + break; } SLANG_UNEXPECTED("JSONTokenType not known"); } diff --git a/source/compiler-core/slang-json-lexer.h b/source/compiler-core/slang-json-lexer.h index 6e4a42a323..cee97ae040 100644 --- a/source/compiler-core/slang-json-lexer.h +++ b/source/compiler-core/slang-json-lexer.h @@ -3,11 +3,11 @@ #define SLANG_JSON_LEXER_H #include "../core/slang-basic.h" - -#include "slang-source-loc.h" #include "slang-diagnostic-sink.h" +#include "slang-source-loc.h" -namespace Slang { +namespace Slang +{ enum class JSONTokenType { @@ -30,9 +30,9 @@ enum class JSONTokenType struct JSONToken { - JSONTokenType type; ///< The token type - SourceLoc loc; ///< Location in the source file - uint32_t length; ///< The length of the token in bytes + JSONTokenType type; ///< The token type + SourceLoc loc; ///< Location in the source file + uint32_t length; ///< The length of the token in bytes }; UnownedStringSlice getJSONTokenAsText(JSONTokenType type); @@ -40,33 +40,34 @@ UnownedStringSlice getJSONTokenAsText(JSONTokenType type); class JSONLexer { public: - /// Peek the current token + /// Peek the current token JSONToken& peekToken() { return m_token; } - /// Peek the current type + /// Peek the current type JSONTokenType peekType() { return m_token.type; } - /// Peek the current SourceLoc + /// Peek the current SourceLoc SourceLoc peekLoc() { return m_token.loc; } - /// Get the lexeme of JSONToken + /// Get the lexeme of JSONToken UnownedStringSlice getLexeme(const JSONToken& tok) const; - /// Peek the lexeme at the current position + /// Peek the lexeme at the current position UnownedStringSlice peekLexeme() const { return getLexeme(m_token); } - + JSONTokenType advance(); - /// Expects a token of type type. If found advances, if not returns an error and outputs to diagnostic sink + /// Expects a token of type type. If found advances, if not returns an error and outputs to + /// diagnostic sink SlangResult expect(JSONTokenType type); - /// Same as expect except out will hold the token. + /// Same as expect except out will hold the token. SlangResult expect(JSONTokenType type, JSONToken& out); - /// Returns true and advances if current token is type + /// Returns true and advances if current token is type bool advanceIf(JSONTokenType type); bool advanceIf(JSONTokenType type, JSONToken& out); - /// Must be called before use + /// Must be called before use SlangResult init(SourceView* sourceView, DiagnosticSink* sink); - /// Determines the first token from text. Useful for diagnostics on DiagnosticSink + /// Determines the first token from text. Useful for diagnostics on DiagnosticSink static UnownedStringSlice calcLexemeLocation(const UnownedStringSlice& text); protected: @@ -76,8 +77,11 @@ class JSONLexer const char* cursor; }; - /// Get the location of the cursor - SLANG_FORCE_INLINE SourceLoc _getLoc(const char* cursor) const { return m_startLoc + (cursor - m_contentStart); } + /// Get the location of the cursor + SLANG_FORCE_INLINE SourceLoc _getLoc(const char* cursor) const + { + return m_startLoc + (cursor - m_contentStart); + } const char* _lexLineComment(const char* cursor); const char* _lexBlockComment(const char* cursor); const char* _lexWhitespace(const char* cursor); diff --git a/source/compiler-core/slang-json-native.cpp b/source/compiler-core/slang-json-native.cpp index eb0f7d9ee7..1f9a4dbc67 100644 --- a/source/compiler-core/slang-json-native.cpp +++ b/source/compiler-core/slang-json-native.cpp @@ -1,14 +1,13 @@ #include "slang-json-native.h" -#include "slang-com-helper.h" - #include "../core/slang-rtti-util.h" - +#include "slang-com-helper.h" #include "slang-json-diagnostics.h" -namespace Slang { +namespace Slang +{ -/* static */RttiTypeFuncsMap JSONNativeUtil::getTypeFuncsMap() +/* static */ RttiTypeFuncsMap JSONNativeUtil::getTypeFuncsMap() { RttiTypeFuncsMap typeMap; typeMap.add(GetRttiInfo::get(), GetRttiTypeFuncsForZeroPod::getFuncs()); @@ -17,7 +16,7 @@ namespace Slang { /* !!!!!!!!!!!!!!!!!!!!!!!!!!!! JSONToNativeConverter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */Index JSONToNativeConverter::_getFieldCount(const StructRttiInfo* structRttiInfo) +/* static */ Index JSONToNativeConverter::_getFieldCount(const StructRttiInfo* structRttiInfo) { if (structRttiInfo->m_super) { @@ -29,7 +28,9 @@ namespace Slang { } } -/* static */Index JSONToNativeConverter::_findFieldIndex(const StructRttiInfo* structRttiInfo, const UnownedStringSlice& fieldName) +/* static */ Index JSONToNativeConverter::_findFieldIndex( + const StructRttiInfo* structRttiInfo, + const UnownedStringSlice& fieldName) { if (structRttiInfo->m_super) { @@ -40,9 +41,13 @@ namespace Slang { } } - ConstArrayView fields(structRttiInfo->m_fields, structRttiInfo->m_fieldCount); + ConstArrayView fields( + structRttiInfo->m_fields, + structRttiInfo->m_fieldCount); - Index index = fields.findFirstIndex([fieldName](const StructRttiInfo::Field& field) ->bool { return fieldName == field.m_name; }); + Index index = fields.findFirstIndex( + [fieldName](const StructRttiInfo::Field& field) -> bool + { return fieldName == field.m_name; }); if (index >= 0 && structRttiInfo->m_super) { index += _getFieldCount(structRttiInfo->m_super); @@ -51,7 +56,11 @@ namespace Slang { return index; } -SlangResult JSONToNativeConverter::_structToNative(const ConstArrayView& pairs, const StructRttiInfo* structRttiInfo, void* out, Index& outFieldCount) +SlangResult JSONToNativeConverter::_structToNative( + const ConstArrayView& pairs, + const StructRttiInfo* structRttiInfo, + void* out, + Index& outFieldCount) { Index fieldCount = 0; @@ -77,14 +86,19 @@ SlangResult JSONToNativeConverter::_structToNative(const ConstArrayViewdiagnose(SourceLoc(), JSONDiagnostics::fieldRequiredOnType, field.m_name, structRttiInfo->m_name); + m_sink->diagnose( + SourceLoc(), + JSONDiagnostics::fieldRequiredOnType, + field.m_name, + structRttiInfo->m_name); // Unable to find this key return SLANG_FAIL; } // If there are any of the pairs, that are not in the type.. it's an error - const Index index = pairs.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); + const Index index = pairs.findFirstIndex( + [key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); if (index < 0) { if (field.m_flags & StructRttiInfo::Flag::Optional) @@ -92,7 +106,11 @@ SlangResult JSONToNativeConverter::_structToNative(const ConstArrayViewdiagnose(SourceLoc(), JSONDiagnostics::fieldRequiredOnType, field.m_name, structRttiInfo->m_name); + m_sink->diagnose( + SourceLoc(), + JSONDiagnostics::fieldRequiredOnType, + field.m_name, + structRttiInfo->m_name); // Unable to find this key return SLANG_FAIL; @@ -107,7 +125,7 @@ SlangResult JSONToNativeConverter::_structToNative(const ConstArrayViewm_kind) { - case RttiInfo::Kind::Bool: + case RttiInfo::Kind::Bool: { *(bool*)out = m_container->asBool(in); return SLANG_OK; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { if (in.getKind() != JSONValue::Kind::Object) { @@ -150,38 +168,44 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* for (auto& pair : pairs) { UnownedStringSlice fieldName = m_container->getStringFromKey(pair.key); - const Index index = _findFieldIndex(structRttiInfo, UnownedStringSlice(fieldName)); + const Index index = + _findFieldIndex(structRttiInfo, UnownedStringSlice(fieldName)); if (index < 0) { - m_sink->diagnose(pair.keyLoc, JSONDiagnostics::fieldNotDefinedOnType, fieldName, structRttiInfo->m_name); + m_sink->diagnose( + pair.keyLoc, + JSONDiagnostics::fieldNotDefinedOnType, + fieldName, + structRttiInfo->m_name); } } - // If these are different then there are fields defined in the object that are *not* defined in class definition + // If these are different then there are fields defined in the object that are *not* + // defined in class definition return SLANG_FAIL; } return SLANG_OK; } - case RttiInfo::Kind::Enum: + case RttiInfo::Kind::Enum: { return SLANG_E_NOT_IMPLEMENTED; } - case RttiInfo::Kind::String: + case RttiInfo::Kind::String: { *(String*)out = m_container->getTransientString(in); return SLANG_OK; } - case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::UnownedStringSlice: { - // Problem -> if the slice is a lexeme, then when we decode with getString, it will lose scope. - // So we do something a bit odd and place the decoding string + // Problem -> if the slice is a lexeme, then when we decode with getString, it will lose + // scope. So we do something a bit odd and place the decoding string *(UnownedStringSlice*)out = m_container->getString(in); return SLANG_OK; } - case RttiInfo::Kind::List: + case RttiInfo::Kind::List: { if (in.getKind() == JSONValue::Kind::Null) return SLANG_OK; @@ -200,7 +224,8 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); auto elementType = listRttiInfo->m_elementType; - SLANG_RETURN_ON_FAIL(RttiUtil::setListCount(m_typeMap, elementType, out, arr.getCount())); + SLANG_RETURN_ON_FAIL( + RttiUtil::setListCount(m_typeMap, elementType, out, arr.getCount())); // Okay, we need to copy over one by one Byte* dstEles = list.getBuffer(); @@ -211,13 +236,14 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* return SLANG_OK; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { if (in.getKind() != JSONValue::Kind::Array) { return SLANG_FAIL; } - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(rttiInfo); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const Index elementCount = Index(fixedArrayRttiInfo->m_elementCount); const auto elementSize = elementType->m_size; @@ -226,7 +252,11 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* if (srcArray.getCount() > elementCount) { - m_sink->diagnose(in.loc, JSONDiagnostics::tooManyElementsForArray, srcArray.getCount(), elementCount); + m_sink->diagnose( + in.loc, + JSONDiagnostics::tooManyElementsForArray, + srcArray.getCount(), + elementCount); return SLANG_FAIL; } @@ -238,13 +268,13 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* return SLANG_OK; } - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Dictionary: { - // We can *only* serialize this into a straight JSON object iff the key is a string-like type - // We could turn into (say) an array of keys and values + // We can *only* serialize this into a straight JSON object iff the key is a string-like + // type We could turn into (say) an array of keys and values break; } - case RttiInfo::Kind::Other: + case RttiInfo::Kind::Other: { if (rttiInfo == GetRttiInfo::get()) { @@ -255,16 +285,19 @@ SlangResult JSONToNativeConverter::convert(const JSONValue& in, const RttiInfo* } return SLANG_FAIL; } - default: break; + default: + break; } return SLANG_FAIL; } -SlangResult JSONToNativeConverter::convertArrayToStruct(const JSONValue& value, const RttiInfo* rttiInfo, void* out) +SlangResult JSONToNativeConverter::convertArrayToStruct( + const JSONValue& value, + const RttiInfo* rttiInfo, + void* out) { // Check converting JSON array into a struct, as that's what this method supports - if (!(rttiInfo->m_kind == RttiInfo::Kind::Struct && - value.getKind() == JSONValue::Kind::Array)) + if (!(rttiInfo->m_kind == RttiInfo::Kind::Struct && value.getKind() == JSONValue::Kind::Array)) { // If they are the wrong types then just fail return SLANG_FAIL; @@ -274,7 +307,8 @@ SlangResult JSONToNativeConverter::convertArrayToStruct(const JSONValue& value, Index totalFieldCount = 0; ShortList infos; - for (const StructRttiInfo* cur = static_cast(rttiInfo); cur; cur = cur->m_super) + for (const StructRttiInfo* cur = static_cast(rttiInfo); cur; + cur = cur->m_super) { totalFieldCount += cur->m_fieldCount; infos.add(cur); @@ -300,7 +334,8 @@ SlangResult JSONToNativeConverter::convertArrayToStruct(const JSONValue& value, { // Convert the field const auto& field = info->m_fields[j]; - SLANG_RETURN_ON_FAIL(convert(array[argIndex++], field.m_type, dstBase + field.m_offset)); + SLANG_RETURN_ON_FAIL( + convert(array[argIndex++], field.m_type, dstBase + field.m_offset)); } } @@ -309,7 +344,10 @@ SlangResult JSONToNativeConverter::convertArrayToStruct(const JSONValue& value, /* !!!!!!!!!!!!!!!!!!!!!!!!!!!! NativeToJSONConverter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -SlangResult NativeToJSONConverter::_structToJSON(const StructRttiInfo* structRttiInfo, const void* src, List& outPairs) +SlangResult NativeToJSONConverter::_structToJSON( + const StructRttiInfo* structRttiInfo, + const void* src, + List& outPairs) { // Do the super class first if (structRttiInfo->m_super) @@ -326,7 +364,8 @@ SlangResult NativeToJSONConverter::_structToJSON(const StructRttiInfo* structRtt if (field.m_flags & StructRttiInfo::Flag::Optional) { - const RttiDefaultValue defaultValue = RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask)); + const RttiDefaultValue defaultValue = + RttiDefaultValue(field.m_flags & uint8_t(RttiDefaultValue::Mask)); if (RttiUtil::isDefault(defaultValue, field.m_type, base + field.m_offset)) { // If it's a default, we don't bother writing it @@ -340,7 +379,11 @@ SlangResult NativeToJSONConverter::_structToJSON(const StructRttiInfo* structRtt if (SLANG_FAILED(res)) { - m_sink->diagnose(SourceLoc(), JSONDiagnostics::unableToConvertField, field.m_name, structRttiInfo->m_name); + m_sink->diagnose( + SourceLoc(), + JSONDiagnostics::unableToConvertField, + field.m_name, + structRttiInfo->m_name); return res; } @@ -366,25 +409,26 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void* switch (rttiInfo->m_kind) { - case RttiInfo::Kind::Invalid: return SLANG_FAIL; - case RttiInfo::Kind::Bool: + case RttiInfo::Kind::Invalid: + return SLANG_FAIL; + case RttiInfo::Kind::Bool: { out = JSONValue::makeBool(RttiUtil::asBool(rttiInfo, in)); return SLANG_OK; } - case RttiInfo::Kind::String: + case RttiInfo::Kind::String: { const String& str = *(const String*)in; out = m_container->createString(str.getUnownedSlice()); return SLANG_OK; } - case RttiInfo::Kind::UnownedStringSlice: + case RttiInfo::Kind::UnownedStringSlice: { const UnownedStringSlice& slice = *(const UnownedStringSlice*)in; out = m_container->createString(slice); return SLANG_OK; } - case RttiInfo::Kind::Struct: + case RttiInfo::Kind::Struct: { const StructRttiInfo* structRttiInfo = static_cast(rttiInfo); @@ -393,11 +437,11 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void* out = m_container->createObject(pairs.getBuffer(), pairs.getCount()); return SLANG_OK; } - case RttiInfo::Kind::Enum: - { + case RttiInfo::Kind::Enum: + { return SLANG_E_NOT_IMPLEMENTED; } - case RttiInfo::Kind::List: + case RttiInfo::Kind::List: { const ListRttiInfo* listRttiInfo = static_cast(rttiInfo); const auto elementRttiInfo = listRttiInfo->m_elementType; @@ -422,9 +466,10 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void* out = m_container->createArray(dstValues.getBuffer(), count); return SLANG_OK; } - case RttiInfo::Kind::FixedArray: + case RttiInfo::Kind::FixedArray: { - const FixedArrayRttiInfo* fixedArrayRttiInfo = static_cast(rttiInfo); + const FixedArrayRttiInfo* fixedArrayRttiInfo = + static_cast(rttiInfo); const auto elementType = fixedArrayRttiInfo->m_elementType; const auto elementCount = Index(fixedArrayRttiInfo->m_elementCount); const auto elementSize = elementType->m_size; @@ -441,21 +486,22 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void* out = m_container->createArray(dstValues.getBuffer(), elementCount); return SLANG_OK; } - case RttiInfo::Kind::Dictionary: + case RttiInfo::Kind::Dictionary: { - const DictionaryRttiInfo* listRttiInfo = static_cast(rttiInfo); + const DictionaryRttiInfo* listRttiInfo = + static_cast(rttiInfo); const auto keyRttiInfo = listRttiInfo->m_keyType; const auto valueRttiInfo = listRttiInfo->m_valueType; SLANG_UNUSED(keyRttiInfo); SLANG_UNUSED(valueRttiInfo); - // We can *only* serialize this into a straight JSON object iff the key is a string-like type - // We could turn into (say) an array of keys and values + // We can *only* serialize this into a straight JSON object iff the key is a string-like + // type We could turn into (say) an array of keys and values break; } - case RttiInfo::Kind::Other: + case RttiInfo::Kind::Other: { if (rttiInfo == GetRttiInfo::get()) { @@ -468,13 +514,17 @@ SlangResult NativeToJSONConverter::convert(const RttiInfo* rttiInfo, const void* } break; } - default: break; + default: + break; } return SLANG_E_NOT_IMPLEMENTED; } -SlangResult NativeToJSONConverter::convertStructToArray(const RttiInfo* rttiInfo, const void* in, JSONValue& out) +SlangResult NativeToJSONConverter::convertStructToArray( + const RttiInfo* rttiInfo, + const void* in, + JSONValue& out) { if (rttiInfo->m_kind != RttiInfo::Kind::Struct) { @@ -485,7 +535,8 @@ SlangResult NativeToJSONConverter::convertStructToArray(const RttiInfo* rttiInfo // Work out the total amount of fields, and all invloved struct types Index totalFieldsCount = 0; ShortList infos; - for (const StructRttiInfo* cur = static_cast(rttiInfo); cur; cur = cur->m_super) + for (const StructRttiInfo* cur = static_cast(rttiInfo); cur; + cur = cur->m_super) { totalFieldsCount += Index(cur->m_fieldCount); infos.add(cur); @@ -511,7 +562,8 @@ SlangResult NativeToJSONConverter::convertStructToArray(const RttiInfo* rttiInfo { const auto& field = structRttiInfo->m_fields[j]; // Convert the field - SLANG_RETURN_ON_FAIL(convert(field.m_type, argsBase + field.m_offset, argsArray[argsArrayIndex++])); + SLANG_RETURN_ON_FAIL( + convert(field.m_type, argsBase + field.m_offset, argsArray[argsArrayIndex++])); } } } diff --git a/source/compiler-core/slang-json-native.h b/source/compiler-core/slang-json-native.h index 6920d59e99..381d95fe0e 100644 --- a/source/compiler-core/slang-json-native.h +++ b/source/compiler-core/slang-json-native.h @@ -1,35 +1,46 @@ #ifndef SLANG_COMPILER_CORE_JSON_NATIVE_H #define SLANG_COMPILER_CORE_JSON_NATIVE_H -#include "slang.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - #include "slang-json-value.h" +#include "slang.h" -namespace Slang { +namespace Slang +{ struct JSONToNativeConverter { SlangResult convert(const JSONValue& value, const RttiInfo* rttiInfo, void* out); - template - SlangResult convert(const JSONValue& value, T* in) { return convert(value, GetRttiInfo::get(), (void*)in); } - - template - SlangResult convertArrayToStruct(const JSONValue& value, T* in) { return convertArrayToStruct(value, GetRttiInfo::get(), (void*)in); } + template + SlangResult convert(const JSONValue& value, T* in) + { + return convert(value, GetRttiInfo::get(), (void*)in); + } + + template + SlangResult convertArrayToStruct(const JSONValue& value, T* in) + { + return convertArrayToStruct(value, GetRttiInfo::get(), (void*)in); + } SlangResult convertArrayToStruct(const JSONValue& value, const RttiInfo* rttiInfo, void* out); - JSONToNativeConverter(JSONContainer* container, RttiTypeFuncsMap* typeMap, DiagnosticSink* sink): - m_container(container), - m_typeMap(typeMap), - m_sink(sink) - {} + JSONToNativeConverter(JSONContainer* container, RttiTypeFuncsMap* typeMap, DiagnosticSink* sink) + : m_container(container), m_typeMap(typeMap), m_sink(sink) + { + } protected: static Index _getFieldCount(const StructRttiInfo* structRttiInfo); - static Index _findFieldIndex(const StructRttiInfo* structRttiInfo, const UnownedStringSlice& fieldName); + static Index _findFieldIndex( + const StructRttiInfo* structRttiInfo, + const UnownedStringSlice& fieldName); - SlangResult _structToNative(const ConstArrayView& pairs, const StructRttiInfo* structRttiInfo, void* out, Index& outFieldCount); + SlangResult _structToNative( + const ConstArrayView& pairs, + const StructRttiInfo* structRttiInfo, + void* out, + Index& outFieldCount); DiagnosticSink* m_sink; RttiTypeFuncsMap* m_typeMap; @@ -40,21 +51,29 @@ struct NativeToJSONConverter { SlangResult convert(const RttiInfo* rttiInfo, const void* in, JSONValue& out); - template - SlangResult convert(T* in, JSONValue& out) { return convert(GetRttiInfo::get(), (const void*)in, out); } + template + SlangResult convert(T* in, JSONValue& out) + { + return convert(GetRttiInfo::get(), (const void*)in, out); + } SlangResult convertStructToArray(const RttiInfo* rttiInfo, const void* in, JSONValue& out); - template - SlangResult convertStructToArray(T* in, JSONValue& out) { return convertStructToArray(GetRttiInfo::get(), (const void*)in, out); } + template + SlangResult convertStructToArray(T* in, JSONValue& out) + { + return convertStructToArray(GetRttiInfo::get(), (const void*)in, out); + } - NativeToJSONConverter(JSONContainer* container, RttiTypeFuncsMap* typeMap, DiagnosticSink* sink) : - m_container(container), - m_typeMap(typeMap), - m_sink(sink) - {} + NativeToJSONConverter(JSONContainer* container, RttiTypeFuncsMap* typeMap, DiagnosticSink* sink) + : m_container(container), m_typeMap(typeMap), m_sink(sink) + { + } protected: - SlangResult _structToJSON(const StructRttiInfo* structRttiInfo, const void* src, List& outPairs); + SlangResult _structToJSON( + const StructRttiInfo* structRttiInfo, + const void* src, + List& outPairs); DiagnosticSink* m_sink; RttiTypeFuncsMap* m_typeMap; diff --git a/source/compiler-core/slang-json-parser.cpp b/source/compiler-core/slang-json-parser.cpp index 52e46258a7..c436468a4a 100644 --- a/source/compiler-core/slang-json-parser.cpp +++ b/source/compiler-core/slang-json-parser.cpp @@ -1,15 +1,15 @@ // slang-json-parser.cpp #include "slang-json-parser.h" -#include "slang-json-diagnostics.h" - #include "../core/slang-string-escape-util.h" +#include "slang-json-diagnostics.h" /* https://www.json.org/json-en.html */ -namespace Slang { +namespace Slang +{ SlangResult JSONParser::_parseObject() { @@ -92,32 +92,35 @@ SlangResult JSONParser::_parseValue() { switch (m_lexer->peekType()) { - case JSONTokenType::True: - case JSONTokenType::False: - case JSONTokenType::Null: - case JSONTokenType::IntegerLiteral: - case JSONTokenType::FloatLiteral: - case JSONTokenType::StringLiteral: + case JSONTokenType::True: + case JSONTokenType::False: + case JSONTokenType::Null: + case JSONTokenType::IntegerLiteral: + case JSONTokenType::FloatLiteral: + case JSONTokenType::StringLiteral: { const JSONToken& tok = m_lexer->peekToken(); m_listener->addLexemeValue(tok.type, m_lexer->peekLexeme(), tok.loc); m_lexer->advance(); return SLANG_OK; } - case JSONTokenType::LBracket: + case JSONTokenType::LBracket: { return _parseArray(); } - case JSONTokenType::LBrace: + case JSONTokenType::LBrace: { return _parseObject(); } - default: + default: { - m_sink->diagnose(m_lexer->peekLoc(), JSONDiagnostics::unexpectedToken, getJSONTokenAsText(m_lexer->peekType())); + m_sink->diagnose( + m_lexer->peekLoc(), + JSONDiagnostics::unexpectedToken, + getJSONTokenAsText(m_lexer->peekType())); return SLANG_FAIL; } - case JSONTokenType::Invalid: + case JSONTokenType::Invalid: { // It's a lex error, so just fail return SLANG_FAIL; @@ -125,7 +128,11 @@ SlangResult JSONParser::_parseValue() } } -SlangResult JSONParser::parse(JSONLexer* lexer, SourceView* sourceView, JSONListener* listener, DiagnosticSink* sink) +SlangResult JSONParser::parse( + JSONLexer* lexer, + SourceView* sourceView, + JSONListener* listener, + DiagnosticSink* sink) { m_sourceView = sourceView; m_lexer = lexer; @@ -180,7 +187,8 @@ void JSONWriter::_nextLine() void JSONWriter::_maybeNextLine() { - // Nothing has been emitted, because nothing has been indented, and we must indent before an emit + // Nothing has been emitted, because nothing has been indented, and we must indent before an + // emit if (m_emittedIndent < 0) { } @@ -194,13 +202,13 @@ void JSONWriter::_handleFormat(Location loc) { switch (m_format) { - case IndentationStyle::Allman: + case IndentationStyle::Allman: { if (isComma(loc)) { _maybeNextLine(); } - else + else { if (isBefore(loc)) { @@ -221,7 +229,7 @@ void JSONWriter::_handleFormat(Location loc) } break; } - case IndentationStyle::KNR: + case IndentationStyle::KNR: { if (isComma(loc)) { @@ -231,7 +239,7 @@ void JSONWriter::_handleFormat(Location loc) _maybeNextLine(); } } - else + else { if (isBefore(loc)) { @@ -321,7 +329,7 @@ void JSONWriter::startArray(SourceLoc loc) _handleFormat(Location::BeforeOpenArray); _maybeEmitIndent(); - m_builder << "["; + m_builder << "["; _handleFormat(Location::AfterOpenArray); m_state.m_flags |= State::Flag::HasPrevious; @@ -352,7 +360,8 @@ void JSONWriter::endArray(SourceLoc loc) void JSONWriter::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc) { SLANG_UNUSED(loc); - SLANG_ASSERT(m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0); + SLANG_ASSERT( + m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0); _maybeEmitFieldComma(); _maybeEmitIndent(); @@ -371,7 +380,8 @@ void JSONWriter::addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc) void JSONWriter::addQuotedKey(const UnownedStringSlice& key, SourceLoc loc) { SLANG_UNUSED(loc); - SLANG_ASSERT(m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0); + SLANG_ASSERT( + m_state.m_kind == State::Kind::Object && (m_state.m_flags & State::Flag::HasKey) == 0); // It should be quoted SLANG_ASSERT(key.getLength() >= 2 && key[0] == '"' && key[key.getLength() - 1] == '"'); @@ -412,29 +422,29 @@ void JSONWriter::addLexemeValue(JSONTokenType type, const UnownedStringSlice& va switch (type) { - case JSONTokenType::IntegerLiteral: - case JSONTokenType::FloatLiteral: - case JSONTokenType::StringLiteral: + case JSONTokenType::IntegerLiteral: + case JSONTokenType::FloatLiteral: + case JSONTokenType::StringLiteral: { m_builder << value; break; } - case JSONTokenType::True: + case JSONTokenType::True: { m_builder << UnownedStringSlice::fromLiteral("true"); break; } - case JSONTokenType::False: + case JSONTokenType::False: { m_builder << UnownedStringSlice::fromLiteral("false"); break; } - case JSONTokenType::Null: + case JSONTokenType::Null: { m_builder << UnownedStringSlice::fromLiteral("null"); break; } - default: + default: { SLANG_ASSERT(!"Can only emit values"); } @@ -460,7 +470,8 @@ void JSONWriter::addFloatValue(double value, SourceLoc loc) void JSONWriter::addBoolValue(bool inValue, SourceLoc loc) { _preValue(loc); - const UnownedStringSlice slice = inValue ? UnownedStringSlice::fromLiteral("true") : UnownedStringSlice::fromLiteral("false"); + const UnownedStringSlice slice = inValue ? UnownedStringSlice::fromLiteral("true") + : UnownedStringSlice::fromLiteral("false"); m_builder << slice; _postValue(); } diff --git a/source/compiler-core/slang-json-parser.h b/source/compiler-core/slang-json-parser.h index 2391ea0d2e..89be90d810 100644 --- a/source/compiler-core/slang-json-parser.h +++ b/source/compiler-core/slang-json-parser.h @@ -5,54 +5,58 @@ #include "slang-json-lexer.h" -namespace Slang { +namespace Slang +{ class JSONListener { public: - /// Start an object + /// Start an object virtual void startObject(SourceLoc loc) = 0; - /// End an object + /// End an object virtual void endObject(SourceLoc loc) = 0; - /// Start an array + /// Start an array virtual void startArray(SourceLoc loc) = 0; - /// End and array + /// End and array virtual void endArray(SourceLoc loc) = 0; - /// Add the key. Must be followed by addXXXValue. + /// Add the key. Must be followed by addXXXValue. virtual void addQuotedKey(const UnownedStringSlice& key, SourceLoc loc) = 0; virtual void addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc) = 0; - /// Can be performed in an array or after an addLexemeKey in an object - virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) = 0; + /// Can be performed in an array or after an addLexemeKey in an object + virtual void addLexemeValue( + JSONTokenType type, + const UnownedStringSlice& value, + SourceLoc loc) = 0; - /// An integer value + /// An integer value virtual void addIntegerValue(int64_t value, SourceLoc loc) = 0; - /// Add a floating point value + /// Add a floating point value virtual void addFloatValue(double value, SourceLoc loc) = 0; - /// Add a boolean value + /// Add a boolean value virtual void addBoolValue(bool value, SourceLoc loc) = 0; - /// Add a string value. NOTE! string is unescaped/quoted + /// Add a string value. NOTE! string is unescaped/quoted virtual void addStringValue(const UnownedStringSlice& string, SourceLoc loc) = 0; - /// Add a null value + /// Add a null value virtual void addNullValue(SourceLoc loc) = 0; }; class JSONWriter : public JSONListener { public: - /* + /* https://en.wikipedia.org/wiki/Indentation_style */ enum class IndentationStyle { - Allman, ///< After every value, and opening, closing all other types - KNR, ///< K&R like. Fields have CR. + Allman, ///< After every value, and opening, closing all other types + KNR, ///< K&R like. Fields have CR. }; - enum class LocationType : uint8_t + enum class LocationType : uint8_t { Object, Array, @@ -78,11 +82,22 @@ class JSONWriter : public JSONListener CountOf, }; - static LocationType getLocationType(Location loc) { return isObject(loc) ? LocationType::Object : (isComma(loc) ? LocationType::Comma : LocationType::Array); } + static LocationType getLocationType(Location loc) + { + return isObject(loc) ? LocationType::Object + : (isComma(loc) ? LocationType::Comma : LocationType::Array); + } - static bool isObjectLike(Location loc) { return Index(loc) <= Index(Location::AfterCloseArray); } + static bool isObjectLike(Location loc) + { + return Index(loc) <= Index(Location::AfterCloseArray); + } static bool isObject(Location loc) { return Index(loc) <= Index(Location::AfterCloseObject); } - static bool isArray(Location loc) { return Index(loc) >= Index(Location::BeforeOpenArray) && Index(loc) <= Index(Location::AfterCloseArray); } + static bool isArray(Location loc) + { + return Index(loc) >= Index(Location::BeforeOpenArray) && + Index(loc) <= Index(Location::AfterCloseArray); + } static bool isComma(Location loc) { return Index(loc) >= Index(Location::FieldComma); } static bool isOpen(Location loc) { return isObjectLike(loc) && (Index(loc) & 1) == 0; } static bool isClose(Location loc) { return isObjectLike(loc) && (Index(loc) & 1) != 0; } @@ -96,14 +111,15 @@ class JSONWriter : public JSONListener virtual void endArray(SourceLoc loc) SLANG_OVERRIDE; virtual void addQuotedKey(const UnownedStringSlice& key, SourceLoc loc) SLANG_OVERRIDE; virtual void addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc) SLANG_OVERRIDE; - virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) SLANG_OVERRIDE; + virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) + SLANG_OVERRIDE; virtual void addIntegerValue(int64_t value, SourceLoc loc) SLANG_OVERRIDE; virtual void addFloatValue(double value, SourceLoc loc) SLANG_OVERRIDE; virtual void addBoolValue(bool value, SourceLoc loc) SLANG_OVERRIDE; virtual void addStringValue(const UnownedStringSlice& string, SourceLoc loc) SLANG_OVERRIDE; virtual void addNullValue(SourceLoc loc) SLANG_OVERRIDE; - /// Get the builder + /// Get the builder StringBuilder& getBuilder() { return m_builder; } JSONWriter(IndentationStyle format, Index lineLengthLimit = -1) @@ -131,7 +147,7 @@ class JSONWriter : public JSONListener enum Enum : Flags { HasPrevious = 0x01, - HasKey = 0x02, + HasKey = 0x02, }; }; @@ -139,10 +155,14 @@ class JSONWriter : public JSONListener { switch (m_kind) { - case Kind::Root: return (m_flags & Flag::HasPrevious) == 0; - case Kind::Array: return true; - case Kind::Object: return (m_flags & Flag::HasKey) != 0; - default: return false; + case Kind::Root: + return (m_flags & Flag::HasPrevious) == 0; + case Kind::Array: + return true; + case Kind::Object: + return (m_flags & Flag::HasKey) != 0; + default: + return false; } } @@ -156,7 +176,7 @@ class JSONWriter : public JSONListener Index _getLineLengthAfterIndent(); - /// Only emits the indent if at start of line + /// Only emits the indent if at start of line void _maybeEmitIndent(); void _emitIndent(); @@ -167,20 +187,24 @@ class JSONWriter : public JSONListener void _postValue(); void _indent() { m_currentIndent++; } - void _dedent() { --m_currentIndent; SLANG_ASSERT(m_currentIndent >= 0); } + void _dedent() + { + --m_currentIndent; + SLANG_ASSERT(m_currentIndent >= 0); + } - /// True if the line is indented at the required level + /// True if the line is indented at the required level bool _hasIndent() { return m_emittedIndent >= 0 && m_emittedIndent == m_currentIndent; } - + Index m_currentIndent = 0; char m_indentChar = ' '; Index m_indentCharCount = 4; Index m_lineIndex = 0; Index m_lineStart = 0; - Index m_emittedIndent = -1; /// If -1 for current line there is no indent emitted + Index m_emittedIndent = -1; /// If -1 for current line there is no indent emitted - Index m_lineLengthLimit = -1; /// The limit is only applied *AFTER* indentation + Index m_lineLengthLimit = -1; /// The limit is only applied *AFTER* indentation IndentationStyle m_format; @@ -192,7 +216,11 @@ class JSONWriter : public JSONListener class JSONParser { public: - SlangResult parse(JSONLexer* lexer, SourceView* sourceView, JSONListener* listener, DiagnosticSink* sink); + SlangResult parse( + JSONLexer* lexer, + SourceView* sourceView, + JSONListener* listener, + DiagnosticSink* sink); protected: SlangResult _parseValue(); @@ -206,7 +234,6 @@ class JSONParser }; - } // namespace Slang #endif diff --git a/source/compiler-core/slang-json-rpc-connection.cpp b/source/compiler-core/slang-json-rpc-connection.cpp index af9dd9e48d..79ffc95831 100644 --- a/source/compiler-core/slang-json-rpc-connection.cpp +++ b/source/compiler-core/slang-json-rpc-connection.cpp @@ -1,23 +1,25 @@ // slang-json-rpc-connection.cpp #include "slang-json-rpc-connection.h" -#include "../core/slang-string-util.h" #include "../core/slang-process-util.h" #include "../core/slang-short-list.h" - -#include "slang-json-rpc.h" +#include "../core/slang-string-util.h" #include "slang-json-native.h" +#include "slang-json-rpc.h" -namespace Slang { +namespace Slang +{ /// Ctor -JSONRPCConnection::JSONRPCConnection(): - m_container(nullptr), - m_typeMap(JSONNativeUtil::getTypeFuncsMap()) +JSONRPCConnection::JSONRPCConnection() + : m_container(nullptr), m_typeMap(JSONNativeUtil::getTypeFuncsMap()) { } -SlangResult JSONRPCConnection::init(HTTPPacketConnection* connection, CallStyle defaultCallStyle, Process* process) +SlangResult JSONRPCConnection::init( + HTTPPacketConnection* connection, + CallStyle defaultCallStyle, + Process* process) { m_connection = connection; m_process = process; @@ -25,11 +27,12 @@ SlangResult JSONRPCConnection::init(HTTPPacketConnection* connection, CallStyle { // If a call style isn't set, use the prefered style const CallStyle preferedCallStyle = CallStyle::Array; - defaultCallStyle = (defaultCallStyle == CallStyle::Default) ? preferedCallStyle : defaultCallStyle; + defaultCallStyle = + (defaultCallStyle == CallStyle::Default) ? preferedCallStyle : defaultCallStyle; m_defaultCallStyle = defaultCallStyle; } - - + + m_sourceManager.initialize(nullptr, nullptr); m_diagnosticSink.init(&m_sourceManager, &JSONLexer::calcLexemeLocation); m_container.setSourceManager(&m_sourceManager); @@ -77,7 +80,7 @@ void JSONRPCConnection::disconnect() { if (m_connection) { - // Send. If succeeded, wait + // Send. If succeeded, wait if (SLANG_SUCCEEDED(sendCall(UnownedStringSlice::fromLiteral("quit")))) { // Wait for termination @@ -126,7 +129,10 @@ SlangResult JSONRPCConnection::sendError(JSONRPC::ErrorCode code, const JSONValu return sendError(code, m_diagnosticSink.outputBuffer.getUnownedSlice(), id); } -SlangResult JSONRPCConnection::sendError(JSONRPC::ErrorCode errorCode, const UnownedStringSlice& msg, const JSONValue& id) +SlangResult JSONRPCConnection::sendError( + JSONRPC::ErrorCode errorCode, + const UnownedStringSlice& msg, + const JSONValue& id) { JSONRPCErrorResponse errorResponse; errorResponse.error.code = Int(errorCode); @@ -136,25 +142,33 @@ SlangResult JSONRPCConnection::sendError(JSONRPC::ErrorCode errorCode, const Uno return sendRPC(&errorResponse); } -SlangResult JSONRPCConnection::checkArrayObjectWrap( const JSONValue& srcArgs, const RttiInfo* dstArgsRttiInfo, void* dstArgs, const JSONValue& id ) +SlangResult JSONRPCConnection::checkArrayObjectWrap( + const JSONValue& srcArgs, + const RttiInfo* dstArgsRttiInfo, + void* dstArgs, + const JSONValue& id) { - if ( dstArgsRttiInfo->m_kind == RttiInfo::Kind::Struct && - srcArgs.getKind() == JSONValue::Kind::Array ) + if (dstArgsRttiInfo->m_kind == RttiInfo::Kind::Struct && + srcArgs.getKind() == JSONValue::Kind::Array) { - auto array = m_container.getArray( srcArgs ); - if ( array.getCount() == 1 ) + auto array = m_container.getArray(srcArgs); + if (array.getCount() == 1) { - return toNativeOrSendError( array[0], dstArgsRttiInfo, dstArgs, id ); + return toNativeOrSendError(array[0], dstArgsRttiInfo, dstArgs, id); } return SLANG_OK; } else { - return toNativeOrSendError( srcArgs, dstArgsRttiInfo, dstArgs, id ); + return toNativeOrSendError(srcArgs, dstArgsRttiInfo, dstArgs, id); } } -SlangResult JSONRPCConnection::toNativeArgsOrSendError(const JSONValue& srcArgs, const RttiInfo* dstArgsRttiInfo, void* dstArgs, const JSONValue& id) +SlangResult JSONRPCConnection::toNativeArgsOrSendError( + const JSONValue& srcArgs, + const RttiInfo* dstArgsRttiInfo, + void* dstArgs, + const JSONValue& id) { if (dstArgsRttiInfo->m_kind == RttiInfo::Kind::Struct && srcArgs.getKind() == JSONValue::Kind::Array) @@ -172,12 +186,16 @@ SlangResult JSONRPCConnection::toNativeArgsOrSendError(const JSONValue& srcArgs, } } -SlangResult JSONRPCConnection::toNativeOrSendError(const JSONValue& value, const RttiInfo* info, void* dst, const JSONValue& id) +SlangResult JSONRPCConnection::toNativeOrSendError( + const JSONValue& value, + const RttiInfo* info, + void* dst, + const JSONValue& id) { m_diagnosticSink.outputBuffer.clear(); JSONToNativeConverter converter(&m_container, &m_typeMap, &m_diagnosticSink); - + if (SLANG_FAILED(converter.convert(value, info, dst))) { return sendError(JSONRPC::ErrorCode::InvalidRequest, id); @@ -196,7 +214,10 @@ SlangResult JSONRPCConnection::sendCall(const UnownedStringSlice& method, const return SLANG_OK; } -SlangResult JSONRPCConnection::sendResult(const RttiInfo* rttiInfo, const void* result, const JSONValue& id) +SlangResult JSONRPCConnection::sendResult( + const RttiInfo* rttiInfo, + const void* result, + const JSONValue& id) { JSONResultResponse response; response.id = id; @@ -209,12 +230,21 @@ SlangResult JSONRPCConnection::sendResult(const RttiInfo* rttiInfo, const void* return SLANG_OK; } -SlangResult JSONRPCConnection::sendCall(const UnownedStringSlice& method, const RttiInfo* argsRttiInfo, const void* args, const JSONValue& id) +SlangResult JSONRPCConnection::sendCall( + const UnownedStringSlice& method, + const RttiInfo* argsRttiInfo, + const void* args, + const JSONValue& id) { return sendCall(m_defaultCallStyle, method, argsRttiInfo, args, id); } -SlangResult JSONRPCConnection::sendCall(CallStyle callStyle, const UnownedStringSlice& method, const RttiInfo* argsRttiInfo, const void* args, const JSONValue& id) +SlangResult JSONRPCConnection::sendCall( + CallStyle callStyle, + const UnownedStringSlice& method, + const RttiInfo* argsRttiInfo, + const void* args, + const JSONValue& id) { JSONRPCCall call; call.id = id; @@ -222,7 +252,7 @@ SlangResult JSONRPCConnection::sendCall(CallStyle callStyle, const UnownedString // Set up the converter to now convert the args. NativeToJSONConverter converter(&m_container, &m_typeMap, &m_diagnosticSink); - + // If we have a struct *and* call style is 'array', do special handling if (argsRttiInfo->m_kind == RttiInfo::Kind::Struct && _getCallStyle(callStyle) == CallStyle::Array) @@ -235,7 +265,7 @@ SlangResult JSONRPCConnection::sendCall(CallStyle callStyle, const UnownedString // Convert the args/params in the 'object' sytle SLANG_RETURN_ON_FAIL(converter.convert(argsRttiInfo, args, call.params)); } - + // Send the RPC SLANG_RETURN_ON_FAIL(sendRPC(&call)); return SLANG_OK; @@ -263,7 +293,8 @@ SlangResult JSONRPCConnection::tryReadMessage() clearBuffers(); { - const SlangResult res = JSONRPCUtil::parseJSON(slice, &m_container, &m_diagnosticSink, m_jsonRoot); + const SlangResult res = + JSONRPCUtil::parseJSON(slice, &m_container, &m_diagnosticSink, m_jsonRoot); // Consume that content/packet m_connection->consumeContent(); @@ -346,4 +377,4 @@ SlangResult JSONRPCConnection::getRPCOrSendError(const RttiInfo* rttiInfo, void* return res; } -} // namespcae Slang +} // namespace Slang diff --git a/source/compiler-core/slang-json-rpc-connection.h b/source/compiler-core/slang-json-rpc-connection.h index f5525d0334..5ee963ec82 100644 --- a/source/compiler-core/slang-json-rpc-connection.h +++ b/source/compiler-core/slang-json-rpc-connection.h @@ -3,17 +3,15 @@ #include "../../source/core/slang-http.h" #include "../../source/core/slang-process.h" - #include "slang-diagnostic-sink.h" -#include "slang-source-loc.h" -#include "slang-json-value.h" -#include "slang-json-rpc.h" - #include "slang-json-diagnostics.h" - +#include "slang-json-rpc.h" +#include "slang-json-value.h" +#include "slang-source-loc.h" #include "slang-test-server-protocol.h" -namespace Slang { +namespace Slang +{ /* A type to handle communication via the JSON-RPC protocol. @@ -23,164 +21,245 @@ use the JSON-RPC protocol types. These types will hold items that can vary (like in JSONValue parameters. Code can use regular JSON functions to access/process. Doing conversions to native types and JSON manually can be a fairly monotonous task. To avoid this -effort Rtti and JSON<->Rtti conversions can be used. For example sendCall will send a JSON-RPC 'call' method, -with the parameters being converted from some native type. For this to work the type T must be determinable -via GetRttiType, and T must only contain types that JSON<->Rtti conversion supports. +effort Rtti and JSON<->Rtti conversions can be used. For example sendCall will send a JSON-RPC +'call' method, with the parameters being converted from some native type. For this to work the type +T must be determinable via GetRttiType, and T must only contain types that JSON<->Rtti conversion +supports. */ class JSONRPCConnection : public RefObject { public: - enum class CallStyle { - Default, ///< The default - Object, ///< Params are passed as an object - Array, ///< Params are passed as an array + Default, ///< The default + Object, ///< Params are passed as an object + Array, ///< Params are passed as an array }; - /// An init function must be called before use - /// If a process is implementing the server it should be passed in if the process needs to shut down if the connection does - SlangResult init(HTTPPacketConnection* connection, CallStyle callStyle = CallStyle::Default, Process* process = nullptr); + /// An init function must be called before use + /// If a process is implementing the server it should be passed in if the process needs to shut + /// down if the connection does + SlangResult init( + HTTPPacketConnection* connection, + CallStyle callStyle = CallStyle::Default, + Process* process = nullptr); - /// Initialize using stdin/out streams for input/output. - SlangResult initWithStdStreams(CallStyle callStyle = CallStyle::Default, Process* process = nullptr); + /// Initialize using stdin/out streams for input/output. + SlangResult initWithStdStreams( + CallStyle callStyle = CallStyle::Default, + Process* process = nullptr); - /// Disconnect. May block while server shuts down + /// Disconnect. May block while server shuts down void disconnect(); - SlangResult checkArrayObjectWrap( const JSONValue& srcArgs, const RttiInfo* dstArgsRttiInfo, void* dstArgs, const JSONValue& id ); - - /// Convert value to dst. Will write response on fails - SlangResult toNativeOrSendError(const JSONValue& value, const RttiInfo* info, void* dst, const JSONValue& id); - - template - SlangResult toNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id) { return toNativeOrSendError(value, GetRttiInfo::get(), data, id); } - - /// Convert value to dst. - /// The 'Args' aspect here is to handle Args/Params in JSON-RPC which can be specified as an array or object style. - /// This call will automatically handle either case. - /// toNativeOrSendError does not assume the thing being converted is args, and so doesn't allow such a transformation. - /// Will write error response on failure. - SlangResult toNativeArgsOrSendError(const JSONValue& srcArgs, const RttiInfo* dstArgsRttiInfo, void* dstArgs, const JSONValue& id); + SlangResult checkArrayObjectWrap( + const JSONValue& srcArgs, + const RttiInfo* dstArgsRttiInfo, + void* dstArgs, + const JSONValue& id); + + /// Convert value to dst. Will write response on fails + SlangResult toNativeOrSendError( + const JSONValue& value, + const RttiInfo* info, + void* dst, + const JSONValue& id); + + template + SlangResult toNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id) + { + return toNativeOrSendError(value, GetRttiInfo::get(), data, id); + } - template - SlangResult toNativeArgsOrSendError(const JSONValue& srcArgs, T* dstArgs, const JSONValue& id) { return toNativeArgsOrSendError(srcArgs, GetRttiInfo::get(), dstArgs, id); } + /// Convert value to dst. + /// The 'Args' aspect here is to handle Args/Params in JSON-RPC which can be specified as an + /// array or object style. This call will automatically handle either case. toNativeOrSendError + /// does not assume the thing being converted is args, and so doesn't allow such a + /// transformation. Will write error response on failure. + SlangResult toNativeArgsOrSendError( + const JSONValue& srcArgs, + const RttiInfo* dstArgsRttiInfo, + void* dstArgs, + const JSONValue& id); + + template + SlangResult toNativeArgsOrSendError(const JSONValue& srcArgs, T* dstArgs, const JSONValue& id) + { + return toNativeArgsOrSendError(srcArgs, GetRttiInfo::get(), dstArgs, id); + } - template + template SlangResult toValidNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id); - /// Send a RPC response (ie should only be one of the JSONRPC classes) + /// Send a RPC response (ie should only be one of the JSONRPC classes) SlangResult sendRPC(const RttiInfo* info, const void* data); - template - SlangResult sendRPC(const T* data) { return sendRPC(GetRttiInfo::get(), (const void*)data); } + template + SlangResult sendRPC(const T* data) + { + return sendRPC(GetRttiInfo::get(), (const void*)data); + } - /// Send an error + /// Send an error SlangResult sendError(JSONRPC::ErrorCode code, const JSONValue& id); - SlangResult sendError(JSONRPC::ErrorCode errorCode, const UnownedStringSlice& msg, const JSONValue& id); - - /// Send a 'call' - /// Uses the default CallStyle as set when init - SlangResult sendCall(const UnownedStringSlice& method, const RttiInfo* argsRttiInfo, const void* args, const JSONValue& id = JSONValue()); - template - SlangResult sendCall(const UnownedStringSlice& method, const T* args, const JSONValue& id = JSONValue()) { return sendCall(method, GetRttiInfo::get(), (const void*)args, id); } + SlangResult sendError( + JSONRPC::ErrorCode errorCode, + const UnownedStringSlice& msg, + const JSONValue& id); + + /// Send a 'call' + /// Uses the default CallStyle as set when init + SlangResult sendCall( + const UnownedStringSlice& method, + const RttiInfo* argsRttiInfo, + const void* args, + const JSONValue& id = JSONValue()); + template + SlangResult sendCall( + const UnownedStringSlice& method, + const T* args, + const JSONValue& id = JSONValue()) + { + return sendCall(method, GetRttiInfo::get(), (const void*)args, id); + } - /// Send a 'call' - /// Uses the call mechanism specified in callStyle. It is valid to pass as Default. - SlangResult sendCall(CallStyle callStyle, const UnownedStringSlice& method, const RttiInfo* argsRttiInfo, const void* args, const JSONValue& id = JSONValue()); - template - SlangResult sendCall(CallStyle callStyle, const UnownedStringSlice& method, const T* args, const JSONValue& id = JSONValue()) { return sendCall(callStyle, method, GetRttiInfo::get(), (const void*)args, id); } + /// Send a 'call' + /// Uses the call mechanism specified in callStyle. It is valid to pass as Default. + SlangResult sendCall( + CallStyle callStyle, + const UnownedStringSlice& method, + const RttiInfo* argsRttiInfo, + const void* args, + const JSONValue& id = JSONValue()); + template + SlangResult sendCall( + CallStyle callStyle, + const UnownedStringSlice& method, + const T* args, + const JSONValue& id = JSONValue()) + { + return sendCall(callStyle, method, GetRttiInfo::get(), (const void*)args, id); + } - /// Send a call, wheret there are no arguments + /// Send a call, wheret there are no arguments SlangResult sendCall(const UnownedStringSlice& method, const JSONValue& id = JSONValue()); - template - SlangResult sendResult(const T* result, const JSONValue& id) { return sendResult(GetRttiInfo::get(), (const void*)result, id); } + template + SlangResult sendResult(const T* result, const JSONValue& id) + { + return sendResult(GetRttiInfo::get(), (const void*)result, id); + } SlangResult sendResult(const RttiInfo* rttiInfo, const void* result, const JSONValue& id); - /// Try to read a message. Will return if message is not available. + /// Try to read a message. Will return if message is not available. SlangResult tryReadMessage(); - /// Will block for message/result up to time + /// Will block for message/result up to time SlangResult waitForResult(Int timeOutInMs = -1); - /// If we have an JSON-RPC message m_jsonRoot the root. + /// If we have an JSON-RPC message m_jsonRoot the root. bool hasMessage() const { return m_jsonRoot.isValid(); } - /// If there is a message returns kind of JSON RPC message + /// If there is a message returns kind of JSON RPC message JSONRPCMessageType getMessageType(); - /// Get JSON-RPC message (ie one of JSONRPC classes) - template - SlangResult getRPC(T* out) { return getRPC(GetRttiInfo::get(), (void*)out); } + /// Get JSON-RPC message (ie one of JSONRPC classes) + template + SlangResult getRPC(T* out) + { + return getRPC(GetRttiInfo::get(), (void*)out); + } SlangResult getRPC(const RttiInfo* rttiInfo, void* out); - /// Get JSON-RPC message (ie one of JSONRPC prefixed classes) - /// If there is a message and there is a failure, will send an error response - template - SlangResult getRPCOrSendError(T* out) { return getRPCOrSendError(GetRttiInfo::get(), (void*)out); } + /// Get JSON-RPC message (ie one of JSONRPC prefixed classes) + /// If there is a message and there is a failure, will send an error response + template + SlangResult getRPCOrSendError(T* out) + { + return getRPCOrSendError(GetRttiInfo::get(), (void*)out); + } SlangResult getRPCOrSendError(const RttiInfo* rttiInfo, void* out); - /// Get message (has to be part of JSONRPCResultResponse) - template - SlangResult getMessage(T* out) { return getMessage(GetRttiInfo::get(), (void*)out); } + /// Get message (has to be part of JSONRPCResultResponse) + template + SlangResult getMessage(T* out) + { + return getMessage(GetRttiInfo::get(), (void*)out); + } SlangResult getMessage(const RttiInfo* rttiInfo, void* out); - /// If there is a message and there is a failure, will send an error response - template - SlangResult getMessageOrSendError(T* out) { return getMessageOrSendError(GetRttiInfo::get(), (void*)out); } + /// If there is a message and there is a failure, will send an error response + template + SlangResult getMessageOrSendError(T* out) + { + return getMessageOrSendError(GetRttiInfo::get(), (void*)out); + } SlangResult getMessageOrSendError(const RttiInfo* rttiInfo, void* out); - /// Clears all the internal buffers (for JSON/Source/etc). - /// Happens automatically on tryReadMessage/readMessage + /// Clears all the internal buffers (for JSON/Source/etc). + /// Happens automatically on tryReadMessage/readMessage void clearBuffers(); - /// True if this connection is active + /// True if this connection is active bool isActive(); - /// Get the id of the current message + /// Get the id of the current message JSONValue getCurrentMessageId(); - /// Get the diagnostic sink. Can queue up errors before sending an error - DiagnosticSink* getSink() { return &m_diagnosticSink; } + /// Get the diagnostic sink. Can queue up errors before sending an error + DiagnosticSink* getSink() { return &m_diagnosticSink; } - /// Get the container - JSONContainer* getContainer() { return &m_container; } + /// Get the container + JSONContainer* getContainer() { return &m_container; } - /// Turn a value into a persistant value. This will also remove any sourceLoc under the assumption that it's highly likely - /// it will become invalid in most usage scenarios. - PersistentJSONValue getPersistentValue(const JSONValue& value) { return PersistentJSONValue(value, &m_container, SourceLoc()); } + /// Turn a value into a persistant value. This will also remove any sourceLoc under the + /// assumption that it's highly likely it will become invalid in most usage scenarios. + PersistentJSONValue getPersistentValue(const JSONValue& value) + { + return PersistentJSONValue(value, &m_container, SourceLoc()); + } HTTPPacketConnection* getUnderlyingConnection() { return m_connection.Ptr(); } - /// Dtor + /// Dtor ~JSONRPCConnection() { disconnect(); } - /// Ctor + /// Ctor JSONRPCConnection(); protected: - CallStyle _getCallStyle(CallStyle callStyle) const { return (callStyle == CallStyle::Default) ? m_defaultCallStyle : callStyle; } + CallStyle _getCallStyle(CallStyle callStyle) const + { + return (callStyle == CallStyle::Default) ? m_defaultCallStyle : callStyle; + } - RefPtr m_process; ///< Backing process (optional) - RefPtr m_connection; ///< The underlying 'transport' connection, whilst HTTP currently doesn't have to be + RefPtr m_process; ///< Backing process (optional) + RefPtr m_connection; ///< The underlying 'transport' connection, whilst + ///< HTTP currently doesn't have to be - DiagnosticSink m_diagnosticSink; ///< Holds any diagnostics typically generated by parsing JSON, producing JSON from native types + DiagnosticSink m_diagnosticSink; ///< Holds any diagnostics typically generated by parsing JSON, + ///< producing JSON from native types - SourceManager m_sourceManager; ///< Holds the JSON text for current message/output. Is cleared regularly. - JSONContainer m_container; ///< Holds the backing memory for jsonMemory, and used when converting input into output JSON + SourceManager + m_sourceManager; ///< Holds the JSON text for current message/output. Is cleared regularly. + JSONContainer m_container; ///< Holds the backing memory for jsonMemory, and used when + ///< converting input into output JSON - JSONValue m_jsonRoot; ///< The root JSON value for the currently read message. + JSONValue m_jsonRoot; ///< The root JSON value for the currently read message. + + CallStyle m_defaultCallStyle = CallStyle::Array; ///< The default calling style - CallStyle m_defaultCallStyle = CallStyle::Array; ///< The default calling style - RttiTypeFuncsMap m_typeMap; - Int m_terminationTimeOutInMs = 1 * 1000; ///< Time to wait for termination response. Default is 1 second + Int m_terminationTimeOutInMs = + 1 * 1000; ///< Time to wait for termination response. Default is 1 second }; // --------------------------------------------------------------------------- -template -SlangResult JSONRPCConnection::toValidNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id) +template +SlangResult JSONRPCConnection::toValidNativeOrSendError( + const JSONValue& value, + T* data, + const JSONValue& id) { const RttiInfo* rttiInfo = GetRttiInfo::get(); @@ -191,7 +270,10 @@ SlangResult JSONRPCConnection::toValidNativeOrSendError(const JSONValue& value, if (rttiInfo->isNamed()) { const NamedRttiInfo* namedRttiInfo = static_cast(rttiInfo); - m_diagnosticSink.diagnose(SourceLoc(), JSONDiagnostics::argsAreInvalid, namedRttiInfo->m_name); + m_diagnosticSink.diagnose( + SourceLoc(), + JSONDiagnostics::argsAreInvalid, + namedRttiInfo->m_name); } return sendError(JSONRPC::ErrorCode::InvalidRequest, id); @@ -202,4 +284,3 @@ SlangResult JSONRPCConnection::toValidNativeOrSendError(const JSONValue& value, } // namespace Slang #endif // SLANG_COMPILER_CORE_JSON_RPC_CONNECTION_H - diff --git a/source/compiler-core/slang-json-rpc.cpp b/source/compiler-core/slang-json-rpc.cpp index f4a61da1ed..bf96edefae 100644 --- a/source/compiler-core/slang-json-rpc.cpp +++ b/source/compiler-core/slang-json-rpc.cpp @@ -1,17 +1,18 @@ #include "slang-json-rpc.h" #include "slang-com-helper.h" - #include "slang-json-native.h" -namespace Slang { +namespace Slang +{ // https://www.jsonrpc.org/specification /* static */ const UnownedStringSlice JSONRPC::jsonRpc = UnownedStringSlice::fromLiteral("jsonrpc"); -/* static */const UnownedStringSlice JSONRPC::jsonRpcVersion = UnownedStringSlice::fromLiteral("2.0"); -/* static */const UnownedStringSlice JSONRPC::id = UnownedStringSlice::fromLiteral("id"); +/* static */ const UnownedStringSlice JSONRPC::jsonRpcVersion = + UnownedStringSlice::fromLiteral("2.0"); +/* static */ const UnownedStringSlice JSONRPC::id = UnownedStringSlice::fromLiteral("id"); static const auto g_result = UnownedStringSlice::fromLiteral("result"); static const auto g_error = UnownedStringSlice::fromLiteral("error"); @@ -29,7 +30,8 @@ static const StructRttiInfo _makeJSONRPCErrorResponse_ErrorRtti() builder.addField("message", &obj.message); return builder.make(); } -/* static */const StructRttiInfo JSONRPCErrorResponse::Error::g_rttiInfo = _makeJSONRPCErrorResponse_ErrorRtti(); +/* static */ const StructRttiInfo JSONRPCErrorResponse::Error::g_rttiInfo = + _makeJSONRPCErrorResponse_ErrorRtti(); static const StructRttiInfo _makeJSONRPCErrorResponseRtti() { @@ -43,7 +45,8 @@ static const StructRttiInfo _makeJSONRPCErrorResponseRtti() return builder.make(); } -/* static */const StructRttiInfo JSONRPCErrorResponse::g_rttiInfo = _makeJSONRPCErrorResponseRtti(); +/* static */ const StructRttiInfo JSONRPCErrorResponse::g_rttiInfo = + _makeJSONRPCErrorResponseRtti(); static const StructRttiInfo _makeJSONRPCCallResponseRtti() { @@ -58,7 +61,7 @@ static const StructRttiInfo _makeJSONRPCCallResponseRtti() return builder.make(); } -/* static */const StructRttiInfo JSONRPCCall::g_rttiInfo = _makeJSONRPCCallResponseRtti(); +/* static */ const StructRttiInfo JSONRPCCall::g_rttiInfo = _makeJSONRPCCallResponseRtti(); static const StructRttiInfo _makeJSONResultResponseResponseRtti() { @@ -71,9 +74,12 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() return builder.make(); } -/* static */const StructRttiInfo JSONResultResponse::g_rttiInfo = _makeJSONResultResponseResponseRtti(); +/* static */ const StructRttiInfo JSONResultResponse::g_rttiInfo = + _makeJSONResultResponseResponseRtti(); -/* static */JSONRPCMessageType JSONRPCUtil::getMessageType(JSONContainer* container, const JSONValue& value) +/* static */ JSONRPCMessageType JSONRPCUtil::getMessageType( + JSONContainer* container, + const JSONValue& value) { if (value.getKind() == JSONValue::Kind::Object) { @@ -103,13 +109,18 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() return JSONRPCMessageType::Invalid; } -/* static */SlangResult JSONRPCUtil::parseJSON(const UnownedStringSlice& slice, JSONContainer* container, DiagnosticSink* sink, JSONValue& outValue) +/* static */ SlangResult JSONRPCUtil::parseJSON( + const UnownedStringSlice& slice, + JSONContainer* container, + DiagnosticSink* sink, + JSONValue& outValue) { SourceManager* sourceManager = sink->getSourceManager(); // Now need to parse as JSON String contents(slice); - SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); + SourceFile* sourceFile = + sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); JSONLexer lexer; @@ -124,7 +135,12 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() return SLANG_OK; } -/* static */SlangResult JSONRPCUtil::convertToNative(JSONContainer* container, const JSONValue& value, DiagnosticSink* sink, const RttiInfo* rttiInfo, void* out) +/* static */ SlangResult JSONRPCUtil::convertToNative( + JSONContainer* container, + const JSONValue& value, + DiagnosticSink* sink, + const RttiInfo* rttiInfo, + void* out) { auto typeMap = JSONNativeUtil::getTypeFuncsMap(); @@ -133,7 +149,11 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() return SLANG_OK; } -/* static */SlangResult JSONRPCUtil::convertToJSON(const RttiInfo* rttiInfo, const void* in, DiagnosticSink* sink, StringBuilder& out) +/* static */ SlangResult JSONRPCUtil::convertToJSON( + const RttiInfo* rttiInfo, + const void* in, + DiagnosticSink* sink, + StringBuilder& out) { SourceManager* sourceManager = sink->getSourceManager(); JSONContainer container(sourceManager); @@ -153,7 +173,7 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() return SLANG_OK; } -/* static */JSONValue JSONRPCUtil::getId(JSONContainer* container, const JSONValue& root) +/* static */ JSONValue JSONRPCUtil::getId(JSONContainer* container, const JSONValue& root) { if (root.getKind() == JSONValue::Kind::Object) { @@ -162,7 +182,8 @@ static const StructRttiInfo _makeJSONResultResponseResponseRtti() if (key != JSONKey(0)) { auto obj = container->getObject(root); - Index index = obj.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); + Index index = obj.findFirstIndex( + [key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); if (index >= 0) { diff --git a/source/compiler-core/slang-json-rpc.h b/source/compiler-core/slang-json-rpc.h index 6baba7829a..b9140934f2 100644 --- a/source/compiler-core/slang-json-rpc.h +++ b/source/compiler-core/slang-json-rpc.h @@ -1,29 +1,28 @@ #ifndef SLANG_COMPILER_CORE_JSON_RPC_H #define SLANG_COMPILER_CORE_JSON_RPC_H -#include "slang.h" +#include "../core/slang-http.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - -#include "slang-json-value.h" - #include "slang-json-parser.h" -#include "../core/slang-http.h" +#include "slang-json-value.h" +#include "slang.h" -namespace Slang { +namespace Slang +{ /// Struct to hold values associated with JSON-RPC struct JSONRPC { enum class ErrorCode { - ParseError = -32700, ///< Invalid JSON was received by the server. - InvalidRequest = -32600, ///< The JSON sent is not a valid Request object. - MethodNotFound = -32601, ///< The method does not exist / is not available. - InvalidParams = -32602, ///< Invalid method parameter(s). - InternalError = -32603, ///< Internal JSON - RPC error. + ParseError = -32700, ///< Invalid JSON was received by the server. + InvalidRequest = -32600, ///< The JSON sent is not a valid Request object. + MethodNotFound = -32601, ///< The method does not exist / is not available. + InvalidParams = -32602, ///< Invalid method parameter(s). + InternalError = -32603, ///< Internal JSON - RPC error. - ServerImplStart = -32000, ///< Server implementation defined error range + ServerImplStart = -32000, ///< Server implementation defined error range ServerImplEnd = -32099, }; @@ -32,9 +31,9 @@ struct JSONRPC auto kind = value.getKind(); switch (kind) { - case JSONValue::Kind::Integer: - case JSONValue::Kind::Invalid: - case JSONValue::Kind::String: + case JSONValue::Kind::Integer: + case JSONValue::Kind::Invalid: + case JSONValue::Kind::String: { return true; } @@ -53,30 +52,36 @@ struct JSONRPCErrorResponse { bool isValid() const { return code != 0; } - Int code = 0; ///< Value from ErrorCode - UnownedStringSlice message; ///< Error message - + Int code = 0; ///< Value from ErrorCode + UnownedStringSlice message; ///< Error message + static const StructRttiInfo g_rttiInfo; }; - bool isValid() const { return jsonrpc == JSONRPC::jsonRpcVersion && error.isValid() && JSONRPC::isIdOk(id); } + bool isValid() const + { + return jsonrpc == JSONRPC::jsonRpcVersion && error.isValid() && JSONRPC::isIdOk(id); + } UnownedStringSlice jsonrpc = JSONRPC::jsonRpcVersion; Error error; - JSONValue data; ///< Optional data describing the errro - JSONValue id; ///< Id associated with this request + JSONValue data; ///< Optional data describing the errro + JSONValue id; ///< Id associated with this request static const StructRttiInfo g_rttiInfo; }; struct JSONRPCCall { - bool isValid() const { return method.getLength() > 0 && jsonrpc == JSONRPC::jsonRpcVersion && JSONRPC::isIdOk(id); } + bool isValid() const + { + return method.getLength() > 0 && jsonrpc == JSONRPC::jsonRpcVersion && JSONRPC::isIdOk(id); + } UnownedStringSlice jsonrpc = JSONRPC::jsonRpcVersion; - UnownedStringSlice method; ///< The name of the method - JSONValue params; ///< Can be invalid/array/object - JSONValue id; ///< Id associated with this request + UnownedStringSlice method; ///< The name of the method + JSONValue params; ///< Can be invalid/array/object + JSONValue id; ///< Id associated with this request static const StructRttiInfo g_rttiInfo; }; @@ -86,8 +91,8 @@ struct JSONResultResponse bool isValid() const { return jsonrpc == JSONRPC::jsonRpcVersion && JSONRPC::isIdOk(id); } UnownedStringSlice jsonrpc = JSONRPC::jsonRpcVersion; - JSONValue result; ///< The result value - JSONValue id; ///< Id associated with this request + JSONValue result; ///< The result value + JSONValue id; ///< Id associated with this request static const StructRttiInfo g_rttiInfo; }; @@ -105,30 +110,50 @@ enum class JSONRPCMessageType class JSONRPCUtil { public: - - /// Determine the response type + /// Determine the response type static JSONRPCMessageType getMessageType(JSONContainer* container, const JSONValue& value); - /// Parse slice into JSONContainer. outValue is the root of the hierarchy. - /// NOTE! Uses and *assumes* there is a source manager on the sink. outValue is likely only usable whilst the sourceManger is in scope - /// The sourceLoc can only be interpretted with the sourceLoc anyway - static SlangResult parseJSON(const UnownedStringSlice& slice, JSONContainer* container, DiagnosticSink* sink, JSONValue& outValue); - - /// Convert value into out - static SlangResult convertToNative(JSONContainer* container, const JSONValue& value, DiagnosticSink* sink, const RttiInfo* rttiInfo, void* out); - template - static SlangResult convertToNative(JSONContainer* container, const JSONValue& value, DiagnosticSink* sink, T& out) { return convertToNative(container, value, sink, GetRttiInfo::get(), (void*)&out); } + /// Parse slice into JSONContainer. outValue is the root of the hierarchy. + /// NOTE! Uses and *assumes* there is a source manager on the sink. outValue is likely only + /// usable whilst the sourceManger is in scope The sourceLoc can only be interpretted with the + /// sourceLoc anyway + static SlangResult parseJSON( + const UnownedStringSlice& slice, + JSONContainer* container, + DiagnosticSink* sink, + JSONValue& outValue); + + /// Convert value into out + static SlangResult convertToNative( + JSONContainer* container, + const JSONValue& value, + DiagnosticSink* sink, + const RttiInfo* rttiInfo, + void* out); + template + static SlangResult convertToNative( + JSONContainer* container, + const JSONValue& value, + DiagnosticSink* sink, + T& out) + { + return convertToNative(container, value, sink, GetRttiInfo::get(), (void*)&out); + } - /// Convert to JSON - static SlangResult convertToJSON(const RttiInfo* rttiInfo, const void* in, DiagnosticSink* sink, StringBuilder& out); + /// Convert to JSON + static SlangResult convertToJSON( + const RttiInfo* rttiInfo, + const void* in, + DiagnosticSink* sink, + StringBuilder& out); - template + template static SlangResult convertToJSON(const T* in, DiagnosticSink* sink, StringBuilder& out) { return convertToJSON(GetRttiInfo::get(), (const void*)in, sink, out); } - /// Get an id directly from root (assumed id: is in root object definition). + /// Get an id directly from root (assumed id: is in root object definition). static JSONValue getId(JSONContainer* container, const JSONValue& root); }; diff --git a/source/compiler-core/slang-json-source-map-util.cpp b/source/compiler-core/slang-json-source-map-util.cpp index f66ee50da5..99fe25546a 100644 --- a/source/compiler-core/slang-json-source-map-util.cpp +++ b/source/compiler-core/slang-json-source-map-util.cpp @@ -1,21 +1,22 @@ #include "slang-json-source-map-util.h" -#include "slang-com-helper.h" - -#include "../core/slang-string-util.h" #include "../core/slang-blob.h" - +#include "../core/slang-string-util.h" +#include "slang-com-helper.h" #include "slang-json-native.h" -namespace Slang { +namespace Slang +{ /* -Support for source maps. Source maps provide a standardized mechanism to associate a location in one output file -with another. +Support for source maps. Source maps provide a standardized mechanism to associate a location in one +output file with another. -* [Source Map Proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?hl=en_US&pli=1&pli=1) +* [Source Map +Proposal](https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?hl=en_US&pli=1&pli=1) * [Chrome Source Map post](https://developer.chrome.com/blog/sourcemaps/) -* [Base64 VLQs in Source Maps](https://www.lucidchart.com/techblog/2019/08/22/decode-encoding-base64-vlqs-source-maps/) +* [Base64 VLQs in Source +Maps](https://www.lucidchart.com/techblog/2019/08/22/decode-encoding-base64-vlqs-source-maps/) Example... @@ -30,7 +31,8 @@ Example... } */ -namespace { // anonymous +namespace +{ // anonymous struct JSONSourceMap { @@ -38,14 +40,16 @@ struct JSONSourceMap int32_t version = 3; /// An optional name of the generated code that this source map is associated with. String file; - /// An optional source root, useful for relocating source files on a server or removing repeated values in - /// the “sources” entry. This value is prepended to the individual entries in the “source” field. + /// An optional source root, useful for relocating source files on a server or removing repeated + /// values in the “sources” entry. This value is prepended to the individual entries in the + /// “source” field. String sourceRoot; /// A list of original sources used by the “mappings” entry. List sources; - /// An optional list of source content, useful when the “source” can’t be hosted. The contents are listed in the same order as the sources in line 5. - /// “null” may be used if some original sources should be retrieved by name. - /// Because could be a string or nullptr, we use JSONValue to hold value. + /// An optional list of source content, useful when the “source” can’t be hosted. The contents + /// are listed in the same order as the sources in line 5. “null” may be used if some original + /// sources should be retrieved by name. Because could be a string or nullptr, we use JSONValue + /// to hold value. List sourcesContent; /// A list of symbol names used by the “mappings” entry. List names; @@ -55,7 +59,7 @@ struct JSONSourceMap static const StructRttiInfo g_rttiInfo; }; -} // anonymous +} // namespace static const StructRttiInfo _makeJSONSourceMap_Rtti() { @@ -73,10 +77,11 @@ static const StructRttiInfo _makeJSONSourceMap_Rtti() return builder.make(); } -/* static */const StructRttiInfo JSONSourceMap::g_rttiInfo = _makeJSONSourceMap_Rtti(); +/* static */ const StructRttiInfo JSONSourceMap::g_rttiInfo = _makeJSONSourceMap_Rtti(); // Encode a 6 bit value to VLQ encoding -static const unsigned char g_vlqEncodeTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +static const unsigned char g_vlqEncodeTable[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; struct VlqDecodeTable { @@ -88,19 +93,22 @@ struct VlqDecodeTable map[g_vlqEncodeTable[i]] = int8_t(i); } } - /// Returns a *negative* value if invalid - SLANG_FORCE_INLINE int8_t operator[](unsigned char c) const { return (c & ~char(0x7f)) ? -1 : map[c]; } + /// Returns a *negative* value if invalid + SLANG_FORCE_INLINE int8_t operator[](unsigned char c) const + { + return (c & ~char(0x7f)) ? -1 : map[c]; + } int8_t map[128]; }; static const VlqDecodeTable g_vlqDecodeTable; -/* +/* https://docs.google.com/document/d/1U1RGAehQwRypUTovF1KRlpiOFze0b-_2gc6fAH0KY0k/edit?hl=en_US&pli=1&pli=1# -The VLQ is a Base64 value, where the most significant bit (the 6th bit) is used as the continuation -bit, and the “digits” are encoded into the string least significant first, and where the least significant -bit of the first digit is used as the sign bit. */ +The VLQ is a Base64 value, where the most significant bit (the 6th bit) is used as the continuation +bit, and the “digits” are encoded into the string least significant first, and where the least +significant bit of the first digit is used as the sign bit. */ static SlangResult _decode(UnownedStringSlice& ioEncoded, Index& out) { @@ -125,12 +133,11 @@ static SlangResult _decode(UnownedStringSlice& ioEncoded, Index& out) { return SLANG_FAIL; } - + v += (decodeValue & 0x1f) << shift; shift += 5; - } - while (decodeValue & 0x20); + } while (decodeValue & 0x20); } // Save out the remaining part @@ -148,31 +155,34 @@ void _encode(Index v, StringBuilder& out) // We want to make v always positive to encode // we use the last bit to indicate negativity - v = (v < 0) ? (1 - v) : v; - + v = (v < 0) ? (1 - v) : v; + // We'll use a simple buffer, so as to not have to constantly update he StringBuffer char dst[8]; char* cur = dst; - do + do { const Index nextV = v >> 5; const Index encodeValue = (v & 0x1f) + (nextV ? 0x20 : 0); // Encode 5 bits, plus continuation bit char c = g_vlqEncodeTable[encodeValue]; - + // Save the char *cur++ = c; - + v = nextV; - } - while (v); + } while (v); out.append(dst, cur); } -/* static */SlangResult JSONSourceMapUtil::decode(JSONContainer* container, JSONValue root, DiagnosticSink* sink, SourceMap& outSourceMap) +/* static */ SlangResult JSONSourceMapUtil::decode( + JSONContainer* container, + JSONValue root, + DiagnosticSink* sink, + SourceMap& outSourceMap) { outSourceMap.clear(); @@ -192,7 +202,7 @@ void _encode(Index v, StringBuilder& out) outSourceMap.m_sourceRoot = native.sourceRoot; const Count sourcesCount = native.sources.getCount(); - + // These should all be unique, but for simplicity, we build a table outSourceMap.m_sources.setCount(sourcesCount); for (Index i = 0; i < sourcesCount; ++i) @@ -237,10 +247,10 @@ void _encode(Index v, StringBuilder& out) List lines; StringUtil::split(native.mappings, ';', lines); - + List segments; - // Index into sources + // Index into sources Index sourceFileIndex = 0; Index sourceLine = 0; @@ -280,9 +290,17 @@ void _encode(Index v, StringBuilder& out) // It can be 4 or 5 parts if (segment.getLength()) { - /* If present, an zero-based index into the "sources" list. This field is a base 64 VLQ relative to the previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is represented. - If present, the zero-based starting line in the original source represented. This field is a base 64 VLQ relative to the previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is represented. Always present if there is a source field. - If present, the zero-based starting column of the line in the source represented. This field is a base 64 VLQ relative to the previous occurrence of this field, unless this is the first occurrence of this field, in which case the whole value is represented. Always present if there is a source field. + /* If present, an zero-based index into the "sources" list. This field is a base 64 + VLQ relative to the previous occurrence of this field, unless this is the first + occurrence of this field, in which case the whole value is represented. If + present, the zero-based starting line in the original source represented. This + field is a base 64 VLQ relative to the previous occurrence of this field, unless + this is the first occurrence of this field, in which case the whole value is + represented. Always present if there is a source field. If present, the + zero-based starting column of the line in the source represented. This field is a + base 64 VLQ relative to the previous occurrence of this field, unless this is the + first occurrence of this field, in which case the whole value is represented. + Always present if there is a source field. */ Index sourceFileDelta; @@ -304,9 +322,10 @@ void _encode(Index v, StringBuilder& out) // 5 parts if (segment.getLength() > 0) { - /* If present, the zero - based index into the "names" list associated with this segment. - This field is a base 64 VLQ relative to the previous occurrence of this field, unless this is the first occurrence - of this field, in which case the whole value is represented. + /* If present, the zero - based index into the "names" list associated with this + segment. This field is a base 64 VLQ relative to the previous occurrence of this + field, unless this is the first occurrence of this field, in which case the + whole value is represented. */ Index nameDelta; @@ -334,7 +353,11 @@ void _encode(Index v, StringBuilder& out) return SLANG_OK; } -SlangResult JSONSourceMapUtil::encode(const SourceMap& sourceMap, JSONContainer* container, DiagnosticSink* sink, JSONValue& outValue) +SlangResult JSONSourceMapUtil::encode( + const SourceMap& sourceMap, + JSONContainer* container, + DiagnosticSink* sink, + JSONValue& outValue) { // Convert to native JSONSourceMap native; @@ -359,10 +382,11 @@ SlangResult JSONSourceMapUtil::encode(const SourceMap& sourceMap, JSONContainer* for (Index i = 0; i < count; ++i) { const auto srcValue = sourceMap.m_sourcesContent[i]; - - const JSONValue dstValue = (srcValue == StringSlicePool::kNullHandle) ? - native.sourcesContent[i] = JSONValue::makeNull() : - container->createString(sourceMap.m_slicePool.getSlice(srcValue)); + + const JSONValue dstValue = + (srcValue == StringSlicePool::kNullHandle) + ? native.sourcesContent[i] = JSONValue::makeNull() + : container->createString(sourceMap.m_slicePool.getSlice(srcValue)); native.sourcesContent[i] = dstValue; } @@ -408,7 +432,7 @@ SlangResult JSONSourceMapUtil::encode(const SourceMap& sourceMap, JSONContainer* // We reset the generated column index at the start of each new generated line Index generatedColumn = 0; - + for (Index j = 0; j < entriesCount; ++j) { auto entry = entries[j]; @@ -459,18 +483,22 @@ SlangResult JSONSourceMapUtil::encode(const SourceMap& sourceMap, JSONContainer* RttiTypeFuncsMap typeMap = JSONNativeUtil::getTypeFuncsMap(); NativeToJSONConverter converter(container, &typeMap, sink); - SLANG_RETURN_ON_FAIL(converter.convert(GetRttiInfo::get(), &native, outValue)); + SLANG_RETURN_ON_FAIL( + converter.convert(GetRttiInfo::get(), &native, outValue)); } return SLANG_OK; } -/* static */SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, SourceMap& outSourceMap) +/* static */ SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, SourceMap& outSourceMap) { return read(blob, nullptr, outSourceMap); } -SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, DiagnosticSink* parentSink, SourceMap& outSourceMap) +SlangResult JSONSourceMapUtil::read( + ISlangBlob* blob, + DiagnosticSink* parentSink, + SourceMap& outSourceMap) { outSourceMap.clear(); @@ -485,7 +513,8 @@ SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, DiagnosticSink* parentSink JSONValue rootValue; { // Now need to parse as JSON - SourceFile* sourceFile = sourceManager.createSourceFileWithBlob(PathInfo::makeUnknown(), blob); + SourceFile* sourceFile = + sourceManager.createSourceFileWithBlob(PathInfo::makeUnknown(), blob); SourceView* sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc()); JSONLexer lexer; @@ -505,7 +534,9 @@ SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, DiagnosticSink* parentSink } -/* static */SlangResult JSONSourceMapUtil::write(const SourceMap& sourceMap, ComPtr& outBlob) +/* static */ SlangResult JSONSourceMapUtil::write( + const SourceMap& sourceMap, + ComPtr& outBlob) { SourceManager sourceMapSourceManager; sourceMapSourceManager.initialize(nullptr, nullptr); @@ -517,7 +548,10 @@ SlangResult JSONSourceMapUtil::read(ISlangBlob* blob, DiagnosticSink* parentSink return SLANG_OK; } -/* static */ SlangResult JSONSourceMapUtil::write(const SourceMap& sourceMap, DiagnosticSink* sink, ComPtr& outBlob) +/* static */ SlangResult JSONSourceMapUtil::write( + const SourceMap& sourceMap, + DiagnosticSink* sink, + ComPtr& outBlob) { auto sourceManager = sink->getSourceManager(); diff --git a/source/compiler-core/slang-json-source-map-util.h b/source/compiler-core/slang-json-source-map-util.h index d61936ce45..0e6f4248cc 100644 --- a/source/compiler-core/slang-json-source-map-util.h +++ b/source/compiler-core/slang-json-source-map-util.h @@ -1,29 +1,40 @@ #ifndef SLANG_COMPILER_CORE_JSON_SOURCE_MAP_UTIL_H #define SLANG_COMPILER_CORE_JSON_SOURCE_MAP_UTIL_H -#include "slang-source-map.h" - #include "slang-json-value.h" +#include "slang-source-map.h" -namespace Slang { - -struct JSONSourceMapUtil +namespace Slang { - /// Decode from root into the source map - static SlangResult decode(JSONContainer* container, JSONValue root, DiagnosticSink* sink, SourceMap& out); - - /// Converts the source map contents into JSON - static SlangResult encode(const SourceMap& sourceMap, JSONContainer* container, DiagnosticSink* sink, JSONValue& outValue); - /// Read the blob (encoded as JSON) as a source map. - /// Sink is optional, and can be passed as nullptr +struct JSONSourceMapUtil +{ + /// Decode from root into the source map + static SlangResult decode( + JSONContainer* container, + JSONValue root, + DiagnosticSink* sink, + SourceMap& out); + + /// Converts the source map contents into JSON + static SlangResult encode( + const SourceMap& sourceMap, + JSONContainer* container, + DiagnosticSink* sink, + JSONValue& outValue); + + /// Read the blob (encoded as JSON) as a source map. + /// Sink is optional, and can be passed as nullptr static SlangResult read(ISlangBlob* blob, DiagnosticSink* sink, SourceMap& outSourceMap); static SlangResult read(ISlangBlob* blob, SourceMap& outSourceMap); - /// Write source map to outBlob JSON + /// Write source map to outBlob JSON static SlangResult write(const SourceMap& sourceMap, ComPtr& outBlob); - /// Write out the source map into a blob - static SlangResult write(const SourceMap& sourceMap, DiagnosticSink* sink, ComPtr& outBlob); + /// Write out the source map into a blob + static SlangResult write( + const SourceMap& sourceMap, + DiagnosticSink* sink, + ComPtr& outBlob); }; } // namespace Slang diff --git a/source/compiler-core/slang-json-value.cpp b/source/compiler-core/slang-json-value.cpp index 2e1eb6812c..ae38bd0865 100644 --- a/source/compiler-core/slang-json-value.cpp +++ b/source/compiler-core/slang-json-value.cpp @@ -4,28 +4,28 @@ #include "../core/slang-string-escape-util.h" #include "../core/slang-string-util.h" -namespace Slang { - -/* static */const JSONValue::Kind JSONValue::g_typeToKind[] = +namespace Slang { - JSONValue::Kind::Invalid, // Invalid - JSONValue::Kind::Bool, // True, - JSONValue::Kind::Bool, // False - JSONValue::Kind::Null, // Null, +/* static */ const JSONValue::Kind JSONValue::g_typeToKind[] = { + JSONValue::Kind::Invalid, // Invalid + + JSONValue::Kind::Bool, // True, + JSONValue::Kind::Bool, // False + JSONValue::Kind::Null, // Null, - JSONValue::Kind::String, // StringLexeme, - JSONValue::Kind::Integer, // IntegerLexeme, - JSONValue::Kind::Float, // FloatLexeme, + JSONValue::Kind::String, // StringLexeme, + JSONValue::Kind::Integer, // IntegerLexeme, + JSONValue::Kind::Float, // FloatLexeme, - JSONValue::Kind::Integer, // IntegerValue, - JSONValue::Kind::Float, // FloatValue, - JSONValue::Kind::String, // StringValue, + JSONValue::Kind::Integer, // IntegerValue, + JSONValue::Kind::Float, // FloatValue, + JSONValue::Kind::String, // StringValue, - JSONValue::Kind::String, // StringRepresentation + JSONValue::Kind::String, // StringRepresentation - JSONValue::Kind::Array, // Array, - JSONValue::Kind::Object, // Object, + JSONValue::Kind::Array, // Array, + JSONValue::Kind::Object, // Object, }; static bool _isDefault(const RttiInfo* type, const void* in) @@ -44,7 +44,7 @@ static OtherRttiInfo _getJSONValueRttiInfo() info.m_typeFuncs = GetRttiTypeFuncs::getFuncs(); return info; } -/* static */const OtherRttiInfo JSONValue::g_rttiInfo = _getJSONValueRttiInfo(); +/* static */ const OtherRttiInfo JSONValue::g_rttiInfo = _getJSONValueRttiInfo(); static JSONKeyValue _makeInvalidKeyValue() { @@ -54,7 +54,7 @@ static JSONKeyValue _makeInvalidKeyValue() return keyValue; } -/* static */JSONKeyValue g_invalid = _makeInvalidKeyValue(); +/* static */ JSONKeyValue g_invalid = _makeInvalidKeyValue(); /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -66,15 +66,19 @@ bool JSONValue::asBool() const { switch (type) { - case JSONValue::Type::True: return true; - case JSONValue::Type::False: - case JSONValue::Type::Null: + case JSONValue::Type::True: + return true; + case JSONValue::Type::False: + case JSONValue::Type::Null: { return false; } - case JSONValue::Type::IntegerValue: return intValue != 0; - case JSONValue::Type::FloatValue: return floatValue != 0; - default: break; + case JSONValue::Type::IntegerValue: + return intValue != 0; + case JSONValue::Type::FloatValue: + return floatValue != 0; + default: + break; } if (isLexeme(type)) @@ -85,7 +89,7 @@ bool JSONValue::asBool() const { SLANG_ASSERT(!"Not bool convertable"); } - + return false; } @@ -93,14 +97,17 @@ int64_t JSONValue::asInteger() const { switch (type) { - case JSONValue::Type::True: return 1; - case JSONValue::Type::False: - case JSONValue::Type::Null: + case JSONValue::Type::True: + return 1; + case JSONValue::Type::False: + case JSONValue::Type::Null: { return 0; } - case JSONValue::Type::IntegerValue: return intValue; - case JSONValue::Type::FloatValue: return int64_t(floatValue); + case JSONValue::Type::IntegerValue: + return intValue; + case JSONValue::Type::FloatValue: + return int64_t(floatValue); break; } @@ -120,15 +127,19 @@ double JSONValue::asFloat() const { switch (type) { - case JSONValue::Type::True: return 1.0; - case JSONValue::Type::False: - case JSONValue::Type::Null: + case JSONValue::Type::True: + return 1.0; + case JSONValue::Type::False: + case JSONValue::Type::Null: { return 0.0; } - case JSONValue::Type::IntegerValue: return double(intValue); - case JSONValue::Type::FloatValue: return floatValue; - default: break; + case JSONValue::Type::IntegerValue: + return double(intValue); + case JSONValue::Type::FloatValue: + return floatValue; + default: + break; } if (isLexeme(type)) @@ -139,7 +150,7 @@ double JSONValue::asFloat() const { SLANG_ASSERT(!"Not float convertable"); } - + return 0; } @@ -197,7 +208,8 @@ UnownedStringSlice PersistentJSONValue::getSlice() const void PersistentJSONValue::set(const UnownedStringSlice& slice, SourceLoc inLoc) { - StringRepresentation* oldRep = (type == JSONValue::Type::StringRepresentation) ? stringRep : nullptr; + StringRepresentation* oldRep = + (type == JSONValue::Type::StringRepresentation) ? stringRep : nullptr; type = Type::StringRepresentation; loc = inLoc; @@ -205,13 +217,11 @@ void PersistentJSONValue::set(const UnownedStringSlice& slice, SourceLoc inLoc) StringRepresentation* newRep = nullptr; const auto sliceLength = slice.getLength(); - + // If we have an oldRep that is unique and large enough reuse it if (sliceLength) { - if (oldRep && - oldRep->isUniquelyReferenced() && - sliceLength <= oldRep->capacity) + if (oldRep && oldRep->isUniquelyReferenced() && sliceLength <= oldRep->capacity) { oldRep->setContents(slice); newRep = oldRep; @@ -220,7 +230,7 @@ void PersistentJSONValue::set(const UnownedStringSlice& slice, SourceLoc inLoc) } else { - newRep = StringRepresentation::createWithReference(slice); + newRep = StringRepresentation::createWithReference(slice); } SLANG_ASSERT(newRep->debugGetReferenceCount() >= 1); @@ -248,25 +258,26 @@ bool PersistentJSONValue::operator==(const ThisType& rhs) const return true; } - if (type != rhs.type || - loc != rhs.loc) + if (type != rhs.type || loc != rhs.loc) { return false; } switch (type) { - case Type::Invalid: - case Type::True: - case Type::False: - case Type::Null: + case Type::Invalid: + case Type::True: + case Type::False: + case Type::Null: { // The type is all that needs to be checked return true; } - case Type::IntegerValue: return intValue == rhs.intValue; - case Type::FloatValue: return floatValue == rhs.floatValue; - case Type::StringRepresentation: + case Type::IntegerValue: + return intValue == rhs.intValue; + case Type::FloatValue: + return floatValue == rhs.floatValue; + case Type::StringRepresentation: { if (stringRep == rhs.stringRep) { @@ -276,7 +287,8 @@ bool PersistentJSONValue::operator==(const ThisType& rhs) const auto rhsSlice = StringRepresentation::asSlice(rhs.stringRep); return thisSlice == rhsSlice; } - default: break; + default: + break; } SLANG_ASSERT(!"Not valid Persistent type"); @@ -290,8 +302,8 @@ void PersistentJSONValue::_init(const JSONValue& in, JSONContainer* container) switch (in.type) { - case Type::StringValue: - case Type::StringLexeme: + case Type::StringValue: + case Type::StringLexeme: { if (!container) { @@ -301,7 +313,7 @@ void PersistentJSONValue::_init(const JSONValue& in, JSONContainer* container) _init(container->getTransientString(in), in.loc); break; } - case Type::StringRepresentation: + case Type::StringRepresentation: { *(JSONValue*)this = in; if (stringRep) @@ -310,27 +322,27 @@ void PersistentJSONValue::_init(const JSONValue& in, JSONContainer* container) } break; } - case Type::IntegerLexeme: + case Type::IntegerLexeme: { type = JSONValue::Type::IntegerValue; intValue = container->asInteger(in); loc = in.loc; break; } - case Type::FloatLexeme: + case Type::FloatLexeme: { type = JSONValue::Type::FloatValue; floatValue = container->asFloat(in); loc = in.loc; break; } - case Type::Array: - case Type::Object: + case Type::Array: + case Type::Object: { SLANG_ASSERT(!"Not a simple JSON type"); break; } - default: + default: { *(JSONValue*)this = in; break; @@ -364,9 +376,8 @@ void PersistentJSONValue::set(const JSONValue& in, JSONContainer* container) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -JSONContainer::JSONContainer(SourceManager* sourceManager): - m_slicePool(StringSlicePool::Style::Default), - m_sourceManager(sourceManager) +JSONContainer::JSONContainer(SourceManager* sourceManager) + : m_slicePool(StringSlicePool::Style::Default), m_sourceManager(sourceManager) { // Index 0 is the empty array or object _addRange(Range::Type::None, 0, 0); @@ -385,7 +396,7 @@ void JSONContainer::reset() m_currentView = nullptr; } -/* static */bool JSONContainer::areKeysUnique(const JSONKeyValue* keyValues, Index keyValueCount) +/* static */ bool JSONContainer::areKeysUnique(const JSONKeyValue* keyValues, Index keyValueCount) { for (Index i = 1; i < keyValueCount; ++i) { @@ -447,7 +458,10 @@ JSONValue JSONContainer::createArray(const JSONValue* values, Index valuesCount, return value; } -JSONValue JSONContainer::createObject(const JSONKeyValue* keyValues, Index keyValueCount, SourceLoc loc) +JSONValue JSONContainer::createObject( + const JSONKeyValue* keyValues, + Index keyValueCount, + SourceLoc loc) { if (keyValueCount <= 0) { @@ -514,7 +528,9 @@ ArrayView JSONContainer::getArray(const JSONValue& in) return ArrayView((JSONValue*)nullptr, 0); } const Range& range = m_ranges[in.rangeIndex]; - SLANG_ASSERT(range.startIndex <= m_arrayValues.getCount() && range.startIndex + range.count <= m_arrayValues.getCount()); + SLANG_ASSERT( + range.startIndex <= m_arrayValues.getCount() && + range.startIndex + range.count <= m_arrayValues.getCount()); return ArrayView(m_arrayValues.getBuffer() + range.startIndex, range.count); } @@ -558,27 +574,28 @@ UnownedStringSlice JSONContainer::getString(const JSONValue& in) { switch (in.type) { - case JSONValue::Type::StringValue: + case JSONValue::Type::StringValue: { return getStringFromKey(in.stringKey); } - case JSONValue::Type::StringLexeme: + case JSONValue::Type::StringLexeme: { auto slice = getTransientString(in); auto handle = m_slicePool.add(slice); return m_slicePool.getSlice(handle); } - case JSONValue::Type::StringRepresentation: + case JSONValue::Type::StringRepresentation: { return StringRepresentation::asSlice(in.stringRep); } - case JSONValue::Type::Null: + case JSONValue::Type::Null: { return UnownedStringSlice(); } - default: break; + default: + break; } - + SLANG_ASSERT(!"Not a string type"); return UnownedStringSlice(); } @@ -587,17 +604,18 @@ UnownedStringSlice JSONContainer::getTransientString(const JSONValue& in) { switch (in.type) { - case JSONValue::Type::StringRepresentation: + case JSONValue::Type::StringRepresentation: { return StringRepresentation::asSlice(in.stringRep); } - case JSONValue::Type::StringValue: + case JSONValue::Type::StringValue: { return getStringFromKey(in.stringKey); } - case JSONValue::Type::StringLexeme: + case JSONValue::Type::StringLexeme: { - StringEscapeHandler* handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON); + StringEscapeHandler* handler = + StringEscapeUtil::getHandler(StringEscapeUtil::Style::JSON); UnownedStringSlice lexeme = getLexeme(in); UnownedStringSlice unquoted = StringEscapeUtil::unquote(handler, lexeme); @@ -613,7 +631,7 @@ UnownedStringSlice JSONContainer::getTransientString(const JSONValue& in) return unquoted; } } - case JSONValue::Type::Null: + case JSONValue::Type::Null: { return UnownedStringSlice(); } @@ -625,16 +643,20 @@ UnownedStringSlice JSONContainer::getTransientString(const JSONValue& in) JSONKey JSONContainer::getStringKey(const JSONValue& in) { - return (in.type == JSONValue::Type::StringValue) ? in.stringKey : getKey(getTransientString(in)); + return (in.type == JSONValue::Type::StringValue) ? in.stringKey + : getKey(getTransientString(in)); } - + bool JSONContainer::asBool(const JSONValue& value) { switch (value.type) { - case JSONValue::Type::IntegerLexeme: return asInteger(value) != 0; - case JSONValue::Type::FloatLexeme: return asFloat(value) != 0.0; - default: return value.asBool(); + case JSONValue::Type::IntegerLexeme: + return asInteger(value) != 0; + case JSONValue::Type::FloatLexeme: + return asFloat(value) != 0.0; + default: + return value.asBool(); } } @@ -643,26 +665,27 @@ JSONValue JSONContainer::asValue(const JSONValue& inValue) JSONValue value = inValue; switch (value.type) { - case JSONValue::Type::StringLexeme: + case JSONValue::Type::StringLexeme: { const UnownedStringSlice slice = getTransientString(inValue); value.stringKey = getKey(slice); value.type = JSONValue::Type::StringValue; break; } - case JSONValue::Type::IntegerLexeme: + case JSONValue::Type::IntegerLexeme: { value.floatValue = value.asFloat(); value.type = JSONValue::Type::IntegerValue; break; } - case JSONValue::Type::FloatLexeme: + case JSONValue::Type::FloatLexeme: { value.floatValue = value.asFloat(); value.type = JSONValue::Type::FloatValue; break; } - default: break; + default: + break; } return value; @@ -687,12 +710,14 @@ void JSONContainer::clearSourceManagerDependency(JSONValue* ioValues, Index valu { switch (range.type) { - case Range::Type::Array: + case Range::Type::Array: { - _clearSourceManagerDependency(m_arrayValues.getBuffer() + range.startIndex, range.count); + _clearSourceManagerDependency( + m_arrayValues.getBuffer() + range.startIndex, + range.count); break; } - case Range::Type::Object: + case Range::Type::Object: { const Index count = range.count; auto pairs = m_objectValues.getBuffer() + range.startIndex; @@ -706,7 +731,8 @@ void JSONContainer::clearSourceManagerDependency(JSONValue* ioValues, Index valu } break; } - default: break; + default: + break; } } @@ -718,7 +744,7 @@ int64_t JSONContainer::asInteger(const JSONValue& value) { switch (value.type) { - case JSONValue::Type::IntegerLexeme: + case JSONValue::Type::IntegerLexeme: { UnownedStringSlice slice = getLexeme(value); int64_t intValue; @@ -729,8 +755,10 @@ int64_t JSONContainer::asInteger(const JSONValue& value) SLANG_ASSERT(!"Couldn't convert int"); return 0; } - case JSONValue::Type::FloatLexeme: return int64_t(asFloat(value)); - default: return value.asInteger(); + case JSONValue::Type::FloatLexeme: + return int64_t(asFloat(value)); + default: + return value.asInteger(); } } @@ -738,8 +766,9 @@ double JSONContainer::asFloat(const JSONValue& value) { switch (value.type) { - case JSONValue::Type::IntegerLexeme: return double(asInteger(value)); - case JSONValue::Type::FloatLexeme: + case JSONValue::Type::IntegerLexeme: + return double(asInteger(value)); + case JSONValue::Type::FloatLexeme: { UnownedStringSlice slice = getLexeme(value); double floatValue; @@ -750,20 +779,23 @@ double JSONContainer::asFloat(const JSONValue& value) SLANG_ASSERT(!"Couldn't convert double"); return 0.0; } - default: return value.asFloat(); + default: + return value.asFloat(); } } Index JSONContainer::findObjectIndex(const JSONValue& obj, JSONKey key) const { auto pairs = getObject(obj); - return pairs.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); + return pairs.findFirstIndex( + [key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); } JSONValue JSONContainer::findObjectValue(const JSONValue& obj, JSONKey key) const { auto pairs = getObject(obj); - const Index index = pairs.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); + const Index index = + pairs.findFirstIndex([key](const JSONKeyValue& pair) -> bool { return pair.key == key; }); return (index >= 0) ? pairs[index].value : JSONValue::makeInvalid(); } @@ -787,7 +819,6 @@ void JSONContainer::addToArray(JSONValue& array, const JSONValue& value) // We can just add to the end array.rangeIndex = _addRange(Range::Type::Array, m_arrayValues.getCount(), 1); m_arrayValues.add(value); - } else { @@ -837,7 +868,10 @@ void JSONContainer::_removeKey(JSONValue& obj, Index globalIndex) if (localIndex < range.count - 1) { auto localBuf = m_objectValues.getBuffer() + range.startIndex; - ::memmove(localBuf + localIndex, localBuf + localIndex + 1, sizeof(*localBuf) * (range.count - (localIndex + 1))); + ::memmove( + localBuf + localIndex, + localBuf + localIndex + 1, + sizeof(*localBuf) * (range.count - (localIndex + 1))); } --range.count; @@ -865,8 +899,8 @@ bool JSONContainer::removeKey(JSONValue& obj, const UnownedStringSlice& slice) return false; } -template -/* static */void JSONContainer::_add(Range& ioRange, List& ioList, const T& value) +template +/* static */ void JSONContainer::_add(Range& ioRange, List& ioList, const T& value) { // If we have capacity, we can add to the end if (ioRange.count < ioRange.capacity) @@ -938,7 +972,7 @@ void JSONContainer::_destroyRange(Index rangeIndex) // If the range is at the end, shrink it switch (range.type) { - case Range::Type::Array: + case Range::Type::Array: { if (range.startIndex + range.capacity == m_arrayValues.getCount()) { @@ -946,7 +980,7 @@ void JSONContainer::_destroyRange(Index rangeIndex) } break; } - case Range::Type::Object: + case Range::Type::Object: { if (range.startIndex + range.capacity == m_objectValues.getCount()) { @@ -954,7 +988,8 @@ void JSONContainer::_destroyRange(Index rangeIndex) } break; } - default: break; + default: + break; } range.type = Range::Type::Destroyed; @@ -971,7 +1006,7 @@ void JSONContainer::destroy(JSONValue& value) } void JSONContainer::destroyRecursively(JSONValue& inValue) -{ +{ if (!(inValue.needsDestroy() && m_ranges[inValue.rangeIndex].isActive())) { inValue.type = JSONValue::Type::Invalid; @@ -1000,7 +1035,7 @@ void JSONContainer::destroyRecursively(JSONValue& inValue) for (Index i = 0; i < count; ++i) { auto& value = buf[i]; - // If we have an active range, add to work list, and destroy + // If we have an active range, add to work list, and destroy if (value.needsDestroy() && m_ranges[value.rangeIndex].isActive()) { activeRanges.add(m_ranges[value.rangeIndex]); @@ -1009,7 +1044,7 @@ void JSONContainer::destroyRecursively(JSONValue& inValue) value.type = JSONValue::Type::Invalid; } } - else + else { SLANG_ASSERT(type == Range::Type::Object); @@ -1019,7 +1054,8 @@ void JSONContainer::destroyRecursively(JSONValue& inValue) { auto& keyValue = buf[i]; auto& value = keyValue.value; - // We want to mark that it's in the list so that if we have a badly formed tree we don't read + // We want to mark that it's in the list so that if we have a badly formed tree we + // don't read if (value.needsDestroy() && m_ranges[value.rangeIndex].isActive()) { activeRanges.add(m_ranges[value.rangeIndex]); @@ -1045,7 +1081,10 @@ bool JSONContainer::areEqual(const JSONValue* a, const JSONValue* b, Index count } -/* static */bool JSONContainer::_sameKeyOrder(const JSONKeyValue* a, const JSONKeyValue* b, Index count) +/* static */ bool JSONContainer::_sameKeyOrder( + const JSONKeyValue* a, + const JSONKeyValue* b, + Index count) { for (Index i = 0; i < count; ++i) { @@ -1064,8 +1103,7 @@ bool JSONContainer::_areEqualOrderedKeys(const JSONKeyValue* a, const JSONKeyVal const auto& curA = a[i]; const auto& curB = b[i]; - if (curA.key != curB.key || - !areEqual(curA.value, curB.value)) + if (curA.key != curB.key || !areEqual(curA.value, curB.value)) { return false; } @@ -1102,15 +1140,17 @@ bool JSONContainer::areEqual(const JSONKeyValue* a, const JSONKeyValue* b, Index } else { - // We need to compare with keys in the same order + // We need to compare with keys in the same order List sortedAs; sortedAs.addRange(a, count); List sortedBs; sortedBs.addRange(b, count); - sortedAs.sort([](const JSONKeyValue&a, const JSONKeyValue& b) -> bool { return a.key < b.key; }); - sortedBs.sort([](const JSONKeyValue&a, const JSONKeyValue& b) -> bool { return a.key < b.key; }); + sortedAs.sort( + [](const JSONKeyValue& a, const JSONKeyValue& b) -> bool { return a.key < b.key; }); + sortedBs.sort( + [](const JSONKeyValue& a, const JSONKeyValue& b) -> bool { return a.key < b.key; }); return _areEqualOrderedKeys(sortedAs.getBuffer(), sortedBs.getBuffer(), count); } @@ -1132,18 +1172,21 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) { switch (a.type) { - default: - // Invalid are never equal - case JSONValue::Type::Invalid: return false; - case JSONValue::Type::True: - case JSONValue::Type::False: - case JSONValue::Type::Null: + default: + // Invalid are never equal + case JSONValue::Type::Invalid: + return false; + case JSONValue::Type::True: + case JSONValue::Type::False: + case JSONValue::Type::Null: { return true; } - case JSONValue::Type::IntegerLexeme:return asInteger(a) == asInteger(b); - case JSONValue::Type::FloatLexeme: return asFloat(a) == asFloat(b); - case JSONValue::Type::StringLexeme: + case JSONValue::Type::IntegerLexeme: + return asInteger(a) == asInteger(b); + case JSONValue::Type::FloatLexeme: + return asFloat(a) == asFloat(b); + case JSONValue::Type::StringLexeme: { // If the lexemes are equal they are equal UnownedStringSlice lexemeA = getLexeme(a); @@ -1151,15 +1194,18 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) // Else we want to decode the string to be sure if they are equal. return lexemeA == lexemeB || getStringKey(a) == getStringKey(b); } - case JSONValue::Type::IntegerValue: return a.intValue == b.intValue; - case JSONValue::Type::FloatValue: return a.floatValue == b.floatValue; - case JSONValue::Type::StringValue: return a.stringKey == b.stringKey; - case JSONValue::Type::StringRepresentation: + case JSONValue::Type::IntegerValue: + return a.intValue == b.intValue; + case JSONValue::Type::FloatValue: + return a.floatValue == b.floatValue; + case JSONValue::Type::StringValue: + return a.stringKey == b.stringKey; + case JSONValue::Type::StringRepresentation: { - return a.stringRep == b.stringRep || - StringRepresentation::asSlice(a.stringRep) == StringRepresentation::asSlice(b.stringRep); + return a.stringRep == b.stringRep || StringRepresentation::asSlice(a.stringRep) == + StringRepresentation::asSlice(b.stringRep); } - case JSONValue::Type::Array: + case JSONValue::Type::Array: { if (a.rangeIndex == b.rangeIndex) { @@ -1169,9 +1215,10 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) auto arrayB = getArray(b); const Index count = arrayA.getCount(); - return (count == arrayB.getCount()) && areEqual(arrayA.getBuffer(), arrayB.getBuffer(), count); + return (count == arrayB.getCount()) && + areEqual(arrayA.getBuffer(), arrayB.getBuffer(), count); } - case JSONValue::Type::Object: + case JSONValue::Type::Object: { if (a.rangeIndex == b.rangeIndex) { @@ -1181,7 +1228,8 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) const auto bValues = getObject(b); const Index count = aValues.getCount(); - return (count == bValues.getCount()) && areEqual(aValues.getBuffer(), bValues.getBuffer(), count); + return (count == bValues.getCount()) && + areEqual(aValues.getBuffer(), bValues.getBuffer(), count); } } } @@ -1192,10 +1240,14 @@ bool JSONContainer::areEqual(const JSONValue& a, const JSONValue& b) { switch (kind) { - case JSONValue::Kind::String: return getStringKey(a) == getStringKey(b); - case JSONValue::Kind::Integer: return asInteger(a) == asInteger(b); - case JSONValue::Kind::Float: return asFloat(a) == asFloat(b); - default: break; + case JSONValue::Kind::String: + return getStringKey(a) == getStringKey(b); + case JSONValue::Kind::Integer: + return asInteger(a) == asInteger(b); + case JSONValue::Kind::Float: + return asFloat(a) == asFloat(b); + default: + break; } } @@ -1207,27 +1259,35 @@ void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* li typedef JSONValue::Type Type; switch (value.type) - { - case Type::True: return listener->addBoolValue(true, value.loc); - case Type::False: return listener->addBoolValue(false, value.loc); - case Type::Null: return listener->addNullValue(value.loc); - - case Type::StringLexeme: return listener->addLexemeValue(JSONTokenType::StringLiteral, getLexeme(value), value.loc); - case Type::IntegerLexeme: return listener->addLexemeValue(JSONTokenType::IntegerLiteral, getLexeme(value), value.loc); - case Type::FloatLexeme: return listener->addLexemeValue(JSONTokenType::FloatLiteral, getLexeme(value), value.loc); - - case Type::IntegerValue: return listener->addIntegerValue(value.intValue, value.loc); - case Type::FloatValue: return listener->addFloatValue(value.floatValue, value.loc); - case Type::StringValue: + { + case Type::True: + return listener->addBoolValue(true, value.loc); + case Type::False: + return listener->addBoolValue(false, value.loc); + case Type::Null: + return listener->addNullValue(value.loc); + + case Type::StringLexeme: + return listener->addLexemeValue(JSONTokenType::StringLiteral, getLexeme(value), value.loc); + case Type::IntegerLexeme: + return listener->addLexemeValue(JSONTokenType::IntegerLiteral, getLexeme(value), value.loc); + case Type::FloatLexeme: + return listener->addLexemeValue(JSONTokenType::FloatLiteral, getLexeme(value), value.loc); + + case Type::IntegerValue: + return listener->addIntegerValue(value.intValue, value.loc); + case Type::FloatValue: + return listener->addFloatValue(value.floatValue, value.loc); + case Type::StringValue: { const auto slice = getStringFromKey(value.stringKey); return listener->addStringValue(slice, value.loc); } - case Type::StringRepresentation: + case Type::StringRepresentation: { return listener->addStringValue(getTransientString(value), value.loc); } - case Type::Array: + case Type::Array: { listener->startArray(value.loc); @@ -1241,7 +1301,7 @@ void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* li listener->endArray(SourceLoc()); break; } - case Type::Object: + case Type::Object: { listener->startObject(value.loc); @@ -1260,7 +1320,7 @@ void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* li listener->endObject(SourceLoc()); break; } - default: + default: { SLANG_ASSERT(!"Invalid type"); return; @@ -1274,9 +1334,8 @@ void JSONContainer::traverseRecursively(const JSONValue& value, JSONListener* li !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -JSONBuilder::JSONBuilder(JSONContainer* container, Flags flags): - m_container(container), - m_flags(flags) +JSONBuilder::JSONBuilder(JSONContainer* container, Flags flags) + : m_container(container), m_flags(flags) { m_state.m_kind = State::Kind::Root; m_state.m_startIndex = 0; @@ -1308,12 +1367,12 @@ void JSONBuilder::_popState() // Reset the end depending on typpe switch (m_state.m_kind) { - case State::Kind::Array: + case State::Kind::Array: { m_values.setCount(m_state.m_startIndex); break; } - case State::Kind::Object: + case State::Kind::Object: { m_keyValues.setCount(m_state.m_startIndex); break; @@ -1346,18 +1405,18 @@ void JSONBuilder::_add(const JSONValue& value) SLANG_ASSERT(value.isValid()); switch (m_state.m_kind) { - case State::Kind::Root: + case State::Kind::Root: { SLANG_ASSERT(!m_rootValue.isValid()); m_rootValue = value; break; } - case State::Kind::Array: + case State::Kind::Array: { m_values.add(value); break; } - case State::Kind::Object: + case State::Kind::Object: { SLANG_ASSERT(m_state.hasKey()); @@ -1398,7 +1457,10 @@ void JSONBuilder::endObject(SourceLoc loc) SLANG_ASSERT(m_state.m_kind == State::Kind::Object); const Index count = m_keyValues.getCount() - m_state.m_startIndex; - const JSONValue value = m_container->createObject(m_keyValues.getBuffer() + m_state.m_startIndex, count, m_state.m_loc); + const JSONValue value = m_container->createObject( + m_keyValues.getBuffer() + m_state.m_startIndex, + count, + m_state.m_loc); // Pop current state _popState(); @@ -1422,7 +1484,8 @@ void JSONBuilder::endArray(SourceLoc loc) SLANG_ASSERT(m_state.m_kind == State::Kind::Array); const Index count = m_values.getCount() - m_state.m_startIndex; - const JSONValue value = m_container->createArray(m_values.getBuffer() + m_state.m_startIndex, count, m_state.m_loc); + const JSONValue value = + m_container->createArray(m_values.getBuffer() + m_state.m_startIndex, count, m_state.m_loc); // Pop current state _popState(); @@ -1449,11 +1512,14 @@ void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& v { switch (type) { - case JSONTokenType::True: return _add(JSONValue::makeBool(true, loc)); - case JSONTokenType::False: return _add(JSONValue::makeBool(false, loc)); - case JSONTokenType::Null: return _add(JSONValue::makeNull(loc)); - - case JSONTokenType::IntegerLiteral: + case JSONTokenType::True: + return _add(JSONValue::makeBool(true, loc)); + case JSONTokenType::False: + return _add(JSONValue::makeBool(false, loc)); + case JSONTokenType::Null: + return _add(JSONValue::makeNull(loc)); + + case JSONTokenType::IntegerLiteral: { if (m_flags & Flag::ConvertLexemes) { @@ -1470,7 +1536,7 @@ void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& v } break; } - case JSONTokenType::FloatLiteral: + case JSONTokenType::FloatLiteral: { if (m_flags & Flag::ConvertLexemes) { @@ -1487,7 +1553,7 @@ void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& v } break; } - case JSONTokenType::StringLiteral: + case JSONTokenType::StringLiteral: { if (m_flags & Flag::ConvertLexemes) { @@ -1504,7 +1570,7 @@ void JSONBuilder::addLexemeValue(JSONTokenType type, const UnownedStringSlice& v } break; } - default: + default: { SLANG_ASSERT(!"Unhandled type"); } diff --git a/source/compiler-core/slang-json-value.h b/source/compiler-core/slang-json-value.h index 0abe7c9a6a..d9b17f1d52 100644 --- a/source/compiler-core/slang-json-value.h +++ b/source/compiler-core/slang-json-value.h @@ -3,15 +3,13 @@ #define SLANG_JSON_VALUE_H #include "../core/slang-basic.h" - -#include "slang-source-loc.h" +#include "../core/slang-rtti-info.h" #include "slang-diagnostic-sink.h" - #include "slang-json-parser.h" +#include "slang-source-loc.h" -#include "../core/slang-rtti-info.h" - -namespace Slang { +namespace Slang +{ typedef uint32_t JSONKey; @@ -31,7 +29,7 @@ struct JSONValue Array, Object, - CountOf, + CountOf, }; enum class Type @@ -58,39 +56,96 @@ struct JSONValue CountOf, }; - static bool isLexeme(Type type) { return Index(type) >= Index(Type::StringLexeme) && Index(type) <= Index(Type::FloatLexeme); } + static bool isLexeme(Type type) + { + return Index(type) >= Index(Type::StringLexeme) && Index(type) <= Index(Type::FloatLexeme); + } - static JSONValue makeInt(int64_t inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::IntegerValue; value.loc = loc; value.intValue = inValue; return value; } - static JSONValue makeFloat(double inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::FloatValue; value.loc = loc; value.floatValue = inValue; return value; } - static JSONValue makeNull(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Null; value.loc = loc; return value; } - static JSONValue makeBool(bool inValue, SourceLoc loc = SourceLoc()) { JSONValue value; value.type = (inValue ? Type::True : Type::False); value.loc = loc; return value; } + static JSONValue makeInt(int64_t inValue, SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::IntegerValue; + value.loc = loc; + value.intValue = inValue; + return value; + } + static JSONValue makeFloat(double inValue, SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::FloatValue; + value.loc = loc; + value.floatValue = inValue; + return value; + } + static JSONValue makeNull(SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::Null; + value.loc = loc; + return value; + } + static JSONValue makeBool(bool inValue, SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = (inValue ? Type::True : Type::False); + value.loc = loc; + return value; + } - static JSONValue makeLexeme(Type type, SourceLoc loc, Index length) { SLANG_ASSERT(isLexeme(type)); JSONValue value; value.type = type; value.loc = loc; value.length = length; return value; } + static JSONValue makeLexeme(Type type, SourceLoc loc, Index length) + { + SLANG_ASSERT(isLexeme(type)); + JSONValue value; + value.type = type; + value.loc = loc; + value.length = length; + return value; + } - static JSONValue makeEmptyArray(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Array; value.loc = loc; value.rangeIndex = 0; return value; } - static JSONValue makeEmptyObject(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Object; value.loc = loc; value.rangeIndex = 0; return value; } + static JSONValue makeEmptyArray(SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::Array; + value.loc = loc; + value.rangeIndex = 0; + return value; + } + static JSONValue makeEmptyObject(SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::Object; + value.loc = loc; + value.rangeIndex = 0; + return value; + } - static JSONValue makeInvalid(SourceLoc loc = SourceLoc()) { JSONValue value; value.type = Type::Invalid; value.loc = loc; return value; } - // The following functions only work if the value is stored directly NOT as a lexeme. Use the methods on the container - // to access values if it is potentially stored as a lexeme + static JSONValue makeInvalid(SourceLoc loc = SourceLoc()) + { + JSONValue value; + value.type = Type::Invalid; + value.loc = loc; + return value; + } + // The following functions only work if the value is stored directly NOT as a lexeme. Use the + // methods on the container to access values if it is potentially stored as a lexeme - /// As a boolean value + /// As a boolean value bool asBool() const; - /// As an integer value + /// As an integer value int64_t asInteger() const; - /// As a float value + /// As a float value double asFloat() const; - /// True if this is a object like + /// True if this is a object like bool isObjectLike() const { return Index(type) >= Index(Type::Array); } - /// True if this appears to be a valid value + /// True if this appears to be a valid value bool isValid() const { return type != JSONValue::Type::Invalid; } - /// True if needs destroy + /// True if needs destroy bool needsDestroy() const { return isObjectLike() && rangeIndex != 0; } - /// Get the kind + /// Get the kind SLANG_FORCE_INLINE Kind getKind() const { return getKindForType(type); } void reset() @@ -99,20 +154,20 @@ struct JSONValue loc = SourceLoc(); } - /// Given a type return the associated kind + /// Given a type return the associated kind static Kind getKindForType(Type type) { return g_typeToKind[Index(type)]; } - Type type = Type::Invalid; ///< The type of value - SourceLoc loc; ///< The (optional) location in source of this value. + Type type = Type::Invalid; ///< The type of value + SourceLoc loc; ///< The (optional) location in source of this value. - union + union { - Index rangeIndex; ///< Used for Array/Object - Index length; ///< Length in bytes if it is a 'Lexeme' - double floatValue; ///< Float value - int64_t intValue; ///< Integer value - JSONKey stringKey; ///< The pool key if it's a string - StringRepresentation* stringRep; ///< Only ever used on a 'PersistentJSONValue' + Index rangeIndex; ///< Used for Array/Object + Index length; ///< Length in bytes if it is a 'Lexeme' + double floatValue; ///< Float value + int64_t intValue; ///< Integer value + JSONKey stringKey; ///< The pool key if it's a string + StringRepresentation* stringRep; ///< Only ever used on a 'PersistentJSONValue' }; static const Kind g_typeToKind[Index(Type::CountOf)]; @@ -120,12 +175,15 @@ struct JSONValue static const OtherRttiInfo g_rttiInfo; }; -template <> -struct GetRttiInfo { static const RttiInfo* get() { return &JSONValue::g_rttiInfo; } }; +template<> +struct GetRttiInfo +{ + static const RttiInfo* get() { return &JSONValue::g_rttiInfo; } +}; struct JSONKeyValue { - /// True if it's valid + /// True if it's valid bool isValid() const { return value.type != JSONValue::Type::Invalid; } void reset() @@ -141,7 +199,7 @@ struct JSONKeyValue static JSONKeyValue make(JSONKey inKey, JSONValue inValue, SourceLoc inKeyLoc = SourceLoc()) { - return JSONKeyValue{ inKey, inKeyLoc, inValue }; + return JSONKeyValue{inKey, inKeyLoc, inValue}; } static JSONKeyValue g_invalid; @@ -168,31 +226,35 @@ class PersistentJSONValue : public JSONValue typedef JSONValue Super; typedef PersistentJSONValue ThisType; - /// If it's a string type this will always work + /// If it's a string type this will always work String getString() const; UnownedStringSlice getSlice() const; - /// Set to the value + /// Set to the value void set(const JSONValue& in, JSONContainer* container); - /// Set directly to a string + /// Set directly to a string void set(const UnownedStringSlice& slice, SourceLoc loc); - /// True if identical + /// True if identical bool operator==(const ThisType& rhs) const; bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Assignable + /// Assignable void operator=(const ThisType& rhs); PersistentJSONValue(const JSONValue& in, JSONContainer* container) { _init(in, container); } - PersistentJSONValue(const JSONValue& in, JSONContainer* container, SourceLoc inLoc) { _init(in, container); loc = inLoc; } + PersistentJSONValue(const JSONValue& in, JSONContainer* container, SourceLoc inLoc) + { + _init(in, container); + loc = inLoc; + } - /// Copy Ctor + /// Copy Ctor PersistentJSONValue(const ThisType& rhs); - /// Default Ctor (will be set to invalid) + /// Default Ctor (will be set to invalid) PersistentJSONValue() {} - + ~PersistentJSONValue() { if (type == Type::StringRepresentation && stringRep) @@ -200,8 +262,9 @@ class PersistentJSONValue : public JSONValue stringRep->releaseReference(); } } + protected: - /// Assumes this has no valid data + /// Assumes this has no valid data void _init(const JSONValue& in, JSONContainer* container); void _init(const UnownedStringSlice& slice, SourceLoc loc); }; @@ -209,13 +272,15 @@ class PersistentJSONValue : public JSONValue class JSONContainer : public RefObject { public: - - /// Make a new array + /// Make a new array JSONValue createArray(const JSONValue* values, Index valuesCount, SourceLoc loc = SourceLoc()); - /// Make a new object - JSONValue createObject(const JSONKeyValue* keyValues, Index keyValueCount, SourceLoc loc = SourceLoc()); - /// Make a string - JSONValue createString(const UnownedStringSlice& slice, SourceLoc loc = SourceLoc()); + /// Make a new object + JSONValue createObject( + const JSONKeyValue* keyValues, + Index keyValueCount, + SourceLoc loc = SourceLoc()); + /// Make a string + JSONValue createString(const UnownedStringSlice& slice, SourceLoc loc = SourceLoc()); ConstArrayView getArray(const JSONValue& in) const; ConstArrayView getObject(const JSONValue& in) const; @@ -223,104 +288,111 @@ class JSONContainer : public RefObject ArrayView getArray(const JSONValue& in); ArrayView getObject(const JSONValue& in); - /// Add value to array. + /// Add value to array. void addToArray(JSONValue& array, const JSONValue& value); - /// Get the value at the index in the array + /// Get the value at the index in the array JSONValue& getAt(const JSONValue& array, Index index); - /// Returns the index of key in obj, or -1 if not found + /// Returns the index of key in obj, or -1 if not found Index findObjectIndex(const JSONValue& obj, JSONKey key) const; - /// Get the value in the object at key. Returns invalid if not found. + /// Get the value in the object at key. Returns invalid if not found. JSONValue findObjectValue(const JSONValue& obj, JSONKey key) const; - /// Returns the index + /// Returns the index Index findKeyGlobalIndex(const JSONValue& obj, JSONKey key); Index findKeyGlobalIndex(const JSONValue& obj, const UnownedStringSlice& slice); - /// Set a key value for the obj - void setKeyValue(JSONValue& obj, JSONKey key, const JSONValue& value, SourceLoc loc = SourceLoc()); + /// Set a key value for the obj + void setKeyValue( + JSONValue& obj, + JSONKey key, + const JSONValue& value, + SourceLoc loc = SourceLoc()); - /// Returns true if found + /// Returns true if found bool removeKey(JSONValue& obj, JSONKey key); bool removeKey(JSONValue& obj, const UnownedStringSlice& slice); - /// As a boolean value + /// As a boolean value bool asBool(const JSONValue& value); - /// As an integer value + /// As an integer value int64_t asInteger(const JSONValue& value); - /// As a float value + /// As a float value double asFloat(const JSONValue& value); - /// Returns string as a key + /// Returns string as a key JSONKey getStringKey(const JSONValue& in); - /// Get as a string. The slice may used backing lexeme (ie will only last - /// as long as the backing JSON text, or be decoded and be transitory). + /// Get as a string. The slice may used backing lexeme (ie will only last + /// as long as the backing JSON text, or be decoded and be transitory). UnownedStringSlice getTransientString(const JSONValue& in); - /// Get as a string. The contents will stay in scope as long as the container + /// Get as a string. The contents will stay in scope as long as the container UnownedStringSlice getString(const JSONValue& in); - /// Gets the lexeme + /// Gets the lexeme UnownedStringSlice getLexeme(const JSONValue& in); - /// Get a key for a name + /// Get a key for a name JSONKey getKey(const UnownedStringSlice& slice); - /// Returns JSONKey(0) if not found + /// Returns JSONKey(0) if not found JSONKey findKey(const UnownedStringSlice& slice) const; - /// Get the string from the key - UnownedStringSlice getStringFromKey(JSONKey key) const { return m_slicePool.getSlice(StringSlicePool::Handle(key)); } + /// Get the string from the key + UnownedStringSlice getStringFromKey(JSONKey key) const + { + return m_slicePool.getSlice(StringSlicePool::Handle(key)); + } - /// True if they are the same value - /// If object like type comparison is performed recursively. - /// NOTE! That Float and Integer values do not compare & source locations are ignored. + /// True if they are the same value + /// If object like type comparison is performed recursively. + /// NOTE! That Float and Integer values do not compare & source locations are ignored. bool areEqual(const JSONValue& a, const JSONValue& b); bool areEqual(const JSONValue* a, const JSONValue* b, Index count); bool areEqual(const JSONKeyValue* a, const JSONKeyValue* b, Index count); bool areEqual(const JSONValue& a, const UnownedStringSlice& slice); - /// Destroy value + /// Destroy value void destroy(JSONValue& value); - /// Destroy recursively from value + /// Destroy recursively from value void destroyRecursively(JSONValue& value); - /// Traverse a JSON hierarchy from value, outputting to the listener + /// Traverse a JSON hierarchy from value, outputting to the listener void traverseRecursively(const JSONValue& value, JSONListener* listener); - /// Returns the source manager used. - SourceManager* getSourceManager() const { return m_sourceManager; } - /// Set the source manager - void setSourceManager(SourceManager* sourceManger) { m_sourceManager = sourceManger; } + /// Returns the source manager used. + SourceManager* getSourceManager() const { return m_sourceManager; } + /// Set the source manager + void setSourceManager(SourceManager* sourceManger) { m_sourceManager = sourceManger; } - /// Clears all the source locs. Useful if the sourceManager is no longer available, or has itself been reset. - /// All JSONValues which were Lexeme based will become held in the container - /// The source manager will set to nullptr + /// Clears all the source locs. Useful if the sourceManager is no longer available, or has + /// itself been reset. All JSONValues which were Lexeme based will become held in the container + /// The source manager will set to nullptr void clearSourceManagerDependency(JSONValue* ioValues, Index count); - /// Reset the state + /// Reset the state void reset(); - /// Return inValue as a regular value (ie not held as a lexeme) + /// Return inValue as a regular value (ie not held as a lexeme) JSONValue asValue(const JSONValue& inValue); - // Ctor + // Ctor JSONContainer(SourceManager* sourceManger); - /// Returns true if all the keys are unique + /// Returns true if all the keys are unique static bool areKeysUnique(const JSONKeyValue* keyValues, Index keyValueCount); - /// Access the internal set of strings, removing anything from this - /// will invalidate the container, so only do it immediately prior to - /// destruction. - StringSlicePool& getStringSlicePool() {return m_slicePool;}; + /// Access the internal set of strings, removing anything from this + /// will invalidate the container, so only do it immediately prior to + /// destruction. + StringSlicePool& getStringSlicePool() { return m_slicePool; }; protected: struct Range { - // We want to record the underlying range, because we don't track JSONValue, and so we need to know what the range - // applies to if we want to reorder, flatten etc. + // We want to record the underlying range, because we don't track JSONValue, and so we need + // to know what the range applies to if we want to reorder, flatten etc. enum class Type { None, @@ -329,7 +401,7 @@ class JSONContainer : public RefObject Array, }; - /// Is active if it consuming some part of a value list (even if zero count) + /// Is active if it consuming some part of a value list (even if zero count) SLANG_FORCE_INLINE bool isActive() const { return Index(type) >= Index(Type::Object); } Type type; @@ -338,24 +410,24 @@ class JSONContainer : public RefObject Index capacity; }; - template + template static void _add(Range& range, List& list, const T& value); Index _addRange(Range::Type type, Index startIndex, Index count); void _removeKey(JSONValue& obj, Index globalIndex); - /// Note does not destroy values in range. + /// Note does not destroy values in range. void _destroyRange(Index rangeIndex); static bool _sameKeyOrder(const JSONKeyValue* a, const JSONKeyValue* b, Index count); - /// True if the values are equal + /// True if the values are equal bool _areEqualValues(const JSONKeyValue* a, const JSONKeyValue* b, Index count); - /// True if the key and value are equal + /// True if the key and value are equal bool _areEqualOrderedKeys(const JSONKeyValue* a, const JSONKeyValue* b, Index count); void _clearSourceManagerDependency(JSONValue* ioValues, Index count); JSONValue _removeManagerDependency(const JSONValue& inValue); - StringBuilder m_buf; ///< A temporary buffer used to hold unescaped strings + StringBuilder m_buf; ///< A temporary buffer used to hold unescaped strings SourceView* m_currentView = nullptr; SourceManager* m_sourceManager; @@ -370,7 +442,6 @@ class JSONContainer : public RefObject class JSONBuilder : public JSONListener { public: - typedef uint32_t Flags; struct Flag { @@ -387,23 +458,23 @@ class JSONBuilder : public JSONListener virtual void endArray(SourceLoc loc) SLANG_OVERRIDE; virtual void addQuotedKey(const UnownedStringSlice& key, SourceLoc loc) SLANG_OVERRIDE; virtual void addUnquotedKey(const UnownedStringSlice& key, SourceLoc loc) SLANG_OVERRIDE; - virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) SLANG_OVERRIDE; + virtual void addLexemeValue(JSONTokenType type, const UnownedStringSlice& value, SourceLoc loc) + SLANG_OVERRIDE; virtual void addIntegerValue(int64_t value, SourceLoc loc) SLANG_OVERRIDE; virtual void addFloatValue(double value, SourceLoc loc) SLANG_OVERRIDE; virtual void addBoolValue(bool value, SourceLoc loc) SLANG_OVERRIDE; virtual void addStringValue(const UnownedStringSlice& string, SourceLoc loc) SLANG_OVERRIDE; virtual void addNullValue(SourceLoc loc) SLANG_OVERRIDE; - /// Reset the state + /// Reset the state void reset(); - /// Get the root value. Will be set after valid construction + /// Get the root value. Will be set after valid construction const JSONValue& getRootValue() const { return m_rootValue; } JSONBuilder(JSONContainer* container, Flags flags = 0); protected: - struct State { enum class Kind : uint8_t @@ -412,8 +483,16 @@ class JSONBuilder : public JSONListener Object, Array, }; - void setKey(JSONKey key, SourceLoc loc) { m_key = key; m_keyLoc = loc; } - void resetKey() { m_key = JSONKey(0); m_keyLoc = SourceLoc(); } + void setKey(JSONKey key, SourceLoc loc) + { + m_key = key; + m_keyLoc = loc; + } + void resetKey() + { + m_key = JSONKey(0); + m_keyLoc = SourceLoc(); + } bool hasKey() const { return m_key != JSONKey(0); } Kind m_kind; diff --git a/source/compiler-core/slang-language-server-protocol.cpp b/source/compiler-core/slang-language-server-protocol.cpp index 93ea0c9e30..9a382e756d 100644 --- a/source/compiler-core/slang-language-server-protocol.cpp +++ b/source/compiler-core/slang-language-server-protocol.cpp @@ -38,18 +38,25 @@ const StructRttiInfo InlayHintOptions::g_rttiInfo = _makeInlayHintOptionsRtti(); static const StructRttiInfo _makeDocumentOnTypeFormattingOptionsRtti() { DocumentOnTypeFormattingOptions obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DocumentOnTypeFormattingOptions", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DocumentOnTypeFormattingOptions", + nullptr); builder.addField("firstTriggerCharacter", &obj.firstTriggerCharacter); builder.addField("moreTriggerCharacter", &obj.moreTriggerCharacter); builder.ignoreUnknownFields(); return builder.make(); } -const StructRttiInfo DocumentOnTypeFormattingOptions::g_rttiInfo = _makeDocumentOnTypeFormattingOptionsRtti(); +const StructRttiInfo DocumentOnTypeFormattingOptions::g_rttiInfo = + _makeDocumentOnTypeFormattingOptionsRtti(); static const StructRttiInfo _makeCompletionOptionsRtti() { CompletionOptions obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::CompletionOptions", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::CompletionOptions", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("triggerCharacters", &obj.triggerCharacters); builder.addField("resolveProvider", &obj.resolveProvider); builder.addField("allCommitCharacters", &obj.allCommitCharacters); @@ -118,7 +125,10 @@ const StructRttiInfo TextDocumentIdentifier::g_rttiInfo = _makeTextDocumentIdent static const StructRttiInfo _makeVersionedTextDocumentIdentifierRtti() { VersionedTextDocumentIdentifier obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::VersionedTextDocumentIdentifier", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::VersionedTextDocumentIdentifier", + nullptr); builder.addField("uri", &obj.uri); builder.addField("version", &obj.version); builder.ignoreUnknownFields(); @@ -130,8 +140,7 @@ const StructRttiInfo VersionedTextDocumentIdentifier::g_rttiInfo = static const StructRttiInfo _makePositionRtti() { Position obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::Position", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::Position", nullptr); builder.addField("line", &obj.line); builder.addField("character", &obj.character); builder.ignoreUnknownFields(); @@ -176,7 +185,10 @@ const UnownedStringSlice DidOpenTextDocumentParams::methodName = static const StructRttiInfo _makeTextDocumentContentChangeEventRtti() { TextDocumentContentChangeEvent obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::TextDocumentContentChangeEvent", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::TextDocumentContentChangeEvent", + nullptr); builder.addField("range", &obj.range, StructRttiInfo::Flag::Optional); builder.addField("text", &obj.text); builder.ignoreUnknownFields(); @@ -188,8 +200,7 @@ const StructRttiInfo TextDocumentContentChangeEvent::g_rttiInfo = static const StructRttiInfo _makeDidChangeTextDocumentParamsRtti() { DidChangeTextDocumentParams obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::DidChangeTextDocumentParams", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::DidChangeTextDocumentParams", nullptr); builder.addField("textDocument", &obj.textDocument); builder.addField("contentChanges", &obj.contentChanges); builder.ignoreUnknownFields(); @@ -216,7 +227,10 @@ const UnownedStringSlice DidCloseTextDocumentParams::methodName = static const StructRttiInfo _makeWorkspaceFoldersServerCapabilitiesRtti() { WorkspaceFoldersServerCapabilities obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::WorkspaceFoldersServerCapabilities", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::WorkspaceFoldersServerCapabilities", + nullptr); builder.addField("supported", &obj.supported); builder.addField("changeNotifications", &obj.changeNotifications); builder.ignoreUnknownFields(); @@ -370,7 +384,10 @@ const StructRttiInfo Location::g_rttiInfo = _makeLocationRtti(); static const StructRttiInfo _makeDiagnosticRelatedInformationRtti() { DiagnosticRelatedInformation obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DiagnosticRelatedInformation", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DiagnosticRelatedInformation", + nullptr); builder.addField("location", &obj.location); builder.addField("message", &obj.message); builder.ignoreUnknownFields(); @@ -382,8 +399,7 @@ const StructRttiInfo DiagnosticRelatedInformation::g_rttiInfo = static const StructRttiInfo _makeDiagnosticRtti() { Diagnostic obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::Diagnostic", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::Diagnostic", nullptr); builder.addField("code", &obj.code); builder.addField("message", &obj.message); builder.addField("range", &obj.range); @@ -420,7 +436,10 @@ const StructRttiInfo TextDocumentPositionParams::g_rttiInfo = _makeTextDocumentP static const StructRttiInfo _makeHoverParamsRtti() { HoverParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::HoverParams", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::HoverParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.addField("position", &obj.position); builder.ignoreUnknownFields(); @@ -466,7 +485,10 @@ const StructRttiInfo CompletionContext::g_rttiInfo = _makeCompletionContextRtti( static const StructRttiInfo _makeDefinitionParamsRtti() { DefinitionParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DefinitionParams", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DefinitionParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.addField("position", &obj.position); builder.ignoreUnknownFields(); @@ -479,7 +501,10 @@ const UnownedStringSlice DefinitionParams::methodName = static const StructRttiInfo _makeCompletionParamsRtti() { CompletionParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::CompletionParams", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::CompletionParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.addField("position", &obj.position); builder.addField("context", &obj.context, StructRttiInfo::Flag::Optional); @@ -524,7 +549,10 @@ const StructRttiInfo TextEditCompletionItem::g_rttiInfo = _makeTextEditCompletio static const StructRttiInfo _makeSemanticTokensParamsRtti() { SemanticTokensParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::SemanticTokensParams", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::SemanticTokensParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.ignoreUnknownFields(); return builder.make(); @@ -547,7 +575,10 @@ const StructRttiInfo SemanticTokens::g_rttiInfo = _makeSemanticTokensRtti(); static const StructRttiInfo _makeSignatureHelpParamsRtti() { SignatureHelpParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::SignatureHelpParams", &WorkDoneProgressParams::g_rttiInfo); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::SignatureHelpParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.addField("position", &obj.position); builder.ignoreUnknownFields(); @@ -595,7 +626,10 @@ const StructRttiInfo SignatureHelp::g_rttiInfo = _makeSignatureHelpRtti(); static const StructRttiInfo _makeDidChangeConfigurationParamsRtti() { DidChangeConfigurationParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DidChangeConfigurationParams", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DidChangeConfigurationParams", + nullptr); builder.addField("settings", &obj.settings, StructRttiInfo::Flag::Optional); builder.ignoreUnknownFields(); return builder.make(); @@ -608,8 +642,7 @@ const UnownedStringSlice DidChangeConfigurationParams::methodName = static const StructRttiInfo _makeConfigurationItemRtti() { ConfigurationItem obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::ConfigurationItem", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::ConfigurationItem", nullptr); builder.addField("section", &obj.section, StructRttiInfo::Flag::Optional); builder.ignoreUnknownFields(); return builder.make(); @@ -619,8 +652,7 @@ const StructRttiInfo ConfigurationItem::g_rttiInfo = _makeConfigurationItemRtti( static const StructRttiInfo _makeConfigurationParamsRtti() { ConfigurationParams obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::ConfigurationParams", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::ConfigurationParams", nullptr); builder.addField("items", &obj.items, StructRttiInfo::Flag::Optional); builder.ignoreUnknownFields(); return builder.make(); @@ -677,7 +709,9 @@ static const StructRttiInfo _makeDocumentSymbolParamsRtti() { DocumentSymbolParams obj; StructRttiBuilder builder( - &obj, "LanguageServerProtocol::DocumentSymbolParams", &WorkDoneProgressParams::g_rttiInfo); + &obj, + "LanguageServerProtocol::DocumentSymbolParams", + &WorkDoneProgressParams::g_rttiInfo); builder.addField("textDocument", &obj.textDocument); builder.ignoreUnknownFields(); return builder.make(); @@ -689,8 +723,7 @@ const UnownedStringSlice DocumentSymbolParams::methodName = static const StructRttiInfo _makeDocumentSymbolRtti() { DocumentSymbol obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::DocumentSymbol", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::DocumentSymbol", nullptr); builder.addField("name", &obj.name); builder.addField("detail", &obj.detail); builder.addField("kind", &obj.kind); @@ -705,8 +738,7 @@ const StructRttiInfo DocumentSymbol::g_rttiInfo = _makeDocumentSymbolRtti(); static const StructRttiInfo _makeInlayHintParamsRtti() { InlayHintParams obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::InlayHintParams", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::InlayHintParams", nullptr); builder.addField("range", &obj.range); builder.addField("textDocument", &obj.textDocument); builder.ignoreUnknownFields(); @@ -719,8 +751,7 @@ const UnownedStringSlice InlayHintParams::methodName = static const StructRttiInfo _makeInlayHintRtti() { InlayHint obj; - StructRttiBuilder builder( - &obj, "LanguageServerProtocol::InlayHint", nullptr); + StructRttiBuilder builder(&obj, "LanguageServerProtocol::InlayHint", nullptr); builder.addField("position", &obj.position); builder.addField("label", &obj.label); builder.addField("kind", &obj.kind); @@ -748,30 +779,38 @@ const UnownedStringSlice DocumentFormattingParams::methodName = static const StructRttiInfo _makeDocumentRangeFormattingParamsRtti() { DocumentRangeFormattingParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DocumentRangeFormattingParams", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DocumentRangeFormattingParams", + nullptr); builder.addField("textDocument", &obj.textDocument); builder.addField("range", &obj.range); builder.ignoreUnknownFields(); return builder.make(); } -const StructRttiInfo DocumentRangeFormattingParams::g_rttiInfo = _makeDocumentRangeFormattingParamsRtti(); +const StructRttiInfo DocumentRangeFormattingParams::g_rttiInfo = + _makeDocumentRangeFormattingParamsRtti(); const UnownedStringSlice DocumentRangeFormattingParams::methodName = UnownedStringSlice::fromLiteral("textDocument/rangeFormatting"); static const StructRttiInfo _makeDocumentOnTypeFormattingParamsRtti() { DocumentOnTypeFormattingParams obj; - StructRttiBuilder builder(&obj, "LanguageServerProtocol::DocumentOnTypeFormattingParams", nullptr); + StructRttiBuilder builder( + &obj, + "LanguageServerProtocol::DocumentOnTypeFormattingParams", + nullptr); builder.addField("textDocument", &obj.textDocument); builder.addField("position", &obj.position); builder.addField("ch", &obj.ch); builder.ignoreUnknownFields(); return builder.make(); } -const StructRttiInfo DocumentOnTypeFormattingParams::g_rttiInfo = _makeDocumentOnTypeFormattingParamsRtti(); +const StructRttiInfo DocumentOnTypeFormattingParams::g_rttiInfo = + _makeDocumentOnTypeFormattingParamsRtti(); const UnownedStringSlice DocumentOnTypeFormattingParams::methodName = UnownedStringSlice::fromLiteral("textDocument/onTypeFormatting"); } // namespace LanguageServerProtocol -} +} // namespace Slang diff --git a/source/compiler-core/slang-language-server-protocol.h b/source/compiler-core/slang-language-server-protocol.h index ff5cd394ea..d96099da69 100644 --- a/source/compiler-core/slang-language-server-protocol.h +++ b/source/compiler-core/slang-language-server-protocol.h @@ -1,11 +1,12 @@ #pragma once +#include "../../source/compiler-core/slang-json-value.h" +#include "../../source/core/slang-rtti-info.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" #include "slang.h" -#include "../../source/core/slang-rtti-info.h" -#include "../../source/compiler-core/slang-json-value.h" +#include namespace Slang { @@ -191,7 +192,6 @@ struct TextEdit String newText; static const StructRttiInfo g_rttiInfo; - }; struct DidOpenTextDocumentParams @@ -263,7 +263,6 @@ struct InlayHintOptions */ bool resolveProvider = false; static const StructRttiInfo g_rttiInfo; - }; struct DocumentOnTypeFormattingOptions @@ -435,8 +434,7 @@ struct Diagnostic HashCode getHashCode() const { - return combineHash( - code, combineHash(range.start.line, message.getHashCode())); + return combineHash(code, combineHash(range.start.line, message.getHashCode())); } static const StructRttiInfo g_rttiInfo; @@ -472,17 +470,13 @@ struct TextDocumentPositionParams static const StructRttiInfo g_rttiInfo; }; -struct HoverParams - : WorkDoneProgressParams - ,TextDocumentPositionParams +struct HoverParams : WorkDoneProgressParams, TextDocumentPositionParams { static const StructRttiInfo g_rttiInfo; static const UnownedStringSlice methodName; }; -struct DefinitionParams - : WorkDoneProgressParams - , TextDocumentPositionParams +struct DefinitionParams : WorkDoneProgressParams, TextDocumentPositionParams { static const StructRttiInfo g_rttiInfo; static const UnownedStringSlice methodName; @@ -555,9 +549,7 @@ struct CompletionContext static const StructRttiInfo g_rttiInfo; }; -struct CompletionParams - : WorkDoneProgressParams - , TextDocumentPositionParams +struct CompletionParams : WorkDoneProgressParams, TextDocumentPositionParams { CompletionContext context; @@ -712,9 +704,7 @@ struct SemanticTokens static const StructRttiInfo g_rttiInfo; }; -struct SignatureHelpParams - : WorkDoneProgressParams - , TextDocumentPositionParams +struct SignatureHelpParams : WorkDoneProgressParams, TextDocumentPositionParams { static const UnownedStringSlice methodName; @@ -739,7 +729,7 @@ struct ParameterInformation * signature label. Its intended use case is to highlight the parameter * label part in the `SignatureInformation.label`. */ - uint32_t label[2] = { 0, 0 }; + uint32_t label[2] = {0, 0}; /** * The human-readable doc-comment of this parameter. Will be shown @@ -847,14 +837,14 @@ struct ConfigurationParams struct Registration { /** - * The id used to register the request. The id can be used to deregister - * the request again. - */ + * The id used to register the request. The id can be used to deregister + * the request again. + */ String id; /** - * The method / capability to register for. - */ + * The method / capability to register for. + */ String method; static const StructRttiInfo g_rttiInfo; @@ -1051,7 +1041,6 @@ struct InlayHint bool paddingRight = false; static const StructRttiInfo g_rttiInfo; - }; struct DocumentOnTypeFormattingParams @@ -1079,7 +1068,7 @@ struct DocumentOnTypeFormattingParams /** * The formatting options. */ - //FormattingOptions options; + // FormattingOptions options; static const StructRttiInfo g_rttiInfo; static const UnownedStringSlice methodName; @@ -1100,7 +1089,7 @@ struct DocumentRangeFormattingParams /** * The format options */ - //FormattingOptions options; + // FormattingOptions options; static const StructRttiInfo g_rttiInfo; static const UnownedStringSlice methodName; @@ -1116,7 +1105,7 @@ struct DocumentFormattingParams /** * The format options */ - //FormattingOptions options; + // FormattingOptions options; static const StructRttiInfo g_rttiInfo; static const UnownedStringSlice methodName; @@ -1124,3 +1113,23 @@ struct DocumentFormattingParams } // namespace LanguageServerProtocol } // namespace Slang + +namespace Slang +{ +template +struct LanguageServerResult +{ + SlangResult returnCode; + bool isNull = true; + T result; + LanguageServerResult() { returnCode = SLANG_OK; } + LanguageServerResult(std::nullopt_t) { returnCode = SLANG_OK; } + LanguageServerResult(const T& value) + { + result = value; + isNull = false; + returnCode = SLANG_OK; + } + LanguageServerResult(SlangResult code) { returnCode = code; } +}; +} // namespace Slang diff --git a/source/compiler-core/slang-lexer-diagnostic-defs.h b/source/compiler-core/slang-lexer-diagnostic-defs.h index bce2876851..cae8e4157d 100644 --- a/source/compiler-core/slang-lexer-diagnostic-defs.h +++ b/source/compiler-core/slang-lexer-diagnostic-defs.h @@ -12,7 +12,7 @@ // for any arguments. #ifndef DIAGNOSTIC -#error Need to #define DIAGNOSTIC(...) before including +#error Need to #define DIAGNOSTIC(...) before including #define DIAGNOSTIC(id, severity, name, messageFormat) /* */ #endif @@ -29,7 +29,11 @@ DIAGNOSTIC(10003, Error, invalidDigitForBase, "invalid digit for base-$1 literal DIAGNOSTIC(10004, Error, endOfFileInLiteral, "end of file in literal") DIAGNOSTIC(10005, Error, newlineInLiteral, "newline in literal") -DIAGNOSTIC(10010, Error, quoteCannotBeDelimiter, "'\"' encountered before '(' in raw string literal. '\"' cannot be a part of a delimiter.") +DIAGNOSTIC( + 10010, + Error, + quoteCannotBeDelimiter, + "'\"' encountered before '(' in raw string literal. '\"' cannot be a part of a delimiter.") DIAGNOSTIC(10011, Error, unexpectedEndOfInput, "unexpected end of input") diff --git a/source/compiler-core/slang-lexer.cpp b/source/compiler-core/slang-lexer.cpp index 366af91146..84a4df93bb 100644 --- a/source/compiler-core/slang-lexer.cpp +++ b/source/compiler-core/slang-lexer.cpp @@ -6,196 +6,197 @@ // #include "core/slang-char-encode.h" +#include "slang-core-diagnostics.h" #include "slang-name.h" #include "slang-source-loc.h" -#include "slang-core-diagnostics.h" namespace Slang { - Token TokenReader::getEndOfFileToken() - { - return Token(TokenType::EndOfFile, UnownedStringSlice::fromLiteral(""), SourceLoc()); - } +Token TokenReader::getEndOfFileToken() +{ + return Token(TokenType::EndOfFile, UnownedStringSlice::fromLiteral(""), SourceLoc()); +} - const Token* TokenList::begin() const - { - SLANG_ASSERT(m_tokens.getCount()); - return &m_tokens[0]; - } +const Token* TokenList::begin() const +{ + SLANG_ASSERT(m_tokens.getCount()); + return &m_tokens[0]; +} - const Token* TokenList::end() const - { - SLANG_ASSERT(m_tokens.getCount()); - SLANG_ASSERT(m_tokens[m_tokens.getCount() - 1].type == TokenType::EndOfFile); - return &m_tokens[m_tokens.getCount() - 1]; - } +const Token* TokenList::end() const +{ + SLANG_ASSERT(m_tokens.getCount()); + SLANG_ASSERT(m_tokens[m_tokens.getCount() - 1].type == TokenType::EndOfFile); + return &m_tokens[m_tokens.getCount() - 1]; +} - TokenSpan::TokenSpan() - : m_begin(nullptr) - , m_end (nullptr) - {} +TokenSpan::TokenSpan() + : m_begin(nullptr), m_end(nullptr) +{ +} - TokenReader::TokenReader() - : m_cursor(nullptr) - , m_end (nullptr) - { - _updateLookaheadToken(); - } +TokenReader::TokenReader() + : m_cursor(nullptr), m_end(nullptr) +{ + _updateLookaheadToken(); +} - Token& TokenReader::peekToken() - { - return m_nextToken; - } +Token& TokenReader::peekToken() +{ + return m_nextToken; +} - TokenType TokenReader::peekTokenType() const - { - return m_nextToken.type; - } +TokenType TokenReader::peekTokenType() const +{ + return m_nextToken.type; +} - SourceLoc TokenReader::peekLoc() const - { - return m_nextToken.loc; - } +SourceLoc TokenReader::peekLoc() const +{ + return m_nextToken.loc; +} - Token TokenReader::advanceToken() - { - Token result = m_nextToken; - if (m_cursor != m_end) - m_cursor++; - _updateLookaheadToken(); - return result; - } +Token TokenReader::advanceToken() +{ + Token result = m_nextToken; + if (m_cursor != m_end) + m_cursor++; + _updateLookaheadToken(); + return result; +} - void TokenReader::_updateLookaheadToken() - { - // We assume here that we can read a token from a non-null `m_cursor` - // *even* in the case where `m_cursor == m_end`, because the invariant - // for lists of tokens is that they should be terminated with and - // end-of-file token, so that there is always a token "one past the end." - // - m_nextToken = m_cursor ? *m_cursor : getEndOfFileToken(); +void TokenReader::_updateLookaheadToken() +{ + // We assume here that we can read a token from a non-null `m_cursor` + // *even* in the case where `m_cursor == m_end`, because the invariant + // for lists of tokens is that they should be terminated with and + // end-of-file token, so that there is always a token "one past the end." + // + m_nextToken = m_cursor ? *m_cursor : getEndOfFileToken(); - // If the token we read came from the end of the sub-sequence we are - // reading, then we will change the token type to an end-of-file token - // so that code that reads from the sequence and expects a terminating - // EOF will find it. - // - // TODO: We might eventually want a way to look at the actual token type - // and not just use EOF in all cases: e.g., when emitting diagnostic - // messages that include the token that is seen. - // - if(m_cursor == m_end) - m_nextToken.type = TokenType::EndOfFile; - } + // If the token we read came from the end of the sub-sequence we are + // reading, then we will change the token type to an end-of-file token + // so that code that reads from the sequence and expects a terminating + // EOF will find it. + // + // TODO: We might eventually want a way to look at the actual token type + // and not just use EOF in all cases: e.g., when emitting diagnostic + // messages that include the token that is seen. + // + if (m_cursor == m_end) + m_nextToken.type = TokenType::EndOfFile; +} - // Lexer +// Lexer - void Lexer::initialize( - SourceView* sourceView, - DiagnosticSink* sink, - NamePool* namePool, - MemoryArena* memoryArena) - { - m_sourceView = sourceView; - m_sink = sink; - m_namePool = namePool; - m_memoryArena = memoryArena; - - auto content = sourceView->getContent(); - - m_begin = content.begin(); - m_cursor = content.begin(); - m_end = content.end(); - - // Set the start location - m_startLoc = sourceView->getRange().begin; - - // The first token read from a translation unit should be considered to be at - // the start of a line, and *also* as coming after whitespace (conceptually - // both the end-of-file and beginning-of-file pseudo-tokens are whitespace). - // - m_tokenFlags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; - m_lexerFlags = 0; - } +void Lexer::initialize( + SourceView* sourceView, + DiagnosticSink* sink, + NamePool* namePool, + MemoryArena* memoryArena) +{ + m_sourceView = sourceView; + m_sink = sink; + m_namePool = namePool; + m_memoryArena = memoryArena; - Lexer::~Lexer() - { - } + auto content = sourceView->getContent(); - enum { kEOF = -1 }; + m_begin = content.begin(); + m_cursor = content.begin(); + m_end = content.end(); - // Get the next input byte, without any handling of - // escaped newlines, non-ASCII code points, source locations, etc. - static int _peekRaw(Lexer* lexer) - { - // If we are at the end of the input, return a designated end-of-file value - if(lexer->m_cursor == lexer->m_end) - return kEOF; + // Set the start location + m_startLoc = sourceView->getRange().begin; - // Otherwise, just look at the next byte - return *lexer->m_cursor; - } + // The first token read from a translation unit should be considered to be at + // the start of a line, and *also* as coming after whitespace (conceptually + // both the end-of-file and beginning-of-file pseudo-tokens are whitespace). + // + m_tokenFlags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + m_lexerFlags = 0; +} - // Read one input byte without any special handling (similar to `peekRaw`) - static int _advanceRaw(Lexer* lexer) - { - // The logic here is basically the same as for `peekRaw()`, - // escape we advance `cursor` if we aren't at the end. +Lexer::~Lexer() {} - if (lexer->m_cursor == lexer->m_end) - return kEOF; +enum +{ + kEOF = -1 +}; - return *lexer->m_cursor++; - } +// Get the next input byte, without any handling of +// escaped newlines, non-ASCII code points, source locations, etc. +static int _peekRaw(Lexer* lexer) +{ + // If we are at the end of the input, return a designated end-of-file value + if (lexer->m_cursor == lexer->m_end) + return kEOF; - // When the cursor is already at the first byte of an end-of-line sequence, - // consume one or two bytes that compose the sequence. - // - // Basically, a newline is one of: - // - // "\n" - // "\r" - // "\r\n" - // "\n\r" - // - // We always look for the longest match possible. - // - static void _handleNewLineInner(Lexer* lexer, int c) - { - SLANG_ASSERT(c == '\n' || c == '\r'); + // Otherwise, just look at the next byte + return *lexer->m_cursor; +} - int d = _peekRaw(lexer); - if( (c ^ d) == ('\n' ^ '\r') ) - { - _advanceRaw(lexer); - } - } +// Read one input byte without any special handling (similar to `peekRaw`) +static int _advanceRaw(Lexer* lexer) +{ + // The logic here is basically the same as for `peekRaw()`, + // escape we advance `cursor` if we aren't at the end. + + if (lexer->m_cursor == lexer->m_end) + return kEOF; + + return *lexer->m_cursor++; +} + +// When the cursor is already at the first byte of an end-of-line sequence, +// consume one or two bytes that compose the sequence. +// +// Basically, a newline is one of: +// +// "\n" +// "\r" +// "\r\n" +// "\n\r" +// +// We always look for the longest match possible. +// +static void _handleNewLineInner(Lexer* lexer, int c) +{ + SLANG_ASSERT(c == '\n' || c == '\r'); - // Look ahead one code point, dealing with complications like - // escaped newlines. - static int _peek(Lexer* lexer, int offset = 0) + int d = _peekRaw(lexer); + if ((c ^ d) == ('\n' ^ '\r')) { - int pos = 0; - int c = kEOF; + _advanceRaw(lexer); + } +} - do - { - if (lexer->m_cursor + pos == lexer->m_end) - return kEOF; +// Look ahead one code point, dealing with complications like +// escaped newlines. +static int _peek(Lexer* lexer, int offset = 0) +{ + int pos = 0; + int c = kEOF; + + do + { + if (lexer->m_cursor + pos == lexer->m_end) + return kEOF; - c = lexer->m_cursor[pos++]; + c = lexer->m_cursor[pos++]; - while (c == '\\') + while (c == '\\') + { + // We might have a backslash-escaped newline. + // Look at the next byte (if any) to see. + // + // Note(tfoley): We are assuming a null-terminated input here, + // so that we can safely look at the next byte without issue. + int d = lexer->m_cursor[pos++]; + switch (d) { - // We might have a backslash-escaped newline. - // Look at the next byte (if any) to see. - // - // Note(tfoley): We are assuming a null-terminated input here, - // so that we can safely look at the next byte without issue. - int d = lexer->m_cursor[pos++]; - switch (d) - { - case '\r': case '\n': + case '\r': + case '\n': { // The newline was escaped, so return the code point after *that* int e = lexer->m_cursor[pos++]; @@ -205,1139 +206,1346 @@ namespace Slang c = e; continue; } - default: - break; - } - - // Only continue this while loop in the case where we consumed - // some newlines + default: break; } - if (isUtf8LeadingByte((Byte)c)) - { - // Consume all unicode characters. - pos--; - c = getUnicodePointFromUTF8([&]() {return lexer->m_cursor[pos++]; }); - } - // Default case is to just hand along the byte we read as an ASCII code point. - } while (offset--); - return c; - } + // Only continue this while loop in the case where we consumed + // some newlines + break; + } + if (isUtf8LeadingByte((Byte)c)) + { + // Consume all unicode characters. + pos--; + c = getUnicodePointFromUTF8([&]() { return lexer->m_cursor[pos++]; }); + } + // Default case is to just hand along the byte we read as an ASCII code point. + } while (offset--); + + return c; +} - // Get the next code point from the input, and advance the cursor. - static int _advance(Lexer* lexer) +// Get the next code point from the input, and advance the cursor. +static int _advance(Lexer* lexer) +{ + // We are going to loop, but only as a way of handling + // escaped line endings. + for (;;) { - // We are going to loop, but only as a way of handling - // escaped line endings. - for (;;) - { - // If we are at the end of the input, then the task is easy. - if (lexer->m_cursor == lexer->m_end) - return kEOF; + // If we are at the end of the input, then the task is easy. + if (lexer->m_cursor == lexer->m_end) + return kEOF; - // Look at the next raw byte, and decide what to do - int c = *lexer->m_cursor++; + // Look at the next raw byte, and decide what to do + int c = *lexer->m_cursor++; - if (c == '\\') + if (c == '\\') + { + // We might have a backslash-escaped newline. + // Look at the next byte (if any) to see. + // + // Note(tfoley): We are assuming a null-terminated input here, + // so that we can safely look at the next byte without issue. + int d = *lexer->m_cursor; + switch (d) { - // We might have a backslash-escaped newline. - // Look at the next byte (if any) to see. - // - // Note(tfoley): We are assuming a null-terminated input here, - // so that we can safely look at the next byte without issue. - int d = *lexer->m_cursor; - switch (d) - { - case '\r': case '\n': - // handle the end-of-line for our source location tracking - lexer->m_cursor++; - _handleNewLineInner(lexer, d); + case '\r': + case '\n': + // handle the end-of-line for our source location tracking + lexer->m_cursor++; + _handleNewLineInner(lexer, d); - lexer->m_tokenFlags |= TokenFlag::ScrubbingNeeded; + lexer->m_tokenFlags |= TokenFlag::ScrubbingNeeded; - // Now try again, looking at the character after the - // escaped newline. - continue; - - default: - break; - } - } + // Now try again, looking at the character after the + // escaped newline. + continue; - // Consume all unicode characters. - if (isUtf8LeadingByte((Byte)c)) - { - lexer->m_cursor--; - c = getUnicodePointFromUTF8([&]() {return *lexer->m_cursor++; }); + default: + break; } + } - // Default case is to return the raw byte we saw. - return c; + // Consume all unicode characters. + if (isUtf8LeadingByte((Byte)c)) + { + lexer->m_cursor--; + c = getUnicodePointFromUTF8([&]() { return *lexer->m_cursor++; }); } - } - static void _handleNewLine(Lexer* lexer) - { - int c = _advance(lexer); - _handleNewLineInner(lexer, c); + // Default case is to return the raw byte we saw. + return c; } +} + +static void _handleNewLine(Lexer* lexer) +{ + int c = _advance(lexer); + _handleNewLineInner(lexer, c); +} - static void _lexLineComment(Lexer* lexer) +static void _lexLineComment(Lexer* lexer) +{ + for (;;) { - for(;;) + switch (_peek(lexer)) { - switch(_peek(lexer)) - { - case '\n': case '\r': case kEOF: - return; + case '\n': + case '\r': + case kEOF: + return; - default: - _advance(lexer); - continue; - } + default: + _advance(lexer); + continue; } } +} - static void _lexBlockComment(Lexer* lexer) +static void _lexBlockComment(Lexer* lexer) +{ + for (;;) { - for(;;) + switch (_peek(lexer)) { - switch(_peek(lexer)) - { - case kEOF: - // TODO(tfoley) diagnostic! - return; + case kEOF: + // TODO(tfoley) diagnostic! + return; - case '\n': case '\r': - _handleNewLine(lexer); - continue; + case '\n': + case '\r': + _handleNewLine(lexer); + continue; - case '*': + case '*': + _advance(lexer); + switch (_peek(lexer)) + { + case '/': _advance(lexer); - switch( _peek(lexer) ) - { - case '/': - _advance(lexer); - return; - - default: - continue; - } + return; default: - _advance(lexer); continue; } + + default: + _advance(lexer); + continue; } } +} - static void _lexHorizontalSpace(Lexer* lexer) +static void _lexHorizontalSpace(Lexer* lexer) +{ + for (;;) { - for(;;) + switch (_peek(lexer)) { - switch(_peek(lexer)) - { - case ' ': case '\t': - _advance(lexer); - continue; + case ' ': + case '\t': + _advance(lexer); + continue; - default: - return; - } + default: + return; } } +} - static bool isNonAsciiCodePoint(unsigned int codePoint) - { - return codePoint != 0xFFFFFFFF && codePoint >= 0x80; - } +static bool isNonAsciiCodePoint(unsigned int codePoint) +{ + return codePoint != 0xFFFFFFFF && codePoint >= 0x80; +} - static void _lexIdentifier(Lexer* lexer) +static void _lexIdentifier(Lexer* lexer) +{ + for (;;) { - for(;;) + int c = _peek(lexer); + if (('a' <= c) && (c <= 'z') || ('A' <= c) && (c <= 'Z') || ('0' <= c) && (c <= '9') || + (c == '_') || isNonAsciiCodePoint((unsigned int)c)) { - int c = _peek(lexer); - if(('a' <= c ) && (c <= 'z') - || ('A' <= c) && (c <= 'Z') - || ('0' <= c) && (c <= '9') - || (c == '_') - || isNonAsciiCodePoint((unsigned int)c)) - { - _advance(lexer); - continue; - } - return; + _advance(lexer); + continue; } + return; } +} - static SourceLoc _getSourceLoc(Lexer* lexer) - { - return lexer->m_startLoc + (lexer->m_cursor - lexer->m_begin); - } +static SourceLoc _getSourceLoc(Lexer* lexer) +{ + return lexer->m_startLoc + (lexer->m_cursor - lexer->m_begin); +} - static void _lexDigits(Lexer* lexer, int base) +static void _lexDigits(Lexer* lexer, int base) +{ + for (;;) { - for(;;) - { - int c = _peek(lexer); + int c = _peek(lexer); - int digitVal = 0; - switch(c) - { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - digitVal = c - '0'; - break; - - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - if(base <= 10) return; - digitVal = 10 + c - 'a'; - break; - - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - if(base <= 10) return; - digitVal = 10 + c - 'A'; - break; + int digitVal = 0; + switch (c) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + digitVal = c - '0'; + break; - default: - // Not more digits! + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + if (base <= 10) return; - } + digitVal = 10 + c - 'a'; + break; - if(digitVal >= base) - { - if (auto sink = lexer->getDiagnosticSink()) - { - char buffer[] = { (char) c, 0 }; - sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::invalidDigitForBase, buffer, base); - } - } + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (base <= 10) + return; + digitVal = 10 + c - 'A'; + break; - _advance(lexer); + default: + // Not more digits! + return; } - } - static TokenType _maybeLexNumberSuffix(Lexer* lexer, TokenType tokenType) - { - // Be liberal in what we accept here, so that figuring out - // the semantics of a numeric suffix is left up to the parser - // and semantic checking logic. - // - for( ;;) + if (digitVal >= base) { - int c = _peek(lexer); - - // Accept any alphanumeric character, plus underscores. - if(('a' <= c ) && (c <= 'z') - || ('A' <= c) && (c <= 'Z') - || ('0' <= c) && (c <= '9') - || (c == '_')) + if (auto sink = lexer->getDiagnosticSink()) { - _advance(lexer); - continue; + char buffer[] = {(char)c, 0}; + sink->diagnose( + _getSourceLoc(lexer), + LexerDiagnostics::invalidDigitForBase, + buffer, + base); } - - // Stop at the first character that isn't - // alphanumeric. - return tokenType; } + + _advance(lexer); } +} - static bool _isNumberExponent(int c, int base) +static TokenType _maybeLexNumberSuffix(Lexer* lexer, TokenType tokenType) +{ + // Be liberal in what we accept here, so that figuring out + // the semantics of a numeric suffix is left up to the parser + // and semantic checking logic. + // + for (;;) { - switch( c ) - { - default: - return false; - - case 'e': case 'E': - if(base != 10) return false; - break; + int c = _peek(lexer); - case 'p': case 'P': - if(base != 16) return false; - break; + // Accept any alphanumeric character, plus underscores. + if (('a' <= c) && (c <= 'z') || ('A' <= c) && (c <= 'Z') || ('0' <= c) && (c <= '9') || + (c == '_')) + { + _advance(lexer); + continue; } - return true; + // Stop at the first character that isn't + // alphanumeric. + return tokenType; } +} - static bool _maybeLexNumberExponent(Lexer* lexer, int base) +static bool _isNumberExponent(int c, int base) +{ + switch (c) { - if (_peek(lexer) == '#') - { - // Special case #INF - const auto inf = toSlice("#INF"); - for (auto c : inf) - { - if (_peek(lexer) != c) - { - return false; - } - _advance(lexer); - } + default: + return false; - return true; - } + case 'e': + case 'E': + if (base != 10) + return false; + break; - if(!_isNumberExponent(_peek(lexer), base)) + case 'p': + case 'P': + if (base != 16) return false; + break; + } - // we saw an exponent marker - _advance(lexer); + return true; +} - // Now start to read the exponent - switch( _peek(lexer) ) +static bool _maybeLexNumberExponent(Lexer* lexer, int base) +{ + if (_peek(lexer) == '#') + { + // Special case #INF + const auto inf = toSlice("#INF"); + for (auto c : inf) { - case '+': case '-': + if (_peek(lexer) != c) + { + return false; + } _advance(lexer); - break; } - // TODO(tfoley): it would be an error to not see digits here... - - _lexDigits(lexer, 10); - return true; } - static TokenType _lexNumberAfterDecimalPoint(Lexer* lexer, int base) - { - _lexDigits(lexer, base); - _maybeLexNumberExponent(lexer, base); + if (!_isNumberExponent(_peek(lexer), base)) + return false; - return _maybeLexNumberSuffix(lexer, TokenType::FloatingPointLiteral); - } + // we saw an exponent marker + _advance(lexer); - static TokenType _lexNumber(Lexer* lexer, int base) + // Now start to read the exponent + switch (_peek(lexer)) { - // TODO(tfoley): Need to consider whether to allow any kind of digit separator character. + case '+': + case '-': + _advance(lexer); + break; + } - TokenType tokenType = TokenType::IntegerLiteral; + // TODO(tfoley): it would be an error to not see digits here... - // At the start of things, we just concern ourselves with digits - _lexDigits(lexer, base); + _lexDigits(lexer, 10); - if( _peek(lexer) == '.' ) - { - switch (_peek(lexer, 1)) - { - // 123.xxxx or 123.rrrr - case 'x': - case 'r': - break; + return true; +} - default: - tokenType = TokenType::FloatingPointLiteral; +static TokenType _lexNumberAfterDecimalPoint(Lexer* lexer, int base) +{ + _lexDigits(lexer, base); + _maybeLexNumberExponent(lexer, base); - _advance(lexer); - _lexDigits(lexer, base); - } - } + return _maybeLexNumberSuffix(lexer, TokenType::FloatingPointLiteral); +} + +static TokenType _lexNumber(Lexer* lexer, int base) +{ + // TODO(tfoley): Need to consider whether to allow any kind of digit separator character. - if( _maybeLexNumberExponent(lexer, base)) + TokenType tokenType = TokenType::IntegerLiteral; + + // At the start of things, we just concern ourselves with digits + _lexDigits(lexer, base); + + if (_peek(lexer) == '.') + { + switch (_peek(lexer, 1)) { + // 123.xxxx or 123.rrrr + case 'x': + case 'r': + break; + + default: tokenType = TokenType::FloatingPointLiteral; - } - _maybeLexNumberSuffix(lexer, tokenType); - return tokenType; + _advance(lexer); + _lexDigits(lexer, base); + } } - static int _maybeReadDigit(char const** ioCursor, int base) + if (_maybeLexNumberExponent(lexer, base)) { - auto& cursor = *ioCursor; + tokenType = TokenType::FloatingPointLiteral; + } - for(;;) - { - int c = *cursor; - switch(c) - { - default: - return -1; + _maybeLexNumberSuffix(lexer, tokenType); + return tokenType; +} - // TODO: need to decide on digit separator characters - case '_': - cursor++; - continue; +static int _maybeReadDigit(char const** ioCursor, int base) +{ + auto& cursor = *ioCursor; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - cursor++; - return c - '0'; + for (;;) + { + int c = *cursor; + switch (c) + { + default: + return -1; - case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': - if(base > 10) - { - cursor++; - return 10 + c - 'a'; - } - return -1; + // TODO: need to decide on digit separator characters + case '_': + cursor++; + continue; - case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': - if(base > 10) - { - cursor++; - return 10 + c - 'A'; - } - return -1; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + cursor++; + return c - '0'; + + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + if (base > 10) + { + cursor++; + return 10 + c - 'a'; + } + return -1; + + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (base > 10) + { + cursor++; + return 10 + c - 'A'; } + return -1; } } +} - static int _readOptionalBase(char const** ioCursor) +static int _readOptionalBase(char const** ioCursor) +{ + auto& cursor = *ioCursor; + if (*cursor == '0') { - auto& cursor = *ioCursor; - if( *cursor == '0' ) + cursor++; + switch (*cursor) { + case 'x': + case 'X': cursor++; - switch(*cursor) - { - case 'x': case 'X': - cursor++; - return 16; + return 16; - case 'b': case 'B': - cursor++; - return 2; + case 'b': + case 'B': + cursor++; + return 2; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return 8; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return 8; - default: - return 10; - } + default: + return 10; } - - return 10; } + return 10; +} - IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix) - { - IntegerLiteralValue value = 0; - - const UnownedStringSlice content = token.getContent(); +IntegerLiteralValue getIntegerLiteralValue( + Token const& token, + UnownedStringSlice* outSuffix, + bool* outIsDecimalBase) +{ + IntegerLiteralValue value = 0; - char const* cursor = content.begin(); - char const* end = content.end(); + const UnownedStringSlice content = token.getContent(); - int base = _readOptionalBase(&cursor); + char const* cursor = content.begin(); + char const* end = content.end(); - for( ;;) - { - int digit = _maybeReadDigit(&cursor, base); - if(digit < 0) - break; + int base = _readOptionalBase(&cursor); - value = value*base + digit; - } + for (;;) + { + int digit = _maybeReadDigit(&cursor, base); + if (digit < 0) + break; - if(outSuffix) - { - *outSuffix = UnownedStringSlice(cursor, end); - } + value = value * base + digit; + } - return value; + if (outSuffix) + { + *outSuffix = UnownedStringSlice(cursor, end); } - FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, UnownedStringSlice* outSuffix) + if (outIsDecimalBase) { - FloatingPointLiteralValue value = 0; + *outIsDecimalBase = (base == 10); + } - const UnownedStringSlice content = token.getContent(); + return value; +} + +FloatingPointLiteralValue getFloatingPointLiteralValue( + Token const& token, + UnownedStringSlice* outSuffix) +{ + FloatingPointLiteralValue value = 0; - char const* cursor = content.begin(); - char const* end = content.end(); + const UnownedStringSlice content = token.getContent(); - int radix = _readOptionalBase(&cursor); + char const* cursor = content.begin(); + char const* end = content.end(); - bool seenDot = false; - FloatingPointLiteralValue divisor = 1; - for( ;;) + int radix = _readOptionalBase(&cursor); + + bool seenDot = false; + FloatingPointLiteralValue divisor = 1; + for (;;) + { + if (*cursor == '.') { - if(*cursor == '.') - { - cursor++; - seenDot = true; - continue; - } + cursor++; + seenDot = true; + continue; + } - int digit = _maybeReadDigit(&cursor, radix); - if(digit < 0) - break; + int digit = _maybeReadDigit(&cursor, radix); + if (digit < 0) + break; - value = value*radix + digit; + value = value * radix + digit; - if(seenDot) - { - divisor *= radix; - } + if (seenDot) + { + divisor *= radix; } + } - if (*cursor == '#') - { - // It must be INF - const auto inf = toSlice("#INF"); + if (*cursor == '#') + { + // It must be INF + const auto inf = toSlice("#INF"); - if (UnownedStringSlice(cursor, end).startsWith(inf)) + if (UnownedStringSlice(cursor, end).startsWith(inf)) + { + if (outSuffix) { - if(outSuffix) - { - *outSuffix = UnownedStringSlice(cursor + inf.getLength(), end); - } + *outSuffix = UnownedStringSlice(cursor + inf.getLength(), end); + } - value = INFINITY; + value = INFINITY; - return value; - } + return value; } + } + + // Now read optional exponent + if (_isNumberExponent(*cursor, radix)) + { + cursor++; - // Now read optional exponent - if(_isNumberExponent(*cursor, radix)) + bool exponentIsNegative = false; + switch (*cursor) { + default: + break; + + case '-': + exponentIsNegative = true; cursor++; + break; - bool exponentIsNegative = false; - switch(*cursor) - { - default: - break; + case '+': + cursor++; + break; + } - case '-': - exponentIsNegative = true; - cursor++; - break; + int exponentRadix = 10; + int exponent = 0; - case '+': - cursor++; + for (;;) + { + int digit = _maybeReadDigit(&cursor, exponentRadix); + if (digit < 0) break; - } - - int exponentRadix = 10; - int exponent = 0; - - for(;;) - { - int digit = _maybeReadDigit(&cursor, exponentRadix); - if(digit < 0) - break; - - exponent = exponent*exponentRadix + digit; - } - FloatingPointLiteralValue exponentBase = 10; - if(radix == 16) - { - exponentBase = 2; - } - - FloatingPointLiteralValue exponentValue = pow(exponentBase, exponent); + exponent = exponent * exponentRadix + digit; + } - if( exponentIsNegative ) - { - divisor *= exponentValue; - } - else - { - value *= exponentValue; - } + FloatingPointLiteralValue exponentBase = 10; + if (radix == 16) + { + exponentBase = 2; } - value /= divisor; + FloatingPointLiteralValue exponentValue = pow(exponentBase, exponent); - if(outSuffix) + if (exponentIsNegative) + { + divisor *= exponentValue; + } + else { - *outSuffix = UnownedStringSlice(cursor, end); + value *= exponentValue; } + } + + value /= divisor; - return value; + if (outSuffix) + { + *outSuffix = UnownedStringSlice(cursor, end); } - static void _lexStringLiteralBody(Lexer* lexer, char quote) + return value; +} + +static void _lexStringLiteralBody(Lexer* lexer, char quote) +{ + for (;;) { - for(;;) + int c = _peek(lexer); + if (c == quote) + { + _advance(lexer); + return; + } + + switch (c) { - int c = _peek(lexer); - if(c == quote) + case kEOF: + if (auto sink = lexer->getDiagnosticSink()) { - _advance(lexer); - return; + sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::endOfFileInLiteral); } + return; - switch(c) + case '\n': + case '\r': + if (auto sink = lexer->getDiagnosticSink()) { - case kEOF: - if (auto sink = lexer->getDiagnosticSink()) - { - sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::endOfFileInLiteral); - } - return; + sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::newlineInLiteral); + } + return; - case '\n': case '\r': - if (auto sink = lexer->getDiagnosticSink()) + case '\\': + // Need to handle various escape sequence cases + _advance(lexer); + switch (_peek(lexer)) + { + case '\'': + case '\"': + case '\\': + case '?': + case 'a': + case 'b': + case 'f': + case 'n': + case 'r': + case 't': + case 'v': + _advance(lexer); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + // octal escape: up to 3 characters + _advance(lexer); + for (int ii = 0; ii < 3; ++ii) { - sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::newlineInLiteral); + int d = _peek(lexer); + if (('0' <= d) && (d <= '7')) + { + _advance(lexer); + continue; + } + else + { + break; + } } - return; + break; - case '\\': - // Need to handle various escape sequence cases + case 'x': + // hexadecimal escape: any number of characters _advance(lexer); - switch(_peek(lexer)) + for (;;) { - case '\'': - case '\"': - case '\\': - case '?': - case 'a': - case 'b': - case 'f': - case 'n': - case 'r': - case 't': - case 'v': - _advance(lexer); - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': - // octal escape: up to 3 characters - _advance(lexer); - for(int ii = 0; ii < 3; ++ii) + int d = _peek(lexer); + if (('0' <= d) && (d <= '9') || ('a' <= d) && (d <= 'f') || + ('A' <= d) && (d <= 'F')) { - int d = _peek(lexer); - if(('0' <= d) && (d <= '7')) - { - _advance(lexer); - continue; - } - else - { - break; - } + _advance(lexer); + continue; } - break; - - case 'x': - // hexadecimal escape: any number of characters - _advance(lexer); - for(;;) + else { - int d = _peek(lexer); - if(('0' <= d) && (d <= '9') - || ('a' <= d) && (d <= 'f') - || ('A' <= d) && (d <= 'F')) - { - _advance(lexer); - continue; - } - else - { - break; - } + break; } - break; - - // TODO: Unicode escape sequences - } break; - default: - _advance(lexer); - continue; + // TODO: Unicode escape sequences } + break; + + default: + _advance(lexer); + continue; } } +} - static void _lexRawStringLiteralBody(Lexer* lexer) +static void _lexRawStringLiteralBody(Lexer* lexer) +{ + const char* start = lexer->m_cursor; + const char* endOfDelimiter = nullptr; + for (;;) { - const char* start = lexer->m_cursor; - const char* endOfDelimiter = nullptr; - for (;;) + int c = _peek(lexer); + if (c == '(' && endOfDelimiter == nullptr) + endOfDelimiter = lexer->m_cursor; + if (c == '\"') { - int c = _peek(lexer); - if (c == '(' && endOfDelimiter == nullptr) - endOfDelimiter = lexer->m_cursor; - if (c == '\"') + if (!endOfDelimiter) { - if (!endOfDelimiter) + if (auto sink = lexer->getDiagnosticSink()) { - if (auto sink = lexer->getDiagnosticSink()) - { - sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::quoteCannotBeDelimiter); - } + sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::quoteCannotBeDelimiter); } - else + } + else + { + auto testStart = lexer->m_cursor - (endOfDelimiter - start); + if (testStart > endOfDelimiter) { - auto testStart = lexer->m_cursor - (endOfDelimiter - start); - if (testStart > endOfDelimiter) + auto testDelimiter = UnownedStringSlice(testStart, lexer->m_cursor); + auto delimiter = UnownedStringSlice(start, endOfDelimiter); + if (*(testStart - 1) == ')' && testDelimiter == delimiter) { - auto testDelimiter = UnownedStringSlice(testStart, lexer->m_cursor); - auto delimiter = UnownedStringSlice(start, endOfDelimiter); - if (*(testStart - 1) == ')' && testDelimiter == delimiter) - { - _advance(lexer); - return; - } + _advance(lexer); + return; } } } + } - switch (c) + switch (c) + { + case kEOF: + if (auto sink = lexer->getDiagnosticSink()) { - case kEOF: - if (auto sink = lexer->getDiagnosticSink()) - { - sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::endOfFileInLiteral); - } - return; - default: - _advance(lexer); - continue; + sink->diagnose(_getSourceLoc(lexer), LexerDiagnostics::endOfFileInLiteral); } + return; + default: + _advance(lexer); + continue; } } +} - UnownedStringSlice getRawStringLiteralTokenValue(Token const& token) - { - auto content = token.getContent(); - if (content.getLength() <= 5) - return UnownedStringSlice(); - auto start = content.begin() + 2; - auto delimEnd = start; - while (delimEnd < content.end() && *delimEnd != '(') - delimEnd++; - auto delimLength = delimEnd - start; - auto contentEnd = content.end() - delimLength - 2; - auto contentBegin = start + delimLength + 1; - if (contentEnd <= contentBegin) - return UnownedStringSlice(); - return UnownedStringSlice(contentBegin, contentEnd); - } +UnownedStringSlice getRawStringLiteralTokenValue(Token const& token) +{ + auto content = token.getContent(); + if (content.getLength() <= 5) + return UnownedStringSlice(); + auto start = content.begin() + 2; + auto delimEnd = start; + while (delimEnd < content.end() && *delimEnd != '(') + delimEnd++; + auto delimLength = delimEnd - start; + auto contentEnd = content.end() - delimLength - 2; + auto contentBegin = start + delimLength + 1; + if (contentEnd <= contentBegin) + return UnownedStringSlice(); + return UnownedStringSlice(contentBegin, contentEnd); +} - String getStringLiteralTokenValue(Token const& token) - { - SLANG_ASSERT(token.type == TokenType::StringLiteral - || token.type == TokenType::CharLiteral); +String getStringLiteralTokenValue(Token const& token) +{ + SLANG_ASSERT(token.type == TokenType::StringLiteral || token.type == TokenType::CharLiteral); - if (token.getContent().startsWith("R")) - return getRawStringLiteralTokenValue(token); + if (token.getContent().startsWith("R")) + return getRawStringLiteralTokenValue(token); - const UnownedStringSlice content = token.getContent(); + const UnownedStringSlice content = token.getContent(); - char const* cursor = content.begin(); - char const* end = content.end(); - SLANG_UNREFERENCED_VARIABLE(end); + char const* cursor = content.begin(); + char const* end = content.end(); + SLANG_UNREFERENCED_VARIABLE(end); - auto quote = *cursor++; - SLANG_ASSERT(quote == '\'' || quote == '"'); + auto quote = *cursor++; + SLANG_ASSERT(quote == '\'' || quote == '"'); - StringBuilder valueBuilder; - for(;;) - { - SLANG_ASSERT(cursor != end); + StringBuilder valueBuilder; + for (;;) + { + SLANG_ASSERT(cursor != end); - auto c = *cursor++; + auto c = *cursor++; - // If we see a closing quote, then we are at the end of the string literal - if(c == quote) - { - SLANG_ASSERT(cursor == end); - return valueBuilder.produceString(); - } + // If we see a closing quote, then we are at the end of the string literal + if (c == quote) + { + SLANG_ASSERT(cursor == end); + return valueBuilder.produceString(); + } - // Characters that don't being escape sequences are easy; - // just append them to the buffer and move on. - if(c != '\\') - { - valueBuilder.append(c); - continue; - } + // Characters that don't being escape sequences are easy; + // just append them to the buffer and move on. + if (c != '\\') + { + valueBuilder.append(c); + continue; + } - // Now we look at another character to figure out the kind of - // escape sequence we are dealing with: + // Now we look at another character to figure out the kind of + // escape sequence we are dealing with: - char d = *cursor++; + char d = *cursor++; - switch(d) + switch (d) + { + // Simple characters that just needed to be escaped + case '\'': + case '\"': + case '\\': + case '?': + valueBuilder.append(d); + continue; + + // Traditional escape sequences for special characters + case 'a': + valueBuilder.append('\a'); + continue; + case 'b': + valueBuilder.append('\b'); + continue; + case 'f': + valueBuilder.append('\f'); + continue; + case 'n': + valueBuilder.append('\n'); + continue; + case 'r': + valueBuilder.append('\r'); + continue; + case 't': + valueBuilder.append('\t'); + continue; + case 'v': + valueBuilder.append('\v'); + continue; + + // Octal escape: up to 3 characters + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': { - // Simple characters that just needed to be escaped - case '\'': - case '\"': - case '\\': - case '?': - valueBuilder.append(d); - continue; - - // Traditional escape sequences for special characters - case 'a': valueBuilder.append('\a'); continue; - case 'b': valueBuilder.append('\b'); continue; - case 'f': valueBuilder.append('\f'); continue; - case 'n': valueBuilder.append('\n'); continue; - case 'r': valueBuilder.append('\r'); continue; - case 't': valueBuilder.append('\t'); continue; - case 'v': valueBuilder.append('\v'); continue; - - // Octal escape: up to 3 characters - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': + cursor--; + int value = 0; + for (int ii = 0; ii < 3; ++ii) { - cursor--; - int value = 0; - for(int ii = 0; ii < 3; ++ii) + d = *cursor; + if (('0' <= d) && (d <= '7')) { - d = *cursor; - if(('0' <= d) && (d <= '7')) - { - value = value*8 + (d - '0'); + value = value * 8 + (d - '0'); - cursor++; - continue; - } - else - { - break; - } + cursor++; + continue; + } + else + { + break; } - - // TODO: add support for appending an arbitrary code point? - valueBuilder.append((char) value); } - continue; - // Hexadecimal escape: any number of characters - case 'x': + // TODO: add support for appending an arbitrary code point? + valueBuilder.append((char)value); + } + continue; + + // Hexadecimal escape: any number of characters + case 'x': + { + int value = 0; + for (;;) { - int value = 0; - for(;;) + d = *cursor++; + int digitValue = 0; + if (('0' <= d) && (d <= '9')) { - d = *cursor++; - int digitValue = 0; - if(('0' <= d) && (d <= '9')) - { - digitValue = d - '0'; - } - else if( ('a' <= d) && (d <= 'f') ) - { - digitValue = d - 'a'; - } - else if( ('A' <= d) && (d <= 'F') ) - { - digitValue = d - 'A'; - } - else - { - cursor--; - break; - } - - value = value*16 + digitValue; + digitValue = d - '0'; + } + else if (('a' <= d) && (d <= 'f')) + { + digitValue = d - 'a'; + } + else if (('A' <= d) && (d <= 'F')) + { + digitValue = d - 'A'; + } + else + { + cursor--; + break; } - // TODO: add support for appending an arbitrary code point? - valueBuilder.append((char) value); + value = value * 16 + digitValue; } - continue; - - // TODO: Unicode escape sequences + // TODO: add support for appending an arbitrary code point? + valueBuilder.append((char)value); } + continue; + + // TODO: Unicode escape sequences } } +} - String getFileNameTokenValue(Token const& token) - { - const UnownedStringSlice content = token.getContent(); +String getFileNameTokenValue(Token const& token) +{ + const UnownedStringSlice content = token.getContent(); - // A file name usually doesn't process escape sequences - // (this is import on Windows, where `\\` is a valid - // path separator character). + // A file name usually doesn't process escape sequences + // (this is import on Windows, where `\\` is a valid + // path separator character). - // Just trim off the first and last characters to remove the quotes - // (whether they were `""` or `<>`. - return String(content.begin() + 1, content.end() - 1); - } + // Just trim off the first and last characters to remove the quotes + // (whether they were `""` or `<>`. + return String(content.begin() + 1, content.end() - 1); +} - static TokenType _lexTokenImpl(Lexer* lexer) +static TokenType _lexTokenImpl(Lexer* lexer) +{ + int nextCodePoint = _peek(lexer); + switch (nextCodePoint) { - int nextCodePoint = _peek(lexer); - switch(nextCodePoint) - { - default: - break; + default: + break; - case kEOF: - return TokenType::EndOfFile; + case kEOF: + return TokenType::EndOfFile; - case '\r': case '\n': - _handleNewLine(lexer); - return TokenType::NewLine; + case '\r': + case '\n': + _handleNewLine(lexer); + return TokenType::NewLine; - case ' ': case '\t': - _lexHorizontalSpace(lexer); - return TokenType::WhiteSpace; + case ' ': + case '\t': + _lexHorizontalSpace(lexer); + return TokenType::WhiteSpace; + + case '.': + _advance(lexer); + switch (_peek(lexer)) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return _lexNumberAfterDecimalPoint(lexer, 10); case '.': + // Note: consuming the second `.` here means that + // we cannot back up and return a `.` token by itself + // any more. We thus end up having distinct tokens for + // `.`, `..`, and `...` even though the `..` case is + // not part of HLSL. + // _advance(lexer); - switch(_peek(lexer)) + switch (_peek(lexer)) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return _lexNumberAfterDecimalPoint(lexer, 10); - case '.': - // Note: consuming the second `.` here means that - // we cannot back up and return a `.` token by itself - // any more. We thus end up having distinct tokens for - // `.`, `..`, and `...` even though the `..` case is - // not part of HLSL. - // _advance(lexer); - switch(_peek(lexer)) - { - case '.': - _advance(lexer); - return TokenType::Ellipsis; - - default: - return TokenType::DotDot; - } + return TokenType::Ellipsis; default: - return TokenType::Dot; + return TokenType::DotDot; } - case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - return _lexNumber(lexer, 10); + default: + return TokenType::Dot; + } - case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return _lexNumber(lexer, 10); + + case '0': + { + auto loc = _getSourceLoc(lexer); + _advance(lexer); + switch (_peek(lexer)) { - auto loc = _getSourceLoc(lexer); - _advance(lexer); - switch(_peek(lexer)) + default: + return _maybeLexNumberSuffix(lexer, TokenType::IntegerLiteral); + + case '.': + switch (_peek(lexer, 1)) { - default: + // 0.xxxx or 0.rrrr + case 'x': + case 'r': return _maybeLexNumberSuffix(lexer, TokenType::IntegerLiteral); - - case '.': - switch (_peek(lexer, 1)) - { - // 0.xxxx or 0.rrrr - case 'x': - case 'r': - return _maybeLexNumberSuffix(lexer, TokenType::IntegerLiteral); - default: - _advance(lexer); - return _lexNumberAfterDecimalPoint(lexer, 10); - } - - case 'x': case 'X': - _advance(lexer); - return _lexNumber(lexer, 16); - - case 'b': case 'B': + default: _advance(lexer); - return _lexNumber(lexer, 2); - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (auto sink = lexer->getDiagnosticSink()) - { - sink->diagnose(loc, LexerDiagnostics::octalLiteral); - } - return _lexNumber(lexer, 8); + return _lexNumberAfterDecimalPoint(lexer, 10); } - } - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'l': case 'm': case 'n': case 'o': - case 'p': case 'q': case 'r': case 's': case 't': - case 'u': case 'v': case 'w': case 'x': case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'L': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - _lexIdentifier(lexer); - return TokenType::Identifier; - case 'R': - _advance(lexer); - switch (_peek(lexer)) - { - default: - _lexIdentifier(lexer); - return TokenType::Identifier; - case '\"': + case 'x': + case 'X': + _advance(lexer); + return _lexNumber(lexer, 16); + + case 'b': + case 'B': _advance(lexer); - _lexRawStringLiteralBody(lexer); - return TokenType::StringLiteral; + return _lexNumber(lexer, 2); + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (auto sink = lexer->getDiagnosticSink()) + { + sink->diagnose(loc, LexerDiagnostics::octalLiteral); + } + return _lexNumber(lexer, 8); } + } + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'g': + case 'h': + case 'i': + case 'j': + case 'k': + case 'l': + case 'm': + case 'n': + case 'o': + case 'p': + case 'q': + case 'r': + case 's': + case 't': + case 'u': + case 'v': + case 'w': + case 'x': + case 'y': + case 'z': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + case 'G': + case 'H': + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + case 'N': + case 'O': + case 'P': + case 'Q': + case 'S': + case 'T': + case 'U': + case 'V': + case 'W': + case 'X': + case 'Y': + case 'Z': + case '_': + _lexIdentifier(lexer); + return TokenType::Identifier; + case 'R': + _advance(lexer); + switch (_peek(lexer)) + { + default: + _lexIdentifier(lexer); + return TokenType::Identifier; case '\"': _advance(lexer); - _lexStringLiteralBody(lexer, '\"'); + _lexRawStringLiteralBody(lexer); return TokenType::StringLiteral; + } - case '\'': - _advance(lexer); - _lexStringLiteralBody(lexer, '\''); - return TokenType::CharLiteral; + case '\"': + _advance(lexer); + _lexStringLiteralBody(lexer, '\"'); + return TokenType::StringLiteral; + + case '\'': + _advance(lexer); + _lexStringLiteralBody(lexer, '\''); + return TokenType::CharLiteral; + case '+': + _advance(lexer); + switch (_peek(lexer)) + { case '+': _advance(lexer); - switch(_peek(lexer)) - { - case '+': _advance(lexer); return TokenType::OpInc; - case '=': _advance(lexer); return TokenType::OpAddAssign; - default: - return TokenType::OpAdd; - } + return TokenType::OpInc; + case '=': + _advance(lexer); + return TokenType::OpAddAssign; + default: + return TokenType::OpAdd; + } + case '-': + _advance(lexer); + switch (_peek(lexer)) + { case '-': _advance(lexer); - switch(_peek(lexer)) - { - case '-': _advance(lexer); return TokenType::OpDec; - case '=': _advance(lexer); return TokenType::OpSubAssign; - case '>': _advance(lexer); return TokenType::RightArrow; - default: - return TokenType::OpSub; - } + return TokenType::OpDec; + case '=': + _advance(lexer); + return TokenType::OpSubAssign; + case '>': + _advance(lexer); + return TokenType::RightArrow; + default: + return TokenType::OpSub; + } - case '*': + case '*': + _advance(lexer); + switch (_peek(lexer)) + { + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpMulAssign; - default: - return TokenType::OpMul; - } + return TokenType::OpMulAssign; + default: + return TokenType::OpMul; + } + case '/': + _advance(lexer); + switch (_peek(lexer)) + { + case '=': + _advance(lexer); + return TokenType::OpDivAssign; case '/': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpDivAssign; - case '/': _advance(lexer); _lexLineComment(lexer); return TokenType::LineComment; - case '*': _advance(lexer); _lexBlockComment(lexer); return TokenType::BlockComment; - default: - return TokenType::OpDiv; - } + _lexLineComment(lexer); + return TokenType::LineComment; + case '*': + _advance(lexer); + _lexBlockComment(lexer); + return TokenType::BlockComment; + default: + return TokenType::OpDiv; + } - case '%': + case '%': + _advance(lexer); + switch (_peek(lexer)) + { + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpModAssign; - default: - return TokenType::OpMod; - } + return TokenType::OpModAssign; + default: + return TokenType::OpMod; + } + case '|': + _advance(lexer); + switch (_peek(lexer)) + { case '|': _advance(lexer); - switch(_peek(lexer)) - { - case '|': _advance(lexer); return TokenType::OpOr; - case '=': _advance(lexer); return TokenType::OpOrAssign; - default: - return TokenType::OpBitOr; - } + return TokenType::OpOr; + case '=': + _advance(lexer); + return TokenType::OpOrAssign; + default: + return TokenType::OpBitOr; + } + case '&': + _advance(lexer); + switch (_peek(lexer)) + { case '&': _advance(lexer); - switch(_peek(lexer)) - { - case '&': _advance(lexer); return TokenType::OpAnd; - case '=': _advance(lexer); return TokenType::OpAndAssign; - default: - return TokenType::OpBitAnd; - } + return TokenType::OpAnd; + case '=': + _advance(lexer); + return TokenType::OpAndAssign; + default: + return TokenType::OpBitAnd; + } - case '^': + case '^': + _advance(lexer); + switch (_peek(lexer)) + { + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpXorAssign; - default: - return TokenType::OpBitXor; - } + return TokenType::OpXorAssign; + default: + return TokenType::OpBitXor; + } + case '>': + _advance(lexer); + switch (_peek(lexer)) + { case '>': _advance(lexer); - switch(_peek(lexer)) + switch (_peek(lexer)) { - case '>': + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpShrAssign; - default: return TokenType::OpRsh; - } - case '=': _advance(lexer); return TokenType::OpGeq; + return TokenType::OpShrAssign; default: - return TokenType::OpGreater; + return TokenType::OpRsh; } + case '=': + _advance(lexer); + return TokenType::OpGeq; + default: + return TokenType::OpGreater; + } + case '<': + _advance(lexer); + switch (_peek(lexer)) + { case '<': _advance(lexer); - switch(_peek(lexer)) + switch (_peek(lexer)) { - case '<': + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpShlAssign; - default: return TokenType::OpLsh; - } - case '=': _advance(lexer); return TokenType::OpLeq; + return TokenType::OpShlAssign; default: - return TokenType::OpLess; + return TokenType::OpLsh; } + case '=': + _advance(lexer); + return TokenType::OpLeq; + default: + return TokenType::OpLess; + } + case '=': + _advance(lexer); + switch (_peek(lexer)) + { case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpEql; - default: - return TokenType::OpAssign; - } + return TokenType::OpEql; + default: + return TokenType::OpAssign; + } - case '!': + case '!': + _advance(lexer); + switch (_peek(lexer)) + { + case '=': _advance(lexer); - switch(_peek(lexer)) - { - case '=': _advance(lexer); return TokenType::OpNeq; - default: - return TokenType::OpNot; - } + return TokenType::OpNeq; + default: + return TokenType::OpNot; + } + case '#': + _advance(lexer); + switch (_peek(lexer)) + { case '#': _advance(lexer); - switch(_peek(lexer)) - { - case '#': _advance(lexer); return TokenType::PoundPound; + return TokenType::PoundPound; - case '?': _advance(lexer); return TokenType::CompletionRequest; + case '?': + _advance(lexer); + return TokenType::CompletionRequest; - default: - return TokenType::Pound; - } + default: + return TokenType::Pound; + } - case '~': _advance(lexer); return TokenType::OpBitNot; + case '~': + _advance(lexer); + return TokenType::OpBitNot; - case ':': + case ':': { _advance(lexer); if (_peek(lexer) == ':') @@ -1347,151 +1555,174 @@ namespace Slang } return TokenType::Colon; } - case ';': _advance(lexer); return TokenType::Semicolon; - case ',': _advance(lexer); return TokenType::Comma; - - case '{': _advance(lexer); return TokenType::LBrace; - case '}': _advance(lexer); return TokenType::RBrace; - case '[': _advance(lexer); return TokenType::LBracket; - case ']': _advance(lexer); return TokenType::RBracket; - case '(': _advance(lexer); return TokenType::LParent; - case ')': _advance(lexer); return TokenType::RParent; - - case '?': _advance(lexer); return TokenType::QuestionMark; - case '@': _advance(lexer); return TokenType::At; - case '$': + case ';': + _advance(lexer); + return TokenType::Semicolon; + case ',': + _advance(lexer); + return TokenType::Comma; + + case '{': + _advance(lexer); + return TokenType::LBrace; + case '}': + _advance(lexer); + return TokenType::RBrace; + case '[': + _advance(lexer); + return TokenType::LBracket; + case ']': + _advance(lexer); + return TokenType::RBracket; + case '(': + _advance(lexer); + return TokenType::LParent; + case ')': + _advance(lexer); + return TokenType::RParent; + + case '?': + _advance(lexer); + return TokenType::QuestionMark; + case '@': + _advance(lexer); + return TokenType::At; + case '$': { _advance(lexer); - if(_peek(lexer) == '$') + if (_peek(lexer) == '$') { _advance(lexer); return TokenType::DollarDollar; } return TokenType::Dollar; } + } - } - - // We treat all unicode characters as a part of an identifier. - if (isNonAsciiCodePoint(nextCodePoint)) - { - _lexIdentifier(lexer); - return TokenType::Identifier; - } + // We treat all unicode characters as a part of an identifier. + if (isNonAsciiCodePoint(nextCodePoint)) + { + _lexIdentifier(lexer); + return TokenType::Identifier; + } - { - // If none of the above cases matched, then we have an - // unexpected/invalid character. + { + // If none of the above cases matched, then we have an + // unexpected/invalid character. - auto loc = _getSourceLoc(lexer); - int c = _advance(lexer); + auto loc = _getSourceLoc(lexer); + int c = _advance(lexer); - if (auto sink = lexer->getDiagnosticSink()) + if (auto sink = lexer->getDiagnosticSink()) + { + if (c >= 0x20 && c <= 0x7E) { - if(c >= 0x20 && c <= 0x7E) - { - char buffer[] = { (char) c, 0 }; - sink->diagnose(loc, LexerDiagnostics::illegalCharacterPrint, buffer); - } - else if(c == kEOF) - { - sink->diagnose(loc, LexerDiagnostics::unexpectedEndOfInput); - } - else - { - // Fallback: print as hexadecimal - sink->diagnose(loc, LexerDiagnostics::illegalCharacterHex, String((unsigned char)c, 16)); - } + char buffer[] = {(char)c, 0}; + sink->diagnose(loc, LexerDiagnostics::illegalCharacterPrint, buffer); + } + else if (c == kEOF) + { + sink->diagnose(loc, LexerDiagnostics::unexpectedEndOfInput); + } + else + { + // Fallback: print as hexadecimal + sink->diagnose( + loc, + LexerDiagnostics::illegalCharacterHex, + String((unsigned char)c, 16)); } - - return TokenType::Invalid; } + + return TokenType::Invalid; } +} - Token Lexer::lexToken() +Token Lexer::lexToken() +{ + for (;;) { - for(;;) - { - Token token; - token.loc = _getSourceLoc(this); + Token token; + token.loc = _getSourceLoc(this); - char const* textBegin = m_cursor; + char const* textBegin = m_cursor; - auto tokenType = _lexTokenImpl(this); + auto tokenType = _lexTokenImpl(this); - // The flags on the token we just lexed will be based - // on the current state of the lexer. - // - auto tokenFlags = m_tokenFlags; - // - // Depending on what kind of token we just lexed, the - // flags that will be used for the *next* token might - // need to be updated. - // - switch(tokenType) + // The flags on the token we just lexed will be based + // on the current state of the lexer. + // + auto tokenFlags = m_tokenFlags; + // + // Depending on what kind of token we just lexed, the + // flags that will be used for the *next* token might + // need to be updated. + // + switch (tokenType) + { + case TokenType::NewLine: { - case TokenType::NewLine: - { - // If we just reached the end of a line, then the next token - // should count as being at the start of a line, and also after - // whitespace. - // - m_tokenFlags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; - break; - } + // If we just reached the end of a line, then the next token + // should count as being at the start of a line, and also after + // whitespace. + // + m_tokenFlags = TokenFlag::AtStartOfLine | TokenFlag::AfterWhitespace; + break; + } - case TokenType::WhiteSpace: - case TokenType::BlockComment: - case TokenType::LineComment: - { - // True horizontal whitespace and comments both count as whitespace. - // - // Note that a line comment does not include the terminating newline, - // we do not need to set `AtStartOfLine` here. - // - m_tokenFlags |= TokenFlag::AfterWhitespace; - break; - } - - default: - { - // If we read some token other then the above cases, then we are - // neither after whitespace nor at the start of a line. - // - m_tokenFlags = 0; - break; - } + case TokenType::WhiteSpace: + case TokenType::BlockComment: + case TokenType::LineComment: + { + // True horizontal whitespace and comments both count as whitespace. + // + // Note that a line comment does not include the terminating newline, + // we do not need to set `AtStartOfLine` here. + // + m_tokenFlags |= TokenFlag::AfterWhitespace; + break; + } + + default: + { + // If we read some token other then the above cases, then we are + // neither after whitespace nor at the start of a line. + // + m_tokenFlags = 0; + break; } + } - token.type = tokenType; - token.flags = tokenFlags; + token.type = tokenType; + token.flags = tokenFlags; - char const* textEnd = m_cursor; + char const* textEnd = m_cursor; - // Note(tfoley): `StringBuilder::Append()` seems to crash when appending zero bytes - if(textEnd != textBegin) + // Note(tfoley): `StringBuilder::Append()` seems to crash when appending zero bytes + if (textEnd != textBegin) + { + // "scrubbing" token value here to remove escaped newlines... + // + // Only perform this work if we encountered an escaped newline + // while lexing this token (e.g., keep a flag on the lexer), or + // do it on-demand when the actual value of the token is needed. + if (tokenFlags & TokenFlag::ScrubbingNeeded) { - // "scrubbing" token value here to remove escaped newlines... - // - // Only perform this work if we encountered an escaped newline - // while lexing this token (e.g., keep a flag on the lexer), or - // do it on-demand when the actual value of the token is needed. - if (tokenFlags & TokenFlag::ScrubbingNeeded) - { - // Allocate space that will always be more than enough for stripped contents - char* startDst = (char*)m_memoryArena->allocateUnaligned(textEnd - textBegin); - char* dst = startDst; + // Allocate space that will always be more than enough for stripped contents + char* startDst = (char*)m_memoryArena->allocateUnaligned(textEnd - textBegin); + char* dst = startDst; - auto tt = textBegin; - while (tt != textEnd) + auto tt = textBegin; + while (tt != textEnd) + { + char c = *tt++; + if (c == '\\') { - char c = *tt++; - if (c == '\\') + char d = *tt; + switch (d) { - char d = *tt; - switch (d) - { - case '\r': case '\n': + case '\r': + case '\n': { tt++; char e = *tt; @@ -1502,116 +1733,116 @@ namespace Slang } continue; - default: - break; - } + default: + break; } - *dst++ = c; } - token.setContent(UnownedStringSlice(startDst, dst)); - } - else - { - token.setContent(UnownedStringSlice(textBegin, textEnd)); + *dst++ = c; } + token.setContent(UnownedStringSlice(startDst, dst)); } - - if (m_namePool) + else { - if (tokenType == TokenType::Identifier || tokenType == TokenType::CompletionRequest) - { - token.setName(m_namePool->getName(token.getContent())); - } + token.setContent(UnownedStringSlice(textBegin, textEnd)); } - - return token; } - } - TokenList Lexer::lexAllSemanticTokens() - { - TokenList tokenList; - for(;;) + if (m_namePool) { - Token token = lexToken(); - - // We are only interested intokens that are semantically - // significant, so we will skip over forms of whitespace - // and comments. - // - switch( token.type ) + if (tokenType == TokenType::Identifier || tokenType == TokenType::CompletionRequest) { - default: - break; - - case TokenType::WhiteSpace: - case TokenType::BlockComment: - case TokenType::LineComment: - case TokenType::NewLine: - continue; + token.setName(m_namePool->getName(token.getContent())); } - - tokenList.add(token); - if(token.type == TokenType::EndOfFile) - return tokenList; } + + return token; } +} - TokenList Lexer::lexAllMarkupTokens() +TokenList Lexer::lexAllSemanticTokens() +{ + TokenList tokenList; + for (;;) { - TokenList tokenList; - for(;;) - { - Token token = lexToken(); - switch( token.type ) - { - default: - break; + Token token = lexToken(); - case TokenType::WhiteSpace: - case TokenType::NewLine: - continue; - } + // We are only interested intokens that are semantically + // significant, so we will skip over forms of whitespace + // and comments. + // + switch (token.type) + { + default: + break; - tokenList.add(token); - if(token.type == TokenType::EndOfFile) - return tokenList; + case TokenType::WhiteSpace: + case TokenType::BlockComment: + case TokenType::LineComment: + case TokenType::NewLine: + continue; } + + tokenList.add(token); + if (token.type == TokenType::EndOfFile) + return tokenList; } +} - /* static */UnownedStringSlice Lexer::sourceLocationLexer(const UnownedStringSlice& in) +TokenList Lexer::lexAllMarkupTokens() +{ + TokenList tokenList; + for (;;) { - Lexer lexer; + Token token = lexToken(); + switch (token.type) + { + default: + break; - SourceManager sourceManager; - sourceManager.initialize(nullptr, nullptr); + case TokenType::WhiteSpace: + case TokenType::NewLine: + continue; + } - auto sourceFile = sourceManager.createSourceFileWithString(PathInfo::makeUnknown(), in); - auto sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0)); + tokenList.add(token); + if (token.type == TokenType::EndOfFile) + return tokenList; + } +} - DiagnosticSink sink(&sourceManager, nullptr); +/* static */ UnownedStringSlice Lexer::sourceLocationLexer(const UnownedStringSlice& in) +{ + Lexer lexer; - MemoryArena arena; + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); - RootNamePool rootNamePool; - NamePool namePool; - namePool.setRootNamePool(&rootNamePool); + auto sourceFile = sourceManager.createSourceFileWithString(PathInfo::makeUnknown(), in); + auto sourceView = sourceManager.createSourceView(sourceFile, nullptr, SourceLoc::fromRaw(0)); - lexer.initialize(sourceView, &sink, &namePool, &arena); + DiagnosticSink sink(&sourceManager, nullptr); - Token tok = lexer.lexToken(); + MemoryArena arena; - if (tok.type == TokenType::Invalid) - { - return UnownedStringSlice(); - } + RootNamePool rootNamePool; + NamePool namePool; + namePool.setRootNamePool(&rootNamePool); - const int offset = sourceView->getRange().getOffset(tok.loc); + lexer.initialize(sourceView, &sink, &namePool, &arena); - SLANG_ASSERT(offset >= 0 && offset <= in.getLength()); - SLANG_ASSERT(Index(offset + tok.charsCount) <= in.getLength()); + Token tok = lexer.lexToken(); - return UnownedStringSlice(in.begin() + offset, in.begin() + offset + tok.charsCount); + if (tok.type == TokenType::Invalid) + { + return UnownedStringSlice(); } + const int offset = sourceView->getRange().getOffset(tok.loc); + + SLANG_ASSERT(offset >= 0 && offset <= in.getLength()); + SLANG_ASSERT(Index(offset + tok.charsCount) <= in.getLength()); + + return UnownedStringSlice(in.begin() + offset, in.begin() + offset + tok.charsCount); } + +} // namespace Slang diff --git a/source/compiler-core/slang-lexer.h b/source/compiler-core/slang-lexer.h index 3a2506d851..a36719ab79 100644 --- a/source/compiler-core/slang-lexer.h +++ b/source/compiler-core/slang-lexer.h @@ -6,173 +6,179 @@ namespace Slang { - struct NamePool; +struct NamePool; - // +// - struct TokenList - { - const Token* begin() const; - const Token* end() const; +struct TokenList +{ + const Token* begin() const; + const Token* end() const; - SLANG_FORCE_INLINE void add(const Token& token) { m_tokens.add(token); } + SLANG_FORCE_INLINE void add(const Token& token) { m_tokens.add(token); } - List m_tokens; - }; + List m_tokens; +}; - struct TokenSpan +struct TokenSpan +{ + TokenSpan(); + TokenSpan(TokenList const& tokenList) + : m_begin(tokenList.begin()), m_end(tokenList.end()) { - TokenSpan(); - TokenSpan( - TokenList const& tokenList) - : m_begin(tokenList.begin()) - , m_end (tokenList.end ()) - {} + } - const Token* begin() const { return m_begin; } - const Token* end () const { return m_end ; } + const Token* begin() const { return m_begin; } + const Token* end() const { return m_end; } - int getCount() { return (int)(m_end - m_begin); } + int getCount() { return (int)(m_end - m_begin); } - const Token* m_begin; - const Token* m_end; - }; + const Token* m_begin; + const Token* m_end; +}; - struct TokenReader +struct TokenReader +{ + Token m_nextToken; + TokenReader(); + explicit TokenReader(TokenSpan const& tokens) + : m_cursor(tokens.begin()), m_end(tokens.end()) { - Token m_nextToken; - TokenReader(); - explicit TokenReader(TokenSpan const& tokens) - : m_cursor(tokens.begin()) - , m_end (tokens.end ()) - { - _updateLookaheadToken(); - } - explicit TokenReader(TokenList const& tokens) - : m_cursor(tokens.begin()) - , m_end (tokens.end ()) - { - _updateLookaheadToken(); - } - explicit TokenReader(Token const* begin, Token const* end) - : m_cursor(begin) - , m_end (end) + _updateLookaheadToken(); + } + explicit TokenReader(TokenList const& tokens) + : m_cursor(tokens.begin()), m_end(tokens.end()) + { + _updateLookaheadToken(); + } + explicit TokenReader(Token const* begin, Token const* end) + : m_cursor(begin), m_end(end) + { + _updateLookaheadToken(); + } + struct ParsingCursor + { + bool operator==(const ParsingCursor& rhs) const { - _updateLookaheadToken(); + return tokenReaderCursor == rhs.tokenReaderCursor; } - struct ParsingCursor - { - bool operator==(const ParsingCursor& rhs) const { return tokenReaderCursor == rhs.tokenReaderCursor; } - bool operator!=(const ParsingCursor& rhs) const { return !(*this == rhs); } + bool operator!=(const ParsingCursor& rhs) const { return !(*this == rhs); } - bool isValid() const { return tokenReaderCursor != nullptr; } + bool isValid() const { return tokenReaderCursor != nullptr; } - Token nextToken; - const Token* tokenReaderCursor = nullptr; - }; - ParsingCursor getCursor() - { - ParsingCursor rs; - rs.nextToken = m_nextToken; - rs.tokenReaderCursor = m_cursor; - return rs; - } - void setCursor(ParsingCursor cursor) - { - m_cursor = cursor.tokenReaderCursor; - m_nextToken = cursor.nextToken; - } - bool isAtCursor(const ParsingCursor& cursor) const - { - return cursor.tokenReaderCursor == m_cursor; - } - bool isAtEnd() const { return m_cursor == m_end; } - Token& peekToken(); - TokenType peekTokenType() const; - SourceLoc peekLoc() const; + Token nextToken; + const Token* tokenReaderCursor = nullptr; + }; + ParsingCursor getCursor() + { + ParsingCursor rs; + rs.nextToken = m_nextToken; + rs.tokenReaderCursor = m_cursor; + return rs; + } + void setCursor(ParsingCursor cursor) + { + m_cursor = cursor.tokenReaderCursor; + m_nextToken = cursor.nextToken; + } + bool isAtCursor(const ParsingCursor& cursor) const + { + return cursor.tokenReaderCursor == m_cursor; + } + bool isAtEnd() const { return m_cursor == m_end; } + Token& peekToken(); + TokenType peekTokenType() const; + SourceLoc peekLoc() const; - Token advanceToken(); + Token advanceToken(); - int getCount() { return (int)(m_end - m_cursor); } + int getCount() { return (int)(m_end - m_cursor); } - const Token* m_cursor; - const Token* m_end; - static Token getEndOfFileToken(); + const Token* m_cursor; + const Token* m_end; + static Token getEndOfFileToken(); - private: - /// Update the lookahead token in `m_nextToken` to reflect the cursor state - void _updateLookaheadToken(); - }; +private: + /// Update the lookahead token in `m_nextToken` to reflect the cursor state + void _updateLookaheadToken(); +}; - typedef unsigned int LexerFlags; - enum - { - kLexerFlag_SuppressDiagnostics = 1 << 2, ///< Suppress errors about invalid/unsupported characters - }; +typedef unsigned int LexerFlags; +enum +{ + kLexerFlag_SuppressDiagnostics = 1 + << 2, ///< Suppress errors about invalid/unsupported characters +}; - struct Lexer +struct Lexer +{ + void initialize( + SourceView* sourceView, + DiagnosticSink* sink, + NamePool* namePool, + MemoryArena* memoryArena); + + ~Lexer(); + + /// Runs the lexer to try and extract a single token, which is returned. + /// This can be used by the DiagnosticSink to be able to display more appropriate + /// information when displaying a source location - such as underscoring the + /// token at that location. + /// + /// NOTE! This function is relatively slow, and is designed for use around this specific + /// purpose. It does not return a token or a token type, because that information is + /// not needed by the DiagnosticSink. + static UnownedStringSlice sourceLocationLexer(const UnownedStringSlice& in); + + /// Lex the next token in the input stream, returning an EOF token if at end. + Token lexToken(); + + /// Lex all tokens (up to the end of the stream) that are semantically relevant + TokenList lexAllSemanticTokens(); + + /// Lex all tokens (up to the end of the stream) that are relevant to things like markup + TokenList lexAllMarkupTokens(); + + /// Get the diagnostic sink, taking into account flags. Will return null if suppressing + /// diagnostics. + DiagnosticSink* getDiagnosticSink() { - void initialize( - SourceView* sourceView, - DiagnosticSink* sink, - NamePool* namePool, - MemoryArena* memoryArena); - - ~Lexer(); - - /// Runs the lexer to try and extract a single token, which is returned. - /// This can be used by the DiagnosticSink to be able to display more appropriate - /// information when displaying a source location - such as underscoring the - /// token at that location. - /// - /// NOTE! This function is relatively slow, and is designed for use around this specific - /// purpose. It does not return a token or a token type, because that information is - /// not needed by the DiagnosticSink. - static UnownedStringSlice sourceLocationLexer(const UnownedStringSlice& in); - - /// Lex the next token in the input stream, returning an EOF token if at end. - Token lexToken(); - - /// Lex all tokens (up to the end of the stream) that are semantically relevant - TokenList lexAllSemanticTokens(); - - /// Lex all tokens (up to the end of the stream) that are relevant to things like markup - TokenList lexAllMarkupTokens(); - - /// Get the diagnostic sink, taking into account flags. Will return null if suppressing diagnostics. - DiagnosticSink* getDiagnosticSink() - { - return ((m_lexerFlags & kLexerFlag_SuppressDiagnostics) == 0) ? m_sink : nullptr; - } + return ((m_lexerFlags & kLexerFlag_SuppressDiagnostics) == 0) ? m_sink : nullptr; + } - SourceView* m_sourceView; - DiagnosticSink* m_sink; - NamePool* m_namePool; + SourceView* m_sourceView; + DiagnosticSink* m_sink; + NamePool* m_namePool; - char const* m_cursor; + char const* m_cursor; - char const* m_begin; - char const* m_end; + char const* m_begin; + char const* m_end; - /// The starting sourceLoc (same as first location of SourceView) - SourceLoc m_startLoc; + /// The starting sourceLoc (same as first location of SourceView) + SourceLoc m_startLoc; - TokenFlags m_tokenFlags; - LexerFlags m_lexerFlags; + TokenFlags m_tokenFlags; + LexerFlags m_lexerFlags; + + MemoryArena* m_memoryArena; +}; - MemoryArena* m_memoryArena; - }; - - // Helper routines for extracting values from tokens - String getStringLiteralTokenValue(Token const& token); - String getFileNameTokenValue(Token const& token); +// Helper routines for extracting values from tokens +String getStringLiteralTokenValue(Token const& token); +String getFileNameTokenValue(Token const& token); - typedef int64_t IntegerLiteralValue; - typedef double FloatingPointLiteralValue; +typedef int64_t IntegerLiteralValue; +typedef double FloatingPointLiteralValue; - IntegerLiteralValue getIntegerLiteralValue(Token const& token, UnownedStringSlice* outSuffix = 0); - FloatingPointLiteralValue getFloatingPointLiteralValue(Token const& token, UnownedStringSlice* outSuffix = 0); -} +IntegerLiteralValue getIntegerLiteralValue( + Token const& token, + UnownedStringSlice* outSuffix = 0, + bool* outIsDecimalBase = 0); +FloatingPointLiteralValue getFloatingPointLiteralValue( + Token const& token, + UnownedStringSlice* outSuffix = 0); +} // namespace Slang #endif diff --git a/source/compiler-core/slang-llvm-compiler.cpp b/source/compiler-core/slang-llvm-compiler.cpp index 3d24d3aa15..457268b984 100644 --- a/source/compiler-core/slang-llvm-compiler.cpp +++ b/source/compiler-core/slang-llvm-compiler.cpp @@ -6,11 +6,15 @@ namespace Slang { -/* static */SlangResult LLVMDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +/* static */ SlangResult LLVMDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) { ComPtr library; - SLANG_RETURN_ON_FAIL(DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-llvm", library)); + SLANG_RETURN_ON_FAIL( + DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-llvm", library)); SLANG_ASSERT(library); if (!library) @@ -18,14 +22,17 @@ namespace Slang return SLANG_FAIL; } - typedef SlangResult(*CreateDownstreamCompilerFunc)(const Guid& intf, IDownstreamCompiler** outCompiler); + typedef SlangResult ( + *CreateDownstreamCompilerFunc)(const Guid& intf, IDownstreamCompiler** outCompiler); ComPtr downstreamCompiler; // Only accept V4, so we can update IArtifact without breaking anything - if (auto fnV4 = (CreateDownstreamCompilerFunc)library->findFuncByName("createLLVMDownstreamCompiler_V4")) + if (auto fnV4 = (CreateDownstreamCompilerFunc)library->findFuncByName( + "createLLVMDownstreamCompiler_V4")) { - SLANG_RETURN_ON_FAIL(fnV4(IDownstreamCompiler::getTypeGuid(), downstreamCompiler.writeRef())); + SLANG_RETURN_ON_FAIL( + fnV4(IDownstreamCompiler::getTypeGuid(), downstreamCompiler.writeRef())); } else { @@ -37,4 +44,4 @@ namespace Slang return SLANG_OK; } -} +} // namespace Slang diff --git a/source/compiler-core/slang-llvm-compiler.h b/source/compiler-core/slang-llvm-compiler.h index a05e1fed9b..298d9a0add 100644 --- a/source/compiler-core/slang-llvm-compiler.h +++ b/source/compiler-core/slang-llvm-compiler.h @@ -1,18 +1,20 @@ #ifndef SLANG_LLVM_COMPILER_UTIL_H #define SLANG_LLVM_COMPILER_UTIL_H -#include "slang-downstream-compiler-util.h" - #include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" namespace Slang { struct LLVMDownstreamCompilerUtil { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-metal-compiler.cpp b/source/compiler-core/slang-metal-compiler.cpp index f8639b7635..af455a0f7f 100644 --- a/source/compiler-core/slang-metal-compiler.cpp +++ b/source/compiler-core/slang-metal-compiler.cpp @@ -1,102 +1,111 @@ #include "slang-metal-compiler.h" -#include "slang-gcc-compiler-util.h" + #include "slang-artifact-desc-util.h" -#include "slang-artifact-util.h" #include "slang-artifact-representation.h" +#include "slang-artifact-util.h" +#include "slang-gcc-compiler-util.h" namespace Slang { - class MetalDownstreamCompiler : public DownstreamCompilerBase +class MetalDownstreamCompiler : public DownstreamCompilerBase +{ +public: + // Because the metal compiler shares the same commandline interface with clang, + // we will use GccDownstreamCompilerUtil, which implements both gcc and clang, + // to create the inner compiler and wrap it here. + // + ComPtr cppCompiler; + String executablePath; + + MetalDownstreamCompiler(ComPtr& innerCompiler, String path) + : DownstreamCompilerBase(innerCompiler->getDesc()) + , cppCompiler(innerCompiler) + , executablePath(path) { - public: - // Because the metal compiler shares the same commandline interface with clang, - // we will use GccDownstreamCompilerUtil, which implements both gcc and clang, - // to create the inner compiler and wrap it here. - // - ComPtr cppCompiler; - String executablePath; - - MetalDownstreamCompiler(ComPtr& innerCompiler, String path) - : DownstreamCompilerBase(innerCompiler->getDesc()) - , cppCompiler(innerCompiler) - , executablePath(path) - { - } - - virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() override { return true; } - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) override - { - // All compile requests should be routed directly to the inner compiler. - return cppCompiler->compile(options, outArtifact); - } - - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) override - { - // Report that we can convert Metal IR to disassembly. - return ArtifactDescUtil::isDisassembly(from, to) && from.payload == ArtifactPayload::MetalAIR; - } - - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) override - { - // Use metal-objdump to disassemble the Metal IR. - - ExecutableLocation exeLocation(executablePath, "metal-objdump"); - CommandLine cmdLine; - cmdLine.setExecutableLocation(exeLocation); - cmdLine.addArg("--disassemble"); - ComPtr srcFile; - SLANG_RETURN_ON_FAIL(from->requireFile(IArtifact::Keep::No, srcFile.writeRef())); - cmdLine.addArg(String(srcFile->getPath())); - - ExecuteResult exeRes; - SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); - auto artifact = ArtifactUtil::createArtifact(to); - artifact->addRepresentationUnknown(StringBlob::create(exeRes.standardOutput)); - *outArtifact = artifact.detach(); - return SLANG_OK; - } - }; - - static SlangResult locateMetalCompiler(const String& path, DownstreamCompilerSet* set) + } + + virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() override { return true; } + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) override { - ComPtr innerCppCompiler; - - ExecutableLocation metalcLocation = ExecutableLocation(path, "metal"); - - String metalSDKPath = path; - -#if defined (SLANG_APPLE_FAMILY) - // Use xcrun command to find the metal compiler. - CommandLine xcrunCmdLine; - ExecutableLocation xcrunLocation("xcrun"); - xcrunCmdLine.setExecutableLocation(xcrunLocation); - xcrunCmdLine.addArg("--sdk"); - xcrunCmdLine.addArg("macosx"); - xcrunCmdLine.addArg("--find"); - xcrunCmdLine.addArg("metal"); - ExecuteResult exeRes; - if (SLANG_SUCCEEDED(ProcessUtil::execute(xcrunCmdLine, exeRes))) - { - String metalPath = exeRes.standardOutput.trim(); - metalcLocation = ExecutableLocation(ExecutableLocation::Type::Path, metalPath); - metalSDKPath = Path::getParentDirectory(metalcLocation.m_pathOrName); - } -#endif + // All compile requests should be routed directly to the inner compiler. + return cppCompiler->compile(options, outArtifact); + } - SLANG_RETURN_ON_FAIL(GCCDownstreamCompilerUtil::createCompiler(metalcLocation, innerCppCompiler)); + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) override + { + // Report that we can convert Metal IR to disassembly. + return ArtifactDescUtil::isDisassembly(from, to) && + from.payload == ArtifactPayload::MetalAIR; + } + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) override + { + // Use metal-objdump to disassemble the Metal IR. - ComPtr compiler = ComPtr( - new MetalDownstreamCompiler(innerCppCompiler, metalSDKPath)); - set->addCompiler(compiler); + ExecutableLocation exeLocation(executablePath, "metal-objdump"); + CommandLine cmdLine; + cmdLine.setExecutableLocation(exeLocation); + cmdLine.addArg("--disassemble"); + ComPtr srcFile; + SLANG_RETURN_ON_FAIL(from->requireFile(IArtifact::Keep::No, srcFile.writeRef())); + cmdLine.addArg(String(srcFile->getPath())); + + ExecuteResult exeRes; + SLANG_RETURN_ON_FAIL(ProcessUtil::execute(cmdLine, exeRes)); + auto artifact = ArtifactUtil::createArtifact(to); + artifact->addRepresentationUnknown(StringBlob::create(exeRes.standardOutput)); + *outArtifact = artifact.detach(); return SLANG_OK; } +}; - SlangResult MetalDownstreamCompilerUtil::locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set) +static SlangResult locateMetalCompiler(const String& path, DownstreamCompilerSet* set) +{ + ComPtr innerCppCompiler; + + ExecutableLocation metalcLocation = ExecutableLocation(path, "metal"); + + String metalSDKPath = path; + +#if defined(SLANG_APPLE_FAMILY) + // Use xcrun command to find the metal compiler. + CommandLine xcrunCmdLine; + ExecutableLocation xcrunLocation("xcrun"); + xcrunCmdLine.setExecutableLocation(xcrunLocation); + xcrunCmdLine.addArg("--sdk"); + xcrunCmdLine.addArg("macosx"); + xcrunCmdLine.addArg("--find"); + xcrunCmdLine.addArg("metal"); + ExecuteResult exeRes; + if (SLANG_SUCCEEDED(ProcessUtil::execute(xcrunCmdLine, exeRes))) { - SLANG_UNUSED(loader); - return locateMetalCompiler(path, set); + String metalPath = exeRes.standardOutput.trim(); + metalcLocation = ExecutableLocation(ExecutableLocation::Type::Path, metalPath); + metalSDKPath = Path::getParentDirectory(metalcLocation.m_pathOrName); } +#endif + + SLANG_RETURN_ON_FAIL( + GCCDownstreamCompilerUtil::createCompiler(metalcLocation, innerCppCompiler)); + + ComPtr compiler = + ComPtr(new MetalDownstreamCompiler(innerCppCompiler, metalSDKPath)); + set->addCompiler(compiler); + return SLANG_OK; +} +SlangResult MetalDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) +{ + SLANG_UNUSED(loader); + return locateMetalCompiler(path, set); } + +} // namespace Slang diff --git a/source/compiler-core/slang-metal-compiler.h b/source/compiler-core/slang-metal-compiler.h index 7a14e5fa9d..b311a3ea26 100644 --- a/source/compiler-core/slang-metal-compiler.h +++ b/source/compiler-core/slang-metal-compiler.h @@ -1,18 +1,20 @@ #ifndef SLANG_METAL_COMPILER_UTIL_H #define SLANG_METAL_COMPILER_UTIL_H -#include "slang-downstream-compiler-util.h" - #include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" namespace Slang { - struct MetalDownstreamCompilerUtil - { - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); - }; +struct MetalDownstreamCompilerUtil +{ + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); +}; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-misc-diagnostic-defs.h b/source/compiler-core/slang-misc-diagnostic-defs.h index a2ccc4657a..984a3a017c 100644 --- a/source/compiler-core/slang-misc-diagnostic-defs.h +++ b/source/compiler-core/slang-misc-diagnostic-defs.h @@ -14,7 +14,7 @@ // for any arguments. #ifndef DIAGNOSTIC -#error Need to #define DIAGNOSTIC(...) before including +#error Need to #define DIAGNOSTIC(...) before including #define DIAGNOSTIC(id, severity, name, messageFormat) /* */ #endif @@ -24,15 +24,39 @@ DIAGNOSTIC(-1, Note, seeTokenPasteLocation, "see token pasted location") -DIAGNOSTIC(100000, Error, downstreamNameNotKnown, "downstream tool name not known, allowed names are $0") -DIAGNOSTIC(100001, Error, expectedArgumentForOption, "expected an argument for command-line option '$0'") +DIAGNOSTIC( + 100000, + Error, + downstreamNameNotKnown, + "downstream tool name not known, allowed names are $0") +DIAGNOSTIC( + 100001, + Error, + expectedArgumentForOption, + "expected an argument for command-line option '$0'") DIAGNOSTIC(100002, Error, unbalancedDownstreamArguments, "unbalanced downstream arguments") -DIAGNOSTIC(100003, Error, closeOfUnopenDownstreamArgs, "close of an unopen downstream argument scope") +DIAGNOSTIC( + 100003, + Error, + closeOfUnopenDownstreamArgs, + "close of an unopen downstream argument scope") DIAGNOSTIC(100004, Error, downstreamToolNameNotDefined, "downstream tool name not defined") -DIAGNOSTIC(100005, Error, invalidArgumentForOption, "invalid argument format for command-line option '$0'") - -DIAGNOSTIC(99999, Note, noteLocationOfInternalError, "an internal error threw an exception while working on code near this location") - -DIAGNOSTIC(29104, Error, spirvCoreGrammarJSONParseFailure, "unexpected JSON in spirv core grammar file: $0") +DIAGNOSTIC( + 100005, + Error, + invalidArgumentForOption, + "invalid argument format for command-line option '$0'") + +DIAGNOSTIC( + 99999, + Note, + noteLocationOfInternalError, + "an internal error threw an exception while working on code near this location") + +DIAGNOSTIC( + 29104, + Error, + spirvCoreGrammarJSONParseFailure, + "unexpected JSON in spirv core grammar file: $0") #undef DIAGNOSTIC diff --git a/source/compiler-core/slang-name-convention-util.cpp b/source/compiler-core/slang-name-convention-util.cpp index c3d08326c3..3c57f8bc4e 100644 --- a/source/compiler-core/slang-name-convention-util.cpp +++ b/source/compiler-core/slang-name-convention-util.cpp @@ -7,14 +7,15 @@ namespace Slang { -/* static */NameConvention NameConventionUtil::inferConventionFromText(const UnownedStringSlice& slice) +/* static */ NameConvention NameConventionUtil::inferConventionFromText( + const UnownedStringSlice& slice) { // If no chars, or first char isn't alpha we don't know what it is if (slice.getLength() <= 0 || !CharUtil::isAlpha(slice[0])) { return NameConvention::Invalid; } - + typedef int Flags; struct Flag { @@ -33,9 +34,13 @@ namespace Slang { switch (c) { - case '-': flags |= Flag::Dash; break; - case '_': flags |= Flag::Underscore; break; - default: + case '-': + flags |= Flag::Dash; + break; + case '_': + flags |= Flag::Underscore; + break; + default: { if (CharUtil::isLower(c)) { @@ -61,62 +66,76 @@ namespace Slang // Use flags to determine what convention is used switch (flags) { - // We'll assume it's lower camel. - case Flag::Lower: return NameConvention::LowerCamel; - // We'll assume it's upper snake. It almost certainly isn't camel, and snake is more usual - // than kabab. - case Flag::Upper: return NameConvention::UpperSnake; - case Flag::Upper | Flag::Lower: + // We'll assume it's lower camel. + case Flag::Lower: + return NameConvention::LowerCamel; + // We'll assume it's upper snake. It almost certainly isn't camel, and snake is more usual + // than kabab. + case Flag::Upper: + return NameConvention::UpperSnake; + case Flag::Upper | Flag::Lower: { // Looks like camel, choose the right case based on first char - return CharUtil::isUpper(slice[0]) ? NameConvention::UpperCamel : NameConvention::LowerCamel; + return CharUtil::isUpper(slice[0]) ? NameConvention::UpperCamel + : NameConvention::LowerCamel; } - case Flag::Lower | Flag::Dash: return NameConvention::LowerKabab; - case Flag::Upper | Flag::Dash: return NameConvention::UpperKabab; - case Flag::Lower | Flag::Underscore: return NameConvention::LowerSnake; - case Flag::Upper | Flag::Underscore: return NameConvention::UpperSnake; - default: break; + case Flag::Lower | Flag::Dash: + return NameConvention::LowerKabab; + case Flag::Upper | Flag::Dash: + return NameConvention::UpperKabab; + case Flag::Lower | Flag::Underscore: + return NameConvention::LowerSnake; + case Flag::Upper | Flag::Underscore: + return NameConvention::UpperSnake; + default: + break; } // Don't know what this style is return NameConvention::Invalid; } -/* static */NameStyle NameConventionUtil::inferStyleFromText(const UnownedStringSlice& slice) +/* static */ NameStyle NameConventionUtil::inferStyleFromText(const UnownedStringSlice& slice) { for (const char c : slice) { switch (c) { - case '-': return NameStyle::Kabab; - case '_': return NameStyle::Snake; - default: break; + case '-': + return NameStyle::Kabab; + case '_': + return NameStyle::Snake; + default: + break; } } return NameStyle::Camel; } -/* static */void NameConventionUtil::split(NameStyle style, const UnownedStringSlice& slice, List& out) +/* static */ void NameConventionUtil::split( + NameStyle style, + const UnownedStringSlice& slice, + List& out) { switch (style) { - case NameStyle::Kabab: + case NameStyle::Kabab: { StringUtil::split(slice, '-', out); break; } - case NameStyle::Snake: + case NameStyle::Snake: { StringUtil::split(slice, '_', out); break; } - case NameStyle::Camel: + case NameStyle::Camel: { typedef CharUtil::Flags CharFlags; typedef CharUtil::Flag CharFlag; CharFlags prevFlags = 0; - const char*const end = slice.end(); + const char* const end = slice.end(); const char* start = slice.begin(); for (const char* cur = start; cur < end; ++cur) @@ -134,15 +153,18 @@ namespace Slang } else if ((prevFlags & CharFlag::Upper) && cur + 1 < end) { - // This works with capital or uncapitalized acronyms, but if we have two capitalized acronyms following each other - it can't split. - // - // For example + // This works with capital or uncapitalized acronyms, but if we have two + // capitalized acronyms following each other - it can't split. + // + // For example // "IAABBSystem" -> "IAABB", "System" - // - // If it only accepted lower case acronyms the logic could be changed such that the following could be produced - // "IAabbSystem" -> "I", "Aabb", "System" // - // Since Slang source largely goes with upper case acronyms, we work with the heuristic here.. + // If it only accepted lower case acronyms the logic could be changed such + // that the following could be produced "IAabbSystem" -> "I", "Aabb", + // "System" + // + // Since Slang source largely goes with upper case acronyms, we work with + // the heuristic here.. if (CharUtil::isLower(cur[1])) { @@ -151,7 +173,7 @@ namespace Slang } } } - + prevFlags = flags; } @@ -162,7 +184,7 @@ namespace Slang } break; } - case NameStyle::Unknown: + case NameStyle::Unknown: { out.add(slice); break; @@ -175,7 +197,12 @@ void NameConventionUtil::split(const UnownedStringSlice& slice, List 0) { @@ -226,15 +253,21 @@ void NameConventionUtil::split(const UnownedStringSlice& slice, List slices; @@ -286,10 +323,12 @@ void NameConventionUtil::split(const UnownedStringSlice& slice, List& out); + /// Given a slice and a naming convention, split into it's constituent parts. If convention + /// isn't specified, will infer from slice using getConvention. + static void split( + NameStyle nameStyle, + const UnownedStringSlice& slice, + List& out); static void split(const UnownedStringSlice& slice, List& out); - /// Given slices, join together with the specified convention into out - static void join(const UnownedStringSlice* slices, Index slicesCount, NameConvention convention, StringBuilder& out); - - /// Join with a join char, and potentially changing case of input slices - static void join(const UnownedStringSlice* slices, Index slicesCount, NameConvention convention, char joinChar, StringBuilder& out); - - /// Convert from one convention to another. If fromConvention isn't specified, will infer from slice using getConvention. - static void convert(NameStyle fromStyle, const UnownedStringSlice& slice, NameConvention toConvention, StringBuilder& out); - static void convert(const UnownedStringSlice& slice, NameConvention toConvention, StringBuilder& out); + /// Given slices, join together with the specified convention into out + static void join( + const UnownedStringSlice* slices, + Index slicesCount, + NameConvention convention, + StringBuilder& out); + + /// Join with a join char, and potentially changing case of input slices + static void join( + const UnownedStringSlice* slices, + Index slicesCount, + NameConvention convention, + char joinChar, + StringBuilder& out); + + /// Convert from one convention to another. If fromConvention isn't specified, will infer from + /// slice using getConvention. + static void convert( + NameStyle fromStyle, + const UnownedStringSlice& slice, + NameConvention toConvention, + StringBuilder& out); + static void convert( + const UnownedStringSlice& slice, + NameConvention toConvention, + StringBuilder& out); }; -} +} // namespace Slang #endif // SLANG_COMPILER_CORE_NAME_CONVENTION_UTIL_H diff --git a/source/compiler-core/slang-name.cpp b/source/compiler-core/slang-name.cpp index c815b8aa84..6f79d25b53 100644 --- a/source/compiler-core/slang-name.cpp +++ b/source/compiler-core/slang-name.cpp @@ -1,11 +1,13 @@ // slang-name.cpp #include "slang-name.h" -namespace Slang { +namespace Slang +{ String getText(Name* name) { - if (!name) return String(); + if (!name) + return String(); return name->text; } diff --git a/source/compiler-core/slang-name.h b/source/compiler-core/slang-name.h index f8c1201af2..331086d77e 100644 --- a/source/compiler-core/slang-name.h +++ b/source/compiler-core/slang-name.h @@ -7,7 +7,8 @@ #include "../core/slang-basic.h" -namespace Slang { +namespace Slang +{ // The `Name` type is used to represent the name of a type, variable, etc. // @@ -36,7 +37,7 @@ class Name : public RefObject // (e.g., so that it can be printed). String getText(Name* name); -/// Get the text as unowned string slice +/// Get the text as unowned string slice UnownedStringSlice getUnownedStringSliceText(Name* name); // Get a name as a C style string, or nullptr if name is nullptr @@ -50,7 +51,7 @@ const char* getCstr(Name* name); struct RootNamePool { // The mapping from text strings to the corresponding name. - Dictionary > names; + Dictionary> names; }; // A `NamePool` is effectively a way of storing a subset of the @@ -74,10 +75,7 @@ struct NamePool // If the name does not exist, return nullptr Name* tryGetName(String const& text); // Set the parent name pool to use for lookup - void setRootNamePool(RootNamePool* rootNamePool) - { - this->rootPool = rootNamePool; - } + void setRootNamePool(RootNamePool* rootNamePool) { this->rootPool = rootNamePool; } // diff --git a/source/compiler-core/slang-nvrtc-compiler.cpp b/source/compiler-core/slang-nvrtc-compiler.cpp index 80fde277bd..c5ccc8e23a 100644 --- a/source/compiler-core/slang-nvrtc-compiler.cpp +++ b/source/compiler-core/slang-nvrtc-compiler.cpp @@ -1,46 +1,42 @@ // slang-nvrtc-compiler.cpp #include "slang-nvrtc-compiler.h" -#include "../core/slang-common.h" -#include "slang-com-helper.h" - #include "../core/slang-blob.h" - -#include "../core/slang-string-util.h" -#include "../core/slang-string-slice-pool.h" - +#include "../core/slang-char-util.h" +#include "../core/slang-common.h" #include "../core/slang-io.h" -#include "../core/slang-shared-library.h" #include "../core/slang-semantic-version.h" - #include "../core/slang-shared-library.h" -#include "../core/slang-char-util.h" - +#include "../core/slang-string-slice-pool.h" +#include "../core/slang-string-util.h" +#include "slang-artifact-associated-impl.h" +#include "slang-artifact-desc-util.h" #include "slang-artifact-diagnostic-util.h" #include "slang-artifact-util.h" -#include "slang-artifact-desc-util.h" -#include "slang-artifact-associated-impl.h" +#include "slang-com-helper.h" namespace nvrtc { -typedef enum { - NVRTC_SUCCESS = 0, - NVRTC_ERROR_OUT_OF_MEMORY = 1, - NVRTC_ERROR_PROGRAM_CREATION_FAILURE = 2, - NVRTC_ERROR_INVALID_INPUT = 3, - NVRTC_ERROR_INVALID_PROGRAM = 4, - NVRTC_ERROR_INVALID_OPTION = 5, - NVRTC_ERROR_COMPILATION = 6, - NVRTC_ERROR_BUILTIN_OPERATION_FAILURE = 7, - NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION = 8, - NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION = 9, - NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID = 10, - NVRTC_ERROR_INTERNAL_ERROR = 11 +typedef enum +{ + NVRTC_SUCCESS = 0, + NVRTC_ERROR_OUT_OF_MEMORY = 1, + NVRTC_ERROR_PROGRAM_CREATION_FAILURE = 2, + NVRTC_ERROR_INVALID_INPUT = 3, + NVRTC_ERROR_INVALID_PROGRAM = 4, + NVRTC_ERROR_INVALID_OPTION = 5, + NVRTC_ERROR_COMPILATION = 6, + NVRTC_ERROR_BUILTIN_OPERATION_FAILURE = 7, + NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION = 8, + NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION = 9, + NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID = 10, + NVRTC_ERROR_INTERNAL_ERROR = 11 } nvrtcResult; -typedef struct _nvrtcProgram *nvrtcProgram; +typedef struct _nvrtcProgram* nvrtcProgram; +// clang-format off #define SLANG_NVRTC_FUNCS(x) \ x(const char*, nvrtcGetErrorString, (nvrtcResult result)) \ x(nvrtcResult, nvrtcVersion, (int *major, int *minor)) \ @@ -53,6 +49,7 @@ typedef struct _nvrtcProgram *nvrtcProgram; x(nvrtcResult, nvrtcGetProgramLog, (nvrtcProgram prog, char *log))\ x(nvrtcResult, nvrtcAddNameExpression, (nvrtcProgram prog, const char * const name_expression)) \ x(nvrtcResult, nvrtcGetLoweredName, (nvrtcProgram prog, const char *const name_expression, const char** lowered_name)) +// clang-format on } // namespace nvrtc @@ -64,37 +61,38 @@ static SlangResult _asResult(nvrtcResult res) { switch (res) { - case NVRTC_SUCCESS: + case NVRTC_SUCCESS: { return SLANG_OK; } - case NVRTC_ERROR_OUT_OF_MEMORY: + case NVRTC_ERROR_OUT_OF_MEMORY: { return SLANG_E_OUT_OF_MEMORY; } - case NVRTC_ERROR_PROGRAM_CREATION_FAILURE: - case NVRTC_ERROR_INVALID_INPUT: - case NVRTC_ERROR_INVALID_PROGRAM: + case NVRTC_ERROR_PROGRAM_CREATION_FAILURE: + case NVRTC_ERROR_INVALID_INPUT: + case NVRTC_ERROR_INVALID_PROGRAM: { return SLANG_FAIL; } - case NVRTC_ERROR_INVALID_OPTION: + case NVRTC_ERROR_INVALID_OPTION: { return SLANG_E_INVALID_ARG; } - case NVRTC_ERROR_COMPILATION: - case NVRTC_ERROR_BUILTIN_OPERATION_FAILURE: - case NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION: - case NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION: - case NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID: + case NVRTC_ERROR_COMPILATION: + case NVRTC_ERROR_BUILTIN_OPERATION_FAILURE: + case NVRTC_ERROR_NO_NAME_EXPRESSIONS_AFTER_COMPILATION: + case NVRTC_ERROR_NO_LOWERED_NAMES_BEFORE_COMPILATION: + case NVRTC_ERROR_NAME_EXPRESSION_NOT_VALID: { return SLANG_FAIL; } - case NVRTC_ERROR_INTERNAL_ERROR: + case NVRTC_ERROR_INTERNAL_ERROR: { return SLANG_E_INTERNAL_FAIL; } - default: return SLANG_FAIL; + default: + return SLANG_FAIL; } } @@ -104,29 +102,27 @@ class NVRTCDownstreamCompiler : public DownstreamCompilerBase typedef DownstreamCompilerBase Super; // IDownstreamCompiler - virtual SLANG_NO_THROW SlangResult SLANG_MCALL compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outArtifact) SLANG_OVERRIDE; virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } - virtual SLANG_NO_THROW bool SLANG_MCALL canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; - virtual SLANG_NO_THROW SlangResult SLANG_MCALL convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; - /// Must be called before use + /// Must be called before use SlangResult init(ISlangSharedLibrary* library); NVRTCDownstreamCompiler() {} - -protected: +protected: struct ScopeProgram { - ScopeProgram(NVRTCDownstreamCompiler* compiler, nvrtcProgram program): - m_compiler(compiler), - m_program(program) - { - } - ~ScopeProgram() + ScopeProgram(NVRTCDownstreamCompiler* compiler, nvrtcProgram program) + : m_compiler(compiler), m_program(program) { - m_compiler->m_nvrtcDestroyProgram(&m_program); } + ~ScopeProgram() { m_compiler->m_nvrtcDestroyProgram(&m_program); } NVRTCDownstreamCompiler* m_compiler; nvrtcProgram m_program; }; @@ -137,8 +133,7 @@ class NVRTCDownstreamCompiler : public DownstreamCompilerBase SlangResult _maybeAddHalfSupport(const CompileOptions& options, CommandLine& ioCmdLine); -#define SLANG_NVTRC_MEMBER_FUNCS(ret, name, params) \ - ret (*m_##name) params; +#define SLANG_NVTRC_MEMBER_FUNCS(ret, name, params) ret(*m_##name) params; SLANG_NVRTC_FUNCS(SLANG_NVTRC_MEMBER_FUNCS); @@ -146,19 +141,25 @@ class NVRTCDownstreamCompiler : public DownstreamCompilerBase List m_cudaFp16FoundPaths; bool m_includeSearched = false; - // Holds location of where include (for cuda_fp16.h) is found. + // Holds location of where include (for cuda_fp16.h) is found. String m_includePath; - ComPtr m_sharedLibrary; + ComPtr m_sharedLibrary; }; -#define SLANG_NVRTC_RETURN_ON_FAIL(x) { nvrtcResult _res = x; if (_res != NVRTC_SUCCESS) return _asResult(_res); } +#define SLANG_NVRTC_RETURN_ON_FAIL(x) \ + { \ + nvrtcResult _res = x; \ + if (_res != NVRTC_SUCCESS) \ + return _asResult(_res); \ + } SlangResult NVRTCDownstreamCompiler::init(ISlangSharedLibrary* library) { -#define SLANG_NVTRC_GET_FUNC(ret, name, params) \ - m_##name = (ret (*) params)library->findFuncByName(#name); \ - if (m_##name == nullptr) return SLANG_FAIL; +#define SLANG_NVTRC_GET_FUNC(ret, name, params) \ + m_##name = (ret(*) params)library->findFuncByName(#name); \ + if (m_##name == nullptr) \ + return SLANG_FAIL; SLANG_NVRTC_FUNCS(SLANG_NVTRC_GET_FUNC) @@ -172,7 +173,10 @@ SlangResult NVRTCDownstreamCompiler::init(ISlangSharedLibrary* library) return SLANG_OK; } -static SlangResult _parseLocation(SliceAllocator& allocator, const UnownedStringSlice& in, ArtifactDiagnostic& outDiagnostic) +static SlangResult _parseLocation( + SliceAllocator& allocator, + const UnownedStringSlice& in, + ArtifactDiagnostic& outDiagnostic) { const Index startIndex = in.indexOf('('); @@ -182,7 +186,8 @@ static SlangResult _parseLocation(SliceAllocator& allocator, const UnownedString UnownedStringSlice remaining(in.begin() + startIndex + 1, in.end()); const Int endIndex = remaining.indexOf(')'); - UnownedStringSlice lineText = UnownedStringSlice(remaining.begin(), remaining.begin() + endIndex); + UnownedStringSlice lineText = + UnownedStringSlice(remaining.begin(), remaining.begin() + endIndex); Int line; SLANG_RETURN_ON_FAIL(StringUtil::parseInt(lineText, line)); @@ -206,7 +211,10 @@ static bool _hasDriveLetter(const UnownedStringSlice& line) return line.getLength() > 2 && line[1] == ':' && _isDriveLetter(line[0]); } -static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStringSlice& line, ArtifactDiagnostic& outDiagnostic) +static SlangResult _parseNVRTCLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + ArtifactDiagnostic& outDiagnostic) { typedef ArtifactDiagnostic Diagnostic; typedef ArtifactDiagnostic::Severity Severity; @@ -216,7 +224,7 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin List split; if (_hasDriveLetter(line)) { - // The drive letter has :, which confuses things, so skip that and then fix up first entry + // The drive letter has :, which confuses things, so skip that and then fix up first entry UnownedStringSlice lineWithoutDrive(line.begin() + 2, line.end()); StringUtil::split(lineWithoutDrive, ':', split); split[0] = UnownedStringSlice(line.begin(), split[0].end()); @@ -233,8 +241,7 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin Severity severity = Severity::Unknown; - if (split1 == toSlice("error") || - split1 == toSlice("catastrophic error")) + if (split1 == toSlice("error") || split1 == toSlice("catastrophic error")) { severity = Severity::Error; } @@ -244,14 +251,14 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin } else { - // Fall back position to try and determine if this really is some kind of - // error/warning without succeeding when it's due to some other property - // of the output diagnostics. + // Fall back position to try and determine if this really is some kind of + // error/warning without succeeding when it's due to some other property + // of the output diagnostics. // // Anything ending with " warning:" or " error:" in effect. - - // We can expand to include character after as this is split1, as must be followed by at a minimum - // : (as the split has at least 3 parts). + + // We can expand to include character after as this is split1, as must be followed by at + // a minimum : (as the split has at least 3 parts). const UnownedStringSlice expandSplit1(split1.begin(), split1.end() + 1); if (expandSplit1.endsWith(toSlice(" error:"))) @@ -266,9 +273,9 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin if (severity != Severity::Unknown) { - // The text is everything following the : after the warning. + // The text is everything following the : after the warning. UnownedStringSlice text(split[2].begin(), split.getLast().end()); - + // Trim whitespace at start and end text = text.trim(); @@ -280,19 +287,18 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin return SLANG_OK; } - // TODO(JS): Note here if it's not possible to determine a line as being the main diagnostics - // we fall through to it potentially being a note. + // TODO(JS): Note here if it's not possible to determine a line as being the main + // diagnostics we fall through to it potentially being a note. + // + // That could mean a valid diagnostic (from NVRTCs point of view) is ignored/noted, because + // this code can't parse it. Ideally that situation would lead to an error such that we can + // detect and things will fail. // - // That could mean a valid diagnostic (from NVRTCs point of view) is ignored/noted, because this code - // can't parse it. Ideally that situation would lead to an error such that we can detect - // and things will fail. - // // So we might want to revisit this determination in the future. } // There isn't a diagnostic on this line - if (line.getLength() == 0 || - line.trim().getLength() == 0) + if (line.getLength() == 0 || line.trim().getLength() == 0) { return SLANG_E_NOT_FOUND; } @@ -304,14 +310,18 @@ static SlangResult _parseNVRTCLine(SliceAllocator& allocator, const UnownedStrin return SLANG_OK; } -/* An implementation of Path::Visitor that can be used for finding NVRTC shared library installations. */ +/* An implementation of Path::Visitor that can be used for finding NVRTC shared library + * installations. */ struct NVRTCPathVisitor : Path::Visitor { struct Candidate { typedef Candidate ThisType; - bool operator==(const ThisType& rhs) const { return path == rhs.path && version == rhs.version; } + bool operator==(const ThisType& rhs) const + { + return path == rhs.path && version == rhs.version; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } static Candidate make(const String& path, const SemanticVersion& version) @@ -338,10 +348,13 @@ struct NVRTCPathVisitor : Path::Visitor return -1; } - static bool _orderCandiate(const Candidate& a, const Candidate& b) { return a.version < b.version; } + static bool _orderCandiate(const Candidate& a, const Candidate& b) + { + return a.version < b.version; + } void sortCandidates() { m_candidates.sort(_orderCandiate); } - + #if SLANG_WINDOWS_FAMILY SlangResult getVersion(const UnownedStringSlice& filename, SemanticVersion& outVersion) { @@ -354,7 +367,9 @@ struct NVRTCPathVisitor : Path::Visitor endIndex = (endIndex < 0) ? filename.getLength() : endIndex; // If we have a version slice, split it - UnownedStringSlice versionSlice = UnownedStringSlice(filename.begin() + m_prefix.getLength(), filename.begin() + endIndex); + UnownedStringSlice versionSlice = UnownedStringSlice( + filename.begin() + m_prefix.getLength(), + filename.begin() + endIndex); if (versionSlice.getLength() <= 0) { @@ -380,7 +395,8 @@ struct NVRTCPathVisitor : Path::Visitor } UnownedStringSlice majorSlice = majorMinorSlice.head(majorMinorSlice.getLength() - 1); - UnownedStringSlice minorSlice = majorMinorSlice.subString(majorMinorSlice.getLength() - 1, 1); + UnownedStringSlice minorSlice = + majorMinorSlice.subString(majorMinorSlice.getLength() - 1, 1); Int major; Int minor; @@ -394,7 +410,8 @@ struct NVRTCPathVisitor : Path::Visitor #else // How the path is constructed depends on platform // https://docs.nvidia.com/cuda/nvrtc/index.html - // TODO(JS): Handle version number depending on the platform - it's different for Windows/OSX/Linux + // TODO(JS): Handle version number depending on the platform - it's different for + // Windows/OSX/Linux SlangResult getVersion(const UnownedStringSlice& filename, SemanticVersion& outVersion) { SLANG_UNUSED(filename); @@ -413,16 +430,18 @@ struct NVRTCPathVisitor : Path::Visitor if (m_postfix.getLength() && filename.getLength() >= m_postfix.getLength()) { // We test without case - really for windows - UnownedStringSlice filenamePostfix = filename.tail(filename.getLength() - m_postfix.getLength()); + UnownedStringSlice filenamePostfix = + filename.tail(filename.getLength() - m_postfix.getLength()); if (!filenamePostfix.caseInsensitiveEquals(m_postfix.getUnownedSlice())) { return; } } - + if (filename.getLength() >= m_prefix.getLength() && - filename.subString(0, m_prefix.getLength()).caseInsensitiveEquals(m_prefix.getUnownedSlice())) + filename.subString(0, m_prefix.getLength()) + .caseInsensitiveEquals(m_prefix.getUnownedSlice())) { SemanticVersion version; // If it produces an error, just use 0.0.0 @@ -431,8 +450,9 @@ struct NVRTCPathVisitor : Path::Visitor version = SemanticVersion(); } - // We may want to add multiple versions, if they are in different locations - as there may be multiple entries - // in the PATH, and only one works. We'll only know which works by loading + // We may want to add multiple versions, if they are in different locations - as + // there may be multiple entries in the PATH, and only one works. We'll only know + // which works by loading #if 0 // We already found this version, so let's not add it again @@ -443,10 +463,12 @@ struct NVRTCPathVisitor : Path::Visitor #endif // Strip to make a shared library name - UnownedStringSlice sharedLibraryName = filename.tail(m_prefix.getLength() - m_sharedLibraryStem.getLength()); + UnownedStringSlice sharedLibraryName = + filename.tail(m_prefix.getLength() - m_sharedLibraryStem.getLength()); sharedLibraryName = filename.head(filename.getLength() - m_postfix.getLength()); - auto candidate = Candidate::make(Path::combine(m_basePath, sharedLibraryName), version); + auto candidate = + Candidate::make(Path::combine(m_basePath, sharedLibraryName), version); // If we already have this candidate, then skip if (m_candidates.indexOf(candidate) >= 0) @@ -468,8 +490,8 @@ struct NVRTCPathVisitor : Path::Visitor bool hasCandidates() const { return m_candidates.getCount() > 0; } - NVRTCPathVisitor(const UnownedStringSlice& sharedLibraryStem) : - m_sharedLibraryStem(sharedLibraryStem) + NVRTCPathVisitor(const UnownedStringSlice& sharedLibraryStem) + : m_sharedLibraryStem(sharedLibraryStem) { // Work out the prefix and postfix of the shader StringBuilder buf; @@ -489,7 +511,7 @@ struct NVRTCPathVisitor : Path::Visitor List m_candidates; }; -template +template SLANG_FORCE_INLINE static void _unusedFunction(const T& func) { SLANG_UNUSED(func); @@ -506,7 +528,8 @@ static UnownedStringSlice _getNVRTCBaseName() #endif } -// Candidates are in m_candidates list. Will be ordered from the oldest to newest (in version number) +// Candidates are in m_candidates list. Will be ordered from the oldest to newest (in version +// number) static SlangResult _findNVRTC(NVRTCPathVisitor& visitor) { // First try the instance path (if supported on platform) @@ -522,7 +545,9 @@ static SlangResult _findNVRTC(NVRTCPathVisitor& visitor) if (!visitor.hasCandidates()) { StringBuilder buf; - if (!SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable(UnownedStringSlice::fromLiteral("CUDA_PATH"), buf))) + if (!SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable( + UnownedStringSlice::fromLiteral("CUDA_PATH"), + buf))) { // Look for candidates in the directory visitor.findInDirectory(Path::combine(buf, "bin")); @@ -535,7 +560,8 @@ static SlangResult _findNVRTC(NVRTCPathVisitor& visitor) List splitPath; StringBuilder buf; - if (SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable(UnownedStringSlice::fromLiteral("PATH"), buf))) + if (SLANG_SUCCEEDED( + PlatformUtil::getEnvironmentVariable(UnownedStringSlice::fromLiteral("PATH"), buf))) { // Split so we get individual paths List paths; @@ -544,19 +570,22 @@ static SlangResult _findNVRTC(NVRTCPathVisitor& visitor) // We use a pool to make sure we only check each path once StringSlicePool pool(StringSlicePool::Style::Empty); - // We are going to search the paths in order + // We are going to search the paths in order for (const auto& path : paths) { - // PATH can have the same path multiple times. If we have already searched this path, we don't need to again + // PATH can have the same path multiple times. If we have already searched this + // path, we don't need to again if (!pool.has(path)) { pool.add(path); Path::split(path, splitPath); - // We could search every path, but here we restrict to paths that look like CUDA installations. - // It's a path that contains a CUDA directory and has bin - if (splitPath.indexOf("CUDA") >= 0 && splitPath[splitPath.getCount() - 1].caseInsensitiveEquals(UnownedStringSlice::fromLiteral("bin"))) + // We could search every path, but here we restrict to paths that look like CUDA + // installations. It's a path that contains a CUDA directory and has bin + if (splitPath.indexOf("CUDA") >= 0 && + splitPath[splitPath.getCount() - 1].caseInsensitiveEquals( + UnownedStringSlice::fromLiteral("bin"))) { // Okay lets search it visitor.findInDirectory(path); @@ -566,11 +595,11 @@ static SlangResult _findNVRTC(NVRTCPathVisitor& visitor) } } - // Put into version order with oldest first. + // Put into version order with oldest first. visitor.sortCandidates(); return SLANG_OK; -} +} static const UnownedStringSlice g_fp16HeaderName = UnownedStringSlice::fromLiteral("cuda_fp16.h"); @@ -589,7 +618,10 @@ SlangResult NVRTCDownstreamCompiler::_getIncludePath(String& outPath) return m_includePath.getLength() ? SLANG_OK : SLANG_E_NOT_FOUND; } -SlangResult _findFileInIncludePath(const String& path, const UnownedStringSlice& filename, String& outPath) +SlangResult _findFileInIncludePath( + const String& path, + const UnownedStringSlice& filename, + String& outPath) { if (File::exists(Path::combine(path, filename))) { @@ -622,8 +654,8 @@ SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath) { outPath = String(); - // Try looking up from a symbol. This will work as long as the nvrtc is loaded somehow from a dll/sharedlibrary - // And the header is included from there + // Try looking up from a symbol. This will work as long as the nvrtc is loaded somehow from a + // dll/sharedlibrary And the header is included from there { String libPath = SharedLibraryUtils::getSharedLibraryFileName((void*)m_nvrtcCreateProgram); if (libPath.getLength()) @@ -644,8 +676,7 @@ SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath) // This -2 split holds the version number. const auto pathSplitCount = pathSlices.getCount(); - if (pathSplitCount >= 3 && - pathSlices[pathSplitCount - 1] == toSlice("bin") && + if (pathSplitCount >= 3 && pathSlices[pathSplitCount - 1] == toSlice("bin") && pathSlices[pathSplitCount - 3] == toSlice("CUDA")) { // We want to make sure that one of these paths is CUDA... @@ -663,7 +694,9 @@ SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath) // Try CUDA_PATH environment variable { StringBuilder buf; - if (SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable(UnownedStringSlice::fromLiteral("CUDA_PATH"), buf))) + if (SLANG_SUCCEEDED(PlatformUtil::getEnvironmentVariable( + UnownedStringSlice::fromLiteral("CUDA_PATH"), + buf))) { String includePath = Path::combine(buf, "include"); @@ -678,7 +711,9 @@ SlangResult NVRTCDownstreamCompiler::_findIncludePath(String& outPath) return SLANG_E_NOT_FOUND; } -SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(const DownstreamCompileOptions& options, CommandLine& ioCmdLine) +SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport( + const DownstreamCompileOptions& options, + CommandLine& ioCmdLine) { if ((options.flags & DownstreamCompileOptions::Flag::EnableFloat16) == 0) { @@ -723,7 +758,9 @@ SlangResult NVRTCDownstreamCompiler::_maybeAddHalfSupport(const DownstreamCompil return SLANG_OK; } -SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inOptions, IArtifact** outArtifact) +SlangResult NVRTCDownstreamCompiler::compile( + const DownstreamCompileOptions& inOptions, + IArtifact** outArtifact) { if (!isVersionCompatible(inOptions)) { @@ -745,16 +782,16 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO switch (options.debugInfoType) { - case DebugInfoType::None: + case DebugInfoType::None: { break; } - default: + default: { cmdLine.addArg("--device-debug"); break; } - case DebugInfoType::Maximal: + case DebugInfoType::Maximal: { cmdLine.addArg("--device-debug"); cmdLine.addArg("--generate-line-info"); @@ -763,19 +800,20 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO } // Don't seem to have such a control, so ignore for now - //switch (options.optimizationLevel) + // switch (options.optimizationLevel) //{ // default: break; //} switch (options.floatingPointMode) { - case FloatingPointMode::Default: break; - case FloatingPointMode::Precise: + case FloatingPointMode::Default: + break; + case FloatingPointMode::Precise: { break; } - case FloatingPointMode::Fast: + case FloatingPointMode::Fast: { cmdLine.addArg("--use_fast_math"); break; @@ -813,8 +851,9 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO cmdLine.addArg("-std=c++17"); // Disable all warnings - // This is arguably too much - but nvrtc does not appear to have a mechanism to switch off individual warnings. - // I tried the -Xcudafe mechanism but that does not appear to work for nvrtc + // This is arguably too much - but nvrtc does not appear to have a mechanism to switch off + // individual warnings. I tried the -Xcudafe mechanism but that does not appear to work for + // nvrtc cmdLine.addArg("-w"); } @@ -825,13 +864,13 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO SemanticVersion version(3); // Newer releases of NVRTC only support newer CUDA architectures. - if ( m_desc.version.m_major >= 12 ) + if (m_desc.version.m_major >= 12) { // NVRTC in CUDA 12 only supports `compute_50` and up // (with everything before `compute_52` being deprecated). version = SemanticVersion(5, 0); } - else if ( m_desc.version.m_major == 11 ) + else if (m_desc.version.m_major == 11) { // NVRTC in CUDA 11 only supports `compute_35` and up // (with everything before `compute_52` being deprecated). @@ -869,7 +908,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO // If compiling for OptiX, we need to add the appropriate search paths to the command line. // - if(options.pipelineType == PipelineType::RayTracing) + if (options.pipelineType == PipelineType::RayTracing) { // The device-side OptiX API is accessed through a constellation // of headers provided by the OptiX SDK, so we need to set an @@ -904,7 +943,8 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO // TODO: Confirm that the `LP64` definition here is actually needed. // headerIncludeNames.add("stddef.h"); - headers.add("#pragma once\n" "#define LP64\n"); + headers.add("#pragma once\n" + "#define LP64\n"); // Finally, we want the CUDA prelude to be able to react to whether // or not OptiX is required (most notably by `#include`ing the appropriate @@ -921,7 +961,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO { for (auto compilerSpecificArg : options.compilerSpecificArguments) { - const char*const arg = compilerSpecificArg; + const char* const arg = compilerSpecificArg; cmdLine.addArg(arg); } } @@ -937,7 +977,10 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO auto sourceContents = SliceUtil::toTerminatedCharSlice(storage, sourceBlob); nvrtcProgram program = nullptr; - nvrtcResult res = m_nvrtcCreateProgram(&program, sourceContents, String(sourcePath).getBuffer(), + nvrtcResult res = m_nvrtcCreateProgram( + &program, + sourceContents, + String(sourcePath).getBuffer(), (int)headers.getCount(), headers.getBuffer(), headerIncludeNames.getBuffer()); @@ -954,7 +997,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO dstOptions[i] = cmdLine.m_args[i].getBuffer(); } - res = m_nvrtcCompileProgram(program, int(dstOptions.getCount()), dstOptions.getBuffer()); + res = m_nvrtcCompileProgram(program, int(dstOptions.getCount()), dstOptions.getBuffer()); auto artifact = ArtifactUtil::createArtifactForCompileTarget(options.targetType); auto diagnostics = ArtifactDiagnostics::create(); @@ -1022,7 +1065,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO if (SLANG_SUCCEEDED(lineRes)) { // We only allow info diagnostics after a 'regular' diagnostic. - if (diagnostic.severity == ArtifactDiagnostic::Severity::Info && + if (diagnostic.severity == ArtifactDiagnostic::Severity::Info && diagnostics->getCount() == 0) { continue; @@ -1040,7 +1083,7 @@ SlangResult NVRTCDownstreamCompiler::compile(const DownstreamCompileOptions& inO // If it has a compilation error.. and there isn't already an error set // set as failed. - if (SLANG_SUCCEEDED(diagnostics->getResult()) && + if (SLANG_SUCCEEDED(diagnostics->getResult()) && diagnostics->hasOfAtLeastSeverity(ArtifactDiagnostic::Severity::Error)) { diagnostics->setResult(SLANG_FAIL); @@ -1070,7 +1113,10 @@ bool NVRTCDownstreamCompiler::canConvert(const ArtifactDesc& from, const Artifac return ArtifactDescUtil::isDisassembly(from, to) || ArtifactDescUtil::isDisassembly(to, from); } -SlangResult NVRTCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) +SlangResult NVRTCDownstreamCompiler::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) { if (!canConvert(from->getDesc(), to)) { @@ -1078,8 +1124,8 @@ SlangResult NVRTCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc } // PTX is 'binary like' and 'assembly like' so we allow conversion either way - // We do it by just getting as a blob and sharing that blob. - // A more sophisticated implementation could proxy to the original artifact, but this + // We do it by just getting as a blob and sharing that blob. + // A more sophisticated implementation could proxy to the original artifact, but this // is simpler, and probably fine in most scenarios. ComPtr blob; SLANG_RETURN_ON_FAIL(from->loadBlob(ArtifactKeep::Yes, blob.writeRef())); @@ -1091,11 +1137,13 @@ SlangResult NVRTCDownstreamCompiler::convert(IArtifact* from, const ArtifactDesc return SLANG_OK; } -static SlangResult _findAndLoadNVRTC(ISlangSharedLibraryLoader* loader, ComPtr& outLibrary) +static SlangResult _findAndLoadNVRTC( + ISlangSharedLibraryLoader* loader, + ComPtr& outLibrary) { #if SLANG_WINDOWS_FAMILY && SLANG_PTR_IS_64 - // We only need to search 64 bit versions on windows + // We only need to search 64 bit versions on windows NVRTCPathVisitor visitor(_getNVRTCBaseName()); SLANG_RETURN_ON_FAIL(_findNVRTC(visitor)); @@ -1103,7 +1151,8 @@ static SlangResult _findAndLoadNVRTC(ISlangSharedLibraryLoader* loader, ComPtr= 0; --i) { const auto& candidate = visitor.m_candidates[i]; - if (SLANG_SUCCEEDED(loader->loadSharedLibrary(candidate.path.getBuffer(), outLibrary.writeRef()))) + if (SLANG_SUCCEEDED( + loader->loadSharedLibrary(candidate.path.getBuffer(), outLibrary.writeRef()))) { return SLANG_OK; } @@ -1119,16 +1168,19 @@ static SlangResult _findAndLoadNVRTC(ISlangSharedLibraryLoader* loader, ComPtr library; @@ -1146,8 +1198,8 @@ static SlangResult _findAndLoadNVRTC(ISlangSharedLibraryLoader* loader, ComPtrloadSharedLibrary("nvrtc", library.writeRef()))) { // Try something more sophisticated to locate NVRTC @@ -1169,4 +1221,4 @@ static SlangResult _findAndLoadNVRTC(ISlangSharedLibraryLoader* loader, ComPtr includes, - const HashParams& hashParams, - const List values) - { - StringBuilder sb; - StringWriter writer(&sb, WriterFlags(0)); - WriterHelper w(&writer); +SlangResult writeHashFile( + String outCppPath, + String valueType, + const List includes, + const HashParams& hashParams, + const List values) +{ + StringBuilder sb; + StringWriter writer(&sb, WriterFlags(0)); + WriterHelper w(&writer); - w.print("// Hash function for %s\n", valueType.getBuffer()); - w.print("//\n"); - w.print("// This file was thoughtfully generated by a machine,\n"); - w.print("// don't even think about modifying it yourself!\n"); - w.print("//\n"); - w.print("\n"); - for (const auto& i : includes) - { - if (i.getLength()) - w.print("#include \"%s\"\n", i.getBuffer()); - } - w.print("\n"); - w.print("\n"); - w.print("namespace Slang\n"); - w.print("{\n"); - w.print("\n"); + w.print("// Hash function for %s\n", valueType.getBuffer()); + w.print("//\n"); + w.print("// This file was thoughtfully generated by a machine,\n"); + w.print("// don't even think about modifying it yourself!\n"); + w.print("//\n"); + w.print("\n"); + for (const auto& i : includes) + { + if (i.getLength()) + w.print("#include \"%s\"\n", i.getBuffer()); + } + w.print("\n"); + w.print("\n"); + w.print("namespace Slang\n"); + w.print("{\n"); + w.print("\n"); - w.put(perfectHashToEmbeddableCpp( - hashParams, - valueType.getUnownedSlice(), - (String("lookup") + valueType).getUnownedSlice(), - values - ).getBuffer()); + w.put(perfectHashToEmbeddableCpp( + hashParams, + valueType.getUnownedSlice(), + (String("lookup") + valueType).getUnownedSlice(), + values) + .getBuffer()); - w.print("}\n"); + w.print("}\n"); - return File::writeAllTextIfChanged(outCppPath, sb.getUnownedSlice()); - } + return File::writeAllTextIfChanged(outCppPath, sb.getUnownedSlice()); +} - SlangResult writePerfectHashLookupCppFile(String fileName, List opnames, String enumName, String enumerantPrefix, String enumHeaderFile, DiagnosticSink* sink) +SlangResult writePerfectHashLookupCppFile( + String fileName, + List opnames, + String enumName, + String enumerantPrefix, + String enumHeaderFile, + DiagnosticSink* sink) +{ + HashParams hashParams; + auto r = minimalPerfectHash(opnames, hashParams); + switch (r) { - HashParams hashParams; - auto r = minimalPerfectHash(opnames, hashParams); - switch (r) - { - case HashFindResult::UnavoidableHashCollision: + case HashFindResult::UnavoidableHashCollision: { sink->diagnoseRaw( Severity::Error, @@ -58,24 +65,24 @@ namespace Slang "collision for some input words\n"); return SLANG_FAIL; } - case HashFindResult::NonUniqueKeys: + case HashFindResult::NonUniqueKeys: { sink->diagnoseRaw(Severity::Error, "Input word list has duplicates\n"); return SLANG_FAIL; } - case HashFindResult::Success:; - } - - List values; - values.reserve(hashParams.destTable.getCount()); - for (const auto& v : hashParams.destTable) - values.add(enumerantPrefix + v); - return writeHashFile( - fileName, - enumName, - { "core/slang-common.h", "core/slang-string.h", enumHeaderFile }, - hashParams, - values); + case HashFindResult::Success:; } + List values; + values.reserve(hashParams.destTable.getCount()); + for (const auto& v : hashParams.destTable) + values.add(enumerantPrefix + v); + return writeHashFile( + fileName, + enumName, + {"core/slang-common.h", "core/slang-string.h", enumHeaderFile}, + hashParams, + values); } + +} // namespace Slang diff --git a/source/compiler-core/slang-perfect-hash-codegen.h b/source/compiler-core/slang-perfect-hash-codegen.h index 557f4dba58..d1ddd49b59 100644 --- a/source/compiler-core/slang-perfect-hash-codegen.h +++ b/source/compiler-core/slang-perfect-hash-codegen.h @@ -1,9 +1,15 @@ #pragma once -#include "slang-perfect-hash.h" #include "slang-diagnostic-sink.h" +#include "slang-perfect-hash.h" namespace Slang { - SlangResult writePerfectHashLookupCppFile(String fileName, List opnames, String enumName, String enumPrefix, String enumHeaderFile, DiagnosticSink* sink); +SlangResult writePerfectHashLookupCppFile( + String fileName, + List opnames, + String enumName, + String enumPrefix, + String enumHeaderFile, + DiagnosticSink* sink); } diff --git a/source/compiler-core/slang-perfect-hash.cpp b/source/compiler-core/slang-perfect-hash.cpp index a741f013cd..a2dd88f985 100644 --- a/source/compiler-core/slang-perfect-hash.cpp +++ b/source/compiler-core/slang-perfect-hash.cpp @@ -23,7 +23,7 @@ HashFindResult minimalPerfectHash(const List& ss, HashParams& hashParams } SLANG_ASSERT(UIndex(ss.getCount()) < std::numeric_limits::max()); - const UInt32 nBuckets = UInt32(ss.getCount()); + const UInt32 nBuckets = UInt32(ss.getCount()); List> initialBuckets; initialBuckets.setCount(nBuckets); @@ -55,7 +55,8 @@ HashFindResult minimalPerfectHash(const List& ss, HashParams& hashParams { initialBuckets[hash(s)].add(s); } - initialBuckets.stableSort([](const List& a, const List& b) { return a.getCount() > b.getCount(); }); + initialBuckets.stableSort([](const List& a, const List& b) + { return a.getCount() > b.getCount(); }); // These are our outputs, the salts are calculated such that for all input // word, x, hash(x, salt[hash(x, 0)]) is unique @@ -138,12 +139,16 @@ String perfectHashToEmbeddableCpp( StringBuilder sb; StringWriter writer(&sb, WriterFlags(0)); WriterHelper w(&writer); - const auto line = [&](const char* l){ + const auto line = [&](const char* l) + { w.put(l); w.put("\n"); }; - w.print("bool %s(const UnownedStringSlice& str, %s& value)\n", String(funcName).getBuffer(), String(valueType).getBuffer()); + w.print( + "bool %s(const UnownedStringSlice& str, %s& value)\n", + String(funcName).getBuffer(), + String(valueType).getBuffer()); line("{"); w.print(" static const unsigned tableSalt[%d] = {\n", (int)hashParams.saltTable.getCount()); @@ -176,11 +181,7 @@ String perfectHashToEmbeddableCpp( { const auto& s = hashParams.destTable[i]; const auto& v = values[i]; - w.print( - " {\"%s\", %s},\n", - s.getBuffer(), - v.getBuffer() - ); + w.print(" {\"%s\", %s},\n", s.getBuffer(), v.getBuffer()); } line(" };"); line(""); @@ -211,4 +212,4 @@ String perfectHashToEmbeddableCpp( return sb.produceString(); } -} +} // namespace Slang diff --git a/source/compiler-core/slang-perfect-hash.h b/source/compiler-core/slang-perfect-hash.h index 1488c7a621..50553eee73 100644 --- a/source/compiler-core/slang-perfect-hash.h +++ b/source/compiler-core/slang-perfect-hash.h @@ -1,7 +1,7 @@ #pragma once -#include "../core/slang-string.h" #include "../core/slang-list.h" +#include "../core/slang-string.h" namespace Slang { @@ -12,7 +12,8 @@ struct HashParams List destTable; }; -enum class HashFindResult { +enum class HashFindResult +{ Success, NonUniqueKeys, UnavoidableHashCollision, @@ -27,4 +28,4 @@ String perfectHashToEmbeddableCpp( const UnownedStringSlice& funcName, const List& values); -} +} // namespace Slang diff --git a/source/compiler-core/slang-pretty-writer.cpp b/source/compiler-core/slang-pretty-writer.cpp new file mode 100644 index 0000000000..682b02c1e1 --- /dev/null +++ b/source/compiler-core/slang-pretty-writer.cpp @@ -0,0 +1,85 @@ +#include "slang-pretty-writer.h" + +#include "../core/slang-string-escape-util.h" + +namespace Slang +{ + +void PrettyWriter::writeRaw(char const* begin, char const* end) +{ + SLANG_ASSERT(end >= begin); + writeRaw(UnownedStringSlice(begin, end)); +} + +void PrettyWriter::adjust() +{ + // Only indent if at start of a line + if (m_startOfLine) + { + // Output current indentation + m_builder.appendRepeatedChar(' ', m_indent * 4); + m_startOfLine = false; + } +} + +void PrettyWriter::dedent() +{ + SLANG_ASSERT(m_indent > 0); + m_indent--; +} + +void PrettyWriter::write(const UnownedStringSlice& slice) +{ + const auto end = slice.end(); + auto start = slice.begin(); + + while (start < end) + { + const char* cur = start; + + // Search for \n if there is one + while (cur < end && *cur != '\n') + cur++; + + // If there were some chars, adjust and write + if (cur > start) + { + adjust(); + writeRaw(UnownedStringSlice(start, cur)); + } + + if (cur < end && *cur == '\n') + { + writeRawChar('\n'); + // Skip the CR + cur++; + // Mark we are at the start of a line + m_startOfLine = true; + } + + start = cur; + } +} + +void PrettyWriter::writeEscapedString(const UnownedStringSlice& slice) +{ + adjust(); + auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); + StringEscapeUtil::appendQuoted(handler, slice, m_builder); +} + +void PrettyWriter::maybeComma() +{ + if (auto state = m_commaState) + { + if (!state->needComma) + { + state->needComma = true; + return; + } + } + + write(toSlice(",\n")); +} + +} // namespace Slang diff --git a/source/compiler-core/slang-pretty-writer.h b/source/compiler-core/slang-pretty-writer.h new file mode 100644 index 0000000000..6817047a21 --- /dev/null +++ b/source/compiler-core/slang-pretty-writer.h @@ -0,0 +1,122 @@ +#ifndef SLANG_CORE_PRETTY_WRITER_H +#define SLANG_CORE_PRETTY_WRITER_H + + +#include "../core/slang-char-util.h" +#include "../core/slang-string-util.h" +#include "../core/slang-string.h" + +namespace Slang +{ + +struct PrettyWriter +{ + typedef PrettyWriter ThisType; + + friend struct CommaTrackerRAII; + + struct CommaState + { + bool needComma = false; + }; + + void writeRaw(const UnownedStringSlice& slice) { m_builder.append(slice); } + void writeRaw(char const* begin, char const* end); + void writeRaw(char const* begin) { writeRaw(UnownedStringSlice(begin)); } + + void writeRawChar(int c) { m_builder.appendChar(char(c)); } + + void writeHexChar(int c) { writeRawChar(CharUtil::getHexChar(Index(c))); } + + /// Adjusts indentation if at start of a line + void adjust(); + + /// Increase indentation + void indent() { m_indent++; } + /// Decreate indentation + void dedent(); + + /// Write taking into account any CR that might be in a slice + void write(const UnownedStringSlice& slice); + void write(char const* text) { write(UnownedStringSlice(text)); } + void write(char const* text, size_t length) { write(UnownedStringSlice(text, length)); } + + /// Write the slice as an escaped string + void writeEscapedString(const UnownedStringSlice& slice); + + /// Call before items in a comma-separated JSON list to emit the comma if/when needed + void maybeComma(); + + /// Get the builder the result is being constructed in + StringBuilder& getBuilder() { return m_builder; } + + ThisType& operator<<(const UnownedStringSlice& slice) + { + write(slice); + return *this; + } + ThisType& operator<<(const char* text) + { + write(text); + return *this; + } + ThisType& operator<<(uint64_t val) + { + adjust(); + m_builder << val; + return *this; + } + ThisType& operator<<(int64_t val) + { + adjust(); + m_builder << val; + return *this; + } + ThisType& operator<<(int32_t val) + { + adjust(); + m_builder << val; + return *this; + } + ThisType& operator<<(uint32_t val) + { + adjust(); + m_builder << val; + return *this; + } + ThisType& operator<<(float val) + { + adjust(); + // We want to use a specific format, so we use the StringUtil to specify format, and not + // just use << + StringUtil::appendFormat(m_builder, "%f", val); + return *this; + } + + bool m_startOfLine = true; + int m_indent = 0; + CommaState* m_commaState = nullptr; + StringBuilder m_builder; +}; + +/// Type for tracking whether a comma is needed in a comma-separated JSON list +struct CommaTrackerRAII +{ + CommaTrackerRAII(PrettyWriter& writer) + : m_writer(&writer), m_previousState(writer.m_commaState) + { + writer.m_commaState = &m_state; + } + + ~CommaTrackerRAII() { m_writer->m_commaState = m_previousState; } + +private: + PrettyWriter::CommaState m_state; + PrettyWriter* m_writer; + PrettyWriter::CommaState* m_previousState; +}; + +} // namespace Slang + + +#endif diff --git a/source/compiler-core/slang-slice-allocator.cpp b/source/compiler-core/slang-slice-allocator.cpp index 49fd6a5714..d24c05e9f7 100644 --- a/source/compiler-core/slang-slice-allocator.cpp +++ b/source/compiler-core/slang-slice-allocator.cpp @@ -3,7 +3,8 @@ #include "../core/slang-blob.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SliceUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -20,7 +21,7 @@ namespace Slang { return list; } -/* static */const char* SliceUtil::getTerminated(ISlangBlob* blob, TerminatedCharSlice& outSlice) +/* static */ const char* SliceUtil::getTerminated(ISlangBlob* blob, TerminatedCharSlice& outSlice) { const auto size = blob->getBufferSize(); if (size == 0) @@ -29,7 +30,7 @@ namespace Slang { return outSlice.begin(); } - // If there is a 0 at the end byte, we are zero terminated + // If there is a 0 at the end byte, we are zero terminated const char* chars = (const char*)blob->getBufferPointer(); if (chars[size - 1] == 0) { @@ -51,7 +52,9 @@ namespace Slang { return nullptr; } -/* static */TerminatedCharSlice SliceUtil::toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob) +/* static */ TerminatedCharSlice SliceUtil::toTerminatedCharSlice( + SliceAllocator& allocator, + ISlangBlob* blob) { TerminatedCharSlice slice; if (SliceUtil::getTerminated(blob, slice)) @@ -59,25 +62,29 @@ namespace Slang { return slice; } const auto size = blob->getBufferSize(); - // We are out of options, we just have to allocate with zero termination which allocateString does - auto dst = allocator.getArena().allocateString((const char*)blob->getBufferPointer(), Count(size)); + // We are out of options, we just have to allocate with zero termination which allocateString + // does + auto dst = + allocator.getArena().allocateString((const char*)blob->getBufferPointer(), Count(size)); return TerminatedCharSlice(dst, Count(size)); } -/* static */TerminatedCharSlice SliceUtil::toTerminatedCharSlice(StringBuilder& storage, ISlangBlob* blob) +/* static */ TerminatedCharSlice SliceUtil::toTerminatedCharSlice( + StringBuilder& storage, + ISlangBlob* blob) { TerminatedCharSlice slice; if (SliceUtil::getTerminated(blob, slice)) { return slice; } - + const auto size = blob->getBufferSize(); auto chars = (const char*)blob->getBufferPointer(); storage.clear(); storage.append(UnownedStringSlice(chars, size)); - + return TerminatedCharSlice(storage.getBuffer(), Count(size)); } diff --git a/source/compiler-core/slang-slice-allocator.h b/source/compiler-core/slang-slice-allocator.h index 8d61fa2112..504fbe1b75 100644 --- a/source/compiler-core/slang-slice-allocator.h +++ b/source/compiler-core/slang-slice-allocator.h @@ -2,12 +2,11 @@ #ifndef SLANG_SLICE_ALLOCATOR_H #define SLANG_SLICE_ALLOCATOR_H -// Has definition of CharSlice +// Has definition of CharSlice +#include "../core/slang-memory-arena.h" #include "slang-artifact.h" #include "slang-com-ptr.h" -#include "../core/slang-memory-arena.h" - namespace Slang { @@ -16,50 +15,64 @@ struct SliceAllocator; struct SliceUtil { - /// Convert into a list of strings + /// Convert into a list of strings static List toList(const Slice& in); - /// Gets a 0 terminated string from a blob. If not possible returns nullptr + /// Gets a 0 terminated string from a blob. If not possible returns nullptr static const char* getTerminated(ISlangBlob* blob, TerminatedCharSlice& outSlice); - /// NOTE! the slice is only guarenteed to stay in scope whilst the blob does + /// NOTE! the slice is only guarenteed to stay in scope whilst the blob does static TerminatedCharSlice toTerminatedCharSlice(SliceAllocator& allocator, ISlangBlob* blob); - /// + /// static TerminatedCharSlice toTerminatedCharSlice(StringBuilder& storage, ISlangBlob* blob); - /// The slice will only be in scope whilst the string is - static TerminatedCharSlice asTerminatedCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return TerminatedCharSlice(unowned.begin(), unowned.getLength()); } + /// The slice will only be in scope whilst the string is + static TerminatedCharSlice asTerminatedCharSlice(const String& in) + { + auto unowned = in.getUnownedSlice(); + return TerminatedCharSlice(unowned.begin(), unowned.getLength()); + } - /// Get string as a char slice - static CharSlice asCharSlice(const String& in) { auto unowned = in.getUnownedSlice(); return CharSlice(unowned.begin(), unowned.getLength()); } + /// Get string as a char slice + static CharSlice asCharSlice(const String& in) + { + auto unowned = in.getUnownedSlice(); + return CharSlice(unowned.begin(), unowned.getLength()); + } - template - static Slice asSlice(const List>& list) { return makeSlice((T* const*)list.getBuffer(), list.getCount()); } + template + static Slice asSlice(const List>& list) + { + return makeSlice((T* const*)list.getBuffer(), list.getCount()); + } - /// Get a list as a slice - template - static Slice asSlice(const List& list) { return Slice(list.getBuffer(), list.getCount()); } + /// Get a list as a slice + template + static Slice asSlice(const List& list) + { + return Slice(list.getBuffer(), list.getCount()); + } - template + template static List> toComPtrList(const Slice& in) { ISlangUnknown* check = (T*)nullptr; SLANG_UNUSED(check); List> list; list.setCount(in.count); - for (Index i = 0; i < in.count; ++i) list[i] = ComPtr(in[i]); + for (Index i = 0; i < in.count; ++i) + list[i] = ComPtr(in[i]); return list; } private: - /* - A reason to wrap in a struct rather than have as free functions is doing so will lead to compile time - errors with incorrect usage around temporaries. + A reason to wrap in a struct rather than have as free functions is doing so will lead to compile + time errors with incorrect usage around temporaries. */ /// We don't want to make a temporary list into a slice.. - template + template static Slice asSlice(const List&& list) = delete; // We don't want temporaries to be 'asSliced' so disable static TerminatedCharSlice asTerminatedCharSlice(const String&& in) = delete; @@ -78,7 +91,7 @@ SLANG_FORCE_INLINE CharSlice asCharSlice(const UnownedStringSlice& slice) SLANG_FORCE_INLINE String asString(const CharSlice& slice) { - return String(slice.begin(), slice.end()); + return String(slice.begin(), slice.end()); } struct SliceAllocator @@ -87,21 +100,24 @@ struct SliceAllocator TerminatedCharSlice allocate(const UnownedStringSlice& slice); TerminatedCharSlice allocate(const String& in) { return allocate(in.getUnownedSlice()); } TerminatedCharSlice allocate(const char* in); - TerminatedCharSlice allocate(const char* start, const char* end) { return allocate(UnownedStringSlice(start, end)); } + TerminatedCharSlice allocate(const char* start, const char* end) + { + return allocate(UnownedStringSlice(start, end)); + } Slice allocate(const List& in); - /// Get the backing arena + /// Get the backing arena MemoryArena& getArena() { return m_arena; } void deallocateAll() { m_arena.deallocateAll(); } - SliceAllocator(): - m_arena(2097152) + SliceAllocator() + : m_arena(2097152) { } + protected: - MemoryArena m_arena; }; diff --git a/source/compiler-core/slang-source-embed-util.cpp b/source/compiler-core/slang-source-embed-util.cpp index 45fd9c4b30..cfb83ed573 100644 --- a/source/compiler-core/slang-source-embed-util.cpp +++ b/source/compiler-core/slang-source-embed-util.cpp @@ -3,35 +3,35 @@ // Artifact #include "../compiler-core/slang-artifact-desc-util.h" #include "../compiler-core/slang-artifact-util.h" - -#include "../core/slang-string-util.h" -#include "../core/slang-char-util.h" - -#include "../core/slang-string-escape-util.h" - #include "../core/slang-blob.h" +#include "../core/slang-char-util.h" #include "../core/slang-io.h" +#include "../core/slang-string-escape-util.h" +#include "../core/slang-string-util.h" namespace Slang { -namespace { // anonymous +namespace +{ // anonymous typedef SourceEmbedUtil::Style Style; -} // anonymous - -static const NamesDescriptionValue kSourceEmbedStyleInfos[] = -{ - { ValueInt(Style::None), "none", "No source level embedding" }, - { ValueInt(Style::Default), "default", "The default embedding for the type to be embedded"}, - { ValueInt(Style::Text), "text", "Embed as text. May change line endings. If output isn't text will use 'default'. Size will *not* contain terminating 0." }, - { ValueInt(Style::BinaryText), "binary-text", "Embed as text assuming contents is binary. "}, - { ValueInt(Style::U8), "u8", "Embed as unsigned bytes."}, - { ValueInt(Style::U16), "u16", "Embed as uint16_t."}, - { ValueInt(Style::U32), "u32", "Embed as uint32_t."}, - { ValueInt(Style::U64), "u64", "Embed as uint64_t."}, +} // namespace + +static const NamesDescriptionValue kSourceEmbedStyleInfos[] = { + {ValueInt(Style::None), "none", "No source level embedding"}, + {ValueInt(Style::Default), "default", "The default embedding for the type to be embedded"}, + {ValueInt(Style::Text), + "text", + "Embed as text. May change line endings. If output isn't text will use 'default'. Size will " + "*not* contain terminating 0."}, + {ValueInt(Style::BinaryText), "binary-text", "Embed as text assuming contents is binary. "}, + {ValueInt(Style::U8), "u8", "Embed as unsigned bytes."}, + {ValueInt(Style::U16), "u16", "Embed as uint16_t."}, + {ValueInt(Style::U32), "u32", "Embed as uint32_t."}, + {ValueInt(Style::U64), "u64", "Embed as uint64_t."}, }; -/* static */ConstArrayView SourceEmbedUtil::getStyleInfos() +/* static */ ConstArrayView SourceEmbedUtil::getStyleInfos() { return makeConstArrayView(kSourceEmbedStyleInfos); } @@ -44,14 +44,11 @@ static const NamesDescriptionValue kSourceEmbedStyleInfos[] = static bool _isHeaderExtension(const UnownedStringSlice& in) { // Some "typical" header extensions - return in == toSlice("h") || - in == toSlice("hpp") || - in == toSlice("hxx") || - in == toSlice("h++") || - in == toSlice("hh"); + return in == toSlice("h") || in == toSlice("hpp") || in == toSlice("hxx") || + in == toSlice("h++") || in == toSlice("hh"); } -/* static */String SourceEmbedUtil::getPath(const String& path, const Options& options) +/* static */ String SourceEmbedUtil::getPath(const String& path, const Options& options) { if (!isSupported(options.language)) { @@ -73,10 +70,10 @@ static bool _isHeaderExtension(const UnownedStringSlice& in) // Assume it's a header, and just use the .h extension StringBuilder buf; buf << path << toSlice(".h"); - return std::move(buf); + return buf; } -/* static */SourceEmbedUtil::Style SourceEmbedUtil::getDefaultStyle(const ArtifactDesc& desc) +/* static */ SourceEmbedUtil::Style SourceEmbedUtil::getDefaultStyle(const ArtifactDesc& desc) { if (ArtifactDescUtil::isText(desc)) { @@ -97,7 +94,7 @@ static bool _isHeaderExtension(const UnownedStringSlice& in) return Style::U8; } -// True if we need to copy into a buffer. Necessary if there is an alignement +// True if we need to copy into a buffer. Necessary if there is an alignement // issue or if there is a partial entry static bool _needsCopy(const uint8_t* cur, Count bytesPerElement, Count bytesPerLine) { @@ -105,8 +102,13 @@ static bool _needsCopy(const uint8_t* cur, Count bytesPerElement, Count bytesPer } // NOTE! Assumes T is an unsigned type. Behavior will be incorrect if it is not. -template -static void _appendHex(const T* in, ArrayView elementWork, char* dst, size_t bytesForLine, StringBuilder& out) +template +static void _appendHex( + const T* in, + ArrayView elementWork, + char* dst, + size_t bytesForLine, + StringBuilder& out) { // Check that T is unsigned SLANG_COMPILE_TIME_ASSERT((T(~T(0))) > T(0)); @@ -138,10 +140,13 @@ static void _appendHex(const T* in, ArrayView elementWork, char* dst, size } } -static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayView data, StringBuilder& buf) +static SlangResult _append( + const SourceEmbedUtil::Options& options, + ConstArrayView data, + StringBuilder& buf) { const uint8_t* cur = data.begin(); - + const auto prefix = toSlice("0x"); const auto suffix = toSlice(", "); UnownedStringSlice literalSuffix; @@ -152,42 +157,43 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi switch (options.style) { - case Style::U8: + case Style::U8: { elementType = toSlice("unsigned char"); bytesPerElement = 1; break; } - case Style::U16: + case Style::U16: { elementType = toSlice("uint16_t"); bytesPerElement = 2; break; } - case Style::U32: + case Style::U32: { elementType = toSlice("uint32_t"); bytesPerElement = 4; break; } - case Style::U64: + case Style::U64: { elementType = toSlice("uint64_t"); bytesPerElement = 8; - // On testing on GCC/CLANG/Recent VS, there is no warning/error without suffix, so + // On testing on GCC/CLANG/Recent VS, there is no warning/error without suffix, so // will leave off for now. // literalSuffix = toSlice("ULL"); break; } - default: return SLANG_FAIL; + default: + return SLANG_FAIL; } // Output the variable buf << "const " << elementType << " " << options.variableName << "[] = \n"; buf << "{\n"; - - // Work out the element work + + // Work out the element work char work[80]; Count elementSizeInChars; { @@ -227,7 +233,7 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi // We copy if we want alignment of if we hit a partial at the end if (_needsCopy(lineBytes, bytesPerElement, bytesForLine)) { - // Make sure the last element is zeroed, before copying + // Make sure the last element is zeroed, before copying // Needed if the last element is partial. alignedElements[Index(bytesForLine / sizeof(uint64_t))] = 0; @@ -242,10 +248,18 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi switch (bytesPerElement) { - case 1: _appendHex(lineBytes, workView, dstChars, bytesForLine, buf); break; - case 2: _appendHex((const uint16_t*)lineBytes, workView, dstChars, bytesForLine, buf); break; - case 4: _appendHex((const uint32_t*)lineBytes, workView, dstChars, bytesForLine, buf); break; - case 8: _appendHex((const uint64_t*)lineBytes, workView, dstChars, bytesForLine, buf); break; + case 1: + _appendHex(lineBytes, workView, dstChars, bytesForLine, buf); + break; + case 2: + _appendHex((const uint16_t*)lineBytes, workView, dstChars, bytesForLine, buf); + break; + case 4: + _appendHex((const uint32_t*)lineBytes, workView, dstChars, bytesForLine, buf); + break; + case 8: + _appendHex((const uint64_t*)lineBytes, workView, dstChars, bytesForLine, buf); + break; } buf << "\n"; @@ -256,7 +270,10 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi return SLANG_OK; } -/* static */SlangResult SourceEmbedUtil::createEmbedded(IArtifact* artifact, const Options& inOptions, ComPtr& outArtifact) +/* static */ SlangResult SourceEmbedUtil::createEmbedded( + IArtifact* artifact, + const Options& inOptions, + ComPtr& outArtifact) { if (!isSupported(inOptions.language)) { @@ -270,10 +287,9 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi Options options(inOptions); - // If the style is text, but the artifact *isn't* a text type, we'll + // If the style is text, but the artifact *isn't* a text type, we'll // use 'default' for the type - if (options.style == Style::Text && - !ArtifactDescUtil::isText(desc)) + if (options.style == Style::Text && !ArtifactDescUtil::isText(desc)) { options.style = Style::Default; } @@ -282,7 +298,7 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi { options.style = getDefaultStyle(desc); } - + // If there is no style there is nothing to do if (options.style == Style::None) { @@ -299,10 +315,10 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi ConstArrayView data((const uint8_t*)blob->getBufferPointer(), blob->getBufferSize()); size_t totalSizeInBytes = data.getCount(); - + switch (options.style) { - case Style::Text: + case Style::Text: { totalSizeInBytes = 0; @@ -321,8 +337,8 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi handler->appendEscaped(line, buf); - // Work out the total size, taking into account we may encode line endings and \0 differently - // The +1 is for \n + // Work out the total size, taking into account we may encode line endings and \0 + // differently The +1 is for \n totalSizeInBytes += line.getLength() + 1; buf << "\\n\"\n"; @@ -331,7 +347,7 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi buf << ";\n"; break; } - case Style::BinaryText: + case Style::BinaryText: { auto handler = StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp); @@ -340,10 +356,10 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi // We could encode everything and then split // but if we do that we probably want to not split across an escaped character, // although that may be handled correctly. - + // The other way to this is incrementally, so that's what we will do here UnownedStringSlice text((const char*)data.begin(), data.getCount()); - + auto cur = text.begin(); auto end = text.end(); @@ -358,8 +374,7 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi { handler->appendEscaped(UnownedStringSlice(cur, 1), buf); cur++; - } - while (buf.getLength() - startOffset < options.lineLength - 1); + } while (buf.getLength() - startOffset < options.lineLength - 1); buf << "\"\n"; } @@ -367,24 +382,26 @@ static SlangResult _append(const SourceEmbedUtil::Options& options, ConstArrayVi buf << ";\n"; break; } - case Style::U8: - case Style::U16: - case Style::U32: - case Style::U64: + case Style::U8: + case Style::U16: + case Style::U32: + case Style::U64: { SLANG_RETURN_ON_FAIL(_append(options, data, buf)); break; } - default: + default: { return SLANG_E_NOT_IMPLEMENTED; } } - buf << "const size_t " << options.variableName << "_sizeInBytes = " << uint64_t(totalSizeInBytes) << ";\n\n"; + buf << "const size_t " << options.variableName + << "_sizeInBytes = " << uint64_t(totalSizeInBytes) << ";\n\n"; // Make into an artifact - ArtifactPayload payload = options.language == SLANG_SOURCE_LANGUAGE_C ? ArtifactPayload::C : ArtifactPayload::Cpp; + ArtifactPayload payload = + options.language == SLANG_SOURCE_LANGUAGE_C ? ArtifactPayload::C : ArtifactPayload::Cpp; auto dstDesc = ArtifactDesc::make(ArtifactKind::Source, payload); auto dstArtifact = ArtifactUtil::createArtifact(dstDesc); diff --git a/source/compiler-core/slang-source-embed-util.h b/source/compiler-core/slang-source-embed-util.h index 52115e4ef4..9144bcb4c7 100644 --- a/source/compiler-core/slang-source-embed-util.h +++ b/source/compiler-core/slang-source-embed-util.h @@ -2,13 +2,10 @@ #define SLANG_SOURCE_EMBED_UTIL_H #include "../core/slang-basic.h" - +#include "../core/slang-name-value.h" #include "slang-artifact.h" -#include "slang-diagnostic-sink.h" - #include "slang-com-ptr.h" - -#include "../core/slang-name-value.h" +#include "slang-diagnostic-sink.h" namespace Slang { @@ -18,42 +15,47 @@ struct SourceEmbedUtil { enum class Style : uint32_t { - None, ///< No embedding - Default, ///< Default embedding for the type - Text, ///< Embed as text. May change line endings. If output isn't text will use 'default'. Size will *not* contain terminating 0 - BinaryText, ///< Embed as text assuming contents is binary. - U8, ///< Embed as unsigned bytes - U16, ///< Embed as uint16_t - U32, ///< Embed as uint32_t - U64, ///< Embed as uint64_t + None, ///< No embedding + Default, ///< Default embedding for the type + Text, ///< Embed as text. May change line endings. If output isn't text will use 'default'. + ///< Size will *not* contain terminating 0 + BinaryText, ///< Embed as text assuming contents is binary. + U8, ///< Embed as unsigned bytes + U16, ///< Embed as uint16_t + U32, ///< Embed as uint32_t + U64, ///< Embed as uint64_t CountOf, }; struct Options { - Style style = Style::Default; ///< Style of embedding - Count lineLength = 120; ///< The line length, lines can be larger for some styles, but will aim to keep within range - SlangSourceLanguage language = SLANG_SOURCE_LANGUAGE_C; ///< The language to output for - String variableName; ///< The name to give the variable - String indent = " "; ///< Indenting + Style style = Style::Default; ///< Style of embedding + Count lineLength = 120; ///< The line length, lines can be larger for some styles, but will + ///< aim to keep within range + SlangSourceLanguage language = SLANG_SOURCE_LANGUAGE_C; ///< The language to output for + String variableName; ///< The name to give the variable + String indent = " "; ///< Indenting }; - /// Get the style infos + /// Get the style infos static ConstArrayView getStyleInfos(); - /// Given an artifact and - static SlangResult createEmbedded(IArtifact* artifact, const Options& options, ComPtr& outArtifact); + /// Given an artifact and + static SlangResult createEmbedded( + IArtifact* artifact, + const Options& options, + ComPtr& outArtifact); - /// Returns the default style for the desc + /// Returns the default style for the desc static Style getDefaultStyle(const ArtifactDesc& desc); - /// Returns true if supports the specified language for embedding + /// Returns true if supports the specified language for embedding static bool isSupported(SlangSourceLanguage lang); - /// Given the path return the output path. If no path is available return the empty string + /// Given the path return the output path. If no path is available return the empty string static String getPath(const String& path, const Options& options); }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/slang-source-loc.cpp b/source/compiler-core/slang-source-loc.cpp index 5f1f51a381..5058a15226 100644 --- a/source/compiler-core/slang-source-loc.cpp +++ b/source/compiler-core/slang-source-loc.cpp @@ -1,15 +1,16 @@ // slang-source-loc.cpp #include "slang-source-loc.h" -#include "../core/slang-string-util.h" -#include "../core/slang-string-escape-util.h" #include "../core/slang-char-encode.h" -#include "slang-artifact-representation-impl.h" +#include "../core/slang-string-escape-util.h" +#include "../core/slang-string-util.h" +#include "slang-artifact-desc-util.h" #include "slang-artifact-impl.h" +#include "slang-artifact-representation-impl.h" #include "slang-artifact-util.h" -#include "slang-artifact-desc-util.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!! SourceView !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -17,13 +18,15 @@ const String PathInfo::getMostUniqueIdentity() const { switch (type) { - case Type::Normal: return uniqueIdentity; - case Type::FoundPath: - case Type::FromString: + case Type::Normal: + return uniqueIdentity; + case Type::FoundPath: + case Type::FromString: { return foundPath; } - default: return ""; + default: + return ""; } } @@ -31,9 +34,9 @@ String PathInfo::getName() const { switch (type) { - case Type::Normal: - case Type::FromString: - case Type::FoundPath: + case Type::Normal: + case Type::FromString: + case Type::FoundPath: { return foundPath; } @@ -51,24 +54,25 @@ bool PathInfo::operator==(const ThisType& rhs) const switch (type) { - case Type::TokenPaste: - case Type::TypeParse: - case Type::Unknown: - case Type::CommandLine: + case Type::TokenPaste: + case Type::TypeParse: + case Type::Unknown: + case Type::CommandLine: { return true; } - case Type::Normal: + case Type::Normal: { return foundPath == rhs.foundPath && uniqueIdentity == rhs.uniqueIdentity; } - case Type::FromString: - case Type::FoundPath: + case Type::FromString: + case Type::FoundPath: { // Only have a found path return foundPath == rhs.foundPath; } - default: break; + default: + break; } return false; @@ -78,18 +82,30 @@ void PathInfo::appendDisplayName(StringBuilder& out) const { switch (type) { - case Type::TokenPaste: out << "[Token Paste]"; break; - case Type::TypeParse: out << "[Type Parse]"; break; - case Type::Unknown: out << "[Unknown]"; break; - case Type::CommandLine: out << "[Command Line]"; break; - case Type::Normal: - case Type::FromString: - case Type::FoundPath: + case Type::TokenPaste: + out << "[Token Paste]"; + break; + case Type::TypeParse: + out << "[Type Parse]"; + break; + case Type::Unknown: + out << "[Unknown]"; + break; + case Type::CommandLine: + out << "[Command Line]"; + break; + case Type::Normal: + case Type::FromString: + case Type::FoundPath: { - StringEscapeUtil::appendQuoted(StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp), foundPath.getUnownedSlice(), out); + StringEscapeUtil::appendQuoted( + StringEscapeUtil::getHandler(StringEscapeUtil::Style::Cpp), + foundPath.getUnownedSlice(), + out); break; } - default: break; + default: + break; } } @@ -104,10 +120,10 @@ int SourceView::findEntryIndex(SourceLoc sourceLoc) const const auto rawValue = sourceLoc.getRaw(); - Index hi = m_entries.getCount(); - // If there are no entries, or it is in front of the first entry, then there is no associated entry - if (hi == 0 || - m_entries[0].m_startLoc.getRaw() > sourceLoc.getRaw()) + Index hi = m_entries.getCount(); + // If there are no entries, or it is in front of the first entry, then there is no associated + // entry + if (hi == 0 || m_entries[0].m_startLoc.getRaw() > sourceLoc.getRaw()) { return -1; } @@ -133,29 +149,35 @@ int SourceView::findEntryIndex(SourceLoc sourceLoc) const return int(lo); } -void SourceView::addLineDirective(SourceLoc directiveLoc, StringSlicePool::Handle pathHandle, int line) +void SourceView::addLineDirective( + SourceLoc directiveLoc, + StringSlicePool::Handle pathHandle, + int line) { SLANG_ASSERT(pathHandle != StringSlicePool::Handle(0)); SLANG_ASSERT(m_range.contains(directiveLoc)); // Check that the directiveLoc values are always increasing - SLANG_ASSERT(m_entries.getCount() == 0 || (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw())); + SLANG_ASSERT( + m_entries.getCount() == 0 || + (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw())); // Calculate the offset const int offset = m_range.getOffset(directiveLoc); - + // Get the line index in the original file const int lineIndex = m_sourceFile->calcLineIndexFromOffset(offset); Entry entry; entry.m_startLoc = directiveLoc; entry.m_pathHandle = pathHandle; - + // We also need to make sure that any lookups for line numbers will // get corrected based on this files location. - // We assume the line number coming from the directive is a line number, NOT an index, so the correction needs + 1 - // There is an additional + 1 because we want the NEXT line - ie the line after the #line directive, to the specified value - // Taking both into account means +2 is correct 'fix' + // We assume the line number coming from the directive is a line number, NOT an index, so the + // correction needs + 1 There is an additional + 1 because we want the NEXT line - ie the line + // after the #line directive, to the specified value Taking both into account means +2 is + // correct 'fix' entry.m_lineAdjust = line - (lineIndex + 2); m_entries.add(entry); @@ -163,7 +185,8 @@ void SourceView::addLineDirective(SourceLoc directiveLoc, StringSlicePool::Handl void SourceView::addLineDirective(SourceLoc directiveLoc, const String& path, int line) { - StringSlicePool::Handle pathHandle = getSourceManager()->getStringSlicePool().add(path.getUnownedSlice()); + StringSlicePool::Handle pathHandle = + getSourceManager()->getStringSlicePool().add(path.getUnownedSlice()); return addLineDirective(directiveLoc, pathHandle, line); } @@ -171,9 +194,12 @@ void SourceView::addDefaultLineDirective(SourceLoc directiveLoc) { SLANG_ASSERT(m_range.contains(directiveLoc)); // Check that the directiveLoc values are always increasing - SLANG_ASSERT(m_entries.getCount() == 0 || (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw())); + SLANG_ASSERT( + m_entries.getCount() == 0 || + (m_entries.getLast().m_startLoc.getRaw() < directiveLoc.getRaw())); - // Well if there are no entries, or the last one puts it in default case, then we don't need to add anything + // Well if there are no entries, or the last one puts it in default case, then we don't need to + // add anything if (m_entries.getCount() == 0 || (m_entries.getCount() && m_entries.getLast().isDefault())) { return; @@ -181,8 +207,9 @@ void SourceView::addDefaultLineDirective(SourceLoc directiveLoc) Entry entry; entry.m_startLoc = directiveLoc; - entry.m_lineAdjust = 0; // No line adjustment... we are going back to default - entry.m_pathHandle = StringSlicePool::Handle(0); // Mark that there is no path, and that this is a 'default' + entry.m_lineAdjust = 0; // No line adjustment... we are going back to default + entry.m_pathHandle = + StringSlicePool::Handle(0); // Mark that there is no path, and that this is a 'default' SLANG_ASSERT(entry.isDefault()); @@ -204,16 +231,20 @@ static bool _canFollowSourceMap(SourceFile* sourceFile, SourceLocType type) } // If it's obfuscated we can't follow if we are emitting - if (sourceFile->getSourceMapKind() == SourceMapKind::Obfuscated && - type == SourceLocType::Emit) + if (sourceFile->getSourceMapKind() == SourceMapKind::Obfuscated && type == SourceLocType::Emit) { return false; } - return _isNominalLike(type); + return _isNominalLike(type); } -static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, SourceView* sourceView, SourceLoc loc, SourceLocType type, HandleSourceLoc& outLoc) +static SlangResult _findLocWithSourceMap( + SourceManager* lookupSourceManager, + SourceView* sourceView, + SourceLoc loc, + SourceLocType type, + HandleSourceLoc& outLoc) { auto sourceFile = sourceView->getSourceFile(); @@ -229,9 +260,9 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou Index entryIndex = -1; // Do the initial lookup using the loc - { + { const auto offset = sourceView->getRange().getOffset(loc); - + const auto lineIndex = sourceFile->calcLineIndexFromOffset(offset); const auto colIndex = sourceFile->calcColumnIndex(lineIndex, offset); @@ -239,7 +270,7 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou auto sourceMap = sourceFile->getSourceMap(); SLANG_ASSERT(sourceMap); - entryIndex = sourceMap->get().findEntry(lineIndex, colIndex); + entryIndex = sourceMap->get().findEntry(lineIndex, colIndex); } if (entryIndex < 0) @@ -247,8 +278,8 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou return SLANG_FAIL; } - // Keep searching through source maps - do + // Keep searching through source maps + do { auto sourceMap = sourceFile->getSourceMap()->getPtr(); @@ -259,7 +290,8 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou // If we have a source name, see if it already exists in source manager if (sourceFileName.getLength()) { - if (auto foundSourceFile = lookupSourceManager->findSourceFileByPathRecursively(sourceFileName)) + if (auto foundSourceFile = + lookupSourceManager->findSourceFileByPathRecursively(sourceFileName)) { // We only follow if the source file hasn't already been visisted if (sourceFiles.indexOf(foundSourceFile) < 0) @@ -267,12 +299,14 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou // Add so we don't reprocess sourceFiles.add(foundSourceFile); - // If it has a source map, we try and look up the current location in it's source map + // If it has a source map, we try and look up the current location in it's + // source map if (_canFollowSourceMap(foundSourceFile, type)) { auto foundSourceMap = foundSourceFile->getSourceMap(); - const auto foundEntryIndex = foundSourceMap->get().findEntry(entry.sourceLine, entry.sourceColumn); + const auto foundEntryIndex = + foundSourceMap->get().findEntry(entry.sourceLine, entry.sourceColumn); // If we found the entry repeat the lookup if (foundEntryIndex >= 0) @@ -304,7 +338,10 @@ static SlangResult _findLocWithSourceMap(SourceManager* lookupSourceManager, Sou } -SlangResult SourceView::_findSourceMapLoc(SourceLoc loc, SourceLocType type, HandleSourceLoc& outLoc) +SlangResult SourceView::_findSourceMapLoc( + SourceLoc loc, + SourceLocType type, + HandleSourceLoc& outLoc) { // We only do source map lookups with nominal if (!_isNominalLike(type)) @@ -312,9 +349,9 @@ SlangResult SourceView::_findSourceMapLoc(SourceLoc loc, SourceLocType type, Han return SLANG_E_NOT_FOUND; } - // TODO(JS): - // Ideally we'd do the lookup on the "current" source manager rather than the source manager on this - // view, which may be a parent to the current one. + // TODO(JS): + // Ideally we'd do the lookup on the "current" source manager rather than the source manager on + // this view, which may be a parent to the current one. auto lookupSourceManager = m_sourceFile->getSourceManager(); SLANG_RETURN_ON_FAIL(_findLocWithSourceMap(lookupSourceManager, this, loc, type, outLoc)); @@ -324,31 +361,32 @@ SlangResult SourceView::_findSourceMapLoc(SourceLoc loc, SourceLocType type, Han HandleSourceLoc SourceView::getHandleLoc(SourceLoc loc, SourceLocType type) { - { HandleSourceLoc handleLoc; + { + HandleSourceLoc handleLoc; if (SLANG_SUCCEEDED(_findSourceMapLoc(loc, type, handleLoc))) { return handleLoc; } } - // Get the offset in bytes for this loc + // Get the offset in bytes for this loc const int offset = m_range.getOffset(loc); // We need the line index from the original source file const int lineIndex = m_sourceFile->calcLineIndexFromOffset(offset); - // TODO: + // TODO: // - Tab characters, which should really adjust how we report // columns (although how are we supposed to know the setting // that an IDE expects us to use when reporting locations?) - // + // // For now we just count tabs as single chars const int columnIndex = m_sourceFile->calcColumnIndex(lineIndex, offset); HandleSourceLoc handleLoc; handleLoc.column = columnIndex + 1; handleLoc.line = lineIndex + 1; - + // Only bother looking up the entry information if we want a 'Norminal'-like lookup if (_isNominalLike(type)) { @@ -411,7 +449,7 @@ PathInfo SourceView::getPathInfo(SourceLoc loc, SourceLocType type) return getViewPathInfo(); } - { + { HandleSourceLoc handleLoc; if (SLANG_SUCCEEDED(_findSourceMapLoc(loc, type, handleLoc))) { @@ -420,7 +458,8 @@ PathInfo SourceView::getPathInfo(SourceLoc loc, SourceLocType type) } const int entryIndex = findEntryIndex(loc); - return _getPathInfoFromHandle((entryIndex >= 0) ? m_entries[entryIndex].m_pathHandle : StringSlicePool::Handle(0)); + return _getPathInfoFromHandle( + (entryIndex >= 0) ? m_entries[entryIndex].m_pathHandle : StringSlicePool::Handle(0)); } /* !!!!!!!!!!!!!!!!!!!!!!! SourceFile !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -464,13 +503,13 @@ SourceFile::OffsetRange SourceFile::getOffsetRangeAtLineIndex(Index lineIndex) const uint32_t offsetEnd = uint32_t(getContentSize()); const uint32_t offsetStart = (lineIndex >= count) ? offsetEnd : offsets[lineIndex]; // The line is the span from start, to the end of the content - return OffsetRange{ offsetStart, offsetEnd }; + return OffsetRange{offsetStart, offsetEnd}; } else { const uint32_t offsetStart = offsets[lineIndex]; const uint32_t offsetEnd = offsets[lineIndex + 1]; - return OffsetRange { offsetStart, offsetEnd }; + return OffsetRange{offsetStart, offsetEnd}; } } @@ -483,7 +522,7 @@ UnownedStringSlice SourceFile::getLineAtIndex(Index lineIndex) const UnownedStringSlice content = getContent(); SLANG_ASSERT(range.end <= uint32_t(content.getLength())); - const char*const text = content.begin(); + const char* const text = content.begin(); return UnownedStringSlice(text + range.start, text + range.end); } @@ -517,7 +556,7 @@ int SourceFile::calcLineIndexFromOffset(int offset) while (lo + 1 < hi) { - const Index mid = (hi + lo) >> 1; + const Index mid = (hi + lo) >> 1; const uint32_t midOffset = lineBreakOffsets[mid]; if (midOffset <= uint32_t(offset)) { @@ -535,14 +574,15 @@ int SourceFile::calcLineIndexFromOffset(int offset) int SourceFile::calcColumnOffset(int lineIndex, int offset) { const auto& lineBreakOffsets = getLineBreakOffsets(); - return offset - lineBreakOffsets[lineIndex]; + return offset - lineBreakOffsets[lineIndex]; } int SourceFile::calcColumnIndex(int lineIndex, int offset, int tabSize) { const int colOffset = calcColumnOffset(lineIndex, offset); - // If we don't have the content of the file, the best we can do is to assume there is a char per column + // If we don't have the content of the file, the best we can do is to assume there is a char per + // column if (!hasContent()) { return colOffset; @@ -553,7 +593,7 @@ int SourceFile::calcColumnIndex(int lineIndex, int offset, int tabSize) const auto head = line.head(colOffset); auto colCount = UTF8Util::calcCodePointCount(head); - + if (tabSize >= 0) { Count tabCount = 0; @@ -581,10 +621,7 @@ void SourceFile::setContents(ISlangBlob* blob) // Query the encoding type and discard the Unicode Byte-Order-Marker before decoding size_t offset; - auto type = CharEncoding::determineEncoding( - rawContentBegin, - rawContentSize, - offset); + auto type = CharEncoding::determineEncoding(rawContentBegin, rawContentSize, offset); SLANG_ASSERT(rawContentSize >= offset); List decodedBuffer; @@ -608,16 +645,12 @@ void SourceFile::setContents(const String& content) setContents(contentBlob); } -SourceFile::SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize) : - m_sourceManager(sourceManager), - m_pathInfo(pathInfo), - m_contentSize(contentSize) +SourceFile::SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize) + : m_sourceManager(sourceManager), m_pathInfo(pathInfo), m_contentSize(contentSize) { } -SourceFile::~SourceFile() -{ -} +SourceFile::~SourceFile() {} SHA1::Digest SourceFile::getDigest() { @@ -638,7 +671,10 @@ String SourceFile::calcVerbosePath() const { String displayPath; ComPtr displayPathBlob; - if (SLANG_SUCCEEDED(fileSystemExt->getPath(PathKind::Display, m_pathInfo.foundPath.getBuffer(), displayPathBlob.writeRef()))) + if (SLANG_SUCCEEDED(fileSystemExt->getPath( + PathKind::Display, + m_pathInfo.foundPath.getBuffer(), + displayPathBlob.writeRef()))) { displayPath = StringUtil::getString(displayPathBlob); } @@ -653,9 +689,7 @@ String SourceFile::calcVerbosePath() const /* !!!!!!!!!!!!!!!!!!!!!!!!! SourceManager !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -void SourceManager::initialize( - SourceManager* p, - ISlangFileSystemExt* fileSystemExt) +void SourceManager::initialize(SourceManager* p, ISlangFileSystemExt* fileSystemExt) { m_fileSystemExt = fileSystemExt; @@ -730,8 +764,8 @@ SourceRange SourceManager::allocateSourceRange(UInt size) // TODO: consider using atomics here - SourceLoc beginLoc = m_nextLoc; - SourceLoc endLoc = beginLoc + size; + SourceLoc beginLoc = m_nextLoc; + SourceLoc endLoc = beginLoc + size; // We need to be able to represent the location that is *at* the end of // the input source, so the next available location for a new file @@ -749,7 +783,9 @@ SourceFile* SourceManager::createSourceFileWithSize(const PathInfo& pathInfo, si return sourceFile; } -SourceFile* SourceManager::createSourceFileWithString(const PathInfo& pathInfo, const String& contents) +SourceFile* SourceManager::createSourceFileWithString( + const PathInfo& pathInfo, + const String& contents) { SourceFile* sourceFile = new SourceFile(this, pathInfo, contents.getLength()); m_sourceFiles.add(sourceFile); @@ -765,13 +801,16 @@ SourceFile* SourceManager::createSourceFileWithBlob(const PathInfo& pathInfo, IS return sourceFile; } -SourceView* SourceManager::createSourceView(SourceFile* sourceFile, const PathInfo* pathInfo, SourceLoc initiatingSourceLoc) +SourceView* SourceManager::createSourceView( + SourceFile* sourceFile, + const PathInfo* pathInfo, + SourceLoc initiatingSourceLoc) { SourceRange range = allocateSourceRange(sourceFile->getContentSize()); SourceView* sourceView = nullptr; - if (pathInfo && - (pathInfo->foundPath.getLength() && sourceFile->getPathInfo().foundPath != pathInfo->foundPath)) + if (pathInfo && (pathInfo->foundPath.getLength() && + sourceFile->getPathInfo().foundPath != pathInfo->foundPath)) { sourceView = new SourceView(sourceFile, range, &pathInfo->foundPath, initiatingSourceLoc); } @@ -844,7 +883,7 @@ SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const { // Start with this manager const SourceManager* manager = this; - do + do { SourceView* sourceView = manager->findSourceView(loc); // If we found a hit we are done @@ -854,8 +893,7 @@ SourceView* SourceManager::findSourceViewRecursively(SourceLoc loc) const } // Try the parent manager = manager->m_parent; - } - while (manager); + } while (manager); // Didn't find it return nullptr; } @@ -881,7 +919,7 @@ SourceFile* SourceManager::findSourceFileByPathRecursively(const String& name) c SourceFile* SourceManager::findSourceFileByPath(const String& name) const { - for(auto sourceFile : m_sourceFiles) + for (auto sourceFile : m_sourceFiles) { if (sourceFile->getPathInfo().foundPath == name) { @@ -893,14 +931,14 @@ SourceFile* SourceManager::findSourceFileByPath(const String& name) const SourceFile* SourceManager::findSourceFile(const String& uniqueIdentity) const { - SourceFile*const* filePtr = m_sourceFileMap.tryGetValue(uniqueIdentity); + SourceFile* const* filePtr = m_sourceFileMap.tryGetValue(uniqueIdentity); return (filePtr) ? *filePtr : nullptr; } SourceFile* SourceManager::findSourceFileRecursively(const String& uniqueIdentity) const { const SourceManager* manager = this; - do + do { SourceFile* sourceFile = manager->findSourceFile(uniqueIdentity); if (sourceFile) diff --git a/source/compiler-core/slang-source-loc.h b/source/compiler-core/slang-source-loc.h index bf0be47f64..c46c9063a8 100644 --- a/source/compiler-core/slang-source-loc.h +++ b/source/compiler-core/slang-source-loc.h @@ -3,91 +3,126 @@ #define SLANG_SOURCE_LOC_H_INCLUDED #include "../core/slang-basic.h" -#include "../core/slang-memory-arena.h" -#include "../core/slang-string-slice-pool.h" #include "../core/slang-castable.h" #include "../core/slang-crypto.h" - -#include "slang-source-map.h" - +#include "../core/slang-memory-arena.h" +#include "../core/slang-string-slice-pool.h" #include "slang-com-ptr.h" +#include "slang-source-map.h" #include "slang.h" -namespace Slang { - -/** Overview: - -There needs to be a mechanism where we can easily and quickly track a specific locations in any source file used during a compilation. -This is important because that original location is meaningful to the user as it relates to their original source. Thus SourceLoc are -used so we can display meaningful and accurate errors/warnings as well as being able to always map generated code locations back to their origins. - -A 'SourceLoc' along with associated structures (SourceView, SourceFile, SourceMangager) this can pinpoint the location down to the byte across the -compilation. This could be achieved by storing for every token and instruction the file, line and column number came from. The SourceLoc is used in -lots of places - every AST node, every Token from the lexer, every IRInst - so we really want to make it small. So for this reason we actually -encode SourceLoc as a single integer and then use the associated structures when needed to determine what the location actually refers to - -the source file, line and column number, or in effect the byte in the original file. - -Unfortunately there is extra complications. When a source is parsed it's interpretation (in terms of how a piece of source maps to an 'original' file etc) -can be overridden - for example by using #line directives. Moreover a single source file can be parsed multiple times. When it's parsed multiple times the -interpretation of the mapping (#line directives for example) can change. This is the purpose of the SourceView - it holds the interpretation of a source file -for a specific Lex/Parse. - -Another complication is that not all 'source' comes from SourceFiles, a macro expansion, may generate new 'source' we need to handle this, but also be able -to have a SourceLoc map to the expansion unambiguously. This is handled by creating a SourceFile and SourceView that holds only the macro generated -specific information. +namespace Slang +{ -SourceFile - Is the immutable text contents of a file (or perhaps some generated source - say from doing a macro substitution) -SourceView - Tracks a single parse of a SourceFile. Each SourceView defines a range of source locations used. If a SourceFile is parsed twice, two -SourceViews are created, with unique SourceRanges. This is so that it is possible to tell which specific parse a SourceLoc is from - and so know the right -interpretation for that lex/parse. +/** Overview: + +There needs to be a mechanism where we can easily and quickly track a specific locations in any +source file used during a compilation. This is important because that original location is +meaningful to the user as it relates to their original source. Thus SourceLoc are used so we can +display meaningful and accurate errors/warnings as well as being able to always map generated code +locations back to their origins. + +A 'SourceLoc' along with associated structures (SourceView, SourceFile, SourceMangager) this can +pinpoint the location down to the byte across the compilation. This could be achieved by storing for +every token and instruction the file, line and column number came from. The SourceLoc is used in +lots of places - every AST node, every Token from the lexer, every IRInst - so we really want to +make it small. So for this reason we actually encode SourceLoc as a single integer and then use the +associated structures when needed to determine what the location actually refers to - the source +file, line and column number, or in effect the byte in the original file. + +Unfortunately there is extra complications. When a source is parsed it's interpretation (in terms of +how a piece of source maps to an 'original' file etc) can be overridden - for example by using #line +directives. Moreover a single source file can be parsed multiple times. When it's parsed multiple +times the interpretation of the mapping (#line directives for example) can change. This is the +purpose of the SourceView - it holds the interpretation of a source file for a specific Lex/Parse. + +Another complication is that not all 'source' comes from SourceFiles, a macro expansion, may +generate new 'source' we need to handle this, but also be able to have a SourceLoc map to the +expansion unambiguously. This is handled by creating a SourceFile and SourceView that holds only the +macro generated specific information. + +SourceFile - Is the immutable text contents of a file (or perhaps some generated source - say from +doing a macro substitution) SourceView - Tracks a single parse of a SourceFile. Each SourceView +defines a range of source locations used. If a SourceFile is parsed twice, two SourceViews are +created, with unique SourceRanges. This is so that it is possible to tell which specific parse a +SourceLoc is from - and so know the right interpretation for that lex/parse. */ struct PathInfo { typedef PathInfo ThisType; - /// To be more rigorous about where a path comes from, the type identifies what a paths origin is + /// To be more rigorous about where a path comes from, the type identifies what a paths origin + /// is enum class Type : uint8_t { - Unknown, ///< The path is not known - Normal, ///< Normal has both path and uniqueIdentity - FoundPath, ///< Just has a found path (uniqueIdentity is unknown, or even 'unknowable') - FromString, ///< Created from a string (so found path might not be defined and should not be taken as to map to a loaded file) - TokenPaste, ///< No paths, just created to do a macro expansion - TypeParse, ///< No path, just created to do a type parse - CommandLine, ///< A macro constructed from the command line + Unknown, ///< The path is not known + Normal, ///< Normal has both path and uniqueIdentity + FoundPath, ///< Just has a found path (uniqueIdentity is unknown, or even 'unknowable') + FromString, ///< Created from a string (so found path might not be defined and should not be + ///< taken as to map to a loaded file) + TokenPaste, ///< No paths, just created to do a macro expansion + TypeParse, ///< No path, just created to do a type parse + CommandLine, ///< A macro constructed from the command line }; - /// True if has a canonical path - SLANG_FORCE_INLINE bool hasUniqueIdentity() const { return type == Type::Normal && uniqueIdentity.getLength() > 0; } - /// True if has a regular found path - SLANG_FORCE_INLINE bool hasFoundPath() const { return (type == Type::Normal || type == Type::FoundPath || type == Type::FromString) && foundPath.getLength() > 0; } - /// True if has a found path that has originated from a file (as opposed to string or some other origin) - SLANG_FORCE_INLINE bool hasFileFoundPath() const { return (type == Type::Normal || type == Type::FoundPath) && foundPath.getLength() > 0; } - /// Get the 'name'/path of the item. Will return an empty string if not applicable or not set. + /// True if has a canonical path + SLANG_FORCE_INLINE bool hasUniqueIdentity() const + { + return type == Type::Normal && uniqueIdentity.getLength() > 0; + } + /// True if has a regular found path + SLANG_FORCE_INLINE bool hasFoundPath() const + { + return (type == Type::Normal || type == Type::FoundPath || type == Type::FromString) && + foundPath.getLength() > 0; + } + /// True if has a found path that has originated from a file (as opposed to string or some other + /// origin) + SLANG_FORCE_INLINE bool hasFileFoundPath() const + { + return (type == Type::Normal || type == Type::FoundPath) && foundPath.getLength() > 0; + } + /// Get the 'name'/path of the item. Will return an empty string if not applicable or not set. String getName() const; bool operator==(const ThisType& rhs) const; bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Returns the 'most unique' identity for the path. If has a 'uniqueIdentity' returns that, else the foundPath, else "". + /// Returns the 'most unique' identity for the path. If has a 'uniqueIdentity' returns that, + /// else the foundPath, else "". const String getMostUniqueIdentity() const; - /// Append to out, how to display the path + /// Append to out, how to display the path void appendDisplayName(StringBuilder& out) const; - // So simplify construction. In normal usage it's safer to use make methods over constructing directly. - static PathInfo makeUnknown() { return PathInfo { Type::Unknown, String(), String() }; } - static PathInfo makeTokenPaste() { return PathInfo{ Type::TokenPaste, "token paste", String()}; } - static PathInfo makeNormal(const String& foundPathIn, const String& uniqueIdentity) { SLANG_ASSERT(uniqueIdentity.getLength() > 0 && foundPathIn.getLength() > 0); return PathInfo { Type::Normal, foundPathIn, uniqueIdentity }; } - static PathInfo makePath(const String& pathIn) { SLANG_ASSERT(pathIn.getLength() > 0); return PathInfo { Type::FoundPath, pathIn, String()}; } - static PathInfo makeTypeParse() { return PathInfo { Type::TypeParse, "type string", String() }; } - static PathInfo makeCommandLine() { return PathInfo { Type::CommandLine, "command line", String() }; } - static PathInfo makeFromString(const String& userPath) { return PathInfo{ Type::FromString, userPath, String() }; } - - Type type; ///< The type of path - String foundPath; ///< The path where the file was found (might contain relative elements) - String uniqueIdentity; ///< The unique identity of the file on the path found + // So simplify construction. In normal usage it's safer to use make methods over constructing + // directly. + static PathInfo makeUnknown() { return PathInfo{Type::Unknown, String(), String()}; } + static PathInfo makeTokenPaste() { return PathInfo{Type::TokenPaste, "token paste", String()}; } + static PathInfo makeNormal(const String& foundPathIn, const String& uniqueIdentity) + { + SLANG_ASSERT(uniqueIdentity.getLength() > 0 && foundPathIn.getLength() > 0); + return PathInfo{Type::Normal, foundPathIn, uniqueIdentity}; + } + static PathInfo makePath(const String& pathIn) + { + SLANG_ASSERT(pathIn.getLength() > 0); + return PathInfo{Type::FoundPath, pathIn, String()}; + } + static PathInfo makeTypeParse() { return PathInfo{Type::TypeParse, "type string", String()}; } + static PathInfo makeCommandLine() + { + return PathInfo{Type::CommandLine, "command line", String()}; + } + static PathInfo makeFromString(const String& userPath) + { + return PathInfo{Type::FromString, userPath, String()}; + } + + Type type; ///< The type of path + String foundPath; ///< The path where the file was found (might contain relative elements) + String uniqueIdentity; ///< The unique identity of the file on the path found }; class SourceLoc @@ -102,12 +137,13 @@ class SourceLoc public: SourceLoc() : raw(0) - {} + { + } - SourceLoc( - SourceLoc const& loc) + SourceLoc(SourceLoc const& loc) : raw(loc.raw) - {} + { + } SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return raw == rhs.raw; } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(raw == rhs.raw); } @@ -122,10 +158,7 @@ class SourceLoc return result; } - bool isValid() const - { - return raw != 0; - } + bool isValid() const { return raw != 0; } SourceLoc& operator=(const ThisType& rhs) = default; }; @@ -137,43 +170,54 @@ inline SourceLoc operator+(SourceLoc loc, Int offset) // A range of locations in the input source struct SourceRange { - /// True if the loc is in the range. Range is inclusive on begin to end. - bool contains(SourceLoc loc) const { const auto rawLoc = loc.getRaw(); return rawLoc >= begin.getRaw() && rawLoc <= end.getRaw(); } - /// Get the total size + /// True if the loc is in the range. Range is inclusive on begin to end. + bool contains(SourceLoc loc) const + { + const auto rawLoc = loc.getRaw(); + return rawLoc >= begin.getRaw() && rawLoc <= end.getRaw(); + } + /// Get the total size UInt getSize() const { return UInt(end.getRaw() - begin.getRaw()); } - /// Get the offset of a loc in this range - int getOffset(SourceLoc loc) const { SLANG_ASSERT(contains(loc)); return int(loc.getRaw() - begin.getRaw()); } + /// Get the offset of a loc in this range + int getOffset(SourceLoc loc) const + { + SLANG_ASSERT(contains(loc)); + return int(loc.getRaw() - begin.getRaw()); + } - /// Convert an offset to a loc - SourceLoc getSourceLocFromOffset(uint32_t offset) const { SLANG_ASSERT(offset <= getSize()); return begin + Int(offset); } + /// Convert an offset to a loc + SourceLoc getSourceLocFromOffset(uint32_t offset) const + { + SLANG_ASSERT(offset <= getSize()); + return begin + Int(offset); + } - SourceRange() - {} + SourceRange() {} SourceRange(SourceLoc loc) - : begin(loc) - , end(loc) - {} + : begin(loc), end(loc) + { + } SourceRange(SourceLoc begin, SourceLoc end) - : begin(begin) - , end(end) - {} + : begin(begin), end(end) + { + } SourceLoc begin; SourceLoc end; }; /// Source maps associated with files are could be of different uses. We use the SourceMapKind -/// to indicate the usage. -/// -/// If the source map is obfuscated reasonable/desirable to ignore them on emit (if we didn't we leak information, -/// and we don't emit into the locations in the obfuscated intermediate "file"). +/// to indicate the usage. +/// +/// If the source map is obfuscated reasonable/desirable to ignore them on emit (if we didn't we +/// leak information, and we don't emit into the locations in the obfuscated intermediate "file"). enum class SourceMapKind { - Normal, ///< A regular source map - Obfuscated, ///< Obfuscated source map + Normal, ///< A regular source map + Obfuscated, ///< Obfuscated source map }; // Pre-declare @@ -181,113 +225,124 @@ struct SourceManager; // A logical or physical storage object for a range of input code // that has logically contiguous source locations. -class SourceFile +class SourceFile { public: - struct OffsetRange { - /// We need a value to indicate an invalid range. We can't use 0 as that is valid for an offset range - /// We can't use a negative number, and don't want to make signed so we get the full 32-bits. - /// So we just use the max value as invalid + /// We need a value to indicate an invalid range. We can't use 0 as that is valid for an + /// offset range We can't use a negative number, and don't want to make signed so we get the + /// full 32-bits. So we just use the max value as invalid static const uint32_t kInvalid = 0xffffffff; - /// True if the range is valid + /// True if the range is valid SLANG_FORCE_INLINE bool isValid() const { return end >= start && start != kInvalid; } - /// True if offset is within range (inclusively) - SLANG_FORCE_INLINE bool containsInclusive(uint32_t offset) const { return offset >= start && offset <= end; } + /// True if offset is within range (inclusively) + SLANG_FORCE_INLINE bool containsInclusive(uint32_t offset) const + { + return offset >= start && offset <= end; + } - /// Get the count + /// Get the count SLANG_FORCE_INLINE uint32_t getCount() const { return end - start; } - /// Return an invalid range. - static OffsetRange makeInvalid() { return OffsetRange{ kInvalid, kInvalid }; } + /// Return an invalid range. + static OffsetRange makeInvalid() { return OffsetRange{kInvalid, kInvalid}; } uint32_t start; uint32_t end; }; - /// Returns the line break offsets (in bytes from start of content) - /// Note that this is lazily evaluated - the line breaks are only calculated on the first request + /// Returns the line break offsets (in bytes from start of content) + /// Note that this is lazily evaluated - the line breaks are only calculated on the first + /// request const List& getLineBreakOffsets(); - /// Returns true if the offset is on the specified line - /// NOTE! If offsets are not fully setup (because we don't have source), will only be correct for lines that have offsets + /// Returns true if the offset is on the specified line + /// NOTE! If offsets are not fully setup (because we don't have source), will only be correct + /// for lines that have offsets bool isOffsetOnLine(uint32_t offset, Index lineIndex); - /// Get the line containing the offset. Requires that content is available, else will return an empty slice. + /// Get the line containing the offset. Requires that content is available, else will return an + /// empty slice. UnownedStringSlice getLineContainingOffset(uint32_t offset); - /// Get the line at the specified line index. Requires that content is available, else will return an empty slice. + /// Get the line at the specified line index. Requires that content is available, else will + /// return an empty slice. UnownedStringSlice getLineAtIndex(Index lineIndex); - /// Get the offset range at the specified line index. Works without content. + /// Get the offset range at the specified line index. Works without content. OffsetRange getOffsetRangeAtLineIndex(Index lineIndex); - /// Set the line break offsets + /// Set the line break offsets void setLineBreakOffsets(const uint32_t* offsets, UInt numOffsets); - /// Calculate the line based on the offset + /// Calculate the line based on the offset int calcLineIndexFromOffset(int offset); - /// Calculate the offset (in bytes) for a line + /// Calculate the offset (in bytes) for a line int calcColumnOffset(int line, int offset); - /// Given a line and offset (in bytes for the whole file), return the column index, taking into account tabs - /// and utf8 encoding. - /// Passing tabSize uses the default tab size (currently tab set to 1) + /// Given a line and offset (in bytes for the whole file), return the column index, taking into + /// account tabs and utf8 encoding. Passing tabSize uses the default tab size (currently tab set + /// to 1) int calcColumnIndex(int line, int offset, int tabSize = -1); - /// Get the content holding blob - ISlangBlob* getContentBlob() const { return m_contentBlob; } + /// Get the content holding blob + ISlangBlob* getContentBlob() const { return m_contentBlob; } - /// True if has full set content - bool hasContent() const { return m_contentBlob != nullptr; } + /// True if has full set content + bool hasContent() const { return m_contentBlob != nullptr; } - /// Get the content size - size_t getContentSize() const { return m_contentSize; } + /// Get the content size + size_t getContentSize() const { return m_contentSize; } - /// Get the content - const UnownedStringSlice& getContent() const { return m_content; } + /// Get the content + const UnownedStringSlice& getContent() const { return m_content; } - /// Get path info - const PathInfo& getPathInfo() const { return m_pathInfo; } + /// Get path info + const PathInfo& getPathInfo() const { return m_pathInfo; } - /// Set the content as a blob + /// Set the content as a blob void setContents(ISlangBlob* blob); - /// Set the content as a string + /// Set the content as a string void setContents(const String& content); - /// Calculate a display path -> can canonicalize if necessary + /// Calculate a display path -> can canonicalize if necessary String calcVerbosePath() const; - /// Get the source manager this was created on + /// Get the source manager this was created on SourceManager* getSourceManager() const { return m_sourceManager; } - /// Get the source map associated with this file. If it's set when doing - /// lookup for source locations, the source map will be used + /// Get the source map associated with this file. If it's set when doing + /// lookup for source locations, the source map will be used IBoxValue* getSourceMap() const { return m_sourceMap; } - /// Get the source map kind + /// Get the source map kind SourceMapKind getSourceMapKind() const { return m_sourceMapKind; } - /// Set a source map - void setSourceMap(IBoxValue* sourceMap, SourceMapKind sourceMapKind) { m_sourceMap = sourceMap; m_sourceMapKind = sourceMapKind; } + /// Set a source map + void setSourceMap(IBoxValue* sourceMap, SourceMapKind sourceMapKind) + { + m_sourceMap = sourceMap; + m_sourceMapKind = sourceMapKind; + } - /// Ctor + /// Ctor SourceFile(SourceManager* sourceManager, const PathInfo& pathInfo, size_t contentSize); - /// Dtor + /// Dtor ~SourceFile(); SHA1::Digest getDigest(); - protected: - - SourceManager* m_sourceManager; ///< The source manager this belongs to - PathInfo m_pathInfo; ///< The path The logical file path to report for locations inside this span. +protected: + SourceManager* m_sourceManager; ///< The source manager this belongs to + PathInfo + m_pathInfo; ///< The path The logical file path to report for locations inside this span. - ComPtr m_contentBlob; ///< A blob that owns the storage for the file contents. If nullptr, there is no contents - UnownedStringSlice m_content; ///< The actual contents of the file. - size_t m_contentSize; ///< The size of the actual contents + ComPtr m_contentBlob; ///< A blob that owns the storage for the file contents. If + ///< nullptr, there is no contents + UnownedStringSlice m_content; ///< The actual contents of the file. + size_t m_contentSize; ///< The size of the actual contents SHA1::Digest m_digest; @@ -296,7 +351,7 @@ class SourceFile // the input file: List m_lineBreakOffsets; - // If set then the locations in this file are really from locations from elsewhere, + // If set then the locations in this file are really from locations from elsewhere, // where the SourceMap specifies that mapping ComPtr> m_sourceMap; // What kind of source map it is (if there is one) @@ -305,17 +360,20 @@ class SourceFile enum class SourceLocType { - Nominal, ///< The normal interpretation which takes into account #line directives and source maps - Actual, ///< Ignores #line directives/source maps - and is the location as seen in the actual file - Emit, ///< Behaves the same as `Nominal` but ignores source maps. Used for Emit source locations. + Nominal, ///< The normal interpretation which takes into account #line directives and source + ///< maps + Actual, ///< Ignores #line directives/source maps - and is the location as seen in the actual + ///< file + Emit, ///< Behaves the same as `Nominal` but ignores source maps. Used for Emit source + ///< locations. }; // A source location in a format a human might like to see struct HumaneSourceLoc { PathInfo pathInfo = PathInfo::makeUnknown(); - Int line = 0; - Int column = 0; + Int line = 0; + Int column = 0; }; // Same as HumaneSourceLoc but stores the path only as a handle. @@ -326,85 +384,95 @@ struct HandleSourceLoc Int column = 0; }; -/* A SourceView maps to a single span of SourceLoc range and is equivalent to a single include or more precisely use of a source file. -It is distinct from a SourceFile - because a SourceFile may be included multiple times, with different interpretations (depending -on #defines for example). -*/ +/* A SourceView maps to a single span of SourceLoc range and is equivalent to a single include or +more precisely use of a source file. It is distinct from a SourceFile - because a SourceFile may be +included multiple times, with different interpretations (depending on #defines for example). +*/ class SourceView { - public: - +public: // Each entry represents some contiguous span of locations that // all map to the same logical file. struct Entry { - /// True if this resets the line numbering. It is distinct from a m_lineAdjust being 0, because it also means the path returns to the default. + /// True if this resets the line numbering. It is distinct from a m_lineAdjust being 0, + /// because it also means the path returns to the default. bool isDefault() const { return m_pathHandle == StringSlicePool::Handle(0); } - SourceLoc m_startLoc; ///< Where does this entry begin? - StringSlicePool::Handle m_pathHandle; ///< What is the presumed path for this entry. If 0 it means there is no path. - int32_t m_lineAdjust; ///< Adjustment to apply to source line numbers when printing presumed locations. Relative to the line number in the underlying file. + SourceLoc m_startLoc; ///< Where does this entry begin? + StringSlicePool::Handle m_pathHandle; ///< What is the presumed path for this entry. If 0 it + ///< means there is no path. + int32_t m_lineAdjust; ///< Adjustment to apply to source line numbers when printing presumed + ///< locations. Relative to the line number in the underlying file. }; - /// Given a sourceLoc finds the entry associated with it. If returns -1 then no entry is - /// associated with this location, and therefore the location should be interpreted as an offset - /// into the underlying sourceFile. + /// Given a sourceLoc finds the entry associated with it. If returns -1 then no entry is + /// associated with this location, and therefore the location should be interpreted as an offset + /// into the underlying sourceFile. int findEntryIndex(SourceLoc sourceLoc) const; - /// Add a line directive for this view. The directiveLoc must of course be in this SourceView - /// The path handle, must have been constructed on the SourceManager associated with the view - /// NOTE! Directives are assumed to be added IN ORDER during parsing such that every directiveLoc > previous + /// Add a line directive for this view. The directiveLoc must of course be in this SourceView + /// The path handle, must have been constructed on the SourceManager associated with the view + /// NOTE! Directives are assumed to be added IN ORDER during parsing such that every + /// directiveLoc > previous void addLineDirective(SourceLoc directiveLoc, StringSlicePool::Handle pathHandle, int line); void addLineDirective(SourceLoc directiveLoc, const String& path, int line); - /// Removes any corrections on line numbers and reverts to the source files path + /// Removes any corrections on line numbers and reverts to the source files path void addDefaultLineDirective(SourceLoc directiveLoc); - /// Get the range that this view applies to + /// Get the range that this view applies to const SourceRange& getRange() const { return m_range; } - /// Get the entries + /// Get the entries const List& getEntries() const { return m_entries; } - /// Set the entries list - void setEntries(const Entry* entries, UInt numEntries) { m_entries.clear(); m_entries.addRange(entries, numEntries); } + /// Set the entries list + void setEntries(const Entry* entries, UInt numEntries) + { + m_entries.clear(); + m_entries.addRange(entries, numEntries); + } - /// Get the source file holds the contents this view + /// Get the source file holds the contents this view SourceFile* getSourceFile() const { return m_sourceFile; } - /// Get the source manager + /// Get the source manager SourceManager* getSourceManager() const { return m_sourceFile->getSourceManager(); } - /// Get the associated 'content' (the source text) + /// Get the associated 'content' (the source text) const UnownedStringSlice& getContent() const { return m_sourceFile->getContent(); } - /// Get the size of the content + /// Get the size of the content size_t getContentSize() const { return m_sourceFile->getContentSize(); } - /// Get the humane location - /// Type determines if the location wanted is the original, or the 'normal' (which modifys behavior based on #line directives) + /// Get the humane location + /// Type determines if the location wanted is the original, or the 'normal' (which modifys + /// behavior based on #line directives) HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); - /// Get the humane location, but store the path as a handle + /// Get the humane location, but store the path as a handle HandleSourceLoc getHandleLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); - /// Get the path associated with a location + /// Get the path associated with a location PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); - /// Get the initiating source location - that is the source location that caused the this SourceView to be created - /// Can be SourceLoc(0) if there is no initiating location. - /// For example for a #include - the view's initiating source loc for the view that is the contents of the view - /// will be the location of the #include in the source. - /// For the original source file (ie not an include) - the view will have an initiating source loc of SourceLoc(0) + /// Get the initiating source location - that is the source location that caused the this + /// SourceView to be created Can be SourceLoc(0) if there is no initiating location. For example + /// for a #include - the view's initiating source loc for the view that is the contents of the + /// view will be the location of the #include in the source. For the original source file (ie + /// not an include) - the view will have an initiating source loc of SourceLoc(0) SourceLoc getInitiatingSourceLoc() const { return m_initiatingSourceLoc; } - /// Gets the pathInfo for this view. It may be different from the m_sourceFile's if the path has been - /// overridden by m_viewPath + /// Gets the pathInfo for this view. It may be different from the m_sourceFile's if the path has + /// been overridden by m_viewPath PathInfo getViewPathInfo() const; - /// Ctor - SourceView(SourceFile* sourceFile, SourceRange range, const String* viewPath, SourceLoc initiatingSourceLoc): - m_range(range), - m_sourceFile(sourceFile), - m_initiatingSourceLoc(initiatingSourceLoc) + /// Ctor + SourceView( + SourceFile* sourceFile, + SourceRange range, + const String* viewPath, + SourceLoc initiatingSourceLoc) + : m_range(range), m_sourceFile(sourceFile), m_initiatingSourceLoc(initiatingSourceLoc) { if (viewPath) { @@ -412,116 +480,122 @@ class SourceView } } - protected: - /// Get the pathInfo from a string handle. If it's 0, it will return the _getPathInfo +protected: + /// Get the pathInfo from a string handle. If it's 0, it will return the _getPathInfo PathInfo _getPathInfoFromHandle(StringSlicePool::Handle pathHandle) const; - + SlangResult _findSourceMapLoc(SourceLoc loc, SourceLocType type, HandleSourceLoc& outLoc); - String m_viewPath; ///< Path to this view. If empty the path is the path to the SourceView + String m_viewPath; ///< Path to this view. If empty the path is the path to the SourceView - SourceLoc m_initiatingSourceLoc; ///< An optional source loc that defines where this view was initiated from. SourceLoc(0) if not defined. + SourceLoc m_initiatingSourceLoc; ///< An optional source loc that defines where this view was + ///< initiated from. SourceLoc(0) if not defined. - SourceRange m_range; ///< The range that this SourceView applies to - SourceFile* m_sourceFile; ///< The source file. Can hold the line breaks - List m_entries; ///< An array entries describing how we should interpret a range, starting from the start location. + SourceRange m_range; ///< The range that this SourceView applies to + SourceFile* m_sourceFile; ///< The source file. Can hold the line breaks + List m_entries; ///< An array entries describing how we should interpret a range, + ///< starting from the start location. }; struct SourceManager { - // Initialize a source manager, with an optional parent + // Initialize a source manager, with an optional parent void initialize(SourceManager* parent, ISlangFileSystemExt* fileSystemExt); - /// Allocate a range of SourceLoc locations, these can be used to identify a specific location in the source + /// Allocate a range of SourceLoc locations, these can be used to identify a specific location + /// in the source SourceRange allocateSourceRange(UInt size); - /// Returns the loc for start of next allocation + /// Returns the loc for start of next allocation SourceLoc getNextRangeStart() const { return m_nextLoc; } - /// Create a SourceFile defined with the specified path, and content held within a blob + /// Create a SourceFile defined with the specified path, and content held within a blob SourceFile* createSourceFileWithSize(const PathInfo& pathInfo, size_t contentSize); SourceFile* createSourceFileWithString(const PathInfo& pathInfo, const String& contents); SourceFile* createSourceFileWithBlob(const PathInfo& pathInfo, ISlangBlob* blob); - /// Get the humane source location + /// Get the humane source location HumaneSourceLoc getHumaneLoc(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); - /// Get the path associated with a location + /// Get the path associated with a location PathInfo getPathInfo(SourceLoc loc, SourceLocType type = SourceLocType::Nominal); - /// Create a new source view from a file - /// @param sourceFile is the source file that contains the source - /// @param pathInfo is path used to read the file from - /// @param initiatingSourceLoc the (optional) location in the source that led the the creation of this view. If there isn't an initiating source location pass SourceLoc(0)s - SourceView* createSourceView(SourceFile* sourceFile, const PathInfo* pathInfo, SourceLoc initiatingSourceLoc); - - /// Find a view by a source file location. - /// If not found in this manager will look in the parent SourceManager - /// Returns nullptr if not found. + /// Create a new source view from a file + /// @param sourceFile is the source file that contains the source + /// @param pathInfo is path used to read the file from + /// @param initiatingSourceLoc the (optional) location in the source that led the the creation + /// of this view. If there isn't an initiating source location pass SourceLoc(0)s + SourceView* createSourceView( + SourceFile* sourceFile, + const PathInfo* pathInfo, + SourceLoc initiatingSourceLoc); + + /// Find a view by a source file location. + /// If not found in this manager will look in the parent SourceManager + /// Returns nullptr if not found. SourceView* findSourceViewRecursively(SourceLoc loc) const; - /// Find the SourceView associated with this manager for a specified location - /// Returns nullptr if not found. + /// Find the SourceView associated with this manager for a specified location + /// Returns nullptr if not found. SourceView* findSourceView(SourceLoc loc) const; - /// Searches this manager, and then the parent to see if can find a match for path. - /// If not found returns nullptr. + /// Searches this manager, and then the parent to see if can find a match for path. + /// If not found returns nullptr. SourceFile* findSourceFileRecursively(const String& uniqueIdentity) const; - /// Find if the source file is defined on this manager. + /// Find if the source file is defined on this manager. SourceFile* findSourceFile(const String& uniqueIdentity) const; - /// Find a source file by path. + /// Find a source file by path. SourceFile* findSourceFileByPath(const String& name) const; - /// Find a source file by path recursively. + /// Find a source file by path recursively. SourceFile* findSourceFileByPathRecursively(const String& name) const; - /// Searches this manager, and then the parent to see if can find a match + /// Searches this manager, and then the parent to see if can find a match SourceFile* findSourceFileByContentRecursively(const char* text); - /// Find the source file that contains *the memory* text points to. + /// Find the source file that contains *the memory* text points to. SourceFile* findSourceFileByContent(const char* text) const; - - /// Get the file system associated with this source manager - ISlangFileSystemExt* getFileSystemExt() const { return m_fileSystemExt; } - /// Get the file system associated with this source manager - void setFileSystemExt(ISlangFileSystemExt* fileSystemExt) { m_fileSystemExt = fileSystemExt; } - /// Add a source file, uniqueIdentity must be unique for this manager AND any parents + /// Get the file system associated with this source manager + ISlangFileSystemExt* getFileSystemExt() const { return m_fileSystemExt; } + /// Get the file system associated with this source manager + void setFileSystemExt(ISlangFileSystemExt* fileSystemExt) { m_fileSystemExt = fileSystemExt; } + + /// Add a source file, uniqueIdentity must be unique for this manager AND any parents void addSourceFile(const String& uniqueIdentity, SourceFile* sourceFile); void addSourceFileIfNotExist(const String& uniqueIdentity, SourceFile* sourceFile); - /// Get the slice pool + /// Get the slice pool StringSlicePool& getStringSlicePool() { return m_slicePool; } - /// Get the source range for just this manager - /// Caution - the range will change if allocations are made to this manager. - SourceRange getSourceRange() const { return SourceRange(m_startLoc, m_nextLoc); } - - /// Get the parent manager to this manager. Returns nullptr if there isn't any. + /// Get the source range for just this manager + /// Caution - the range will change if allocations are made to this manager. + SourceRange getSourceRange() const { return SourceRange(m_startLoc, m_nextLoc); } + + /// Get the parent manager to this manager. Returns nullptr if there isn't any. SourceManager* getParent() const { return m_parent; } - /// A memory arena to hold allocations that are in scope for the same time as SourceManager - MemoryArena* getMemoryArena() { return &m_memoryArena; } + /// A memory arena to hold allocations that are in scope for the same time as SourceManager + MemoryArena* getMemoryArena() { return &m_memoryArena; } - /// Allocate a string slice + /// Allocate a string slice UnownedStringSlice allocateStringSlice(const UnownedStringSlice& slice); - /// Get all of the source files + /// Get all of the source files const List& getSourceFiles() const { return m_sourceFiles; } - /// Get the source views + /// Get the source views const List& getSourceViews() const { return m_sourceViews; } - /// Resets state. Will release all views/source + /// Resets state. Will release all views/source void reset(); - SourceManager() : - m_memoryArena(2048), - m_slicePool(StringSlicePool::Style::Default) - {} + SourceManager() + : m_memoryArena(2048), m_slicePool(StringSlicePool::Style::Default) + { + } ~SourceManager(); - protected: - +protected: void _resetLoc(); void _resetSource(); @@ -536,7 +610,8 @@ struct SourceManager // The location to be used by the next source file to be loaded SourceLoc m_nextLoc; - // All of the SourceViews constructed on this SourceManager. These are held in increasing order of range, so can find by doing a binary chop. + // All of the SourceViews constructed on this SourceManager. These are held in increasing order + // of range, so can find by doing a binary chop. List m_sourceViews; // All of the SourceFiles constructed on this SourceManager. This owns the SourceFile. List m_sourceFiles; diff --git a/source/compiler-core/slang-source-map.cpp b/source/compiler-core/slang-source-map.cpp index 533c6bde05..9c38e876f2 100644 --- a/source/compiler-core/slang-source-map.cpp +++ b/source/compiler-core/slang-source-map.cpp @@ -1,6 +1,7 @@ #include "slang-source-map.h" -namespace Slang { +namespace Slang +{ void SourceMap::clear() { @@ -35,7 +36,10 @@ void SourceMap::swapWith(ThisType& rhs) m_slicePool.swapWith(rhs.m_slicePool); } -static bool _areEqual(const List& a, const List& b, const List& bToAMap) +static bool _areEqual( + const List& a, + const List& b, + const List& bToAMap) { const auto count = a.getCount(); if (count != b.getCount()) @@ -57,16 +61,20 @@ static bool _areEqual(const List& a, const List& bToAMap) +static bool _areEqual( + const SourceMap::Entry& a, + const SourceMap::Entry& b, + const List& bToAMap) { - return a.generatedColumn == b.generatedColumn && - a.sourceLine == b.sourceLine && - a.sourceColumn == b.sourceColumn && - a.sourceFileIndex == bToAMap[b.sourceFileIndex] && - a.nameIndex == bToAMap[b.nameIndex]; + return a.generatedColumn == b.generatedColumn && a.sourceLine == b.sourceLine && + a.sourceColumn == b.sourceColumn && a.sourceFileIndex == bToAMap[b.sourceFileIndex] && + a.nameIndex == bToAMap[b.nameIndex]; } -static bool _areEqual(const List& a, const List&b, const List& bToAMap) +static bool _areEqual( + const List& a, + const List& b, + const List& bToAMap) { const auto count = a.getCount(); if (count != b.getCount()) @@ -92,8 +100,7 @@ bool SourceMap::operator==(const ThisType& rhs) const return true; } - if (m_file != rhs.m_file || - m_sourceRoot != rhs.m_sourceRoot || + if (m_file != rhs.m_file || m_sourceRoot != rhs.m_sourceRoot || m_lineStarts != rhs.m_lineStarts) { return false; @@ -102,21 +109,19 @@ bool SourceMap::operator==(const ThisType& rhs) const if (m_slicePool == rhs.m_slicePool) { // If the slice pools are the same we can just compare indices directly - return m_sources == rhs.m_sources && - m_sourcesContent == rhs.m_sourcesContent && - m_names == rhs.m_names && - m_lineEntries == rhs.m_lineEntries; + return m_sources == rhs.m_sources && m_sourcesContent == rhs.m_sourcesContent && + m_names == rhs.m_names && m_lineEntries == rhs.m_lineEntries; } else { // Otherwise we need to remap the indices - // Maps a pool handle from the rhs source map to the + // Maps a pool handle from the rhs source map to the List rhsMap; Count count = rhs.m_slicePool.getSlicesCount(); rhsMap.setCount(count); - + const auto startIndex = rhs.m_slicePool.getFirstAddedIndex(); // Work out the map @@ -128,9 +133,9 @@ bool SourceMap::operator==(const ThisType& rhs) const // Do the comparison taking into account the mapping. return _areEqual(m_sources, rhs.m_sources, rhsMap) && - _areEqual(m_sourcesContent, rhs.m_sourcesContent, rhsMap) && - _areEqual(m_names, rhs.m_names, rhsMap) && - _areEqual(m_lineEntries, rhs.m_lineEntries, rhsMap); + _areEqual(m_sourcesContent, rhs.m_sourcesContent, rhsMap) && + _areEqual(m_names, rhs.m_names, rhsMap) && + _areEqual(m_lineEntries, rhs.m_lineEntries, rhsMap); } } @@ -139,7 +144,7 @@ void SourceMap::advanceToLine(Index nextLineIndex) const Count currentLineIndex = getGeneratedLineCount() - 1; SLANG_ASSERT(nextLineIndex >= currentLineIndex); - + if (nextLineIndex <= currentLineIndex) { return; @@ -147,7 +152,7 @@ void SourceMap::advanceToLine(Index nextLineIndex) const auto lastEntryIndex = m_lineEntries.getCount(); - // For all the new entries they will need to point to the end + // For all the new entries they will need to point to the end m_lineStarts.growToCount(nextLineIndex + 1); Index* starts = m_lineStarts.getBuffer(); diff --git a/source/compiler-core/slang-source-map.h b/source/compiler-core/slang-source-map.h index 4060fadb88..73952225ad 100644 --- a/source/compiler-core/slang-source-map.h +++ b/source/compiler-core/slang-source-map.h @@ -1,21 +1,20 @@ #ifndef SLANG_COMPILER_CORE_SOURCE_MAP_H #define SLANG_COMPILER_CORE_SOURCE_MAP_H -#include "slang.h" - -#include "../core/slang-string.h" #include "../core/slang-list.h" - #include "../core/slang-string-slice-pool.h" +#include "../core/slang-string.h" +#include "slang.h" -namespace Slang { +namespace Slang +{ -class SourceMap +class SourceMap { public: typedef SourceMap ThisType; - SLANG_CLASS_GUID(0x731383ea, 0xe516, 0x4cc3, { 0xa6, 0xcf, 0x37, 0xd2, 0x8c, 0x24, 0x5c, 0x5e }); + SLANG_CLASS_GUID(0x731383ea, 0xe516, 0x4cc3, {0xa6, 0xcf, 0x37, 0xd2, 0x8c, 0x24, 0x5c, 0x5e}); struct Entry { @@ -33,73 +32,71 @@ class SourceMap bool operator==(const ThisType& rhs) const { return generatedColumn == rhs.generatedColumn && - sourceFileIndex == rhs.sourceFileIndex && - sourceLine == rhs.sourceLine && - sourceColumn == rhs.sourceColumn && - nameIndex == rhs.nameIndex; + sourceFileIndex == rhs.sourceFileIndex && sourceLine == rhs.sourceLine && + sourceColumn == rhs.sourceColumn && nameIndex == rhs.nameIndex; } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } // Note! All column/line are zero indexed - Index generatedColumn; ///< The generated column - Index sourceFileIndex; ///< The index into the source name/contents - Index sourceLine; ///< The line number in the originating source - Index sourceColumn; ///< The column number in the originating source - Index nameIndex; ///< Name index + Index generatedColumn; ///< The generated column + Index sourceFileIndex; ///< The index into the source name/contents + Index sourceLine; ///< The line number in the originating source + Index sourceColumn; ///< The column number in the originating source + Index nameIndex; ///< Name index }; - /// Get the total number of generated lines + /// Get the total number of generated lines Count getGeneratedLineCount() const { return m_lineStarts.getCount(); } - /// Get the entries on the line + /// Get the entries on the line SLANG_FORCE_INLINE ConstArrayView getEntriesForLine(Index generatedLine) const; - - /// Advance to the specified line index. - /// It is an error to specify a line *before* the current line. It should either be the current - /// output line or a later output line. Interveining lines will be set as empty + + /// Advance to the specified line index. + /// It is an error to specify a line *before* the current line. It should either be the current + /// output line or a later output line. Interveining lines will be set as empty void advanceToLine(Index lineIndex); - /// Add an entry to the current line + /// Add an entry to the current line void addEntry(const Entry& entry) { m_lineEntries.add(entry); } - /// Given the slice returns the index + /// Given the slice returns the index Index getSourceFileIndex(const UnownedStringSlice& slice); - /// Get the name index + /// Get the name index Index getNameIndex(const UnownedStringSlice& slice); - /// Given a row and col index, find the closest entry - /// NOTE! Zero indexed line and column. + /// Given a row and col index, find the closest entry + /// NOTE! Zero indexed line and column. Index findEntry(Index lineIndex, Index colIndex) const; - /// Given an entry index return the entry - const Entry& getEntryByIndex(Index i) const {return m_lineEntries[i]; } + /// Given an entry index return the entry + const Entry& getEntryByIndex(Index i) const { return m_lineEntries[i]; } - /// Given the sourceFileIndex return the name + /// Given the sourceFileIndex return the name UnownedStringSlice getSourceFileName(Index sourceFileIndex) const; - /// Clear the contents of the source map + /// Clear the contents of the source map void clear(); - /// Swap this with rhs + /// Swap this with rhs void swapWith(ThisType& rhs); - /// == - /// - /// Note that equality requires that entries for a line must be *in the same order* - /// even though strictly speaking with different orders could be considered equivalent. + /// == + /// + /// Note that equality requires that entries for a line must be *in the same order* + /// even though strictly speaking with different orders could be considered equivalent. bool operator==(const ThisType& rhs) const; - /// != + /// != bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - /// Ctor - SourceMap(): - m_slicePool(StringSlicePool::Style::Default) + /// Ctor + SourceMap() + : m_slicePool(StringSlicePool::Style::Default) { clear(); } - /// Copy Ctor + /// Copy Ctor SourceMap(const ThisType& rhs) = default; - /// Assignment + /// Assignment ThisType& operator=(const ThisType& rhs) = default; String m_file; @@ -107,10 +104,10 @@ class SourceMap List m_sources; - /// Storage for the contents. Can be unset null to indicate not set. + /// Storage for the contents. Can be unset null to indicate not set. List m_sourcesContent; - - /// The names + + /// The names List m_names; List m_lineStarts; @@ -120,13 +117,16 @@ class SourceMap }; // ------------------------------------------------------------- -SLANG_FORCE_INLINE ConstArrayView SourceMap::getEntriesForLine(Index generatedLine) const +SLANG_FORCE_INLINE ConstArrayView SourceMap::getEntriesForLine( + Index generatedLine) const { SLANG_ASSERT(generatedLine >= 0 && generatedLine < m_lineStarts.getCount()); const Index start = m_lineStarts[generatedLine]; - const Index end = (generatedLine + 1 >= m_lineStarts.getCount()) ? m_lineEntries.getCount() : m_lineStarts[generatedLine + 1]; + const Index end = (generatedLine + 1 >= m_lineStarts.getCount()) + ? m_lineEntries.getCount() + : m_lineStarts[generatedLine + 1]; const auto entries = m_lineEntries.begin(); diff --git a/source/compiler-core/slang-spirv-core-grammar.cpp b/source/compiler-core/slang-spirv-core-grammar.cpp index 9a4a7e17f1..8b5e790718 100644 --- a/source/compiler-core/slang-spirv-core-grammar.cpp +++ b/source/compiler-core/slang-spirv-core-grammar.cpp @@ -2,8 +2,9 @@ #include "../core/slang-rtti-util.h" #include "../core/slang-string-util.h" -#include "slang-json-native.h" #include "slang-core-diagnostics.h" +#include "slang-json-native.h" + #include namespace Slang @@ -22,8 +23,7 @@ struct InstructionPrintingClass SLANG_MAKE_STRUCT_RTTI_INFO( InstructionPrintingClass, SLANG_RTTI_FIELD(tag), - SLANG_OPTIONAL_RTTI_FIELD(heading) -); + SLANG_OPTIONAL_RTTI_FIELD(heading)); struct Operand { @@ -35,7 +35,7 @@ SLANG_MAKE_STRUCT_RTTI_INFO( Operand, SLANG_RTTI_FIELD(kind), SLANG_OPTIONAL_RTTI_FIELD(quantifier) - //SLANG_RTTI_FIELD(name), + // SLANG_RTTI_FIELD(name), ); struct Instruction @@ -52,14 +52,14 @@ SLANG_MAKE_STRUCT_RTTI_INFO( SLANG_RTTI_FIELD_IMPL(class_, "class", 0), SLANG_RTTI_FIELD(opcode), SLANG_OPTIONAL_RTTI_FIELD(capabilities), - SLANG_OPTIONAL_RTTI_FIELD(operands) -); + SLANG_OPTIONAL_RTTI_FIELD(operands)); struct Enumerant { UnownedStringSlice enumerant; JSONValue value; List capabilities; + List aliases; // List parameters; // UnownedStringSlice version; // UnownedStringSlice lastVersion; @@ -70,6 +70,7 @@ SLANG_MAKE_STRUCT_RTTI_INFO( SLANG_RTTI_FIELD(enumerant), SLANG_RTTI_FIELD(value), SLANG_OPTIONAL_RTTI_FIELD(capabilities), + SLANG_OPTIONAL_RTTI_FIELD(aliases), // SLANG_OPTIONAL_RTTI_FIELD(parameters), // SLANG_OPTIONAL_RTTI_FIELD(version), // SLANG_OPTIONAL_RTTI_FIELD(lastVersion), @@ -86,8 +87,7 @@ SLANG_MAKE_STRUCT_RTTI_INFO( OperandKind, SLANG_RTTI_FIELD(category), SLANG_RTTI_FIELD(kind), - SLANG_OPTIONAL_RTTI_FIELD(enumerants) -); + SLANG_OPTIONAL_RTTI_FIELD(enumerants)); struct SPIRVSpec { @@ -109,49 +109,51 @@ SLANG_MAKE_STRUCT_RTTI_INFO( // SLANG_RTTI_FIELD(revision) SLANG_RTTI_FIELD(instruction_printing_class), SLANG_RTTI_FIELD(instructions), - SLANG_RTTI_FIELD(operand_kinds) -); + SLANG_RTTI_FIELD(operand_kinds)); static Dictionary operandKindToDict( - JSONContainer& container, - DiagnosticSink& sink, - const OperandKind& k) + JSONContainer& container, + DiagnosticSink& sink, + const OperandKind& k) { Dictionary dict; dict.reserve(k.enumerants.getCount()); - for(const auto& e : k.enumerants) + for (const auto& e : k.enumerants) { SpvWord valueInt = 0; - switch(e.value.getKind()) + switch (e.value.getKind()) { - case JSONValue::Kind::Integer: + case JSONValue::Kind::Integer: { // TODO: Range check here? valueInt = SpvWord(container.asInteger(e.value)); break; } - case JSONValue::Kind::String: + case JSONValue::Kind::String: { Int i = 0; const auto str = container.getString(e.value); - if(SLANG_FAILED(StringUtil::parseInt(str, i))) + if (SLANG_FAILED(StringUtil::parseInt(str, i))) sink.diagnose( e.value.loc, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "Expected an integer value" - ); + "Expected an integer value"); // TODO: Range check here? valueInt = SpvWord(i); break; - } - default: - sink.diagnose( - e.value.loc, - MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "Expected an integer value (or a string with an integer inside)" - ); + } + default: + sink.diagnose( + e.value.loc, + MiscDiagnostics::spirvCoreGrammarJSONParseFailure, + "Expected an integer value (or a string with an integer inside)"); } dict.add(e.enumerant, valueInt); + + for (auto alias : e.aliases) + { + dict.add(alias, valueInt); + } } return dict; } @@ -159,7 +161,9 @@ static Dictionary operandKindToDict( // // // -RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& source, DiagnosticSink& sink) +RefPtr SPIRVCoreGrammarInfo::loadFromJSON( + SourceView& source, + DiagnosticSink& sink) { // // Load the JSON @@ -175,14 +179,13 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour SLANG_RETURN_NULL_ON_FAIL(parser.parse(&lexer, &source, &builder, &sink)); JSONToNativeConverter converter(&container, &typeMap, &sink); SPIRVSpec spec; - if(SLANG_FAILED(converter.convert(builder.getRootValue(), &spec))) + if (SLANG_FAILED(converter.convert(builder.getRootValue(), &spec))) { // TODO: not having a source loc here is not great... sink.diagnoseWithoutSourceView( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "Failed to match SPIR-V grammar JSON to the expected schema" - ); + "Failed to match SPIR-V grammar JSON to the expected schema"); return nullptr; } @@ -193,42 +196,42 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour res->operandKinds.dict.reserve(spec.operand_kinds.getCount()); uint32_t operandKindIndex = 0; - for(const auto& c : spec.operand_kinds) + for (const auto& c : spec.operand_kinds) { - if(operandKindIndex > std::numeric_limits::max()) + if (operandKindIndex > std::numeric_limits::max()) { sink.diagnoseWithoutSourceView( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "Too many enum categories, expected fewer than 256" - ); + "Too many enum categories, expected fewer than 256"); } - res->operandKinds.dict.add(c.kind, {static_cast(operandKindIndex)}); + res->operandKinds.dict.add( + c.kind, + {static_cast(operandKindIndex)}); operandKindIndex++; } // It's important we reserve the memory now, as we require the iterators to // be stable, as references to them are maintained by the OpInfo structs. Index totalNumOperands = 0; - for(const auto& i : spec.instructions) + for (const auto& i : spec.instructions) totalNumOperands += i.operands.getCapacity(); res->operandTypesStorage.reserve(totalNumOperands); res->opcodes.dict.reserve(spec.instructions.getCount()); - for(const auto& i : spec.instructions) + for (const auto& i : spec.instructions) { res->opcodes.dict.add(i.opname, SpvOp(i.opcode)); - const auto class_ = - i.class_ == "Type-Declaration" ? OpInfo::TypeDeclaration - : i.class_ == "Constant-Creation" ? OpInfo::ConstantCreation - : i.class_ == "Debug" ? OpInfo::Debug - : OpInfo::Other; + const auto class_ = i.class_ == "Type-Declaration" ? OpInfo::TypeDeclaration + : i.class_ == "Constant-Creation" ? OpInfo::ConstantCreation + : i.class_ == "Debug" ? OpInfo::Debug + : OpInfo::Other; - const auto resultTypeIndex - = i.operands.findFirstIndex([](const auto& o){return o.kind == "IdResultType";}); - const auto resultIdIndex - = i.operands.findFirstIndex([](const auto& o){return o.kind == "IdResult";}); + const auto resultTypeIndex = + i.operands.findFirstIndex([](const auto& o) { return o.kind == "IdResultType"; }); + const auto resultIdIndex = + i.operands.findFirstIndex([](const auto& o) { return o.kind == "IdResult"; }); SLANG_ASSERT(resultTypeIndex >= -1 || resultTypeIndex <= 0); SLANG_ASSERT(resultIdIndex >= -1 || resultTypeIndex <= 1); @@ -236,9 +239,9 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour uint16_t maxOperandCount = 0; uint16_t numOperandTypes = 0; const OperandKind* operandTypes = res->operandTypesStorage.end(); - for(const auto& o : i.operands) + for (const auto& o : i.operands) { - if(maxOperandCount == 0xffff) + if (maxOperandCount == 0xffff) { // We are about to overflow maxWordCount, either someone has // put 2^16 operands in the json, or we have a "*" quantified @@ -247,18 +250,16 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour sink.diagnoseWithoutSourceView( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "\"*\"-qualified operand wasn't the last operand" - ); + "\"*\"-qualified operand wasn't the last operand"); } const auto catIndex = res->operandKinds.lookup(o.kind); - if(!catIndex) + if (!catIndex) { sink.diagnoseWithoutSourceView( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "Operand references a kind which doesn't exist" - ); + "Operand references a kind which doesn't exist"); continue; } @@ -267,24 +268,23 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour // The number of "ImageOperands" is dependent on the bitmask // operand, for our purposes treat them as unbounded - if(o.quantifier == "*" || o.kind == "ImageOperands") + if (o.quantifier == "*" || o.kind == "ImageOperands") { maxOperandCount = 0xffff; } - else if(o.quantifier == "?") + else if (o.quantifier == "?") { maxOperandCount++; } - else if(o.quantifier == "") + else if (o.quantifier == "") { // This catches the case where an "?" or "*" qualified operand // appears before any unqualified operands - if(minOperandCount != maxOperandCount) + if (minOperandCount != maxOperandCount) sink.diagnoseWithoutSourceView( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "\"*\" or \"?\" operand appeared before an unqualified operand" - ); + "\"*\" or \"?\" operand appeared before an unqualified operand"); minOperandCount++; maxOperandCount++; } @@ -293,31 +293,30 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour sink.diagnose( SourceLoc{}, MiscDiagnostics::spirvCoreGrammarJSONParseFailure, - "quantifier wasn't empty, * or ?" - ); + "quantifier wasn't empty, * or ?"); } } // There are duplicate opcodes in the json (for renamed instructions, // or the same instruction with different capabilities), for now just // keep the first one. - res->opInfos.dict.addIfNotExists(SpvOp(i.opcode), { - class_, - static_cast(resultTypeIndex), - static_cast(resultIdIndex), - minOperandCount, - maxOperandCount, - numOperandTypes, - operandTypes - }); + res->opInfos.dict.addIfNotExists( + SpvOp(i.opcode), + {class_, + static_cast(resultTypeIndex), + static_cast(resultIdIndex), + minOperandCount, + maxOperandCount, + numOperandTypes, + operandTypes}); res->opNames.dict.addIfNotExists(SpvOp(i.opcode), i.opname); } - for(const auto& k : spec.operand_kinds) + for (const auto& k : spec.operand_kinds) { const auto kindIndex = res->operandKinds.dict.getValue(k.kind); const auto d = operandKindToDict(container, sink, k); - for(const auto& [n, v] : d) + for (const auto& [n, v] : d) { // Add the string to this slice pool as we'll be taking ownership // of it shortly but don't want to invalidate it in the meantime. @@ -329,17 +328,17 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour res->operandKindNames.dict.add(kindIndex, k.kind); - if(k.kind == "Capability") - for(const auto& [n, v] : d) + if (k.kind == "Capability") + for (const auto& [n, v] : d) res->capabilities.dict.add(n, SpvCapability(v)); // If this starts with Id, and the suffix is also an operand kind, // assume that this is an Id wrapper - if(k.kind.startsWith("Id")) + if (k.kind.startsWith("Id")) { - const UnownedStringSlice underneathIdKind{k.kind.begin()+2, k.kind.end()}; + const UnownedStringSlice underneathIdKind{k.kind.begin() + 2, k.kind.end()}; OperandKind targetIndex; - if(res->operandKinds.dict.tryGetValue(underneathIdKind, targetIndex)) + if (res->operandKinds.dict.tryGetValue(underneathIdKind, targetIndex)) res->operandKindUnderneathIds.dict.add(kindIndex, targetIndex); } } @@ -347,4 +346,4 @@ RefPtr SPIRVCoreGrammarInfo::loadFromJSON(SourceView& sour res->strings.swapWith(container.getStringSlicePool()); return res; } -} +} // namespace Slang diff --git a/source/compiler-core/slang-spirv-core-grammar.h b/source/compiler-core/slang-spirv-core-grammar.h index 958aaaef2d..e91caa79aa 100644 --- a/source/compiler-core/slang-spirv-core-grammar.h +++ b/source/compiler-core/slang-spirv-core-grammar.h @@ -1,146 +1,147 @@ #pragma once +#include "../core/slang-dictionary.h" #include "../core/slang-smart-pointer.h" -#include "../core/slang-string.h" #include "../core/slang-string-slice-pool.h" -#include "../core/slang-dictionary.h" -#include "../../external/spirv-headers/include/spirv/unified1/spirv.h" +#include "../core/slang-string.h" + #include +#include namespace Slang { - using SpvWord = uint32_t; - class DiagnosticSink; - class SourceView; +using SpvWord = uint32_t; +class DiagnosticSink; +class SourceView; - struct SPIRVCoreGrammarInfo : public RefObject - { - static RefPtr loadFromJSON(SourceView& source, DiagnosticSink& sink); - static RefPtr& getEmbeddedVersion(); - static inline void freeEmbeddedGrammerInfo() { getEmbeddedVersion() = nullptr; } +struct SPIRVCoreGrammarInfo : public RefObject +{ + static RefPtr loadFromJSON(SourceView& source, DiagnosticSink& sink); + static RefPtr& getEmbeddedVersion(); + static inline void freeEmbeddedGrammerInfo() { getEmbeddedVersion() = nullptr; } - template - struct Lookup + template + struct Lookup + { + std::optional lookup(const K& name) const { - std::optional lookup(const K& name) const - { - T ret; - if(embedded ? embedded(name, ret) : dict.tryGetValue(name, ret)) - return ret; - else - return std::nullopt; - } + T ret; + if (embedded ? embedded(name, ret) : dict.tryGetValue(name, ret)) + return ret; + else + return std::nullopt; + } - bool (*embedded)(const K&, T&) = nullptr; - Dictionary dict; - }; + bool (*embedded)(const K&, T&) = nullptr; + Dictionary dict; + }; - struct OperandKind - { - uint8_t index; - SLANG_COMPONENTWISE_HASHABLE_1; - SLANG_COMPONENTWISE_EQUALITY_1(OperandKind); - }; + struct OperandKind + { + uint8_t index; + SLANG_COMPONENTWISE_HASHABLE_1; + SLANG_COMPONENTWISE_EQUALITY_1(OperandKind); + }; - struct QualifiedEnumName - { - OperandKind kind; - UnownedStringSlice name; - SLANG_COMPONENTWISE_HASHABLE_2; - SLANG_COMPONENTWISE_EQUALITY_2(QualifiedEnumName); - }; + struct QualifiedEnumName + { + OperandKind kind; + UnownedStringSlice name; + SLANG_COMPONENTWISE_HASHABLE_2; + SLANG_COMPONENTWISE_EQUALITY_2(QualifiedEnumName); + }; - struct QualifiedEnumValue - { - OperandKind kind; - SpvWord value; - SLANG_COMPONENTWISE_HASHABLE_2; - SLANG_COMPONENTWISE_EQUALITY_2(QualifiedEnumValue); - }; + struct QualifiedEnumValue + { + OperandKind kind; + SpvWord value; + SLANG_COMPONENTWISE_HASHABLE_2; + SLANG_COMPONENTWISE_EQUALITY_2(QualifiedEnumValue); + }; - struct OpInfo + struct OpInfo + { + enum Class { - enum Class - { - // Unrecognized instructions go in here - Other, + // Unrecognized instructions go in here + Other, - // Adding to this? Don't forget to update the embedding generator - Miscellaneous, - Debug, - Annotation, - Extension, - ModeSetting, - TypeDeclaration, - ConstantCreation, - Memory, - Function, - Image, - Conversion, - Composite, - Arithmetic, - Bit, - Relational_and_Logical, - Derivative, - ControlFlow, - Atomic, - Primitive, - Barrier, - Group, - DeviceSideEnqueue, - Pipe, - NonUniform, - Reserved, - }; - constexpr static int8_t kNoResultTypeId = -1; - constexpr static int8_t kNoResultId = -1; - - Class class_; - // -1 or 0 - int8_t resultTypeIndex = kNoResultTypeId; - // -1 or 0 or 1 - int8_t resultIdIndex = kNoResultId; - // The range of valid operand counts for this instruction, - // including any result type and id. Multi-word operands count as a - // single operand. - uint16_t minOperandCount; - uint16_t maxOperandCount; - // when looking up an operand type, clamp to this number-1 to - // account for variable length operands at the end - uint16_t numOperandTypes; - const OperandKind* operandTypes; + // Adding to this? Don't forget to update the embedding generator + Miscellaneous, + Debug, + Annotation, + Extension, + ModeSetting, + TypeDeclaration, + ConstantCreation, + Memory, + Function, + Image, + Conversion, + Composite, + Arithmetic, + Bit, + Relational_and_Logical, + Derivative, + ControlFlow, + Atomic, + Primitive, + Barrier, + Group, + DeviceSideEnqueue, + Pipe, + NonUniform, + Reserved, }; + constexpr static int8_t kNoResultTypeId = -1; + constexpr static int8_t kNoResultId = -1; - // - // Our tables: - // + Class class_; + // -1 or 0 + int8_t resultTypeIndex = kNoResultTypeId; + // -1 or 0 or 1 + int8_t resultIdIndex = kNoResultId; + // The range of valid operand counts for this instruction, + // including any result type and id. Multi-word operands count as a + // single operand. + uint16_t minOperandCount; + uint16_t maxOperandCount; + // when looking up an operand type, clamp to this number-1 to + // account for variable length operands at the end + uint16_t numOperandTypes; + const OperandKind* operandTypes; + }; - // Instruction name to opcode - Lookup opcodes; - // Capability name to value - Lookup capabilities; - // String-qualified enum name (one with the type prefix) to value - Lookup allEnumsWithTypePrefix; - // kind * enum name to value - Lookup allEnums; - // kine * enum value to unqualified name - Lookup allEnumNames; - // Any other information on instructions - Lookup opInfos; - // Opcode to instruction name - Lookup opNames; - // Operand kind string to numeric id - Lookup operandKinds; - // Operand kind id to string - Lookup operandKindNames; - // Operand kind to the "un-id" version of itself, for example IdMemorySemantics to MemorySemantics - Lookup operandKindUnderneathIds; + // + // Our tables: + // - private: + // Instruction name to opcode + Lookup opcodes; + // Capability name to value + Lookup capabilities; + // String-qualified enum name (one with the type prefix) to value + Lookup allEnumsWithTypePrefix; + // kind * enum name to value + Lookup allEnums; + // kine * enum value to unqualified name + Lookup allEnumNames; + // Any other information on instructions + Lookup opInfos; + // Opcode to instruction name + Lookup opNames; + // Operand kind string to numeric id + Lookup operandKinds; + // Operand kind id to string + Lookup operandKindNames; + // Operand kind to the "un-id" version of itself, for example IdMemorySemantics to + // MemorySemantics + Lookup operandKindUnderneathIds; - // If this is loaded from JSON, we keep the strings around instead of - // copying them as dictionary keys - StringSlicePool strings = StringSlicePool(StringSlicePool::Style::Empty); - List operandTypesStorage; - }; -} +private: + // If this is loaded from JSON, we keep the strings around instead of + // copying them as dictionary keys + StringSlicePool strings = StringSlicePool(StringSlicePool::Style::Empty); + List operandTypesStorage; +}; +} // namespace Slang diff --git a/source/compiler-core/slang-test-server-protocol.cpp b/source/compiler-core/slang-test-server-protocol.cpp index 2a3bb3a3b9..248c6a07a4 100644 --- a/source/compiler-core/slang-test-server-protocol.cpp +++ b/source/compiler-core/slang-test-server-protocol.cpp @@ -1,6 +1,7 @@ #include "slang-test-server-protocol.h" -namespace TestServerProtocol { +namespace TestServerProtocol +{ static const StructRttiInfo _makeExecuteUnitTestArgsRtti() { @@ -12,8 +13,9 @@ static const StructRttiInfo _makeExecuteUnitTestArgsRtti() builder.addField("enabledApis", &obj.enabledApis); return builder.make(); } -/* static */const UnownedStringSlice ExecuteUnitTestArgs::g_methodName = UnownedStringSlice::fromLiteral("unitTest"); -/* static */const StructRttiInfo ExecuteUnitTestArgs::g_rttiInfo = _makeExecuteUnitTestArgsRtti(); +/* static */ const UnownedStringSlice ExecuteUnitTestArgs::g_methodName = + UnownedStringSlice::fromLiteral("unitTest"); +/* static */ const StructRttiInfo ExecuteUnitTestArgs::g_rttiInfo = _makeExecuteUnitTestArgsRtti(); static const StructRttiInfo _makeExecuteToolTestArgsRtti() { @@ -23,8 +25,9 @@ static const StructRttiInfo _makeExecuteToolTestArgsRtti() builder.addField("args", &obj.args); return builder.make(); } -/* static */const StructRttiInfo ExecuteToolTestArgs::g_rttiInfo = _makeExecuteToolTestArgsRtti(); -/* static */const UnownedStringSlice ExecuteToolTestArgs::g_methodName = UnownedStringSlice::fromLiteral("tool"); +/* static */ const StructRttiInfo ExecuteToolTestArgs::g_rttiInfo = _makeExecuteToolTestArgsRtti(); +/* static */ const UnownedStringSlice ExecuteToolTestArgs::g_methodName = + UnownedStringSlice::fromLiteral("tool"); static const StructRttiInfo _makeExecutionResultRtti() { @@ -36,8 +39,9 @@ static const StructRttiInfo _makeExecutionResultRtti() builder.addField("returnCode", &obj.returnCode); return builder.make(); } -/* static */const StructRttiInfo ExecutionResult::g_rttiInfo = _makeExecutionResultRtti(); +/* static */ const StructRttiInfo ExecutionResult::g_rttiInfo = _makeExecutionResultRtti(); -/* static */const UnownedStringSlice QuitArgs::g_methodName = UnownedStringSlice::fromLiteral("quit"); +/* static */ const UnownedStringSlice QuitArgs::g_methodName = + UnownedStringSlice::fromLiteral("quit"); } // namespace TestServerProtocol diff --git a/source/compiler-core/slang-test-server-protocol.h b/source/compiler-core/slang-test-server-protocol.h index b74a1a8727..a15e19701e 100644 --- a/source/compiler-core/slang-test-server-protocol.h +++ b/source/compiler-core/slang-test-server-protocol.h @@ -1,14 +1,14 @@ #ifndef SLANG_COMPILER_CORE_TEST_PROTOCOL_H #define SLANG_COMPILER_CORE_TEST_PROTOCOL_H -#include "slang.h" +#include "../core/slang-rtti-info.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - -#include "../core/slang-rtti-info.h" #include "slang-json-value.h" +#include "slang.h" -namespace TestServerProtocol { +namespace TestServerProtocol +{ using namespace Slang; @@ -24,8 +24,9 @@ struct ExecuteUnitTestArgs struct ExecuteToolTestArgs { - String toolName; ///< The name of the tool (will be a shared library typically - like render-test). Doesn't need -tool suffix. - List args; ///< Arguments passed to the tool during exectution + String toolName; ///< The name of the tool (will be a shared library typically - like + ///< render-test). Doesn't need -tool suffix. + List args; ///< Arguments passed to the tool during exectution static const UnownedStringSlice g_methodName; static const StructRttiInfo g_rttiInfo; @@ -41,11 +42,11 @@ struct ExecutionResult String stdOut; String stdError; int32_t result = SLANG_OK; - int32_t returnCode = 0; ///< As returned if invoked as command line + int32_t returnCode = 0; ///< As returned if invoked as command line static const StructRttiInfo g_rttiInfo; }; -} // namespace Slang +} // namespace TestServerProtocol #endif // SLANG_COMPILER_CORE_TEST_PROTOCOL_H diff --git a/source/compiler-core/slang-tint-compiler.cpp b/source/compiler-core/slang-tint-compiler.cpp new file mode 100644 index 0000000000..c656f9ba17 --- /dev/null +++ b/source/compiler-core/slang-tint-compiler.cpp @@ -0,0 +1,152 @@ +#include "slang-tint-compiler.h" + +#include "../../external/slang-tint-headers/slang-tint.h" +#include "slang-artifact-associated-impl.h" + +namespace Slang +{ + +class TintDownstreamCompiler : public DownstreamCompilerBase +{ + +public: + // IDownstreamCompiler + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + compile(const CompileOptions& options, IArtifact** outResult) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW bool SLANG_MCALL + canConvert(const ArtifactDesc& from, const ArtifactDesc& to) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL + convert(IArtifact* from, const ArtifactDesc& to, IArtifact** outArtifact) SLANG_OVERRIDE; + + virtual SLANG_NO_THROW bool SLANG_MCALL isFileBased() SLANG_OVERRIDE { return false; } + + virtual SLANG_NO_THROW SlangResult SLANG_MCALL getVersionString(slang::IBlob** outVersionString) + SLANG_OVERRIDE; + + SlangResult compile(IArtifact* const sourceArtifact, IArtifact** outArtifact); + + SlangResult init(ISlangSharedLibrary* library); + +protected: + ComPtr m_sharedLibrary; + +private: + tint_CompileFunc m_compile; + tint_FreeResultFunc m_freeResult; +}; + +SlangResult TintDownstreamCompiler::init(ISlangSharedLibrary* library) +{ + tint_CompileFunc compile = (tint_CompileFunc)library->findFuncByName("tint_compile"); + if (compile == nullptr) + { + return SLANG_FAIL; + } + + tint_FreeResultFunc freeResult = + (tint_FreeResultFunc)library->findFuncByName("tint_free_result"); + if (freeResult == nullptr) + { + return SLANG_FAIL; + } + + m_sharedLibrary = library; + m_desc = Desc(SLANG_PASS_THROUGH_TINT); + m_compile = compile; + m_freeResult = freeResult; + return SLANG_OK; +} + +SlangResult TintDownstreamCompilerUtil::locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set) +{ + ComPtr library; + SLANG_RETURN_ON_FAIL( + DownstreamCompilerUtil::loadSharedLibrary(path, loader, nullptr, "slang-tint", library)); + SLANG_ASSERT(library); + + ComPtr compiler = + ComPtr(new TintDownstreamCompiler()); + SLANG_RETURN_ON_FAIL(static_cast(compiler.get())->init(library)); + + set->addCompiler(compiler); + return SLANG_OK; +} + +SlangResult TintDownstreamCompiler::compile(const CompileOptions& options, IArtifact** outArtifact) +{ + IArtifact* sourceArtifact = options.sourceArtifacts[0]; + return compile(sourceArtifact, outArtifact); +} + +SlangResult TintDownstreamCompiler::compile( + IArtifact* const sourceArtifact, + IArtifact** outArtifact) +{ + tint_CompileRequest req = {}; + + if (sourceArtifact == nullptr) + return SLANG_FAIL; + + ComPtr sourceBlob; + SLANG_RETURN_FALSE_ON_FAIL(sourceArtifact->loadBlob(ArtifactKeep::Yes, sourceBlob.writeRef())); + + String wgslCode( + (char*)sourceBlob->getBufferPointer(), + (char*)sourceBlob->getBufferPointer() + sourceBlob->getBufferSize()); + req.wgslCode = wgslCode.begin(); + req.wgslCodeLength = wgslCode.getLength(); + + tint_CompileResult result = {}; + SLANG_DEFER(m_freeResult(&result)); + bool compileSucceeded = m_compile(&req, &result) == 0; + + ComPtr spirvBlob = RawBlob::create(result.buffer, result.bufferSize); + result.buffer = nullptr; + + ComPtr resultArtifact = + ArtifactUtil::createArtifactForCompileTarget(SlangCompileTarget::SLANG_WGSL_SPIRV); + auto diagnostics = ArtifactDiagnostics::create(); + diagnostics->setResult(compileSucceeded ? SLANG_OK : SLANG_FAIL); + ArtifactUtil::addAssociated(resultArtifact, diagnostics); + if (compileSucceeded) + { + resultArtifact->addRepresentationUnknown(spirvBlob); + } + else + { + diagnostics->setRaw(CharSlice(result.error)); + diagnostics->requireErrorDiagnostic(); + } + + *outArtifact = resultArtifact.detach(); + return SLANG_OK; +} + +bool TintDownstreamCompiler::canConvert(const ArtifactDesc& from, const ArtifactDesc& to) +{ + return (from.payload == ArtifactPayload::WGSL) && (to.payload == ArtifactPayload::SPIRV); +} + +SlangResult TintDownstreamCompiler::convert( + IArtifact* from, + const ArtifactDesc& to, + IArtifact** outArtifact) +{ + if (!canConvert(from->getDesc(), to)) + return SLANG_FAIL; + return compile(from, outArtifact); +} + +SlangResult TintDownstreamCompiler::getVersionString(slang::IBlob** /* outVersionString */) +{ + // We just use Tint at whatever version is in our Dawn fork, so nobody should + // depend on the particular version at the moment. + return SLANG_FAIL; +} + +} // namespace Slang diff --git a/source/compiler-core/slang-tint-compiler.h b/source/compiler-core/slang-tint-compiler.h new file mode 100644 index 0000000000..74953c3783 --- /dev/null +++ b/source/compiler-core/slang-tint-compiler.h @@ -0,0 +1,17 @@ +#pragma once + +#include "../core/slang-platform.h" +#include "slang-downstream-compiler-util.h" + +namespace Slang +{ + +struct TintDownstreamCompilerUtil +{ + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); +}; + +} // namespace Slang diff --git a/source/compiler-core/slang-token-defs.h b/source/compiler-core/slang-token-defs.h index 2a66359fe3..fea90b3ee9 100644 --- a/source/compiler-core/slang-token-defs.h +++ b/source/compiler-core/slang-token-defs.h @@ -16,80 +16,79 @@ #error Need to define TOKEN(ID, DESC) before including "token-defs.h" #endif -TOKEN(Unknown, "") -TOKEN(EndOfFile, "end of file") -TOKEN(Invalid, "invalid character") -TOKEN(Identifier, "identifier") -TOKEN(IntegerLiteral, "integer literal") -TOKEN(FloatingPointLiteral, "floating-point literal") -TOKEN(StringLiteral, "string literal") -TOKEN(CharLiteral, "character literal") -TOKEN(WhiteSpace, "whitespace") -TOKEN(NewLine, "end of line") -TOKEN(LineComment, "line comment") -TOKEN(BlockComment, "block comment") +TOKEN(Unknown, "") +TOKEN(EndOfFile, "end of file") +TOKEN(Invalid, "invalid character") +TOKEN(Identifier, "identifier") +TOKEN(IntegerLiteral, "integer literal") +TOKEN(FloatingPointLiteral, "floating-point literal") +TOKEN(StringLiteral, "string literal") +TOKEN(CharLiteral, "character literal") +TOKEN(WhiteSpace, "whitespace") +TOKEN(NewLine, "end of line") +TOKEN(LineComment, "line comment") +TOKEN(BlockComment, "block comment") -#define PUNCTUATION(id, text) \ - TOKEN(id, "'" text "'") +#define PUNCTUATION(id, text) TOKEN(id, "'" text "'") -PUNCTUATION(Semicolon, ";") -PUNCTUATION(Comma, ",") -PUNCTUATION(Dot, ".") -PUNCTUATION(DotDot, "..") -PUNCTUATION(Ellipsis, "...") +PUNCTUATION(Semicolon, ";") +PUNCTUATION(Comma, ",") +PUNCTUATION(Dot, ".") +PUNCTUATION(DotDot, "..") +PUNCTUATION(Ellipsis, "...") -PUNCTUATION(LBrace, "{") -PUNCTUATION(RBrace, "}") -PUNCTUATION(LBracket, "[") -PUNCTUATION(RBracket, "]") -PUNCTUATION(LParent, "(") -PUNCTUATION(RParent, ")") +PUNCTUATION(LBrace, "{") +PUNCTUATION(RBrace, "}") +PUNCTUATION(LBracket, "[") +PUNCTUATION(RBracket, "]") +PUNCTUATION(LParent, "(") +PUNCTUATION(RParent, ")") -PUNCTUATION(OpAssign, "=") -PUNCTUATION(OpAdd, "+") -PUNCTUATION(OpSub, "-") -PUNCTUATION(OpMul, "*") -PUNCTUATION(OpDiv, "/") -PUNCTUATION(OpMod, "%") -PUNCTUATION(OpNot, "!") -PUNCTUATION(OpBitNot, "~") -PUNCTUATION(OpLsh, "<<") -PUNCTUATION(OpRsh, ">>") -PUNCTUATION(OpEql, "==") -PUNCTUATION(OpNeq, "!=") -PUNCTUATION(OpGreater, ">") -PUNCTUATION(OpLess, "<") -PUNCTUATION(OpGeq, ">=") -PUNCTUATION(OpLeq, "<=") -PUNCTUATION(OpAnd, "&&") -PUNCTUATION(OpOr, "||") -PUNCTUATION(OpBitAnd, "&") -PUNCTUATION(OpBitOr, "|") -PUNCTUATION(OpBitXor, "^") -PUNCTUATION(OpInc, "++") -PUNCTUATION(OpDec, "--") +PUNCTUATION(OpAssign, "=") +PUNCTUATION(OpAdd, "+") +PUNCTUATION(OpSub, "-") +PUNCTUATION(OpMul, "*") +PUNCTUATION(OpDiv, "/") +PUNCTUATION(OpMod, "%") +PUNCTUATION(OpNot, "!") +PUNCTUATION(OpBitNot, "~") +PUNCTUATION(OpLsh, "<<") +PUNCTUATION(OpRsh, ">>") +PUNCTUATION(OpEql, "==") +PUNCTUATION(OpNeq, "!=") +PUNCTUATION(OpGreater, ">") +PUNCTUATION(OpLess, "<") +PUNCTUATION(OpGeq, ">=") +PUNCTUATION(OpLeq, "<=") +PUNCTUATION(OpAnd, "&&") +PUNCTUATION(OpOr, "||") +PUNCTUATION(OpBitAnd, "&") +PUNCTUATION(OpBitOr, "|") +PUNCTUATION(OpBitXor, "^") +PUNCTUATION(OpInc, "++") +PUNCTUATION(OpDec, "--") -PUNCTUATION(OpAddAssign, "+=") -PUNCTUATION(OpSubAssign, "-=") -PUNCTUATION(OpMulAssign, "*=") -PUNCTUATION(OpDivAssign, "/=") -PUNCTUATION(OpModAssign, "%=") -PUNCTUATION(OpShlAssign, "<<=") -PUNCTUATION(OpShrAssign, ">>=") -PUNCTUATION(OpAndAssign, "&=") -PUNCTUATION(OpOrAssign, "|=") -PUNCTUATION(OpXorAssign, "^=") +PUNCTUATION(OpAddAssign, "+=") +PUNCTUATION(OpSubAssign, "-=") +PUNCTUATION(OpMulAssign, "*=") +PUNCTUATION(OpDivAssign, "/=") +PUNCTUATION(OpModAssign, "%=") +PUNCTUATION(OpShlAssign, "<<=") +PUNCTUATION(OpShrAssign, ">>=") +PUNCTUATION(OpAndAssign, "&=") +PUNCTUATION(OpOrAssign, "|=") +PUNCTUATION(OpXorAssign, "^=") -PUNCTUATION(QuestionMark, "?") -PUNCTUATION(Colon, ":") -PUNCTUATION(RightArrow, "->") -PUNCTUATION(At, "@") -PUNCTUATION(Dollar, "$") -PUNCTUATION(DollarDollar, "$$") -PUNCTUATION(Pound, "#") -PUNCTUATION(PoundPound, "##") +PUNCTUATION(QuestionMark, "?") +PUNCTUATION(Colon, ":") +PUNCTUATION(RightArrow, "->") +PUNCTUATION(At, "@") +PUNCTUATION(Dollar, "$") +PUNCTUATION(DollarDollar, "$$") +PUNCTUATION(Pound, "#") +PUNCTUATION(PoundPound, "##") -PUNCTUATION(Scope, "::") +PUNCTUATION(Scope, "::") PUNCTUATION(CompletionRequest, "#?") diff --git a/source/compiler-core/slang-token.cpp b/source/compiler-core/slang-token.cpp index 576b08d66a..8b9ec35821 100644 --- a/source/compiler-core/slang-token.cpp +++ b/source/compiler-core/slang-token.cpp @@ -1,19 +1,22 @@ // slang-token.cpp #include "slang-token.h" -//#include +// #include -namespace Slang { +namespace Slang +{ char const* TokenTypeToString(TokenType type) { - switch( type ) + switch (type) { default: SLANG_ASSERT(!"unexpected"); return ""; -#define TOKEN(NAME, DESC) case TokenType::NAME: return DESC; +#define TOKEN(NAME, DESC) \ + case TokenType::NAME: \ + return DESC; #include "slang-token-defs.h" } } diff --git a/source/compiler-core/slang-token.h b/source/compiler-core/slang-token.h index 7feda68242..9978ec5cfb 100644 --- a/source/compiler-core/slang-token.h +++ b/source/compiler-core/slang-token.h @@ -3,11 +3,11 @@ #define SLANG_TOKEN_H_INCLUDED #include "../core/slang-basic.h" - -#include "slang-source-loc.h" #include "slang-name.h" +#include "slang-source-loc.h" -namespace Slang { +namespace Slang +{ class Name; @@ -24,22 +24,21 @@ struct TokenFlag { enum Enum : TokenFlags { - AtStartOfLine = 1 << 0, - AfterWhitespace = 1 << 1, - ScrubbingNeeded = 1 << 2, - Name = 1 << 3, ///< Determines if 'name' is set or 'chars' in the charsNameUnion + AtStartOfLine = 1 << 0, + AfterWhitespace = 1 << 1, + ScrubbingNeeded = 1 << 2, + Name = 1 << 3, ///< Determines if 'name' is set or 'chars' in the charsNameUnion }; }; class Token { public: + TokenType type = TokenType::Unknown; + TokenFlags flags = 0; - TokenType type = TokenType::Unknown; - TokenFlags flags = 0; - - SourceLoc loc; - uint32_t charsCount = 0; ///< Amount of characters. Is set if name or not. + SourceLoc loc; + uint32_t charsCount = 0; ///< Amount of characters. Is set if name or not. union CharsNameUnion { @@ -53,7 +52,7 @@ class Token Index getContentLength() const { return charsCount; } UnownedStringSlice getContent() const; - /// Set content + /// Set content void setContent(const UnownedStringSlice& content); Name* getName() const; @@ -62,13 +61,10 @@ class Token SourceLoc getLoc() const { return loc; } - /// Set the name + /// Set the name SLANG_FORCE_INLINE void setName(Name* inName); - Token() - { - charsNameUnion.chars = nullptr; - } + Token() { charsNameUnion.chars = nullptr; } Token( TokenType inType, @@ -76,18 +72,14 @@ class Token SourceLoc inLoc, TokenFlags inFlags = 0) : flags(inFlags) - { - SLANG_ASSERT((inFlags & TokenFlag::Name) == 0); - type = inType; + { + SLANG_ASSERT((inFlags & TokenFlag::Name) == 0); + type = inType; charsNameUnion.chars = inContent.begin(); charsCount = uint32_t(inContent.getLength()); loc = inLoc; - } - Token( - TokenType inType, - Name* name, - SourceLoc inLoc, - TokenFlags inFlags = 0) + } + Token(TokenType inType, Name* name, SourceLoc inLoc, TokenFlags inFlags = 0) { SLANG_ASSERT(name); type = inType; @@ -101,7 +93,8 @@ class Token // --------------------------------------------------------------------------- SLANG_FORCE_INLINE UnownedStringSlice Token::getContent() const { - return (flags & TokenFlag::Name) ? charsNameUnion.name->text.getUnownedSlice() : UnownedStringSlice(charsNameUnion.chars, charsCount); + return (flags & TokenFlag::Name) ? charsNameUnion.name->text.getUnownedSlice() + : UnownedStringSlice(charsNameUnion.chars, charsCount); } // --------------------------------------------------------------------------- diff --git a/source/compiler-core/slang-visual-studio-compiler-util.cpp b/source/compiler-core/slang-visual-studio-compiler-util.cpp index df3285608a..d831abbd4c 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.cpp +++ b/source/compiler-core/slang-visual-studio-compiler-util.cpp @@ -2,35 +2,45 @@ #include "slang-visual-studio-compiler-util.h" #include "../core/slang-common.h" -#include "slang-com-helper.h" -#include "../core/slang-string-util.h" #include "../core/slang-string-slice-pool.h" +#include "../core/slang-string-util.h" +#include "slang-com-helper.h" // if Visual Studio import the visual studio platform specific header #if SLANG_VC -# include "windows/slang-win-visual-studio-util.h" +#include "windows/slang-win-visual-studio-util.h" #endif #include "../core/slang-io.h" - #include "slang-artifact-desc-util.h" #include "slang-artifact-diagnostic-util.h" -#include "slang-artifact-util.h" #include "slang-artifact-representation-impl.h" +#include "slang-artifact-util.h" namespace Slang { -static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) +static void _addFile( + const String& path, + const ArtifactDesc& desc, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) { - auto fileRep = OSFileArtifactRepresentation::create(IOSFileArtifactRepresentation::Kind::Owned, path.getUnownedSlice(), lockFile); + auto fileRep = OSFileArtifactRepresentation::create( + IOSFileArtifactRepresentation::Kind::Owned, + path.getUnownedSlice(), + lockFile); auto artifact = ArtifactUtil::createArtifact(desc); artifact->addRepresentation(fileRep); outArtifacts.add(artifact); } -/* static */SlangResult VisualStudioCompilerUtil::calcCompileProducts(const CompileOptions& options, ProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) +/* static */ SlangResult VisualStudioCompilerUtil::calcCompileProducts( + const CompileOptions& options, + ProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) { SLANG_ASSERT(options.modulePath.count); @@ -44,35 +54,67 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa { StringBuilder builder; const auto desc = ArtifactDescUtil::makeDescForCompileTarget(options.targetType); - SLANG_RETURN_ON_FAIL(ArtifactDescUtil::calcPathForDesc(desc, modulePath.getUnownedSlice(), builder)); + SLANG_RETURN_ON_FAIL( + ArtifactDescUtil::calcPathForDesc(desc, modulePath.getUnownedSlice(), builder)); _addFile(builder, desc, lockFile, outArtifacts); } if (flags & ProductFlag::Miscellaneous) { - - _addFile(modulePath + ".ilk", ArtifactDesc::make(ArtifactKind::BinaryFormat, ArtifactPayload::Unknown, ArtifactStyle::None), lockFile, outArtifacts); + + _addFile( + modulePath + ".ilk", + ArtifactDesc::make( + ArtifactKind::BinaryFormat, + ArtifactPayload::Unknown, + ArtifactStyle::None), + lockFile, + outArtifacts); if (options.targetType == SLANG_SHADER_SHARED_LIBRARY) { - _addFile(modulePath + ".exp", ArtifactDesc::make(ArtifactKind::BinaryFormat, ArtifactPayload::Unknown, ArtifactStyle::None), lockFile, outArtifacts); - _addFile(modulePath + ".lib", ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::HostCPU, targetDesc), lockFile, outArtifacts); + _addFile( + modulePath + ".exp", + ArtifactDesc::make( + ArtifactKind::BinaryFormat, + ArtifactPayload::Unknown, + ArtifactStyle::None), + lockFile, + outArtifacts); + _addFile( + modulePath + ".lib", + ArtifactDesc::make(ArtifactKind::Library, ArtifactPayload::HostCPU, targetDesc), + lockFile, + outArtifacts); } } if (flags & ProductFlag::Compile) { - _addFile(modulePath + ".obj", ArtifactDesc::make(ArtifactKind::ObjectCode, ArtifactPayload::HostCPU, targetDesc), lockFile, outArtifacts); + _addFile( + modulePath + ".obj", + ArtifactDesc::make(ArtifactKind::ObjectCode, ArtifactPayload::HostCPU, targetDesc), + lockFile, + outArtifacts); } if (flags & ProductFlag::Debug) { // TODO(JS): Could try and determine based on debug information - _addFile(modulePath + ".pdb", ArtifactDesc::make(ArtifactKind::BinaryFormat, ArtifactPayload::PdbDebugInfo, targetDesc), lockFile, outArtifacts); + _addFile( + modulePath + ".pdb", + ArtifactDesc::make( + ArtifactKind::BinaryFormat, + ArtifactPayload::PdbDebugInfo, + targetDesc), + lockFile, + outArtifacts); } return SLANG_OK; } -/* static */SlangResult VisualStudioCompilerUtil::calcArgs(const CompileOptions& options, CommandLine& cmdLine) +/* static */ SlangResult VisualStudioCompilerUtil::calcArgs( + const CompileOptions& options, + CommandLine& cmdLine) { SLANG_ASSERT(options.modulePath.count); @@ -112,17 +154,17 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa switch (options.debugInfoType) { - default: + default: { // Multithreaded statically linked runtime library cmdLine.addArg("/MD"); break; } - case DebugInfoType::None: + case DebugInfoType::None: { break; } - case DebugInfoType::Maximal: + case DebugInfoType::Maximal: { // Multithreaded statically linked *debug* runtime library cmdLine.addArg("/MDd"); @@ -140,44 +182,48 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa switch (options.optimizationLevel) { - case OptimizationLevel::None: + case OptimizationLevel::None: { // No optimization - cmdLine.addArg("/Od"); + cmdLine.addArg("/Od"); break; } - case OptimizationLevel::Default: + case OptimizationLevel::Default: { break; } - case OptimizationLevel::High: + case OptimizationLevel::High: { cmdLine.addArg("/O2"); break; } - case OptimizationLevel::Maximal: + case OptimizationLevel::Maximal: { cmdLine.addArg("/Ox"); break; } - default: break; + default: + break; } switch (options.floatingPointMode) { - case FloatingPointMode::Default: break; - case FloatingPointMode::Precise: + case FloatingPointMode::Default: + break; + case FloatingPointMode::Precise: { // precise is default behavior, VS also has 'strict' // - // ```/fp:strict has behavior similar to /fp:precise, that is, the compiler preserves the source ordering and rounding properties of floating-point code when - // it generates and optimizes object code for the target machine, and observes the standard when handling special values. In addition, the program may safely - // access or modify the floating-point environment at runtime.``` + // ```/fp:strict has behavior similar to /fp:precise, that is, the compiler preserves + // the source ordering and rounding properties of floating-point code when it generates + // and optimizes object code for the target machine, and observes the standard when + // handling special values. In addition, the program may safely access or modify the + // floating-point environment at runtime.``` cmdLine.addArg("/fp:precise"); break; } - case FloatingPointMode::Fast: + case FloatingPointMode::Fast: { cmdLine.addArg("/fp:fast"); break; @@ -188,8 +234,8 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa switch (options.targetType) { - case SLANG_SHADER_SHARED_LIBRARY: - case SLANG_HOST_SHARED_LIBRARY: + case SLANG_SHADER_SHARED_LIBRARY: + case SLANG_HOST_SHARED_LIBRARY: { // Create dynamic link library if (options.debugInfoType == DebugInfoType::None) @@ -204,12 +250,13 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa cmdLine.addPrefixPathArg("/Fe", modulePath, ".dll"); break; } - case SLANG_HOST_EXECUTABLE: + case SLANG_HOST_EXECUTABLE: { cmdLine.addPrefixPathArg("/Fe", modulePath, ".exe"); break; } - default: break; + default: + break; } // Object file specify it's location - needed if we are out @@ -244,12 +291,12 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa { ComPtr fileRep; - // TODO(JS): + // TODO(JS): // Do we want to keep the file on the file system? It's probably reasonable to do so. SLANG_RETURN_ON_FAIL(sourceArtifact->requireFile(ArtifactKeep::Yes, fileRep.writeRef())); cmdLine.addArg(fileRep->getPath()); } - + // Link options (parameters past /link go to linker) cmdLine.addArg("/link"); @@ -288,7 +335,9 @@ static void _addFile(const String& path, const ArtifactDesc& desc, IOSFileArtifa return SLANG_OK; } -static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnostic::Severity& outSeverity) +static SlangResult _parseSeverity( + const UnownedStringSlice& in, + ArtifactDiagnostic::Severity& outSeverity) { typedef ArtifactDiagnostic::Severity Severity; @@ -311,7 +360,10 @@ static SlangResult _parseSeverity(const UnownedStringSlice& in, ArtifactDiagnost return SLANG_OK; } -static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const UnownedStringSlice& line, ArtifactDiagnostic& outDiagnostic) +static SlangResult _parseVisualStudioLine( + SliceAllocator& allocator, + const UnownedStringSlice& line, + ArtifactDiagnostic& outDiagnostic) { typedef IArtifactDiagnostics::Diagnostic Diagnostic; @@ -328,8 +380,8 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown outDiagnostic.stage = ArtifactDiagnostic::Stage::Compile; - const char*const start = line.begin(); - const char*const end = line.end(); + const char* const start = line.begin(); + const char* const end = line.end(); UnownedStringSlice postPath; // Handle the path and line no @@ -409,7 +461,8 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown return SLANG_FAIL; } - const UnownedStringSlice errorSection = UnownedStringSlice(postPath.begin(), postPath.begin() + errorColonIndex); + const UnownedStringSlice errorSection = + UnownedStringSlice(postPath.begin(), postPath.begin() + errorColonIndex); Index errorCodeIndex = errorSection.lastIndexOf(' '); if (errorCodeIndex < 0) { @@ -417,17 +470,20 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown } // Extract the code - outDiagnostic.code = allocator.allocate(errorSection.begin() + errorCodeIndex + 1, errorSection.end()); + outDiagnostic.code = + allocator.allocate(errorSection.begin() + errorCodeIndex + 1, errorSection.end()); if (asStringSlice(outDiagnostic.code).startsWith(UnownedStringSlice::fromLiteral("LNK"))) { outDiagnostic.stage = Diagnostic::Stage::Link; } // Extract the bit before the code - SLANG_RETURN_ON_FAIL(_parseSeverity(UnownedStringSlice(errorSection.begin(), errorSection.begin() + errorCodeIndex).trim(), outDiagnostic.severity)); + SLANG_RETURN_ON_FAIL(_parseSeverity( + UnownedStringSlice(errorSection.begin(), errorSection.begin() + errorCodeIndex).trim(), + outDiagnostic.severity)); // Link codes start with LNK prefix - postError = UnownedStringSlice(postPath.begin() + errorColonIndex + 1, end); + postError = UnownedStringSlice(postPath.begin() + errorColonIndex + 1, end); } outDiagnostic.text = allocator.allocate(postError); @@ -435,7 +491,9 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown return SLANG_OK; } -/* static */SlangResult VisualStudioCompilerUtil::parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* diagnostics) +/* static */ SlangResult VisualStudioCompilerUtil::parseOutput( + const ExecuteResult& exeRes, + IArtifactDiagnostics* diagnostics) { diagnostics->reset(); @@ -466,7 +524,7 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown return SLANG_OK; } -/* static */SlangResult VisualStudioCompilerUtil::locateCompilers( +/* static */ SlangResult VisualStudioCompilerUtil::locateCompilers( const String& path, ISlangSharedLibraryLoader* loader, [[maybe_unused]] DownstreamCompilerSet* set) @@ -484,4 +542,4 @@ static SlangResult _parseVisualStudioLine(SliceAllocator& allocator, const Unown return SLANG_OK; } -} +} // namespace Slang diff --git a/source/compiler-core/slang-visual-studio-compiler-util.h b/source/compiler-core/slang-visual-studio-compiler-util.h index fa1fb7c692..77227ce97a 100644 --- a/source/compiler-core/slang-visual-studio-compiler-util.h +++ b/source/compiler-core/slang-visual-studio-compiler-util.h @@ -9,14 +9,21 @@ namespace Slang struct VisualStudioCompilerUtil : public DownstreamCompilerUtilBase { - /// Calculate Visual Studio family compilers cmdLine arguments from options + /// Calculate Visual Studio family compilers cmdLine arguments from options static SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine); - /// Parse Visual Studio exeRes into CPPCompiler::Output + /// Parse Visual Studio exeRes into CPPCompiler::Output static SlangResult parseOutput(const ExecuteResult& exeRes, IArtifactDiagnostics* outOutput); - static SlangResult calcCompileProducts(const CompileOptions& options, ProductFlags flags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts); + static SlangResult calcCompileProducts( + const CompileOptions& options, + ProductFlags flags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts); - static SlangResult locateCompilers(const String& path, ISlangSharedLibraryLoader* loader, DownstreamCompilerSet* set); + static SlangResult locateCompilers( + const String& path, + ISlangSharedLibraryLoader* loader, + DownstreamCompilerSet* set); }; class VisualStudioDownstreamCompiler : public CommandLineDownstreamCompiler @@ -26,14 +33,32 @@ class VisualStudioDownstreamCompiler : public CommandLineDownstreamCompiler typedef VisualStudioCompilerUtil Util; // CommandLineDownstreamCompiler impl - just forwards to the Util - virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE { return Util::calcArgs(options, cmdLine); } - virtual SlangResult parseOutput(const ExecuteResult& exeResult, IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE { return Util::parseOutput(exeResult, diagnostics); } - virtual SlangResult calcCompileProducts(const CompileOptions& options, DownstreamProductFlags productFlags, IOSFileArtifactRepresentation* lockFile, List>& outArtifacts) SLANG_OVERRIDE { return Util::calcCompileProducts(options, productFlags, lockFile, outArtifacts); } + virtual SlangResult calcArgs(const CompileOptions& options, CommandLine& cmdLine) SLANG_OVERRIDE + { + return Util::calcArgs(options, cmdLine); + } + virtual SlangResult parseOutput( + const ExecuteResult& exeResult, + IArtifactDiagnostics* diagnostics) SLANG_OVERRIDE + { + return Util::parseOutput(exeResult, diagnostics); + } + virtual SlangResult calcCompileProducts( + const CompileOptions& options, + DownstreamProductFlags productFlags, + IOSFileArtifactRepresentation* lockFile, + List>& outArtifacts) SLANG_OVERRIDE + { + return Util::calcCompileProducts(options, productFlags, lockFile, outArtifacts); + } - VisualStudioDownstreamCompiler(const Desc& desc):Super(desc) {} + VisualStudioDownstreamCompiler(const Desc& desc) + : Super(desc) + { + } }; -} +} // namespace Slang #endif diff --git a/source/compiler-core/windows/slang-win-visual-studio-util.cpp b/source/compiler-core/windows/slang-win-visual-studio-util.cpp index cb784b4269..ed09448b52 100644 --- a/source/compiler-core/windows/slang-win-visual-studio-util.cpp +++ b/source/compiler-core/windows/slang-win-visual-studio-util.cpp @@ -3,15 +3,13 @@ #include "../../core/slang-common.h" #include "../../core/slang-process-util.h" #include "../../core/slang-string-util.h" - #include "../slang-json-parser.h" #include "../slang-json-value.h" - #include "../slang-visual-studio-compiler-util.h" #ifdef _WIN32 -# include -# include +#include +#include #pragma comment(lib, "advapi32") #pragma comment(lib, "Shell32") #endif @@ -19,33 +17,35 @@ // The method used to invoke VS was originally inspired by some ideas in // https://github.com/RuntimeCompiledCPlusPlus/RuntimeCompiledCPlusPlus/ -namespace Slang { +namespace Slang +{ // Information on VS versioning can be found here // https://en.wikipedia.org/wiki/Microsoft_Visual_C%2B%2B#Internal_version_numbering -namespace { // anonymous +namespace +{ // anonymous struct RegistryInfo { - const char* regName; ///< The name of the entry in the registry - const char* pathFix; ///< With the value from the registry how to fix the path + const char* regName; ///< The name of the entry in the registry + const char* pathFix; ///< With the value from the registry how to fix the path }; struct VersionInfo { - SemanticVersion version; ///< The version - const char* name; ///< The name of the registry key + SemanticVersion version; ///< The version + const char* name; ///< The name of the registry key }; -} // anonymous +} // namespace static SlangResult _readRegistryKey(const char* path, const char* keyName, String& outString) { // https://docs.microsoft.com/en-us/windows/desktop/api/winreg/nf-winreg-regopenkeyexa - HKEY key; - LONG ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ | KEY_WOW64_32KEY, &key); + HKEY key; + LONG ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, path, 0, KEY_READ | KEY_WOW64_32KEY, &key); if (ret != ERROR_SUCCESS) { return SLANG_FAIL; @@ -77,8 +77,8 @@ static DownstreamCompilerMatchVersion _makeVersion(int main) return version; } -static DownstreamCompilerMatchVersion _makeVersion(int main, int dot) -{ +static DownstreamCompilerMatchVersion _makeVersion(int main, int dot) +{ DownstreamCompilerMatchVersion version; version.type = SLANG_PASS_THROUGH_VISUAL_STUDIO; version.matchVersion.set(main, dot); @@ -94,8 +94,7 @@ VersionInfo _makeVersionInfo(const char* name, int high, int dot = 0) } // https://en.wikipedia.org/wiki/Microsoft_Visual_Studio -static const VersionInfo s_versionInfos[] = -{ +static const VersionInfo s_versionInfos[] = { _makeVersionInfo("VS 2005", 8), _makeVersionInfo("VS 2008", 9), _makeVersionInfo("VS 2010", 10), @@ -107,15 +106,14 @@ static const VersionInfo s_versionInfos[] = _makeVersionInfo("VS 2022", 17), }; -// When trying to figure out how this stuff works by running regedit - care is needed, -// because what regedit displays varies on which version of regedit is used. -// In order to use the registry paths used here it's necessary to use Start/Run with +// When trying to figure out how this stuff works by running regedit - care is needed, +// because what regedit displays varies on which version of regedit is used. +// In order to use the registry paths used here it's necessary to use Start/Run with // %systemroot%\syswow64\regedit to view 32 bit keys -static const RegistryInfo s_regInfos[] = -{ - {"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7", "" }, - {"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", "VC\\Auxiliary\\Build\\" }, +static const RegistryInfo s_regInfos[] = { + {"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VC7", ""}, + {"SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", "VC\\Auxiliary\\Build\\"}, }; static bool _canUseVSWhere(SemanticVersion version) @@ -149,7 +147,7 @@ static SlangResult _parseVersion(UnownedStringSlice versionString, SemanticVersi } -/* static */DownstreamCompilerMatchVersion WinVisualStudioUtil::getCompiledVersion() +/* static */ DownstreamCompilerMatchVersion WinVisualStudioUtil::getCompiledVersion() { // Get the version of visual studio used to compile this source // Not const, because otherwise we get an warning/error about constant expression... @@ -157,12 +155,18 @@ static SlangResult _parseVersion(UnownedStringSlice versionString, SemanticVersi switch (version) { - case 1400: return _makeVersion(8); - case 1500: return _makeVersion(9); - case 1600: return _makeVersion(10); - case 1700: return _makeVersion(11); - case 1800: return _makeVersion(12); - default: break; + case 1400: + return _makeVersion(8); + case 1500: + return _makeVersion(9); + case 1600: + return _makeVersion(10); + case 1700: + return _makeVersion(11); + case 1800: + return _makeVersion(12); + default: + break; } // Seems like versions go in runs of 10 at this point @@ -176,58 +180,88 @@ static SlangResult _parseVersion(UnownedStringSlice versionString, SemanticVersi { switch (version) { - case 1910: return _makeVersion(15, 0); - case 1911: return _makeVersion(15, 3); - case 1912: return _makeVersion(15, 5); - case 1913: return _makeVersion(15, 6); - case 1914: return _makeVersion(15, 7); - case 1915: return _makeVersion(15, 8); - case 1916: return _makeVersion(15, 9); - default: return _makeVersion(15); + case 1910: + return _makeVersion(15, 0); + case 1911: + return _makeVersion(15, 3); + case 1912: + return _makeVersion(15, 5); + case 1913: + return _makeVersion(15, 6); + case 1914: + return _makeVersion(15, 7); + case 1915: + return _makeVersion(15, 8); + case 1916: + return _makeVersion(15, 9); + default: + return _makeVersion(15); } } else if (version >= 1920 && version < 1930) { switch (version) { - case 1920: return _makeVersion(16, 0); - case 1921: return _makeVersion(16, 1); - case 1922: return _makeVersion(16, 2); - case 1923: return _makeVersion(16, 3); - case 1924: return _makeVersion(16, 4); - case 1925: return _makeVersion(16, 5); - case 1926: return _makeVersion(16, 6); - case 1927: return _makeVersion(16, 7); - case 1928: return _makeVersion(16, 9); - case 1929: return _makeVersion(16, 11); - default: return _makeVersion(16); + case 1920: + return _makeVersion(16, 0); + case 1921: + return _makeVersion(16, 1); + case 1922: + return _makeVersion(16, 2); + case 1923: + return _makeVersion(16, 3); + case 1924: + return _makeVersion(16, 4); + case 1925: + return _makeVersion(16, 5); + case 1926: + return _makeVersion(16, 6); + case 1927: + return _makeVersion(16, 7); + case 1928: + return _makeVersion(16, 9); + case 1929: + return _makeVersion(16, 11); + default: + return _makeVersion(16); } } else if (version >= 1930 && version < 1940) { switch (version) { - case 1930: return _makeVersion(17, 0); - case 1931: return _makeVersion(17, 1); - case 1932: return _makeVersion(17, 2); - default: return _makeVersion(17); + case 1930: + return _makeVersion(17, 0); + case 1931: + return _makeVersion(17, 1); + case 1932: + return _makeVersion(17, 2); + default: + return _makeVersion(17); } } else if (version >= 1940) { // Its an unknown newer version - return DownstreamCompilerMatchVersion(SLANG_PASS_THROUGH_VISUAL_STUDIO, MatchSemanticVersion::makeFuture()); + return DownstreamCompilerMatchVersion( + SLANG_PASS_THROUGH_VISUAL_STUDIO, + MatchSemanticVersion::makeFuture()); } // Unknown version return DownstreamCompilerMatchVersion(SLANG_PASS_THROUGH_VISUAL_STUDIO, MatchSemanticVersion()); } -static SlangResult _parseJson(const String& contents, DiagnosticSink* sink, JSONContainer* container, JSONValue& outRoot) +static SlangResult _parseJson( + const String& contents, + DiagnosticSink* sink, + JSONContainer* container, + JSONValue& outRoot) { auto sourceManager = sink->getSourceManager(); - SourceFile* sourceFile = sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); + SourceFile* sourceFile = + sourceManager->createSourceFileWithString(PathInfo::makeUnknown(), contents); SourceView* sourceView = sourceManager->createSourceView(sourceFile, nullptr, SourceLoc()); JSONLexer lexer; @@ -246,10 +280,13 @@ static void _orderVersions(List& ioVersions) { typedef WinVisualStudioUtil::VersionPath VersionPath; // Put into increasing version order, from oldest to newest - ioVersions.sort([&](const VersionPath& a, const VersionPath& b) -> bool { return a.version < b.version; }); + ioVersions.sort( + [&](const VersionPath& a, const VersionPath& b) -> bool { return a.version < b.version; }); } -static SlangResult _findVersionsWithVSWhere(const VersionInfo* versionInfo, List& outVersions) +static SlangResult _findVersionsWithVSWhere( + const VersionInfo* versionInfo, + List& outVersions) { typedef WinVisualStudioUtil::VersionPath VersionPath; @@ -269,12 +306,14 @@ static SlangResult _findVersionsWithVSWhere(const VersionInfo* versionInfo, List // Using -? we can find out vswhere options. - // Previous args - works but returns multiple versions, without listing what version is associated with which path - // or the order. - //String args[] = { "-version", versionName, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", ""-property", "installationPath" }; + // Previous args - works but returns multiple versions, without listing what version is + // associated with which path or the order. + // String args[] = { "-version", versionName, "-requires", + // "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", ""-property", "installationPath" }; - // Use JSON parsing, we can verify the versions for a path, otherwise multiple versions are returned - // not just the version specified. The ordering isn't defined (and -sort doesn't appear to work) + // Use JSON parsing, we can verify the versions for a path, otherwise multiple versions are + // returned not just the version specified. The ordering isn't defined (and -sort doesn't appear + // to work) SemanticVersion requiredVersion; if (versionInfo) @@ -288,9 +327,14 @@ static SlangResult _findVersionsWithVSWhere(const VersionInfo* versionInfo, List // Add other args { - // TODO(JS): + // TODO(JS): // For arm targets will probably need something different for tooling - String args[] = { "-format", "json", "-utf8", "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" }; + String args[] = { + "-format", + "json", + "-utf8", + "-requires", + "Microsoft.VisualStudio.Component.VC.Tools.x86.x64"}; cmd.addArgs(args, SLANG_COUNT_OF(args)); } @@ -316,12 +360,13 @@ static SlangResult _findVersionsWithVSWhere(const VersionInfo* versionInfo, List auto arr = container->getArray(jsonRoot); const auto pathKey = container->getKey(UnownedStringSlice::fromLiteral("installationPath")); - const auto versionKey = container->getKey(UnownedStringSlice::fromLiteral("installationVersion")); + const auto versionKey = + container->getKey(UnownedStringSlice::fromLiteral("installationVersion")); // Find all the versions, that match for (auto elem : arr) { - // Get the path and the name + // Get the path and the name if (elem.getKind() != JSONValue::Kind::Object) { continue; @@ -389,7 +434,7 @@ static SlangResult _findVersionsWithRegistery(List& outVersionPaths) +/* static */ SlangResult WinVisualStudioUtil::find(List& outVersionPaths) { outVersionPaths.clear(); @@ -422,12 +467,15 @@ static SlangResult _findVersionsWithRegistery(List bool { return cur.version.m_major == majorVersion; }); + foundIndex = outVersionPaths.findFirstIndex( + [&](const VersionPath& cur) -> bool + { return cur.version.m_major == majorVersion; }); } else { // See if we can find the exact version - foundIndex = outVersionPaths.findFirstIndex([&](const VersionPath& cur) -> bool { return cur.version == regVersion.version; }); + foundIndex = outVersionPaths.findFirstIndex( + [&](const VersionPath& cur) -> bool { return cur.version == regVersion.version; }); } // If it wasn't found add it. @@ -441,7 +489,7 @@ static SlangResult _findVersionsWithRegistery(List versionPaths; SLANG_RETURN_ON_FAIL(find(versionPaths)); @@ -464,20 +512,23 @@ static SlangResult _findVersionsWithRegistery(List& outVersionPaths); - /// Find and add to the set (if not already there) + /// Find and add to the set (if not already there) static SlangResult find(DownstreamCompilerSet* set); - /// Create the cmdLine to start compiler for specified path + /// Create the cmdLine to start compiler for specified path static void calcExecuteCompilerArgs(const VersionPath& versionPath, CommandLine& outCmdLine); - /// Run visual studio on specified path with the parameters specified on the command line. Output placed in outResult. - static SlangResult executeCompiler(const VersionPath& versionPath, const CommandLine& commandLine, ExecuteResult& outResult); + /// Run visual studio on specified path with the parameters specified on the command line. + /// Output placed in outResult. + static SlangResult executeCompiler( + const VersionPath& versionPath, + const CommandLine& commandLine, + ExecuteResult& outResult); - /// Gets the msc compiler used to compile this version. + /// Gets the msc compiler used to compile this version. static DownstreamCompilerMatchVersion getCompiledVersion(); }; } // namespace Slang -#endif +#endif diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt new file mode 100644 index 0000000000..8228d00670 --- /dev/null +++ b/source/core/CMakeLists.txt @@ -0,0 +1,11 @@ +slang_add_target( + . + STATIC + EXCLUDE_FROM_ALL + USE_EXTRA_WARNINGS + LINK_WITH_PRIVATE miniz lz4_static Threads::Threads ${CMAKE_DL_LIBS} + LINK_WITH_PUBLIC unordered_dense::unordered_dense + INCLUDE_DIRECTORIES_PUBLIC + ${slang_SOURCE_DIR}/source + ${slang_SOURCE_DIR}/include +) diff --git a/source/core/slang-allocator.h b/source/core/slang-allocator.h index 8942f993b8..03cfabe40b 100644 --- a/source/core/slang-allocator.h +++ b/source/core/slang-allocator.h @@ -5,89 +5,77 @@ #include #ifdef _MSC_VER -# include +#include #endif #include namespace Slang { - inline void* alignedAllocate(size_t size, size_t alignment) - { +inline void* alignedAllocate(size_t size, size_t alignment) +{ #ifdef _MSC_VER - return _aligned_malloc(size, alignment); + return _aligned_malloc(size, alignment); #elif defined(__CYGWIN__) - return aligned_alloc(alignment, size); + return aligned_alloc(alignment, size); #else - void* rs = nullptr; - int succ = posix_memalign(&rs, alignment, size); - return (succ == 0) ? rs : nullptr; + void* rs = nullptr; + int succ = posix_memalign(&rs, alignment, size); + return (succ == 0) ? rs : nullptr; #endif - } +} - inline void alignedDeallocate(void* ptr) - { +inline void alignedDeallocate(void* ptr) +{ #ifdef _MSC_VER - _aligned_free(ptr); + _aligned_free(ptr); #else - free(ptr); + free(ptr); #endif - } +} - class StandardAllocator - { - public: - // not really called - void* allocate(size_t size) - { - return ::malloc(size); - } - void deallocate(void * ptr) - { - return ::free(ptr); - } - }; +class StandardAllocator +{ +public: + // not really called + void* allocate(size_t size) { return ::malloc(size); } + void deallocate(void* ptr) { return ::free(ptr); } +}; - template - class AlignedAllocator - { - public: - void* allocate(size_t size) - { - return alignedAllocate(size, ALIGNMENT); - } - void deallocate(void * ptr) - { - return alignedDeallocate(ptr); - } - }; +template +class AlignedAllocator +{ +public: + void* allocate(size_t size) { return alignedAllocate(size, ALIGNMENT); } + void deallocate(void* ptr) { return alignedDeallocate(ptr); } +}; - template - class AllocateMethod +template +class AllocateMethod +{ +public: + static inline T* allocateArray(Index count) { - public: - static inline T* allocateArray(Index count) + TAllocator allocator; + T* rs = (T*)allocator.allocate(count * sizeof(T)); + if (!std::is_trivially_constructible::value) { - TAllocator allocator; - T* rs = (T*)allocator.allocate(count * sizeof(T)); - if (!std::is_trivially_constructible::value) - { - for (Index i = 0; i < count; i++) - new (rs + i) T(); - } - return rs; + for (Index i = 0; i < count; i++) + new (rs + i) T(); } - static inline void deallocateArray(T* ptr, Index count) + return rs; + } + static inline void deallocateArray(T* ptr, Index count) + { + TAllocator allocator; + if (!std::is_trivially_destructible::value) { - TAllocator allocator; - if (!std::is_trivially_destructible::value) - { - for (Index i = 0; i < count; i++) - ptr[i].~T(); - } - allocator.deallocate(ptr); + for (Index i = 0; i < count; i++) + ptr[i].~T(); } - }; + allocator.deallocate(ptr); + } +}; #if 0 template @@ -104,6 +92,6 @@ namespace Slang } }; #endif -} +} // namespace Slang #endif diff --git a/source/core/slang-archive-file-system.cpp b/source/core/slang-archive-file-system.cpp index e219fcbb55..9513e6372d 100644 --- a/source/core/slang-archive-file-system.cpp +++ b/source/core/slang-archive-file-system.cpp @@ -1,29 +1,28 @@ #include "slang-archive-file-system.h" +#include "../core/slang-castable.h" +#include "slang-blob.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" - -#include "../core/slang-castable.h" - #include "slang-io.h" -#include "slang-string-util.h" -#include "slang-blob.h" - #include "slang-riff-file-system.h" +#include "slang-string-util.h" // Compression systems #include "slang-deflate-compression-system.h" #include "slang-lz4-compression-system.h" // Zip file system -#include "slang-zip-file-system.h" - #include "slang-riff.h" +#include "slang-zip-file-system.h" namespace Slang { -SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComPtr& outFileSystem) +SlangResult loadArchiveFileSystem( + const void* data, + size_t dataSizeInBytes, + ComPtr& outFileSystem) { ComPtr fileSystem; if (ZipFileSystem::isArchive(data, dataSizeInBytes)) @@ -34,7 +33,7 @@ SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComP else if (RiffFileSystem::isArchive(data, dataSizeInBytes)) { // It's riff contained (Slang specific) - fileSystem = new RiffFileSystem(nullptr); + fileSystem = new RiffFileSystem(nullptr); } else { @@ -52,26 +51,28 @@ SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComP outFileSystem = fileSystem; return SLANG_OK; } - -SlangResult createArchiveFileSystem(SlangArchiveType type, ComPtr& outFileSystem) + +SlangResult createArchiveFileSystem( + SlangArchiveType type, + ComPtr& outFileSystem) { switch (type) { - case SLANG_ARCHIVE_TYPE_ZIP: + case SLANG_ARCHIVE_TYPE_ZIP: { return ZipFileSystem::create(outFileSystem); } - case SLANG_ARCHIVE_TYPE_RIFF: + case SLANG_ARCHIVE_TYPE_RIFF: { outFileSystem = new RiffFileSystem(nullptr); return SLANG_OK; } - case SLANG_ARCHIVE_TYPE_RIFF_DEFLATE: + case SLANG_ARCHIVE_TYPE_RIFF_DEFLATE: { outFileSystem = new RiffFileSystem(DeflateCompressionSystem::getSingleton()); return SLANG_OK; } - case SLANG_ARCHIVE_TYPE_RIFF_LZ4: + case SLANG_ARCHIVE_TYPE_RIFF_LZ4: { outFileSystem = new RiffFileSystem(LZ4CompressionSystem::getSingleton()); return SLANG_OK; diff --git a/source/core/slang-archive-file-system.h b/source/core/slang-archive-file-system.h index 13b226019f..25bac08128 100644 --- a/source/core/slang-archive-file-system.h +++ b/source/core/slang-archive-file-system.h @@ -2,9 +2,7 @@ #define SLANG_CORE_ARCHIVE_FILE_SYSTEM_H #include "slang-basic.h" - #include "slang-com-ptr.h" - #include "slang-compression-system.h" namespace Slang @@ -12,20 +10,32 @@ namespace Slang class IArchiveFileSystem : public ISlangCastable { - SLANG_COM_INTERFACE(0x5c565aac, 0xe834, 0x41fc, { 0x8b, 0xb, 0x7d, 0x4c, 0xf3, 0x8b, 0x89, 0x50 }); - - /// Loads an archive. - SLANG_NO_THROW virtual SlangResult SLANG_MCALL loadArchive(const void* archive, size_t archiveSizeInBytes) = 0; - /// Get as an archive (that can be saved to disk) - /// NOTE! If the blob is not owned, it's contents can be invalidated by any call to a method of the file system or loss of scope - SLANG_NO_THROW virtual SlangResult SLANG_MCALL storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) = 0; - /// Set the compression - used for any subsequent items added + SLANG_COM_INTERFACE( + 0x5c565aac, + 0xe834, + 0x41fc, + {0x8b, 0xb, 0x7d, 0x4c, 0xf3, 0x8b, 0x89, 0x50}); + + /// Loads an archive. + SLANG_NO_THROW virtual SlangResult SLANG_MCALL + loadArchive(const void* archive, size_t archiveSizeInBytes) = 0; + /// Get as an archive (that can be saved to disk) + /// NOTE! If the blob is not owned, it's contents can be invalidated by any call to a method of + /// the file system or loss of scope + SLANG_NO_THROW virtual SlangResult SLANG_MCALL + storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) = 0; + /// Set the compression - used for any subsequent items added SLANG_NO_THROW virtual void SLANG_MCALL setCompressionStyle(const CompressionStyle& style) = 0; }; -SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, ComPtr& outFileSystem); -SlangResult createArchiveFileSystem(SlangArchiveType type, ComPtr& outFileSystem); +SlangResult loadArchiveFileSystem( + const void* data, + size_t dataSizeInBytes, + ComPtr& outFileSystem); +SlangResult createArchiveFileSystem( + SlangArchiveType type, + ComPtr& outFileSystem); -} +} // namespace Slang #endif diff --git a/source/core/slang-array-view.h b/source/core/slang-array-view.h index 50270e0a04..21b6ce1134 100644 --- a/source/core/slang-array-view.h +++ b/source/core/slang-array-view.h @@ -6,222 +6,225 @@ namespace Slang { - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ConstArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!! - template - class ConstArrayView - { - public: - typedef ConstArrayView ThisType; +template +class ConstArrayView +{ +public: + typedef ConstArrayView ThisType; - SLANG_FORCE_INLINE const T* begin() const { return m_buffer; } - - SLANG_FORCE_INLINE const T* end() const { return m_buffer + m_count; } - - SLANG_FORCE_INLINE Count getCount() const { return m_count; } + SLANG_FORCE_INLINE const T* begin() const { return m_buffer; } - SLANG_FORCE_INLINE const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - - SLANG_FORCE_INLINE const T* getBuffer() const { return m_buffer; } - - template - Index indexOf(const T2& val) const - { - for (Index i = 0; i < m_count; i++) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T* end() const { return m_buffer + m_count; } - template - Index lastIndexOf(const T2& val) const - { - for (Index i = m_count - 1; i >= 0; i--) - { - if (m_buffer[i] == val) - return i; - } - return -1; - } + SLANG_FORCE_INLINE Count getCount() const { return m_count; } - template - Index findFirstIndex(const Func& predicate) const - { - for (Index i = 0; i < m_count; i++) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } - template - Index findLastIndex(const Func& predicate) const - { - for (Index i = m_count - 1; i >= 0; i--) - { - if (predicate(m_buffer[i])) - return i; - } - return -1; - } + SLANG_FORCE_INLINE const T* getBuffer() const { return m_buffer; } - bool containsMemory(const ThisType& rhs) const + template + Index indexOf(const T2& val) const + { + for (Index i = 0; i < m_count; i++) { - return rhs.getBuffer() >= getBuffer() && rhs.end() <= end(); + if (m_buffer[i] == val) + return i; } + return -1; + } - bool operator==(const ThisType& rhs) const + template + Index lastIndexOf(const T2& val) const + { + for (Index i = m_count - 1; i >= 0; i--) { - if (&rhs == this) - { - return true; - } - const Count count = getCount(); - if (count != rhs.getCount()) - { - return false; - } - const T* thisEle = getBuffer(); - const T* rhsEle = rhs.getBuffer(); - for (Index i = 0; i < count; ++i) - { - if (thisEle[i] != rhsEle[i]) - { - return false; - } - } - return true; + if (m_buffer[i] == val) + return i; } - SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } + return -1; + } - ThisType head(Index index) const + template + Index findFirstIndex(const Func& predicate) const + { + for (Index i = 0; i < m_count; i++) { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer, index); + if (predicate(m_buffer[i])) + return i; } - ThisType tail(Index index) const + return -1; + } + + template + Index findLastIndex(const Func& predicate) const + { + for (Index i = m_count - 1; i >= 0; i--) { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer + index, m_count - index); + if (predicate(m_buffer[i])) + return i; } + return -1; + } - ConstArrayView() : - m_buffer(nullptr), - m_count(0) + bool containsMemory(const ThisType& rhs) const + { + return rhs.getBuffer() >= getBuffer() && rhs.end() <= end(); + } + + bool operator==(const ThisType& rhs) const + { + if (&rhs == this) { + return true; } - - ConstArrayView(const T* buffer, Count count) : - m_buffer(const_cast(buffer)), - m_count(count) + const Count count = getCount(); + if (count != rhs.getCount()) { + return false; } - - protected: - ConstArrayView(T* buffer, Count count) : - m_buffer(buffer), - m_count(count) + const T* thisEle = getBuffer(); + const T* rhsEle = rhs.getBuffer(); + for (Index i = 0; i < count; ++i) { + if (thisEle[i] != rhsEle[i]) + { + return false; + } } + return true; + } + SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - T* m_buffer; ///< Note that this isn't const, as is used for derived class ArrayView also - Count m_count; - }; + ThisType head(Index index) const + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer, index); + } + ThisType tail(Index index) const + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer + index, m_count - index); + } - template - ConstArrayView makeConstArrayViewSingle(const T& obj) + ConstArrayView() + : m_buffer(nullptr), m_count(0) { - return ConstArrayView(&obj, 1); - } + } - template - ConstArrayView makeConstArrayView(const T* buffer, Count count) + ConstArrayView(const T* buffer, Count count) + : m_buffer(const_cast(buffer)), m_count(count) { - return ConstArrayView(buffer, count); } - template - ConstArrayView makeConstArrayView(const T (&arr)[N]) +protected: + ConstArrayView(T* buffer, Count count) + : m_buffer(buffer), m_count(count) { - return ConstArrayView(arr, Index(N)); } + T* m_buffer; ///< Note that this isn't const, as is used for derived class ArrayView also + Count m_count; +}; - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +template +ConstArrayView makeConstArrayViewSingle(const T& obj) +{ + return ConstArrayView(&obj, 1); +} - template - class ArrayView: public ConstArrayView - { - public: - typedef ArrayView ThisType; +template +ConstArrayView makeConstArrayView(const T* buffer, Count count) +{ + return ConstArrayView(buffer, count); +} - typedef ConstArrayView Super; - - using Super::m_buffer; - using Super::m_count; +template +ConstArrayView makeConstArrayView(const T (&arr)[N]) +{ + return ConstArrayView(arr, Index(N)); +} - using Super::begin; - T* begin() { return m_buffer; } - using Super::end; - T* end() { return m_buffer + m_count; } - - using Super::head; - using Super::tail; +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArrayView !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - using Super::operator[]; - inline T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } +template +class ArrayView : public ConstArrayView +{ +public: + typedef ArrayView ThisType; - using Super::getBuffer; - inline T* getBuffer() { return m_buffer; } + typedef ConstArrayView Super; - ThisType head(Index index) - { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer, index); - } - ThisType tail(Index index) - { - SLANG_ASSERT(index >= 0 && index <= m_count); - return ThisType(m_buffer + index, m_count - index); - } + using Super::m_buffer; + using Super::m_count; + + using Super::begin; + T* begin() { return m_buffer; } - T& getLast() { return m_buffer[m_count - 1]; } + using Super::end; + T* end() { return m_buffer + m_count; } - ArrayView() : Super() {} - ArrayView(T* buffer, Index size) :Super(buffer, size) {} - }; + using Super::head; + using Super::tail; - template - ArrayView makeArrayViewSingle(T& obj) + using Super::operator[]; + inline T& operator[](Index idx) { - return ArrayView(&obj, 1); - } - - template - ArrayView makeArrayView(T* buffer, Count count) + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + + using Super::getBuffer; + inline T* getBuffer() { return m_buffer; } + + ThisType head(Index index) { - return ArrayView(buffer, count); + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer, index); } + ThisType tail(Index index) + { + SLANG_ASSERT(index >= 0 && index <= m_count); + return ThisType(m_buffer + index, m_count - index); + } + + T& getLast() { return m_buffer[m_count - 1]; } - template - ArrayView makeArrayView(T (&arr)[N]) + ArrayView() + : Super() { - return ArrayView(arr, Count(N)); } + ArrayView(T* buffer, Index size) + : Super(buffer, size) + { + } +}; + +template +ArrayView makeArrayViewSingle(T& obj) +{ + return ArrayView(&obj, 1); +} +template +ArrayView makeArrayView(T* buffer, Count count) +{ + return ArrayView(buffer, count); +} +template +ArrayView makeArrayView(T (&arr)[N]) +{ + return ArrayView(arr, Count(N)); } + +} // namespace Slang + #endif diff --git a/source/core/slang-array.h b/source/core/slang-array.h index d24ff09709..5c2fefc261 100644 --- a/source/core/slang-array.h +++ b/source/core/slang-array.h @@ -1,197 +1,220 @@ #ifndef SLANG_CORE_ARRAY_H #define SLANG_CORE_ARRAY_H -#include "slang-exception.h" #include "slang-array-view.h" +#include "slang-exception.h" namespace Slang { - /* An array container with fixed maximum size defined by COUNT. */ - template - class Array - { - public: - T* begin() { return m_buffer; } - const T* begin() const { return m_buffer; } - - const T* end() const { return m_buffer + m_count; } - T* end() { return m_buffer + m_count; } - - inline Index getCapacity() const { return COUNT; } - inline Index getCount() const { return m_count; } - inline const T& getFirst() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - inline T& getFirst() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[0]; - } - inline const T& getLast() const - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } - inline T& getLast() - { - SLANG_ASSERT(m_count > 0); - return m_buffer[m_count - 1]; - } - inline void setCount(Index newCount) - { - SLANG_ASSERT(newCount >= 0 && newCount <= COUNT); - m_count = newCount; - } - inline void add(const T& item) - { - SLANG_ASSERT(m_count < COUNT); - m_buffer[m_count++] = item; - } - inline void add(T&& item) - { - SLANG_ASSERT(m_count < COUNT); - m_buffer[m_count++] = _Move(item); - } - - inline const T& operator [](Index idx) const - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - inline T& operator [](Index idx) - { - SLANG_ASSERT(idx >= 0 && idx < m_count); - return m_buffer[idx]; - } - - inline const T* getBuffer() const { return m_buffer; } - inline T* getBuffer() { return m_buffer; } - - inline void clear() { m_count = 0; } - - template - Index indexOf(const T2& val) const { return getView().indexOf(val); } - template - Index lastIndexOf(const T2& val) const { return getView().lastIndexOf(val); } - template - Index findFirstIndex(const Func& predicate) const { return getView().findFirstIndex(predicate); } - template - Index findLastIndex(const Func& predicate) const { return getView().findLastIndex(predicate); } - - inline ConstArrayView getView() const { return ConstArrayView(m_buffer, m_count); } - inline ConstArrayView getView(Index start, Index count) const - { - SLANG_ASSERT(start >= 0 && count >= 0); - SLANG_ASSERT(start <= m_count && start + count < m_count); - return ConstArrayView(m_buffer + start, count); - } - - inline ArrayView getView() { return ArrayView(m_buffer, m_count); } - inline ArrayView getView(Index start, Index count) - { - SLANG_ASSERT(start >= 0 && count >= 0); - SLANG_ASSERT(start <= m_count && start + count < m_count); - return ArrayView(m_buffer + start, count); - } - - private: - T m_buffer[COUNT]; - Index m_count = 0; - }; - - template - class Array - { - public: - T* begin() { return nullptr; } - const T* begin() const { return nullptr; } - - const T* end() const { return nullptr; } - T* end() { return nullptr; } - - inline Index getCapacity() const { return 0; } - inline Index getCount() const { return 0; } - inline void setCount(Index newCount) - { - SLANG_ASSERT(newCount == 0); - } - inline const T* getBuffer() const { return nullptr; } - inline T* getBuffer() { return nullptr; } - inline void clear() {} - - template - Index indexOf(const T2& val) const { return getView().indexOf(val); } - template - Index lastIndexOf(const T2& val) const { return getView().lastIndexOf(val); } - template - Index findFirstIndex(const Func& predicate) const { return getView().findFirstIndex(predicate); } - template - Index findLastIndex(const Func& predicate) const { return getView().findLastIndex(predicate); } - - inline ConstArrayView getView() const { return ConstArrayView(nullptr, 0); } - inline ConstArrayView getView(Index start, Index count) const - { - SLANG_ASSERT(start == 0 && count == 0); - return ConstArrayView(nullptr, 0); - } - - inline ArrayView getView() { return ArrayView(nullptr, 0); } - inline ArrayView getView(Index start, Index count) - { - SLANG_ASSERT(start == 0 && count == 0); - return ArrayView(nullptr, 0); - } - }; - - template - struct FirstType - { - typedef T Type; - }; - - - template - void insertArray(Array&) {} - - template - void insertArray(Array& arr, const T& val, TArgs... args) - { - arr.add(val); - insertArray(arr, args...); - } - - template - auto makeArray(TArgs ...args) -> Array::Type, sizeof...(args)> - { - Array::Type, Index(sizeof...(args))> rs; - insertArray::Type>(rs, args...); - return rs; - } - - template - auto makeArray() -> Array - { - return Array(); - } - - - template - void addToList(TList&) - { - } - template - void addToList(TList& list, T node) - { - list.add(node); - } - template - void addToList(TList& list, T node, TArgs ... args) - { - list.add(node); - addToList(list, args...); +/* An array container with fixed maximum size defined by COUNT. */ +template +class Array +{ +public: + T* begin() { return m_buffer; } + const T* begin() const { return m_buffer; } + + const T* end() const { return m_buffer + m_count; } + T* end() { return m_buffer + m_count; } + + inline Index getCapacity() const { return COUNT; } + inline Index getCount() const { return m_count; } + inline const T& getFirst() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + inline T& getFirst() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[0]; + } + inline const T& getLast() const + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } + inline T& getLast() + { + SLANG_ASSERT(m_count > 0); + return m_buffer[m_count - 1]; + } + inline void setCount(Index newCount) + { + SLANG_ASSERT(newCount >= 0 && newCount <= COUNT); + m_count = newCount; + } + inline void add(const T& item) + { + SLANG_ASSERT(m_count < COUNT); + m_buffer[m_count++] = item; + } + inline void add(T&& item) + { + SLANG_ASSERT(m_count < COUNT); + m_buffer[m_count++] = _Move(item); + } + + inline const T& operator[](Index idx) const + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + inline T& operator[](Index idx) + { + SLANG_ASSERT(idx >= 0 && idx < m_count); + return m_buffer[idx]; + } + + inline const T* getBuffer() const { return m_buffer; } + inline T* getBuffer() { return m_buffer; } + + inline void clear() { m_count = 0; } + + template + Index indexOf(const T2& val) const + { + return getView().indexOf(val); + } + template + Index lastIndexOf(const T2& val) const + { + return getView().lastIndexOf(val); + } + template + Index findFirstIndex(const Func& predicate) const + { + return getView().findFirstIndex(predicate); + } + template + Index findLastIndex(const Func& predicate) const + { + return getView().findLastIndex(predicate); + } + + inline ConstArrayView getView() const { return ConstArrayView(m_buffer, m_count); } + inline ConstArrayView getView(Index start, Index count) const + { + SLANG_ASSERT(start >= 0 && count >= 0); + SLANG_ASSERT(start <= m_count && start + count < m_count); + return ConstArrayView(m_buffer + start, count); + } + + inline ArrayView getView() { return ArrayView(m_buffer, m_count); } + inline ArrayView getView(Index start, Index count) + { + SLANG_ASSERT(start >= 0 && count >= 0); + SLANG_ASSERT(start <= m_count && start + count < m_count); + return ArrayView(m_buffer + start, count); } + +private: + T m_buffer[COUNT]; + Index m_count = 0; +}; + +template +class Array +{ +public: + T* begin() { return nullptr; } + const T* begin() const { return nullptr; } + + const T* end() const { return nullptr; } + T* end() { return nullptr; } + + inline Index getCapacity() const { return 0; } + inline Index getCount() const { return 0; } + inline void setCount(Index newCount) { SLANG_ASSERT(newCount == 0); } + inline const T* getBuffer() const { return nullptr; } + inline T* getBuffer() { return nullptr; } + inline void clear() {} + + template + Index indexOf(const T2& val) const + { + return getView().indexOf(val); + } + template + Index lastIndexOf(const T2& val) const + { + return getView().lastIndexOf(val); + } + template + Index findFirstIndex(const Func& predicate) const + { + return getView().findFirstIndex(predicate); + } + template + Index findLastIndex(const Func& predicate) const + { + return getView().findLastIndex(predicate); + } + + inline ConstArrayView getView() const { return ConstArrayView(nullptr, 0); } + inline ConstArrayView getView(Index start, Index count) const + { + SLANG_ASSERT(start == 0 && count == 0); + return ConstArrayView(nullptr, 0); + } + + inline ArrayView getView() { return ArrayView(nullptr, 0); } + inline ArrayView getView(Index start, Index count) + { + SLANG_ASSERT(start == 0 && count == 0); + return ArrayView(nullptr, 0); + } +}; + +template +struct FirstType +{ + typedef T Type; +}; + + +template +void insertArray(Array&) +{ +} + +template +void insertArray(Array& arr, const T& val, TArgs... args) +{ + arr.add(val); + insertArray(arr, args...); +} + +template +auto makeArray(TArgs... args) -> Array::Type, sizeof...(args)> +{ + Array::Type, Index(sizeof...(args))> rs; + insertArray::Type>(rs, args...); + return rs; +} + +template +auto makeArray() -> Array +{ + return Array(); +} + + +template +void addToList(TList&) +{ +} +template +void addToList(TList& list, T node) +{ + list.add(node); +} +template +void addToList(TList& list, T node, TArgs... args) +{ + list.add(node); + addToList(list, args...); } +} // namespace Slang #endif diff --git a/source/core/slang-basic.h b/source/core/slang-basic.h index 5387af4aa2..d37782160c 100644 --- a/source/core/slang-basic.h +++ b/source/core/slang-basic.h @@ -1,14 +1,14 @@ #ifndef SLANG_CORE_BASIC_H #define SLANG_CORE_BASIC_H -#include "slang-common.h" -#include "slang-math.h" -#include "slang-string.h" #include "slang-array.h" +#include "slang-common.h" +#include "slang-dictionary.h" +#include "slang-exception.h" #include "slang-list.h" +#include "slang-math.h" #include "slang-short-list.h" #include "slang-smart-pointer.h" -#include "slang-exception.h" -#include "slang-dictionary.h" +#include "slang-string.h" #endif diff --git a/source/core/slang-blob.cpp b/source/core/slang-blob.cpp index 19a4281bd2..ea4f4b6c08 100644 --- a/source/core/slang-blob.cpp +++ b/source/core/slang-blob.cpp @@ -1,13 +1,13 @@ #include "slang-blob.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! BlobBase !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ ISlangUnknown* BlobBase::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ISlangBlob::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangBlob::getTypeGuid()) { return static_cast(this); } @@ -41,12 +41,11 @@ void StringBlob::_setUniqueRep(StringRepresentation* uniqueRep) m_uniqueRep = uniqueRep; - m_slice = uniqueRep ? - UnownedTerminatedStringSlice(uniqueRep->getData(), uniqueRep->getLength()) : - UnownedTerminatedStringSlice(); + m_slice = uniqueRep ? UnownedTerminatedStringSlice(uniqueRep->getData(), uniqueRep->getLength()) + : UnownedTerminatedStringSlice(); } -/* static */StringRepresentation* StringBlob::_createUniqueCopy(StringRepresentation* rep) +/* static */ StringRepresentation* StringBlob::_createUniqueCopy(StringRepresentation* rep) { if (rep) { @@ -75,7 +74,7 @@ void StringBlob::_setWithMove(StringRepresentation* rep) if (rep && !rep->isUniquelyReferenced()) { _setUniqueRep(_createUniqueCopy(rep)); - // We need to release a ref as rep is passed in with the 'current' ref count + // We need to release a ref as rep is passed in with the 'current' ref count rep->releaseReference(); } else @@ -84,7 +83,7 @@ void StringBlob::_setWithMove(StringRepresentation* rep) } } -/* static */ComPtr StringBlob::create(const UnownedStringSlice& slice) +/* static */ ComPtr StringBlob::create(const UnownedStringSlice& slice) { StringRepresentation* rep = nullptr; if (slice.getLength()) @@ -93,27 +92,27 @@ void StringBlob::_setWithMove(StringRepresentation* rep) } auto blob = new StringBlob; - + // rep must be unique at this point blob->_setUniqueRep(rep); return ComPtr(blob); } -/* static */ComPtr StringBlob::create(const String& in) +/* static */ ComPtr StringBlob::create(const String& in) { auto blob = new StringBlob; blob->_setWithCopy(in.getStringRepresentation()); return ComPtr(blob); } -/* static */ComPtr StringBlob::moveCreate(String& in) +/* static */ ComPtr StringBlob::moveCreate(String& in) { auto blob = new StringBlob; blob->_setWithMove(in.detachStringRepresentation()); return ComPtr(blob); } -/* static */ComPtr StringBlob::moveCreate(String&& in) +/* static */ ComPtr StringBlob::moveCreate(String&& in) { auto blob = new StringBlob; blob->_setWithMove(in.detachStringRepresentation()); @@ -167,7 +166,7 @@ void* RawBlob::getObject(const Guid& guid) // If the data has 0 termination, we can return the pointer if (guid == SlangTerminatedChars::getTypeGuid() && m_data.isTerminated()) { - return (char*)m_data.getData(); + return (char*)m_data.getData(); } return nullptr; } @@ -185,7 +184,7 @@ void* ScopeBlob::castAs(const SlangUUID& guid) return obj; } - // If the contained thing is castable, ask it + // If the contained thing is castable, ask it if (m_castable) { return m_castable->castAs(guid); @@ -225,7 +224,7 @@ void* ListBlob::getObject(const Guid& guid) /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! StaticBlob !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ -SlangResult StaticBlob::queryInterface(SlangUUID const& guid, void** outObject) +SlangResult StaticBlob::queryInterface(SlangUUID const& guid, void** outObject) { if (auto intf = getInterface(guid)) { @@ -246,8 +245,7 @@ void* StaticBlob::castAs(const SlangUUID& guid) ISlangUnknown* StaticBlob::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ISlangBlob::getTypeGuid()) + if (guid == ISlangUnknown::getTypeGuid() || guid == ISlangBlob::getTypeGuid()) { return static_cast(this); } diff --git a/source/core/slang-blob.h b/source/core/slang-blob.h index 2b752b306a..af3206fb5b 100644 --- a/source/core/slang-blob.h +++ b/source/core/slang-blob.h @@ -1,22 +1,20 @@ #ifndef SLANG_CORE_BLOB_H #define SLANG_CORE_BLOB_H -#include "../../include/slang.h" - -#include "slang-string.h" -#include "slang-list.h" - -#include - +#include "../core/slang-com-object.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" +#include "slang-list.h" +#include "slang-string.h" +#include "slang.h" -#include "../core/slang-com-object.h" +#include -namespace Slang { +namespace Slang +{ /** Base class for simple blobs. -*/ + */ class BlobBase : public ISlangBlob, public ICastable, public ComBaseObject { public: @@ -33,53 +31,57 @@ class BlobBase : public ISlangBlob, public ICastable, public ComBaseObject /** A blob that uses a `StringRepresentation` for its storage. -By design the StringBlob owns a unique reference to the StringRepresentation. +By design the StringBlob owns a unique reference to the StringRepresentation. This is because StringBlob, implements an interface which should work across threads. */ class StringBlob : public BlobBase { public: - SLANG_CLASS_GUID(0xf7e0e93c, 0xde70, 0x4531, { 0x9c, 0x9f, 0xdd, 0xa3, 0xf6, 0xc6, 0xc0, 0xdd }); + SLANG_CLASS_GUID(0xf7e0e93c, 0xde70, 0x4531, {0x9c, 0x9f, 0xdd, 0xa3, 0xf6, 0xc6, 0xc0, 0xdd}); // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_slice.begin(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_slice.begin(); + } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_slice.getLength(); } - /// Since in is not being moved will *always* create a new representation, unless the in is empty + /// Since in is not being moved will *always* create a new representation, unless the in is + /// empty static ComPtr create(const String& in); - /// Create from a slice + /// Create from a slice static ComPtr create(const UnownedStringSlice& slice); - /// Moves from in into the created blob. - /// NOTE! That will only use the representation from in, if it is *unique* - /// otherwise it will make a new copy. + /// Moves from in into the created blob. + /// NOTE! That will only use the representation from in, if it is *unique* + /// otherwise it will make a new copy. static ComPtr moveCreate(String& in); static ComPtr moveCreate(String&& in); - /// Dtor + /// Dtor ~StringBlob(); protected: - - /// Init with a rep when can't be owned. + /// Init with a rep when can't be owned. void _setWithCopy(StringRepresentation* rep); - /// Init with a representation that has been moved. + /// Init with a representation that has been moved. void _setWithMove(StringRepresentation* rep); - /// Create a unique copy of rep. - /// If nullptr will work (if rep is empty, will return that) + /// Create a unique copy of rep. + /// If nullptr will work (if rep is empty, will return that) static StringRepresentation* _createUniqueCopy(StringRepresentation* rep); - /// Rep can only be nullptr or have a single ref + /// Rep can only be nullptr or have a single ref void _setUniqueRep(StringRepresentation* rep); void* getObject(const Guid& guid); - UnownedTerminatedStringSlice m_slice; ///< The contents - StringRepresentation* m_uniqueRep = nullptr; ///< Holds actual bytes. Can be nullptr if it's an empty string. + UnownedTerminatedStringSlice m_slice; ///< The contents + StringRepresentation* m_uniqueRep = + nullptr; ///< Holds actual bytes. Can be nullptr if it's an empty string. }; class ListBlob : public BlobBase @@ -91,17 +93,32 @@ class ListBlob : public BlobBase // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data.getBuffer(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_data.getBuffer(); + } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getCount(); } - static ComPtr create(const List& data) { return ComPtr(new ListBlob(data)); } - - static ComPtr moveCreate(List& data) { return ComPtr(new ListBlob(_Move(data))); } + static ComPtr create(const List& data) + { + return ComPtr(new ListBlob(data)); + } + + static ComPtr moveCreate(List& data) + { + return ComPtr(new ListBlob(_Move(data))); + } protected: - explicit ListBlob(const List& data) : m_data(data) {} - // Move ctor - explicit ListBlob(List&& data) : m_data(data) {} + explicit ListBlob(const List& data) + : m_data(data) + { + } + // Move ctor + explicit ListBlob(List&& data) + : m_data(data) + { + } void* getObject(const Guid& guid); @@ -126,7 +143,7 @@ class ScopedAllocation m_capacityInBytes = size; return m_data; } - /// Allocate size including a 0 byte at `size`. + /// Allocate size including a 0 byte at `size`. void* allocateTerminated(size_t size) { SLANG_ASSUME(size != std::numeric_limits::max()); @@ -146,7 +163,8 @@ class ScopedAllocation m_sizeInBytes = 0; m_capacityInBytes = 0; } - // Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain intact. + // Reallocate so the buffer is the specified capacity/size. Contents of buffer up to size remain + // intact. void reallocate(size_t capacity) { if (capacity != m_capacityInBytes) @@ -156,7 +174,8 @@ class ScopedAllocation m_capacityInBytes = capacity; } } - /// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no allocation) + /// Makes this no longer own the allocation. Returns the allocated data (or nullptr if no + /// allocation) void* detach() { void* data = m_data; @@ -185,14 +204,14 @@ class ScopedAllocation return dst; } - /// Get the allocated data. Returns nullptr if there is no allocated data + /// Get the allocated data. Returns nullptr if there is no allocated data void* getData() const { return m_data; } - /// Get the size of the allocated data. + /// Get the size of the allocated data. size_t getSizeInBytes() const { return m_sizeInBytes; } - /// Get the capacity in bytes + /// Get the capacity in bytes size_t getCapacityInBytes() const { return m_capacityInBytes; } - void setSizeInBytes(size_t size) + void setSizeInBytes(size_t size) { SLANG_ASSERT(size <= m_capacityInBytes); m_sizeInBytes = size; @@ -205,13 +224,14 @@ class ScopedAllocation Swap(m_capacityInBytes, rhs.m_capacityInBytes); } - /// True if has zero termination, at the byte at m_sizeInBytes - bool isTerminated() const { return m_capacityInBytes > m_sizeInBytes && ((const char*)m_data)[m_sizeInBytes] == 0; } + /// True if has zero termination, at the byte at m_sizeInBytes + bool isTerminated() const + { + return m_capacityInBytes > m_sizeInBytes && ((const char*)m_data)[m_sizeInBytes] == 0; + } - ScopedAllocation() : - m_data(nullptr), - m_sizeInBytes(0), - m_capacityInBytes(0) + ScopedAllocation() + : m_data(nullptr), m_sizeInBytes(0), m_capacityInBytes(0) { } @@ -228,15 +248,21 @@ class ScopedAllocation }; /** A blob that manages some raw data that it owns. -*/ + */ class RawBlob : public BlobBase { public: // ICastable virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data.getData(); } - SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_data.getSizeInBytes(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_data.getData(); + } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return m_data.getSizeInBytes(); + } static ComPtr moveCreate(ScopedAllocation& alloc) { @@ -245,7 +271,7 @@ class RawBlob : public BlobBase return ComPtr(blob); } - /// Create a blob that will retain (a copy of) raw data. + /// Create a blob that will retain (a copy of) raw data. static inline ComPtr create(void const* inData, size_t size) { return ComPtr(new RawBlob(inData, size)); @@ -254,10 +280,7 @@ class RawBlob : public BlobBase protected: // Ctor // NOTE! Takes a copy of the input data - RawBlob(const void* data, size_t size) - { - memcpy(m_data.allocateTerminated(size), data, size); - } + RawBlob(const void* data, size_t size) { memcpy(m_data.allocateTerminated(size), data, size); } void* getObject(const Guid& guid); @@ -281,9 +304,8 @@ class UnownedRawBlob : public BlobBase protected: // Ctor - UnownedRawBlob(const void* data, size_t size) : - m_data(data), - m_dataSizeInBytes(size) + UnownedRawBlob(const void* data, size_t size) + : m_data(data), m_dataSizeInBytes(size) { } @@ -300,9 +322,9 @@ This is useful when a Blob is useful to represent some global immutable chunk of class StaticBlob : public ISlangBlob, public ICastable { public: - // ISlangUnknown - SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) SLANG_OVERRIDE; + SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) + SLANG_OVERRIDE; SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return 1; } SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return 1; } @@ -313,9 +335,8 @@ class StaticBlob : public ISlangBlob, public ICastable SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_data; } SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_dataCount; } - StaticBlob(const void* data, size_t dataCount): - m_data(data), - m_dataCount(dataCount) + StaticBlob(const void* data, size_t dataCount) + : m_data(data), m_dataCount(dataCount) { } @@ -334,8 +355,14 @@ class ScopeBlob : public BlobBase virtual SLANG_NO_THROW void* SLANG_MCALL castAs(const SlangUUID& guid) SLANG_OVERRIDE; // ISlangBlob - SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE { return m_blob->getBufferPointer(); } - SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE { return m_blob->getBufferSize(); } + SLANG_NO_THROW void const* SLANG_MCALL getBufferPointer() SLANG_OVERRIDE + { + return m_blob->getBufferPointer(); + } + SLANG_NO_THROW size_t SLANG_MCALL getBufferSize() SLANG_OVERRIDE + { + return m_blob->getBufferSize(); + } static inline ComPtr create(ISlangBlob* blob, ISlangUnknown* scope) { @@ -343,11 +370,9 @@ class ScopeBlob : public BlobBase } protected: - // Ctor - ScopeBlob(ISlangBlob* blob, ISlangUnknown* scope) : - m_blob(blob), - m_scope(scope) + ScopeBlob(ISlangBlob* blob, ISlangUnknown* scope) + : m_blob(blob), m_scope(scope) { // Cache the ICastable interface if there is one. blob->queryInterface(SLANG_IID_PPV_ARGS(m_castable.writeRef())); @@ -355,7 +380,8 @@ class ScopeBlob : public BlobBase ComPtr m_scope; ComPtr m_blob; - ComPtr m_castable; ///< Set if the blob has this interface. Set to nullptr if does not. + ComPtr + m_castable; ///< Set if the blob has this interface. Set to nullptr if does not. }; } // namespace Slang diff --git a/source/core/slang-byte-encode-util.cpp b/source/core/slang-byte-encode-util.cpp index c7022397fc..f3f375c605 100644 --- a/source/core/slang-byte-encode-util.cpp +++ b/source/core/slang-byte-encode-util.cpp @@ -1,17 +1,18 @@ #include "slang-byte-encode-util.h" -namespace Slang { +namespace Slang +{ // Descriptions of algorithms here... // https://github.com/stoklund/varint #if SLANG_LITTLE_ENDIAN && SLANG_UNALIGNED_ACCESS // Testing on i7, unaligned access is around 40% faster -# define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 1 +#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 1 #endif #ifndef SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS -# define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 0 +#define SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS 0 #endif #define SLANG_REPEAT_2(n) n, n @@ -22,23 +23,22 @@ namespace Slang { #define SLANG_REPEAT_64(n) SLANG_REPEAT_32(n), SLANG_REPEAT_32(n) #define SLANG_REPEAT_128(n) SLANG_REPEAT_64(n), SLANG_REPEAT_64(n) -/* static */const int8_t ByteEncodeUtil::s_msb8[256] = -{ - - 1, - 0, - SLANG_REPEAT_2(1), - SLANG_REPEAT_4(2), - SLANG_REPEAT_8(3), - SLANG_REPEAT_16(4), +/* static */ const int8_t ByteEncodeUtil::s_msb8[256] = { + -1, + 0, + SLANG_REPEAT_2(1), + SLANG_REPEAT_4(2), + SLANG_REPEAT_8(3), + SLANG_REPEAT_16(4), SLANG_REPEAT_32(5), SLANG_REPEAT_64(6), SLANG_REPEAT_128(7), }; -/* static */size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num) +/* static */ size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num) { size_t totalNumEncodeBytes = 0; - + for (size_t i = 0; i < num; i++) { const uint32_t v = in[i]; @@ -59,7 +59,10 @@ namespace Slang { return totalNumEncodeBytes; } -/* static */size_t ByteEncodeUtil::encodeLiteUInt32(const uint32_t* in, size_t num, uint8_t* encodeOut) +/* static */ size_t ByteEncodeUtil::encodeLiteUInt32( + const uint32_t* in, + size_t num, + uint8_t* encodeOut) { uint8_t* encodeStart = encodeOut; @@ -67,7 +70,7 @@ namespace Slang { { uint32_t v = in[i]; - if(v < kLiteCut1) + if (v < kLiteCut1) { *encodeOut++ = uint8_t(v); } @@ -95,7 +98,10 @@ namespace Slang { return size_t(encodeOut - encodeStart); } -/* static */void ByteEncodeUtil::encodeLiteUInt32(const uint32_t* in, size_t num, List& encodeArrayOut) +/* static */ void ByteEncodeUtil::encodeLiteUInt32( + const uint32_t* in, + size_t num, + List& encodeArrayOut) { // Make sure there is at least enough space for all bytes encodeArrayOut.setCount(num); @@ -111,7 +117,7 @@ namespace Slang { const size_t offset = size_t(encodeOut - encodeArrayOut.begin()); const UInt oldCapacity = encodeArrayOut.getCapacity(); - + // Make some more space encodeArrayOut.reserve(oldCapacity + (oldCapacity >> 1) + kMaxLiteEncodeUInt32); // Make the size the capacity @@ -154,7 +160,7 @@ namespace Slang { encodeArrayOut.compress(); } -/* static */int ByteEncodeUtil::encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]) +/* static */ int ByteEncodeUtil::encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]) { // 0-184 1 byte value = B0 // 185 - 248 2 bytes value = 185 + 256 * (B0 - 185) + B1 @@ -187,8 +193,7 @@ namespace Slang { } } -static const uint32_t s_unalignedUInt32Mask[5] = -{ +static const uint32_t s_unalignedUInt32Mask[5] = { 0x00000000, 0x000000ff, 0x0000ffff, @@ -196,8 +201,8 @@ static const uint32_t s_unalignedUInt32Mask[5] = 0xffffffff, }; -// Decode the >= kLiteCut2. -// in is pointing past the first byte. +// Decode the >= kLiteCut2. +// in is pointing past the first byte. // Only valid numBytesRemaining is 2, 3, or 4 SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int numBytesRemaining) { @@ -205,26 +210,37 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int #if SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS switch (numBytesRemaining) { - case 2: value = *(const uint16_t*)in; break; - case 3: value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); break; - case 4: value = *(const uint32_t*)in; break; - default: break; + case 2: + value = *(const uint16_t*)in; + break; + case 3: + value = (uint32_t(in[2]) << 16) | (uint32_t(in[1]) << 8) | uint32_t(in[0]); + break; + case 4: + value = *(const uint32_t*)in; + break; + default: + break; } #else // This works on all cpus although slower value = in[0]; switch (numBytesRemaining) { - case 4: value |= uint32_t(in[3]) << 24; /* fall thru */ - case 3: value |= uint32_t(in[2]) << 16; /* fall thru */ - case 2: value |= uint32_t(in[1]) << 8; /* fall thru */ - case 1: break; + case 4: + value |= uint32_t(in[3]) << 24; /* fall thru */ + case 3: + value |= uint32_t(in[2]) << 16; /* fall thru */ + case 2: + value |= uint32_t(in[1]) << 8; /* fall thru */ + case 1: + break; } #endif return value; } -/* static */int ByteEncodeUtil::decodeLiteUInt32(const uint8_t* in, uint32_t* out) +/* static */ int ByteEncodeUtil::decodeLiteUInt32(const uint8_t* in, uint32_t* out) { uint8_t b0 = *in++; if (b0 < kLiteCut1) @@ -246,7 +262,10 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int } } -/* static */size_t ByteEncodeUtil::decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut) +/* static */ size_t ByteEncodeUtil::decodeLiteUInt32( + const uint8_t* encodeIn, + size_t numValues, + uint32_t* valuesOut) { const uint8_t* encodeStart = encodeIn; @@ -267,13 +286,13 @@ SLANG_FORCE_INLINE static uint32_t _decodeLiteCut2UInt32(const uint8_t* in, int const int numBytesRemaining = b0 - kLiteCut2 + 2 - 1; // For unaligned access, do not use unaligned access for the last two values, - // (3rd last is safe because this value will have at least 2 bytes, followed by at worst two 1-byte values) - // otherwise we can access outside the bounds of the encoded array + // (3rd last is safe because this value will have at least 2 bytes, followed by at worst + // two 1-byte values) otherwise we can access outside the bounds of the encoded array // This prevents memory validation tools from causing an exception here if (SLANG_BYTE_ENCODE_USE_UNALIGNED_ACCESS && i < numValues - 2) { const uint32_t mask = s_unalignedUInt32Mask[numBytesRemaining]; - //const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); + // const uint32_t mask = ~(uint32_t(0xffffff00) << ((numBytesRemaining - 1) * 8)); valuesOut[i] = (*(const uint32_t*)encodeIn) & mask; } else diff --git a/source/core/slang-byte-encode-util.h b/source/core/slang-byte-encode-util.h index 728f9ac2fa..81fc0ef983 100644 --- a/source/core/slang-byte-encode-util.h +++ b/source/core/slang-byte-encode-util.h @@ -3,88 +3,90 @@ #include "slang-list.h" -namespace Slang { +namespace Slang +{ struct ByteEncodeUtil { enum { kMaxLiteEncodeUInt16 = 3, /// One byte for prefix, the remaining 2 bytes hold the value - kMaxLiteEncodeUInt32 = 5, /// One byte for prefix, the remaining 4 bytes hold the value + kMaxLiteEncodeUInt32 = 5, /// One byte for prefix, the remaining 4 bytes hold the value // Cut values for 'Lite' encoding style kLiteCut1 = 185, kLiteCut2 = 249, }; - /** Find the most significant bit for 8 bits - @param v The value to find most significant bit on - @return The most significant bit, or -1 if no bits are set - */ + /** Find the most significant bit for 8 bits + @param v The value to find most significant bit on + @return The most significant bit, or -1 if no bits are set + */ SLANG_FORCE_INLINE static int calcMsb8(uint32_t v); - - /** Find the most significant bit for 32 bits - @param v The value to find most significant bit on - @return The most significant bit, or -1 if no bits are set - */ + + /** Find the most significant bit for 32 bits + @param v The value to find most significant bit on + @return The most significant bit, or -1 if no bits are set + */ SLANG_FORCE_INLINE static int calcMsb32(uint32_t v); - - /** Calculates the 'most significant' byte ie the highest bytes that is non zero. - Note return value is *undefined* if in is 0. - @param in Value - cannot be 0. - @return The byte index of the highest byte that is non zero. - */ + + /** Calculates the 'most significant' byte ie the highest bytes that is non zero. + Note return value is *undefined* if in is 0. + @param in Value - cannot be 0. + @return The byte index of the highest byte that is non zero. + */ SLANG_FORCE_INLINE static int calcNonZeroMsByte32(uint32_t in); - /** Calculates the 'most significant' byte ie the highest bytes that is non zero. - @param in Value - cannot be 0. - @return The byte index of the highest byte that is non zero. - */ + /** Calculates the 'most significant' byte ie the highest bytes that is non zero. + @param in Value - cannot be 0. + @return The byte index of the highest byte that is non zero. + */ SLANG_FORCE_INLINE static int calcMsByte32(uint32_t in); - /// Calculate the size of encoding bytes + /// Calculate the size of encoding bytes static size_t calcEncodeLiteSizeUInt32(const uint32_t* in, size_t num); - /// Calculate the size of a single value + /// Calculate the size of a single value static size_t calcEncodeLiteSizeUInt32(uint32_t in); - - /** Encodes a uint32_t as an integer - @return the number of bytes needed to encode */ + + /** Encodes a uint32_t as an integer + @return the number of bytes needed to encode */ static int encodeLiteUInt32(uint32_t in, uint8_t out[kMaxLiteEncodeUInt32]); - /** Decode a lite encoding. - @param in The lite encoded bytes - @param out Value constructed - @return number of bytes on in consumed */ + /** Decode a lite encoding. + @param in The lite encoded bytes + @param out Value constructed + @return number of bytes on in consumed */ static int decodeLiteUInt32(const uint8_t* in, uint32_t* out); - /** Encode an array of uint32_t - @param in The values to encode - @param num The amount of values to encode - @param encodeOut The buffer to hold the encoded value. MUST be large enough to hold the encoding - @return The size of the encoding in bytes - */ + /** Encode an array of uint32_t + @param in The values to encode + @param num The amount of values to encode + @param encodeOut The buffer to hold the encoded value. MUST be large enough to hold the encoding + @return The size of the encoding in bytes + */ static size_t encodeLiteUInt32(const uint32_t* in, size_t num, uint8_t* encodeOut); - /** Encode an array of uint32_t - @param in The values to encode - @param num The amount of values to encode - @param encodeOut The buffer to hold the encoded value. - */ + /** Encode an array of uint32_t + @param in The values to encode + @param num The amount of values to encode + @param encodeOut The buffer to hold the encoded value. + */ static void encodeLiteUInt32(const uint32_t* in, size_t num, List& encodeOut); - /** Encode an array of uint32_t - @param encodeIn The encoded values - @param numValues The amount of values to be decoded (NOTE! This is the number of valuesOut, not encodeIn) - @param valuesOut The buffer to hold the encoded value. MUST be large enough to hold the encoding - @return The amount of bytes decoded - */ - static size_t decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut); + /** Encode an array of uint32_t + @param encodeIn The encoded values + @param numValues The amount of values to be decoded (NOTE! This is the number of valuesOut, not + encodeIn) + @param valuesOut The buffer to hold the encoded value. MUST be large enough to hold the encoding + @return The amount of bytes decoded + */ + static size_t decodeLiteUInt32(const uint8_t* encodeIn, size_t numValues, uint32_t* valuesOut); - /// Table that maps 8 bits to it's most significant bit. If 0 returns -1. + /// Table that maps 8 bits to it's most significant bit. If 0 returns -1. static const int8_t s_msb8[256]; }; -#if SLANG_VC +#if SLANG_VC // Works on ARM and x86/64 on visual studio compiler // --------------------------------------------------------------------------- @@ -102,7 +104,7 @@ SLANG_FORCE_INLINE int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) SLANG_FORCE_INLINE int ByteEncodeUtil::calcMsByte32(uint32_t in) { if (in == 0) - { + { return -1; } // Can use intrinsic @@ -113,7 +115,7 @@ SLANG_FORCE_INLINE int ByteEncodeUtil::calcMsByte32(uint32_t in) } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v) { SLANG_ASSERT((v & 0xffffff00) == 0); if (v == 0) @@ -126,7 +128,7 @@ SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v) { if (v == 0) { @@ -140,41 +142,36 @@ SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) #else // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcNonZeroMsByte32(uint32_t in) { - return (in & 0xffff0000) ? - ((in & 0xff000000) ? 3 : 2) : - ((in & 0x0000ff00) ? 1 : 0); + return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2) : ((in & 0x0000ff00) ? 1 : 0); } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsByte32(uint32_t in) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsByte32(uint32_t in) { - return (in & 0xffff0000) ? - ((in & 0xff000000) ? 3 : 2) : - ((in & 0x0000ff00) ? 1 : - ((in == 0) ? -1 : 0)); + return (in & 0xffff0000) ? ((in & 0xff000000) ? 3 : 2) + : ((in & 0x0000ff00) ? 1 : ((in == 0) ? -1 : 0)); } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb8(uint32_t v) -{ - SLANG_ASSERT((v & 0xffffff00) == 0); - return s_msb8[v]; +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb8(uint32_t v) +{ + SLANG_ASSERT((v & 0xffffff00) == 0); + return s_msb8[v]; } // --------------------------------------------------------------------------- -SLANG_FORCE_INLINE /* static */int ByteEncodeUtil::calcMsb32(uint32_t v) +SLANG_FORCE_INLINE /* static */ int ByteEncodeUtil::calcMsb32(uint32_t v) { - return (v & 0xffff0000) ? - ((v & 0xff000000) ? s_msb8[v >> 24] + 24 : s_msb8[v >> 16] + 16) : - ((v & 0x0000ff00) ? s_msb8[v >> 8] + 8 : s_msb8[v]); + return (v & 0xffff0000) ? ((v & 0xff000000) ? s_msb8[v >> 24] + 24 : s_msb8[v >> 16] + 16) + : ((v & 0x0000ff00) ? s_msb8[v >> 8] + 8 : s_msb8[v]); } #endif // --------------------------------------------------------------------------- -inline /* static */size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(uint32_t v) +inline /* static */ size_t ByteEncodeUtil::calcEncodeLiteSizeUInt32(uint32_t v) { if (v < kLiteCut1) { diff --git a/source/core/slang-castable.cpp b/source/core/slang-castable.cpp index f3c6541dd9..ece87fe2b5 100644 --- a/source/core/slang-castable.cpp +++ b/source/core/slang-castable.cpp @@ -1,11 +1,12 @@ // slang-castable.cpp #include "slang-castable.h" -namespace Slang { +namespace Slang +{ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CastableUtil !!!!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */ComPtr CastableUtil::getCastable(ISlangUnknown* unk) +/* static */ ComPtr CastableUtil::getCastable(ISlangUnknown* unk) { SLANG_ASSERT(unk); ComPtr castable; @@ -52,8 +53,7 @@ void* UnknownCastableAdapter::castAs(const Guid& guid) void* UnknownCastableAdapter::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IUnknownCastableAdapter::getTypeGuid()) { return static_cast(this); diff --git a/source/core/slang-castable.h b/source/core/slang-castable.h index e2b9c4a8e5..50b41766ae 100644 --- a/source/core/slang-castable.h +++ b/source/core/slang-castable.h @@ -3,16 +3,15 @@ #define SLANG_CASTABLE_H +#include "../core/slang-com-object.h" #include "slang-com-helper.h" #include "slang-com-ptr.h" -#include "../core/slang-com-object.h" - namespace Slang { // Dynamic cast of ICastable derived types -template +template SLANG_FORCE_INLINE T* dynamicCast(ICastable* castable) { if (castable) @@ -24,7 +23,7 @@ SLANG_FORCE_INLINE T* dynamicCast(ICastable* castable) } // as style cast -template +template SLANG_FORCE_INLINE T* as(ICastable* castable) { if (castable) @@ -36,34 +35,38 @@ SLANG_FORCE_INLINE T* as(ICastable* castable) } /* An interface for boxing values */ -class IBoxValueBase: public ICastable +class IBoxValueBase : public ICastable { - SLANG_COM_INTERFACE(0x8b4aad81, 0x4934, 0x4a67, { 0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54 }); + SLANG_COM_INTERFACE( + 0x8b4aad81, + 0x4934, + 0x4a67, + {0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54}); - /// Get the contained object + /// Get the contained object virtual SLANG_NO_THROW void* SLANG_MCALL getValuePtr() = 0; - /// Get the guid that represents the contained ref object + /// Get the guid that represents the contained ref object virtual SLANG_NO_THROW SlangUUID SLANG_MCALL getValueTypeGuid() = 0; }; -template +template class IBoxValue : public IBoxValueBase { - public: - +public: SLANG_FORCE_INLINE T& get() { return *reinterpret_cast(getValuePtr()); } SLANG_FORCE_INLINE T* getPtr() { return reinterpret_cast(getValuePtr()); } }; // Cast into a boxed value type -template +template SLANG_FORCE_INLINE IBoxValue* asBoxValue(ICastable* castable) { IBoxValueBase* base = as(castable); - return (base && base->getValueTypeGuid() == T::getTypeGuid()) ? static_cast*>(base) : nullptr; + return (base && base->getValueTypeGuid() == T::getTypeGuid()) ? static_cast*>(base) + : nullptr; } -template +template class BoxValue : public ComBaseObject, public IBoxValue { public: @@ -78,24 +81,23 @@ class BoxValue : public ComBaseObject, public IBoxValue BoxValue() {} - explicit BoxValue(const T& rhs): - m_value(rhs) + explicit BoxValue(const T& rhs) + : m_value(rhs) { } protected: - void* getInterface(const Guid& guid); + void* getInterface(const Guid& guid); void* getObject(const Guid& guid); - + T m_value; }; // ------------------------------------------------------------ -template +template void* BoxValue::getInterface(const Guid& guid) { - if (guid == ISlangUnknown::getTypeGuid() || - guid == ICastable::getTypeGuid() || + if (guid == ISlangUnknown::getTypeGuid() || guid == ICastable::getTypeGuid() || guid == IBoxValueBase::getTypeGuid()) { return static_cast(this); @@ -104,7 +106,7 @@ void* BoxValue::getInterface(const Guid& guid) } // ------------------------------------------------------------ -template +template void* BoxValue::getObject(const Guid& guid) { if (guid == T::getTypeGuid()) @@ -115,7 +117,7 @@ void* BoxValue::getObject(const Guid& guid) } // ------------------------------------------------------------ -template +template void* BoxValue::castAs(const Guid& guid) { if (auto ptr = getObject(guid)) @@ -124,22 +126,28 @@ void* BoxValue::castAs(const Guid& guid) } return getInterface(guid); } - + /* Adapter interface to make a non castable types work as ICastable */ class IUnknownCastableAdapter : public ICastable { - SLANG_COM_INTERFACE(0x8b4aad81, 0x4934, 0x4a67, { 0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54 }); + SLANG_COM_INTERFACE( + 0x8b4aad81, + 0x4934, + 0x4a67, + {0xb2, 0xe2, 0xe9, 0x17, 0xfc, 0x29, 0x12, 0x54}); /// When using the adapter, this provides a way to directly get the internal no ICastable type virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() = 0; }; -/* An adapter such that types which aren't derived from ICastable, can be used as such. +/* An adapter such that types which aren't derived from ICastable, can be used as such. With the following caveats. -* the interfaces/objects of the adapter are checked *first*, so IUnknown will always be for the adapter -* assumes when doing a queryInterface on the contained item, it will remain in scope when released (this is *not* strict COM) +* the interfaces/objects of the adapter are checked *first*, so IUnknown will always be for the +adapter +* assumes when doing a queryInterface on the contained item, it will remain in scope when released +(this is *not* strict COM) */ class UnknownCastableAdapter : public ComBaseObject, public IUnknownCastableAdapter { @@ -150,10 +158,13 @@ class UnknownCastableAdapter : public ComBaseObject, public IUnknownCastableAdap SLANG_NO_THROW void* SLANG_MCALL castAs(const Guid& guid) SLANG_OVERRIDE; // IUnknownCastableAdapter - virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() SLANG_OVERRIDE { return m_contained; } + virtual SLANG_NO_THROW ISlangUnknown* SLANG_MCALL getContained() SLANG_OVERRIDE + { + return m_contained; + } - UnknownCastableAdapter(ISlangUnknown* unk): - m_contained(unk) + UnknownCastableAdapter(ISlangUnknown* unk) + : m_contained(unk) { SLANG_ASSERT(unk); } @@ -171,15 +182,15 @@ class UnknownCastableAdapter : public ComBaseObject, public IUnknownCastableAdap struct CastableUtil { - /// Given an ISlangUnkown return as a castable interface. - /// Can use UnknownCastableAdapter if can't queryInterface unk to ICastable + /// Given an ISlangUnkown return as a castable interface. + /// Can use UnknownCastableAdapter if can't queryInterface unk to ICastable static ComPtr getCastable(ISlangUnknown* unk); }; -// A way to clone an interface (that derives from IClonable) such that it returns an interface +// A way to clone an interface (that derives from IClonable) such that it returns an interface // of the same type. -template +template SLANG_FORCE_INLINE ComPtr cloneInterface(T* in) { SLANG_ASSERT(in); diff --git a/source/core/slang-char-encode.cpp b/source/core/slang-char-encode.cpp index 526c6c923a..a27e7ba827 100644 --- a/source/core/slang-char-encode.cpp +++ b/source/core/slang-char-encode.cpp @@ -3,20 +3,23 @@ namespace Slang { -class Utf8CharEncoding : public CharEncoding +class Utf8CharEncoding : public CharEncoding { public: typedef CharEncoding Super; - virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override - { + virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override + { ioBuffer.addRange((const Byte*)slice.begin(), slice.getLength()); - } - virtual void decode(const Byte* bytes, int length, List& ioChars) override - { + } + virtual void decode(const Byte* bytes, int length, List& ioChars) override + { ioChars.addRange((const char*)bytes, length); - } - Utf8CharEncoding() : Super(CharEncodeType::UTF8) {} + } + Utf8CharEncoding() + : Super(CharEncodeType::UTF8) + { + } }; class Utf32CharEncoding : public CharEncoding @@ -24,93 +27,98 @@ class Utf32CharEncoding : public CharEncoding public: typedef CharEncoding Super; - virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override - { - Index ptr = 0; - while (ptr < slice.getLength()) - { - const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte - { - if (ptr < slice.getLength()) - return slice[ptr++]; - else - return '\0'; - }); + virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override + { + Index ptr = 0; + while (ptr < slice.getLength()) + { + const Char32 codePoint = getUnicodePointFromUTF8( + [&]() -> Byte + { + if (ptr < slice.getLength()) + return slice[ptr++]; + else + return '\0'; + }); // Note: Assumes byte order is same as arch byte order ioBuffer.addRange((const Byte*)&codePoint, 4); - } - } - virtual void decode(const Byte* bytes, int length, List& ioBuffer) override - { + } + } + virtual void decode(const Byte* bytes, int length, List& ioBuffer) override + { // Note: Assumes bytes is Char32 aligned SLANG_ASSERT((size_t(bytes) & 3) == 0); - const Char32* content = (const Char32*)bytes; - for (int i = 0; i < (length >> 2); i++) - { - char buf[5]; - int count = encodeUnicodePointToUTF8(content[i], buf); + const Char32* content = (const Char32*)bytes; + for (int i = 0; i < (length >> 2); i++) + { + char buf[5]; + int count = encodeUnicodePointToUTF8(content[i], buf); for (int j = 0; j < count; j++) ioBuffer.addRange(buf, count); - } - } + } + } - Utf32CharEncoding() : Super(CharEncodeType::UTF32) {} + Utf32CharEncoding() + : Super(CharEncodeType::UTF32) + { + } }; -class Utf16CharEncoding : public CharEncoding //UTF16 +class Utf16CharEncoding : public CharEncoding // UTF16 { public: typedef CharEncoding Super; - Utf16CharEncoding(bool reverseOrder): - Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16), - m_reverseOrder(reverseOrder) - {} - virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override - { - Index index = 0; - while (index < slice.getLength()) - { - const Char32 codePoint = getUnicodePointFromUTF8([&]() -> Byte - { - if (index < slice.getLength()) - return slice[index++]; - else - return '\0'; - }); - - Char16 buffer[2]; - int count; - if (!m_reverseOrder) - count = encodeUnicodePointToUTF16(codePoint, buffer); - else - count = encodeUnicodePointToUTF16Reversed(codePoint, buffer); + Utf16CharEncoding(bool reverseOrder) + : Super(reverseOrder ? CharEncodeType::UTF16Reversed : CharEncodeType::UTF16) + , m_reverseOrder(reverseOrder) + { + } + virtual void encode(const UnownedStringSlice& slice, List& ioBuffer) override + { + Index index = 0; + while (index < slice.getLength()) + { + const Char32 codePoint = getUnicodePointFromUTF8( + [&]() -> Byte + { + if (index < slice.getLength()) + return slice[index++]; + else + return '\0'; + }); + + Char16 buffer[2]; + int count; + if (!m_reverseOrder) + count = encodeUnicodePointToUTF16(codePoint, buffer); + else + count = encodeUnicodePointToUTF16Reversed(codePoint, buffer); ioBuffer.addRange((const Byte*)buffer, count * 2); - } - } - virtual void decode(const Byte* bytes, int length, List& ioBuffer) override - { - Index index = 0; - while (index < length) - { - auto readByte = [&]() -> Byte - { - return (index < length) ? bytes[index++] : Byte(0); - }; - const Char32 codePoint = m_reverseOrder ? - getUnicodePointFromUTF16Reversed(readByte) : - getUnicodePointFromUTF16(readByte); - - char buf[5]; - int count = encodeUnicodePointToUTF8(codePoint, buf); - ioBuffer.addRange((const char*)buf, count); - } - } + } + } + virtual void decode(const Byte* bytes, int length, List& ioBuffer) override + { + Index index = 0; + while (index < length) + { + auto readByte = [&]() -> Byte { return (index < length) ? bytes[index++] : Byte(0); }; + const Char32 codePoint = m_reverseOrder ? getUnicodePointFromUTF16Reversed(readByte) + : getUnicodePointFromUTF16(readByte); + + char buf[5]; + int count = encodeUnicodePointToUTF8(codePoint, buf); + ioBuffer.addRange((const char*)buf, count); + } + } private: bool m_reverseOrder = false; }; -/* static */CharEncodeType CharEncoding::determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset) +/* static */ CharEncodeType CharEncoding::determineEncoding( + const Byte* bytes, + size_t bytesCount, + size_t& outOffset) { // TODO(JS): Assumes the bytes are suitably aligned @@ -137,7 +145,7 @@ class Utf16CharEncoding : public CharEncoding //UTF16 // If we don't have a 'mark' byte then we are bit stumped. We'll look for // null (non-terminator) bytes and assume they mean we have a 16-bit encoding - for(size_t i = 0; i < (bytesCount-1); i += 2) + for (size_t i = 0; i < (bytesCount - 1); i += 2) { #if SLANG_LITTLE_ENDIAN const auto low = bytes[i]; @@ -164,41 +172,42 @@ static Utf16CharEncoding _utf16Encoding(false); static Utf16CharEncoding _utf16EncodingReversed(true); static Utf32CharEncoding _utf32Encoding; -/* static */CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)] -{ - &_utf8Encoding, // UTF8, - &_utf16Encoding, // UTF16, - &_utf16EncodingReversed, // UTF16Reversed, - &_utf32Encoding, // UTF32, +/* static */ CharEncoding* const CharEncoding::g_encoding[Index(CharEncodeType::CountOf)]{ + &_utf8Encoding, // UTF8, + &_utf16Encoding, // UTF16, + &_utf16EncodingReversed, // UTF16Reversed, + &_utf32Encoding, // UTF32, }; CharEncoding* CharEncoding::UTF8 = &_utf8Encoding; CharEncoding* CharEncoding::UTF16 = &_utf16Encoding; CharEncoding* CharEncoding::UTF16Reversed = &_utf16EncodingReversed; CharEncoding* CharEncoding::UTF32 = &_utf32Encoding; - + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! UTF8Util !!!!!!!!!!!!!!!!!!!!!!!!! */ -/* static */Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in) +/* static */ Index UTF8Util::calcCodePointCount(const UnownedStringSlice& in) { Index count = 0; // Analyse with bytes... const int8_t* cur = (const int8_t*)in.begin(); - const int8_t*const end = (const int8_t*)in.end(); + const int8_t* const end = (const int8_t*)in.end(); while (cur < end) { const auto c = *cur++; - + count++; // If c < 0 it means the top bit is set... which means we have multiple bytes if (c < 0) { // https://en.wikipedia.org/wiki/UTF-8 - // All continuation bytes contain exactly six bits from the code point.So the next six bits of the code point - /// are stored in the low order six bits of the next byte, and 10 is stored in the high order two bits to + // All continuation bytes contain exactly six bits from the code point.So the next six + // bits of the code point + /// are stored in the low order six bits of the next byte, and 10 is stored in the high + /// order two bits to // mark it as a continuation byte(so 10000010). while (cur < end && (*cur & 0xc0) == 0x80) @@ -217,7 +226,8 @@ Index UTF8Util::calcUTF16CharCount(const UnownedStringSlice& in) Index readPtr = 0; for (;;) { - int c = getUnicodePointFromUTF8([&]() -> Byte + int c = getUnicodePointFromUTF8( + [&]() -> Byte { if (readPtr < in.getLength()) return in[readPtr++]; diff --git a/source/core/slang-char-encode.h b/source/core/slang-char-encode.h index a7cd501ab2..74968a6ab7 100644 --- a/source/core/slang-char-encode.h +++ b/source/core/slang-char-encode.h @@ -1,13 +1,13 @@ #ifndef SLANG_CORE_CHAR_ENCODE_H #define SLANG_CORE_CHAR_ENCODE_H -#include "slang-secure-crt.h" #include "slang-basic.h" +#include "slang-secure-crt.h" namespace Slang { -// NOTE! Order must be kept the same to match up with +// NOTE! Order must be kept the same to match up with enum class CharEncodeType { UTF8, @@ -17,7 +17,7 @@ enum class CharEncodeType CountOf, }; -template +template Char32 getUnicodePointFromUTF8(const ReadByteFunc& readByte) { Char32 codePoint = 0; @@ -38,7 +38,7 @@ Char32 getUnicodePointFromUTF8(const ReadByteFunc& readByte) return codePoint; } -template +template Char32 getUnicodePointFromUTF16(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -55,7 +55,7 @@ Char32 getUnicodePointFromUTF16(const ReadByteFunc& readByte) return Char32(word0); } -template +template Char32 getUnicodePointFromUTF16Reversed(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -72,7 +72,7 @@ Char32 getUnicodePointFromUTF16Reversed(const ReadByteFunc& readByte) return Char32(word0); } -template +template Char32 getUnicodePointFromUTF32(const ReadByteFunc& readByte) { uint32_t byte0 = Byte(readByte()); @@ -163,52 +163,55 @@ static const Char16 kUTF16ReversedHeader = 0xFFFE; class CharEncoding { public: - static CharEncoding* UTF8,* UTF16,* UTF16Reversed,* UTF32; + static CharEncoding *UTF8, *UTF16, *UTF16Reversed, *UTF32; - /// Encode Utf8 held in slice append into ioBuffer + /// Encode Utf8 held in slice append into ioBuffer virtual void encode(const UnownedStringSlice& str, List& ioBuffer) = 0; - /// Decode buffer into Utf8 held in ioBuffer + /// Decode buffer into Utf8 held in ioBuffer virtual void decode(const Byte* buffer, int length, List& ioBuffer) = 0; - virtual ~CharEncoding() {} + virtual ~CharEncoding() {} - /// Get the encoding type + /// Get the encoding type CharEncodeType getEncodingType() const { return m_encodingType; } - /// Given some bytes determines a character encoding type, based on the initial bytes. - /// If can't be determined will assume UTF8. - /// Outputs the offset to the first non mark in outOffset - static CharEncodeType determineEncoding(const Byte* bytes, size_t bytesCount, size_t& outOffset); + /// Given some bytes determines a character encoding type, based on the initial bytes. + /// If can't be determined will assume UTF8. + /// Outputs the offset to the first non mark in outOffset + static CharEncodeType determineEncoding( + const Byte* bytes, + size_t bytesCount, + size_t& outOffset); - /// Get the + /// Get the static CharEncoding* getEncoding(CharEncodeType type) { return g_encoding[Index(type)]; } - CharEncoding(CharEncodeType encodingType) : - m_encodingType(encodingType) + CharEncoding(CharEncodeType encodingType) + : m_encodingType(encodingType) { } protected: - CharEncodeType m_encodingType; - static CharEncoding*const g_encoding[Index(CharEncodeType::CountOf)]; + static CharEncoding* const g_encoding[Index(CharEncodeType::CountOf)]; }; struct UTF8Util { - /// Given a slice calculate the number of code points (unicode chars) - /// - /// NOTE! This doesn't check the *validity* of code points/encoding. - /// Non valid utf8 input or ending starting in partial characters, will produce - /// undefined results without error. + /// Given a slice calculate the number of code points (unicode chars) + /// + /// NOTE! This doesn't check the *validity* of code points/encoding. + /// Non valid utf8 input or ending starting in partial characters, will produce + /// undefined results without error. static Index calcCodePointCount(const UnownedStringSlice& in); - /// Given a slice in UTF8, calculate the number of UTF16 characters needed to represent the string. + /// Given a slice in UTF8, calculate the number of UTF16 characters needed to represent the + /// string. static Index calcUTF16CharCount(const UnownedStringSlice& in); }; -} +} // namespace Slang #endif diff --git a/source/core/slang-char-util.cpp b/source/core/slang-char-util.cpp index ea9e6dbf27..f9c61ec03a 100644 --- a/source/core/slang-char-util.cpp +++ b/source/core/slang-char-util.cpp @@ -1,8 +1,9 @@ #include "slang-char-util.h" -namespace Slang { +namespace Slang +{ -/* static */CharUtil::CharFlagMap CharUtil::makeCharFlagMap() +/* static */ CharUtil::CharFlagMap CharUtil::makeCharFlagMap() { CharUtil::CharFlagMap map; memset(&map, 0, sizeof(map)); @@ -46,11 +47,11 @@ namespace Slang { return map; } -/* static */int CharUtil::_ensureLink() +/* static */ int CharUtil::_ensureLink() { return makeCharFlagMap().flags[0]; } -/* static */const CharUtil::CharFlagMap CharUtil::g_charFlagMap = makeCharFlagMap(); +/* static */ const CharUtil::CharFlagMap CharUtil::g_charFlagMap = makeCharFlagMap(); } // namespace Slang diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h index 88af24426c..896eb69567 100644 --- a/source/core/slang-char-util.h +++ b/source/core/slang-char-util.h @@ -3,7 +3,8 @@ #include "slang-string.h" -namespace Slang { +namespace Slang +{ struct CharUtil { @@ -12,12 +13,13 @@ struct CharUtil { enum Enum : Flags { - Upper = 0x01, ///< A-Z - Lower = 0x02, ///< a-z - Digit = 0x04, ///< 0-9 - HorizontalWhitespace = 0x08, ///< Whitespace that can appear horizontally (ie excluding CR/LF) - HexDigit = 0x10, ///< 0-9, a-f, A-F - VerticalWhitespace = 0x20, ///< \n \r + Upper = 0x01, ///< A-Z + Lower = 0x02, ///< a-z + Digit = 0x04, ///< 0-9 + HorizontalWhitespace = + 0x08, ///< Whitespace that can appear horizontally (ie excluding CR/LF) + HexDigit = 0x10, ///< 0-9, a-f, A-F + VerticalWhitespace = 0x20, ///< \n \r }; }; @@ -26,40 +28,62 @@ struct CharUtil SLANG_FORCE_INLINE static bool isUpper(char c) { return c >= 'A' && c <= 'Z'; } SLANG_FORCE_INLINE static bool isHorizontalWhitespace(char c) { return c == ' ' || c == '\t'; } SLANG_FORCE_INLINE static bool isVerticalWhitespace(char c) { return c == '\n' || c == '\r'; } - SLANG_FORCE_INLINE static bool isWhitespace(char c) { return (getFlags(c) & (Flag::HorizontalWhitespace | Flag::VerticalWhitespace)) != 0; } + SLANG_FORCE_INLINE static bool isWhitespace(char c) + { + return (getFlags(c) & (Flag::HorizontalWhitespace | Flag::VerticalWhitespace)) != 0; + } - /// True if it's alpha - SLANG_FORCE_INLINE static bool isAlpha(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; } - /// True if it's alpha or a digit - SLANG_FORCE_INLINE static bool isAlphaOrDigit(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower | Flag::Digit)) != 0; } + /// True if it's alpha + SLANG_FORCE_INLINE static bool isAlpha(char c) + { + return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; + } + /// True if it's alpha or a digit + SLANG_FORCE_INLINE static bool isAlphaOrDigit(char c) + { + return (getFlags(c) & (Flag::Upper | Flag::Lower | Flag::Digit)) != 0; + } - /// True if the character is a valid hex character - SLANG_FORCE_INLINE static bool isHexDigit(char c) { return (getFlags(c) & Flag::HexDigit) != 0; } + /// True if the character is a valid hex character + SLANG_FORCE_INLINE static bool isHexDigit(char c) + { + return (getFlags(c) & Flag::HexDigit) != 0; + } - /// True if the character is an octal digit + /// True if the character is an octal digit SLANG_FORCE_INLINE static bool isOctalDigit(char c) { return c >= '0' && c <= '7'; } - /// For a given character get the associated flags + /// For a given character get the associated flags SLANG_FORCE_INLINE static Flags getFlags(char c) { return g_charFlagMap.flags[size_t(c)]; } - /// Given a character return the lower case equivalent - SLANG_FORCE_INLINE static char toLower(char c) { return (c >= 'A' && c <= 'Z') ? (c -'A' + 'a') : c; } - /// Given a character return the upper case equivalent - SLANG_FORCE_INLINE static char toUpper(char c) { return (c >= 'a' && c <= 'z') ? (c -'a' + 'A') : c; } + /// Given a character return the lower case equivalent + SLANG_FORCE_INLINE static char toLower(char c) + { + return (c >= 'A' && c <= 'Z') ? (c - 'A' + 'a') : c; + } + /// Given a character return the upper case equivalent + SLANG_FORCE_INLINE static char toUpper(char c) + { + return (c >= 'a' && c <= 'z') ? (c - 'a' + 'A') : c; + } - /// Given a value between 0-15 inclusive returns the hex digit. Uses lower case hex. - SLANG_FORCE_INLINE static char getHexChar(Index i) { SLANG_ASSERT((i & ~Index(0xf)) == 0); return char(i >= 10 ? (i - 10 + 'a') : (i + '0')); } + /// Given a value between 0-15 inclusive returns the hex digit. Uses lower case hex. + SLANG_FORCE_INLINE static char getHexChar(Index i) + { + SLANG_ASSERT((i & ~Index(0xf)) == 0); + return char(i >= 10 ? (i - 10 + 'a') : (i + '0')); + } - /// Returns the value if c interpretted as a decimal digit - /// If c is not a valid digit returns -1 + /// Returns the value if c interpretted as a decimal digit + /// If c is not a valid digit returns -1 inline static int getDecimalDigitValue(char c) { return isDigit(c) ? (c - '0') : -1; } - /// Returns the value if c interpretted as a hex digit - /// If c is not a valid hex returns -1 + /// Returns the value if c interpretted as a hex digit + /// If c is not a valid hex returns -1 inline static int getHexDigitValue(char c); - - /// Returns the value if c interpretted as a octal digit - /// If c is not a valid octal returns -1 + + /// Returns the value if c interpretted as a octal digit + /// If c is not a valid octal returns -1 inline static int getOctalDigitValue(char c) { return isOctalDigit(c) ? (c - '0') : -1; } struct CharFlagMap @@ -69,16 +93,17 @@ struct CharUtil static CharFlagMap makeCharFlagMap(); - // HACK! - // JS: Many of the inlined functions of CharUtil just access a global map. That referencing this global is *NOT* enough to - // link correctly with CharUtil on linux for a shared library. Caling this function can force linkage. + // HACK! + // JS: Many of the inlined functions of CharUtil just access a global map. That referencing this + // global is *NOT* enough to link correctly with CharUtil on linux for a shared library. Caling + // this function can force linkage. static int _ensureLink(); static const CharFlagMap g_charFlagMap; }; - + // ------------------------------------------------------------------------------------ -inline /* static */int CharUtil::getHexDigitValue(char c) +inline /* static */ int CharUtil::getHexDigitValue(char c) { if (c >= '0' && c <= '9') { diff --git a/source/core/slang-chunked-list.h b/source/core/slang-chunked-list.h index f963ecfab2..95324f8c95 100644 --- a/source/core/slang-chunked-list.h +++ b/source/core/slang-chunked-list.h @@ -1,16 +1,15 @@ #ifndef SLANG_CORE_CHUNKED_LIST_H #define SLANG_CORE_CHUNKED_LIST_H -#include "../../include/slang.h" - #include "slang-allocator.h" #include "slang-array-view.h" #include "slang-math.h" +#include "slang.h" namespace Slang { // Items stored in a ChunkedList are guaranteed to have fixed address. -template +template class ChunkedList { private: @@ -21,10 +20,7 @@ class ChunkedList uint32_t size = 0; uint32_t capacity = defaultChunkSize; Chunk* next = nullptr; - T* begin() - { - return reinterpret_cast(this + 1); - } + T* begin() { return reinterpret_cast(this + 1); } T* end() { return begin() + size; } }; @@ -60,24 +56,26 @@ class ChunkedList public: typedef ChunkedList ThisType; ChunkedList() - : m_lastChunk(&m_firstChunk) - , m_count(0) - {} - template ChunkedList(const T& val, Args... args) { _init(val, args...); } + : m_lastChunk(&m_firstChunk), m_count(0) + { + } + template + ChunkedList(const T& val, Args... args) + { + _init(val, args...); + } ChunkedList(const ThisType& list) - : m_lastChunk(&m_firstChunk) - , m_count(0) + : m_lastChunk(&m_firstChunk), m_count(0) { this->operator=(list); } ChunkedList(ThisType&& list) - : m_lastChunk(&m_firstChunk) - , m_count(0) + : m_lastChunk(&m_firstChunk), m_count(0) { this->operator=(static_cast(list)); } ~ChunkedList() { _deallocateBuffer(); } - template + template ThisType& operator=(const ChunkedList& list) { clearAndDeallocate(); @@ -213,7 +211,8 @@ class ChunkedList return result; } - template T* addRange(const TContainer& list) + template + T* addRange(const TContainer& list) { Chunk* chunk = _maybeReserveForAdd((uint32_t)list.getCount()); auto result = chunk->begin() + chunk->size; @@ -235,7 +234,6 @@ class ChunkedList } private: - Index m_count = 0; ///< The amount of elements FirstChunk m_firstChunk; Chunk* m_lastChunk = &m_firstChunk; @@ -262,7 +260,8 @@ class ChunkedList return AllocateMethod::deallocateArray(ptr, count); } - template void _init(const T& val, Args... args) + template + void _init(const T& val, Args... args) { add(val); _init(args...); diff --git a/source/core/slang-com-object.h b/source/core/slang-com-object.h index 617b7cccaa..801af61a47 100644 --- a/source/core/slang-com-object.h +++ b/source/core/slang-com-object.h @@ -2,34 +2,35 @@ #define SLANG_COM_OBJECT_H #include "slang-basic.h" + #include namespace Slang { -/// A base class for COM interfaces that require atomic ref counting +/// A base class for COM interfaces that require atomic ref counting /// and are *NOT* derived from RefObject class ComBaseObject { public: - - /// If assigned the the ref count is *NOT* copied + /// If assigned the the ref count is *NOT* copied ComBaseObject& operator=(const ComBaseObject&) { return *this; } - /// Copy Ctor, does not copy ref count - ComBaseObject(const ComBaseObject&) : - m_refCount(0) - {} + /// Copy Ctor, does not copy ref count + ComBaseObject(const ComBaseObject&) + : m_refCount(0) + { + } - /// Default Ctor sets with no refs + /// Default Ctor sets with no refs ComBaseObject() : m_refCount(0) - {} + { + } - /// Dtor needs to be virtual to avoid needing to - /// Implement release for all derived types. - virtual ~ComBaseObject() - {} + /// Dtor needs to be virtual to avoid needing to + /// Implement release for all derived types. + virtual ~ComBaseObject() {} protected: inline uint32_t _releaseImpl(); @@ -50,7 +51,7 @@ inline uint32_t ComBaseObject::_releaseImpl() return count; } -#define SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ +#define SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ SLANG_NO_THROW SlangResult SLANG_MCALL queryInterface(SlangUUID const& uuid, void** outObject) \ SLANG_OVERRIDE \ { \ @@ -63,10 +64,16 @@ inline uint32_t ComBaseObject::_releaseImpl() } \ return SLANG_E_NO_INTERFACE; \ } -#define SLANG_COM_BASE_IUNKNOWN_ADD_REF \ - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return ++m_refCount; } -#define SLANG_COM_BASE_IUNKNOWN_RELEASE \ - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return _releaseImpl(); } +#define SLANG_COM_BASE_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE \ + { \ + return ++m_refCount; \ + } +#define SLANG_COM_BASE_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE \ + { \ + return _releaseImpl(); \ + } #define SLANG_COM_BASE_IUNKNOWN_ALL \ SLANG_COM_BASE_IUNKNOWN_QUERY_INTERFACE \ SLANG_COM_BASE_IUNKNOWN_ADD_REF \ @@ -82,11 +89,12 @@ class ComObject : public RefObject public: ComObject() : comRefCount(0) - {} - ComObject(const ComObject& rhs) : - RefObject(rhs), - comRefCount(0) - {} + { + } + ComObject(const ComObject& rhs) + : RefObject(rhs), comRefCount(0) + { + } ComObject& operator=(const ComObject&) { return *this; } @@ -125,10 +133,16 @@ class ComObject : public RefObject } \ return SLANG_E_NO_INTERFACE; \ } -#define SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ - SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE { return addRefImpl(); } -#define SLANG_COM_OBJECT_IUNKNOWN_RELEASE \ - SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE { return releaseImpl(); } +#define SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ + SLANG_NO_THROW uint32_t SLANG_MCALL addRef() SLANG_OVERRIDE \ + { \ + return addRefImpl(); \ + } +#define SLANG_COM_OBJECT_IUNKNOWN_RELEASE \ + SLANG_NO_THROW uint32_t SLANG_MCALL release() SLANG_OVERRIDE \ + { \ + return releaseImpl(); \ + } #define SLANG_COM_OBJECT_IUNKNOWN_ALL \ SLANG_COM_OBJECT_IUNKNOWN_QUERY_INTERFACE \ SLANG_COM_OBJECT_IUNKNOWN_ADD_REF \ diff --git a/source/core/slang-command-line.cpp b/source/core/slang-command-line.cpp index bfd9ed11a7..8269d37c5d 100644 --- a/source/core/slang-command-line.cpp +++ b/source/core/slang-command-line.cpp @@ -1,17 +1,17 @@ // slang-command-line.cpp #include "slang-command-line.h" +#include "slang-com-helper.h" #include "slang-process.h" - -#include "slang-string.h" #include "slang-string-escape-util.h" #include "slang-string-util.h" +#include "slang-string.h" -#include "slang-com-helper.h" - -namespace Slang { +namespace Slang +{ -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExecutableLocation !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ExecutableLocation !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ void ExecutableLocation::set(const String& dir, const String& name) { diff --git a/source/core/slang-command-line.h b/source/core/slang-command-line.h index 163daf7100..804266ad1d 100644 --- a/source/core/slang-command-line.h +++ b/source/core/slang-command-line.h @@ -2,10 +2,11 @@ #ifndef SLANG_COMMAND_LINE_H #define SLANG_COMMAND_LINE_H -#include "slang-string.h" #include "slang-list.h" +#include "slang-string.h" -namespace Slang { +namespace Slang +{ struct ExecutableLocation { @@ -13,43 +14,67 @@ struct ExecutableLocation enum Type { - Unknown, ///< Not specified - Path, ///< The executable is set as a path (ie won't be searched for) - Name, ///< The executable is passed as a name which will be searched for + Unknown, ///< Not specified + Path, ///< The executable is set as a path (ie won't be searched for) + Name, ///< The executable is passed as a name which will be searched for }; - /// Set the executable path. - /// NOTE! On some targets the executable path *must* include an extension to be able to start as a process - void setPath(const String& path) { m_type = Type::Path; m_pathOrName = path; } + /// Set the executable path. + /// NOTE! On some targets the executable path *must* include an extension to be able to start as + /// a process + void setPath(const String& path) + { + m_type = Type::Path; + m_pathOrName = path; + } - /// Set a filename (such that the path will be looked up) - void setName(const String& filename) { m_type = Type::Name; m_pathOrName = filename; } + /// Set a filename (such that the path will be looked up) + void setName(const String& filename) + { + m_type = Type::Name; + m_pathOrName = filename; + } - void set(Type type, const String& pathOrName) { m_type = type; m_pathOrName = pathOrName; } + void set(Type type, const String& pathOrName) + { + m_type = type; + m_pathOrName = pathOrName; + } - /// Set the executable path from a base directory and an executable name (no suffix such as '.exe' needed) + /// Set the executable path from a base directory and an executable name (no suffix such as + /// '.exe' needed) void set(const String& dir, const String& name); - /// Determines if it's a name or a path when it sets + /// Determines if it's a name or a path when it sets void set(const String& nameOrPath); - /// Append as text to out. + /// Append as text to out. void append(StringBuilder& out) const; - /// Reset state to be same as ctor - void reset() { m_type = Type::Unknown; m_pathOrName = String(); } + /// Reset state to be same as ctor + void reset() + { + m_type = Type::Unknown; + m_pathOrName = String(); + } - /// Equality means exactly the same definition. - /// *NOT* that exactly the same executable is specified - bool operator==(const ThisType& rhs) const { return m_type == rhs.m_type && m_pathOrName == rhs.m_pathOrName; } + /// Equality means exactly the same definition. + /// *NOT* that exactly the same executable is specified + bool operator==(const ThisType& rhs) const + { + return m_type == rhs.m_type && m_pathOrName == rhs.m_pathOrName; + } bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } ExecutableLocation() {} - ExecutableLocation(const String& dir, const String& name) { set(dir, name); } - ExecutableLocation(Type type, const String& pathOrName) : m_type(type), m_pathOrName(pathOrName) {} + ExecutableLocation(const String& dir, const String& name) { set(dir, name); } + ExecutableLocation(Type type, const String& pathOrName) + : m_type(type), m_pathOrName(pathOrName) + { + } explicit ExecutableLocation(const String& nameOrPath) { set(nameOrPath); } - + Type m_type = Type::Unknown; String m_pathOrName; }; @@ -58,42 +83,52 @@ struct CommandLine { typedef CommandLine ThisType; - /// Add args - assumed unescaped + /// Add args - assumed unescaped void addArg(const String& in) { m_args.add(in); } - void addArgs(const String* args, Int argsCount) { for (Int i = 0; i < argsCount; ++i) addArg(args[i]); } + void addArgs(const String* args, Int argsCount) + { + for (Int i = 0; i < argsCount; ++i) + addArg(args[i]); + } void addArgIfNotFound(const String& in); - /// Find the index of an arg which is exact match for slice - SLANG_INLINE Index findArgIndex(const UnownedStringSlice& slice) const { return m_args.indexOf(slice); } + /// Find the index of an arg which is exact match for slice + SLANG_INLINE Index findArgIndex(const UnownedStringSlice& slice) const + { + return m_args.indexOf(slice); + } - /// For handling args where the switch is placed directly in front of the path - void addPrefixPathArg(const char* prefix, const String& path, const char* pathPostfix = nullptr); + /// For handling args where the switch is placed directly in front of the path + void addPrefixPathArg( + const char* prefix, + const String& path, + const char* pathPostfix = nullptr); - /// Get the total number of args + /// Get the total number of args SLANG_FORCE_INLINE Index getArgCount() const { return m_args.getCount(); } - /// Reset to the initial state - void reset() { *this = CommandLine(); } + /// Reset to the initial state + void reset() { *this = CommandLine(); } - /// Append the args + /// Append the args void appendArgs(StringBuilder& out) const; - /// Append the command line to out + /// Append the command line to out void append(StringBuilder& out) const; - /// convert into a string + /// convert into a string String toString() const; - /// Convert just the args to string + /// Convert just the args to string String toStringArgs() const; - /// Set an executable location + /// Set an executable location void setExecutableLocation(const ExecutableLocation& loc) { m_executableLocation = loc; } - ExecutableLocation m_executableLocation; ///< The executable location - List m_args; ///< The arguments (Stored *unescaped*) + ExecutableLocation m_executableLocation; ///< The executable location + List m_args; ///< The arguments (Stored *unescaped*) }; -} +} // namespace Slang #endif // SLANG_COMMAND_LINE_H diff --git a/source/core/slang-command-options-writer.cpp b/source/core/slang-command-options-writer.cpp index afa46db64c..9135998af7 100644 --- a/source/core/slang-command-options-writer.cpp +++ b/source/core/slang-command-options-writer.cpp @@ -2,18 +2,26 @@ #include "slang-command-options-writer.h" -#include "slang-string-util.h" -#include "slang-char-util.h" #include "slang-byte-encode-util.h" +#include "slang-char-util.h" +#include "slang-string-util.h" + +namespace Slang +{ -namespace Slang { - -namespace { // anonymous +namespace +{ // anonymous typedef CommandOptionsWriter::Style Style; -} // anonymous +} // namespace -static bool _isMarkdown(Style style) { return style == Style::Markdown || style == Style::NoLinkMarkdown; } -static bool _hasLinks(Style style) { return style == Style::Markdown; } +static bool _isMarkdown(Style style) +{ + return style == Style::Markdown || style == Style::NoLinkMarkdown; +} +static bool _hasLinks(Style style) +{ + return style == Style::Markdown; +} /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! MarkdownCommandOptionsWriter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -25,17 +33,17 @@ class MarkdownCommandOptionsWriter : public CommandOptionsWriter typedef uint32_t LinkFlags; struct LinkFlag { - enum Enum + enum Enum { Category = 0x1, - Option = 0x2, + Option = 0x2, All = Category | Option, }; }; - MarkdownCommandOptionsWriter(const Options& options): - Super(options) + MarkdownCommandOptionsWriter(const Options& options) + : Super(options) { } @@ -45,15 +53,17 @@ class MarkdownCommandOptionsWriter : public CommandOptionsWriter virtual void appendDescriptionImpl() SLANG_OVERRIDE; void _appendParagraph(const UnownedStringSlice& text, LinkFlags flags = LinkFlag::All); - void _appendParagraph(const ConstArrayView& words, LinkFlags flags = LinkFlag::All); + void _appendParagraph( + const ConstArrayView& words, + LinkFlags flags = LinkFlag::All); - void _appendMaybeLink(const UnownedStringSlice& word, LinkFlags linkFlags); + void _appendMaybeLink(const UnownedStringSlice& word, LinkFlags linkFlags); void _appendText(const UnownedStringSlice& text); void _appendDescriptionForCategory(Index categoryIndex); UnownedStringSlice _getLinkName(CommandOptions::LookupKind kind, Index index); UnownedStringSlice _getLinkName(const NameKey& key, Index index); - + void _appendQuickLinks(); bool m_hasLinks = false; @@ -91,15 +101,16 @@ static bool _needsMarkdownEscape(const UnownedStringSlice& text) { switch (c) { - case '<': - case '>': - case '&': - case '[': - case ']': + case '<': + case '>': + case '&': + case '[': + case ']': { return true; } - default: break; + default: + break; } } @@ -115,12 +126,23 @@ void _appendEscapedMarkdown(const UnownedStringSlice& text, StringBuilder& ioBuf { switch (c) { - case '<': ioBuf << "<"; break; - case '>': ioBuf << ">"; break; - case '&': ioBuf << "&"; break; - case '[': ioBuf << "\\["; break; - case ']': ioBuf << "\\]"; break; - default: ioBuf << c; + case '<': + ioBuf << "<"; + break; + case '>': + ioBuf << ">"; + break; + case '&': + ioBuf << "&"; + break; + case '[': + ioBuf << "\\["; + break; + case ']': + ioBuf << "\\]"; + break; + default: + ioBuf << c; } } } @@ -149,7 +171,9 @@ void MarkdownCommandOptionsWriter::_appendQuickLinks() m_builder << "\n"; } -void MarkdownCommandOptionsWriter::_appendParagraph(const UnownedStringSlice& text, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendParagraph( + const UnownedStringSlice& text, + LinkFlags linkFlags) { List words; StringUtil::splitOnWhitespace(text, words); @@ -171,12 +195,16 @@ static UnownedStringSlice _trimPunctuation(const UnownedStringSlice& word) const char* start = word.begin(); const char* end = word.end(); - while (start < end && _isStartPunctionation(*start)) start++; - while (end > start && _isEndPunctionation(end[-1])) --end; + while (start < end && _isStartPunctionation(*start)) + start++; + while (end > start && _isEndPunctionation(end[-1])) + --end; return UnownedStringSlice(start, end); } -void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& inWord, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendMaybeLink( + const UnownedStringSlice& inWord, + LinkFlags linkFlags) { if (linkFlags) { @@ -190,17 +218,27 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in // Look for options if (trimmedWord[0] == '-' && (linkFlags & LinkFlag::Option)) { - index = m_commandOptions->findTargetIndexByName(LookupKind::Option, trimmedWord, &nameKey); + index = m_commandOptions->findTargetIndexByName( + LookupKind::Option, + trimmedWord, + &nameKey); } - else if (trimmedWord[0] == '<' && trimmedWord[trimmedWord.getLength() - 1] == '>' && (linkFlags & LinkFlag::Category)) + else if ( + trimmedWord[0] == '<' && trimmedWord[trimmedWord.getLength() - 1] == '>' && + (linkFlags & LinkFlag::Category)) { - index = m_commandOptions->findTargetIndexByName(LookupKind::Category, trimmedWord.subString(1, trimmedWord.getLength() - 2), &nameKey); + index = m_commandOptions->findTargetIndexByName( + LookupKind::Category, + trimmedWord.subString(1, trimmedWord.getLength() - 2), + &nameKey); } - + if (index > 0) { // Append before the link - _appendEscapedMarkdown(UnownedStringSlice(inWord.begin(), trimmedWord.begin()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(inWord.begin(), trimmedWord.begin()), + m_builder); // Make into a link m_builder << "["; @@ -208,7 +246,9 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in m_builder << "](#" << _getLinkName(nameKey, index) << ")"; // Append after the link - _appendEscapedMarkdown(UnownedStringSlice(trimmedWord.end(), inWord.end()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(trimmedWord.end(), inWord.end()), + m_builder); return; } } @@ -217,7 +257,9 @@ void MarkdownCommandOptionsWriter::_appendMaybeLink(const UnownedStringSlice& in _appendEscapedMarkdown(inWord, m_builder); } -void MarkdownCommandOptionsWriter::_appendParagraph(const ConstArrayView& words, LinkFlags linkFlags) +void MarkdownCommandOptionsWriter::_appendParagraph( + const ConstArrayView& words, + LinkFlags linkFlags) { if (m_hasLinks && linkFlags) { @@ -271,19 +313,21 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI if (m_hasLinks) { // Output anchor - m_builder << "\n"; + m_builder << "\n"; } m_builder << "# " << category.name << "\n\n"; - + // If there is a description output, making \n split paragraphs if (category.description.getLength() > 0) { _appendText(category.description); - } + } } - for (Index optionIndex = category.optionStartIndex; optionIndex < category.optionEndIndex; ++optionIndex) + for (Index optionIndex = category.optionStartIndex; optionIndex < category.optionEndIndex; + ++optionIndex) { const auto& option = options.getOptionAt(optionIndex); @@ -294,7 +338,7 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI if (isValue) { m_builder << "* "; - // Output all the names + // Output all the names m_builder << "`"; StringUtil::join(names.getBuffer(), names.getCount(), toSlice("`, `"), m_builder); m_builder << "` "; @@ -303,7 +347,8 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI { if (m_hasLinks) { - m_builder << "\n"; + m_builder << "\n"; } m_builder << "## "; @@ -322,17 +367,24 @@ void MarkdownCommandOptionsWriter::_appendDescriptionForCategory(Index categoryI const char* cur = option.usage.begin(); for (auto usedCategory : usedCategories) { - _appendEscapedMarkdown(UnownedStringSlice(cur, usedCategory.begin()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(cur, usedCategory.begin()), + m_builder); // Now do the link - const Index usedCategoryIndex = options.findCategoryByName(usedCategory); + const Index usedCategoryIndex = + options.findCategoryByName(usedCategory); - m_builder << "[" << usedCategory << "](#" << _getLinkName(LookupKind::Category, usedCategoryIndex) << ")"; + m_builder << "[" << usedCategory << "](#" + << _getLinkName(LookupKind::Category, usedCategoryIndex) + << ")"; cur = usedCategory.end(); } - _appendEscapedMarkdown(UnownedStringSlice(cur, option.usage.end()), m_builder); + _appendEscapedMarkdown( + UnownedStringSlice(cur, option.usage.end()), + m_builder); } else { @@ -370,9 +422,9 @@ UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(const NameKey& key return m_pool.getSlice(*ptr); } - UnownedStringSlice prefix = (key.kind == CommandOptions::LookupKind::Category) ? - m_commandOptions->getFirstNameForCategory(index) : - m_commandOptions->getFirstNameForOption(index); + UnownedStringSlice prefix = (key.kind == CommandOptions::LookupKind::Category) + ? m_commandOptions->getFirstNameForCategory(index) + : m_commandOptions->getFirstNameForOption(index); prefix = prefix.trim('-'); if (prefix.getLength() == 0) @@ -406,17 +458,17 @@ UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(const NameKey& key return m_pool.getSlice(handle); } -UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName(CommandOptions::LookupKind kind, Index index) +UnownedStringSlice MarkdownCommandOptionsWriter::_getLinkName( + CommandOptions::LookupKind kind, + Index index) { auto& options = *m_commandOptions; - // Set up the name key - const auto key = (kind == LookupKind::Category) ? - options.getNameKeyForCategory(index) : - options.getNameKeyForOption(index); - - return _getLinkName(key, index); + // Set up the name key + const auto key = (kind == LookupKind::Category) ? options.getNameKeyForCategory(index) + : options.getNameKeyForOption(index); + return _getLinkName(key, index); } /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TextCommandOptionsWriter !!!!!!!!!!!!!!!!!!!!!!!!!!! */ @@ -425,11 +477,12 @@ class TextCommandOptionsWriter : public CommandOptionsWriter { public: typedef CommandOptionsWriter Super; - - TextCommandOptionsWriter(const Options& options) : - Super(options) + + TextCommandOptionsWriter(const Options& options) + : Super(options) { } + protected: // CommandOptionsWriter virtual void appendDescriptionForCategoryImpl(Index categoryIndex) SLANG_OVERRIDE; @@ -580,26 +633,24 @@ void TextCommandOptionsWriter::_appendText(Count indentCount, const UnownedStrin typedef CommandOptionsWriter::Style Style; -static const NamesDescriptionValue s_styleInfos[] = -{ - { ValueInt(Style::Text), "text", "Text suitable for output to a terminal" }, - { ValueInt(Style::Markdown), "markdown", "Markdown" }, - { ValueInt(Style::NoLinkMarkdown), "no-link-markdown", "Markdown without links" }, +static const NamesDescriptionValue s_styleInfos[] = { + {ValueInt(Style::Text), "text", "Text suitable for output to a terminal"}, + {ValueInt(Style::Markdown), "markdown", "Markdown"}, + {ValueInt(Style::NoLinkMarkdown), "no-link-markdown", "Markdown without links"}, }; -/* static */ConstArrayView CommandOptionsWriter::getStyleInfos() +/* static */ ConstArrayView CommandOptionsWriter::getStyleInfos() { return makeConstArrayView(s_styleInfos); } -CommandOptionsWriter::CommandOptionsWriter(const Options& options) : - m_pool(StringSlicePool::Style::Default), - m_options(options) +CommandOptionsWriter::CommandOptionsWriter(const Options& options) + : m_pool(StringSlicePool::Style::Default), m_options(options) { m_options.indent = m_pool.addAndGetSlice(options.indent); } -/* static */RefPtr CommandOptionsWriter::create(const Options& options) +/* static */ RefPtr CommandOptionsWriter::create(const Options& options) { if (_isMarkdown(options.style)) { @@ -611,7 +662,9 @@ CommandOptionsWriter::CommandOptionsWriter(const Options& options) : } } -void CommandOptionsWriter::appendDescriptionForCategory(CommandOptions* options, Index categoryIndex) +void CommandOptionsWriter::appendDescriptionForCategory( + CommandOptions* options, + Index categoryIndex) { m_commandOptions = options; appendDescriptionForCategoryImpl(categoryIndex); @@ -667,7 +720,10 @@ void CommandOptionsWriter::_requireIndent(Count indentCount) } } -void CommandOptionsWriter::_appendWrappedIndented(Count indentCount, List& slices, const UnownedStringSlice& delimit) +void CommandOptionsWriter::_appendWrappedIndented( + Count indentCount, + List& slices, + const UnownedStringSlice& delimit) { Count lineLength = _getCurrentLineLength(); @@ -708,5 +764,3 @@ void CommandOptionsWriter::_appendWrappedIndented(Count indentCount, List getStyleInfos(); struct Options { - Style style = Style::Text; ///< The style - Index lineLength = 120; ///< The maximum amount of characters on a line - UnownedStringSlice indent = toSlice(" ");; + Style style = Style::Text; ///< The style + Index lineLength = 120; ///< The maximum amount of characters on a line + UnownedStringSlice indent = toSlice(" "); + ; }; - /// Append descirption for a category + /// Append descirption for a category void appendDescriptionForCategory(CommandOptions* options, Index categoryIndex); - /// Appends a description of all of the options + /// Appends a description of all of the options void appendDescription(CommandOptions* options); - /// Get the builder that string is being written to + /// Get the builder that string is being written to StringBuilder& getBuilder() { return m_builder; } static RefPtr create(const Options& options); - -protected: - /// Append descirption for a category +protected: + /// Append descirption for a category virtual void appendDescriptionForCategoryImpl(Index categoryIndex) = 0; - /// Appends a description of all of the options + /// Appends a description of all of the options virtual void appendDescriptionImpl() = 0; // Ctor, use create to create a writer CommandOptionsWriter(const Options& options); - /// Get the length of the current line in ascii chars/bytes + /// Get the length of the current line in ascii chars/bytes Count _getCurrentLineLength(); - /// Indentation/wrapping + /// Indentation/wrapping void _requireIndent(Count indentCount); - void _appendWrappedIndented(Count indentCount, List& slices, const UnownedStringSlice& delimit); - + void _appendWrappedIndented( + Count indentCount, + List& slices, + const UnownedStringSlice& delimit); + CommandOptions* m_commandOptions = nullptr; - StringSlicePool m_pool; + StringSlicePool m_pool; StringBuilder m_builder; Options m_options; }; } // namespace Slang -#endif +#endif diff --git a/source/core/slang-command-options.cpp b/source/core/slang-command-options.cpp index 5bbe59a0d8..a4bb8b552e 100644 --- a/source/core/slang-command-options.cpp +++ b/source/core/slang-command-options.cpp @@ -2,11 +2,12 @@ #include "slang-command-options.h" -#include "slang-string-util.h" -#include "slang-char-util.h" #include "slang-byte-encode-util.h" +#include "slang-char-util.h" +#include "slang-string-util.h" -namespace Slang { +namespace Slang +{ UnownedStringSlice CommandOptions::getFirstNameForOption(Index optionIndex) { @@ -26,7 +27,8 @@ CommandOptions::NameKey CommandOptions::getNameKeyForOption(Index optionIndex) const auto& cat = m_categories[opt.categoryIndex]; NameKey key; key.nameIndex = m_pool.findIndex(getFirstNameForOption(optionIndex)); - key.kind = (cat.kind == CategoryKind::Option) ? LookupKind::Option : makeLookupKind(opt.categoryIndex); + key.kind = + (cat.kind == CategoryKind::Option) ? LookupKind::Option : makeLookupKind(opt.categoryIndex); return key; } @@ -38,7 +40,10 @@ CommandOptions::NameKey CommandOptions::getNameKeyForCategory(Index categoryInde return key; } -SlangResult CommandOptions::_addName(LookupKind kind, const UnownedStringSlice& name, Index targetIndex) +SlangResult CommandOptions::_addName( + LookupKind kind, + const UnownedStringSlice& name, + Index targetIndex) { NameKey nameKey; nameKey.kind = kind; @@ -52,7 +57,10 @@ SlangResult CommandOptions::_addName(LookupKind kind, const UnownedStringSlice& return SLANG_OK; } -SlangResult CommandOptions::_addOptionName(const UnownedStringSlice& name, Flags flags, Index targetIndex) +SlangResult CommandOptions::_addOptionName( + const UnownedStringSlice& name, + Flags flags, + Index targetIndex) { SLANG_RETURN_ON_FAIL(_addName(LookupKind::Option, name, targetIndex)); @@ -67,7 +75,10 @@ SlangResult CommandOptions::_addOptionName(const UnownedStringSlice& name, Flags return SLANG_OK; } -SlangResult CommandOptions::_addValueName(const UnownedStringSlice& name, Index categoryIndex, Index optionIndex) +SlangResult CommandOptions::_addValueName( + const UnownedStringSlice& name, + Index categoryIndex, + Index optionIndex) { return _addName(LookupKind(categoryIndex), name, optionIndex); } @@ -122,7 +133,10 @@ Index CommandOptions::_addOption(const UnownedStringSlice& name, const Option& i } } -Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCount, const Option& inOption) +Index CommandOptions::_addOption( + const UnownedStringSlice* names, + Count namesCount, + const Option& inOption) { SLANG_ASSERT(namesCount > 0); SLANG_ASSERT(inOption.categoryIndex >= 0); @@ -134,7 +148,8 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou auto& cat = m_categories[inOption.categoryIndex]; - // If there are already options associated with this category, we have to be in the run of the last ones added + // If there are already options associated with this category, we have to be in the run of the + // last ones added if (cat.optionStartIndex != cat.optionEndIndex) { // If we aren't at the end then this is an error @@ -172,9 +187,10 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou { for (Index i = 0; i < namesCount; ++i) { - _addValueName(names[i], inOption.categoryIndex, optionIndex); + _addValueName(names[i], inOption.categoryIndex, optionIndex); } - if (SLANG_FAILED(_addUserValue(LookupKind(inOption.categoryIndex), inOption.userValue, optionIndex))) + if (SLANG_FAILED( + _addUserValue(LookupKind(inOption.categoryIndex), inOption.userValue, optionIndex))) { return -1; } @@ -198,7 +214,7 @@ Index CommandOptions::_addOption(const UnownedStringSlice* names, Count namesCou // Set the end index cat.optionEndIndex = optionIndex + 1; - + return optionIndex; } @@ -219,7 +235,11 @@ static void _handlePostFix(UnownedStringSlice& ioSlice, CommandOptions::Flags& i } } -void CommandOptions::add(const char* inName, const char* usage, const char* description, UserValue userValue) +void CommandOptions::add( + const char* inName, + const char* usage, + const char* description, + UserValue userValue) { UnownedStringSlice nameSlice(inName); @@ -250,7 +270,13 @@ void CommandOptions::add(const char* inName, const char* usage, const char* desc } } -void CommandOptions::add(const UnownedStringSlice* names, Count namesCount, const char* usage, const char* description, UserValue userValue, Flags flags) +void CommandOptions::add( + const UnownedStringSlice* names, + Count namesCount, + const char* usage, + const char* description, + UserValue userValue, + Flags flags) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -337,7 +363,10 @@ void CommandOptions::addValue(const UnownedStringSlice& name, UserValue userValu _addValue(name, option); } -void CommandOptions::addValue(const UnownedStringSlice& name, const UnownedStringSlice& description, UserValue userValue) +void CommandOptions::addValue( + const UnownedStringSlice& name, + const UnownedStringSlice& description, + UserValue userValue) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -346,7 +375,10 @@ void CommandOptions::addValue(const UnownedStringSlice& name, const UnownedStrin _addValue(name, option); } -void CommandOptions::addValue(const UnownedStringSlice* names, Count namesCount, UserValue userValue) +void CommandOptions::addValue( + const UnownedStringSlice* names, + Count namesCount, + UserValue userValue) { Option option; option.categoryIndex = m_currentCategoryIndex; @@ -377,7 +409,11 @@ void CommandOptions::addValue(const char* name, UserValue userValue) addValue(UnownedStringSlice(name), userValue); } -Index CommandOptions::addCategory(CategoryKind kind, const char* name, const char* description, UserValue userValue) +Index CommandOptions::addCategory( + CategoryKind kind, + const char* name, + const char* description, + UserValue userValue) { const UnownedStringSlice nameSlice(name); @@ -425,7 +461,10 @@ void CommandOptions::setCategory(const char* name) m_currentCategoryIndex = -1; } -Index CommandOptions::findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey) const +Index CommandOptions::findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey) const { // Look up directly { @@ -470,7 +509,10 @@ Index CommandOptions::findTargetIndexByName(LookupKind kind, const UnownedString return -1; } -Index CommandOptions::_findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey) const +Index CommandOptions::_findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey) const { const auto nameIndex = m_pool.findIndex(name); // If the name isn't in the pool then there isn't a category with this name @@ -524,7 +566,9 @@ Index CommandOptions::findCategoryByCaseInsensitiveName(const UnownedStringSlice return -1; } -Index CommandOptions::findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) const +Index CommandOptions::findOptionByCategoryUserValue( + UserValue categoryUserValue, + const UnownedStringSlice& name) const { Index categoryIndex = findTargetIndexByUserValue(LookupKind::Category, categoryUserValue); if (categoryIndex < 0) @@ -535,14 +579,19 @@ Index CommandOptions::findOptionByCategoryUserValue(UserValue categoryUserValue, return findValueByName(categoryIndex, name); } -ConstArrayView CommandOptions::getOptionsForCategory(Index categoryIndex) const +ConstArrayView CommandOptions::getOptionsForCategory( + Index categoryIndex) const { const auto& cat = m_categories[categoryIndex]; - return makeConstArrayView(m_options.getBuffer() + cat.optionStartIndex, cat.optionEndIndex - cat.optionStartIndex); + return makeConstArrayView( + m_options.getBuffer() + cat.optionStartIndex, + cat.optionEndIndex - cat.optionStartIndex); } -void CommandOptions::appendCategoryOptionNames(Index categoryIndex, List& outNames) const +void CommandOptions::appendCategoryOptionNames( + Index categoryIndex, + List& outNames) const { for (const auto& option : getOptionsForCategory(categoryIndex)) { @@ -550,28 +599,33 @@ void CommandOptions::appendCategoryOptionNames(Index categoryIndex, List& outNames) const +void CommandOptions::getCategoryOptionNames(Index categoryIndex, List& outNames) + const { outNames.clear(); appendCategoryOptionNames(categoryIndex, outNames); } -void CommandOptions::splitUsage(const UnownedStringSlice& usageSlice, List& outSlices) const +void CommandOptions::splitUsage( + const UnownedStringSlice& usageSlice, + List& outSlices) const { const auto* cur = usageSlice.begin(); const auto* end = usageSlice.end(); while (cur < end) { - // Find < - while (cur < end && *cur != '<') cur++; + // Find < + while (cur < end && *cur != '<') + cur++; // If we found it look for the end if (cur < end && *cur == '<') { ++cur; auto start = cur; - while (cur < end && (CharUtil::isAlphaOrDigit(*cur) || *cur == '-' || *cur == '_') && *cur != '>') + while (cur < end && (CharUtil::isAlphaOrDigit(*cur) || *cur == '-' || *cur == '_') && + *cur != '>') { cur++; } @@ -594,7 +648,9 @@ void CommandOptions::splitUsage(const UnownedStringSlice& usageSlice, List& outCategories) const +void CommandOptions::findCategoryIndicesFromUsage( + const UnownedStringSlice& slice, + List& outCategories) const { List categoryNames; splitUsage(slice, categoryNames); @@ -609,7 +665,10 @@ void CommandOptions::findCategoryIndicesFromUsage(const UnownedStringSlice& slic } } -Count CommandOptions::getOptionCountInRange(Index categoryIndex, UserValue start, UserValue nonInclEnd) const +Count CommandOptions::getOptionCountInRange( + Index categoryIndex, + UserValue start, + UserValue nonInclEnd) const { const UserIndex startIndex = UserIndex(start); const UserIndex endIndex = UserIndex(nonInclEnd); @@ -631,7 +690,8 @@ Count CommandOptions::getOptionCountInRange(Index categoryIndex, UserValue start return count; } -Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const +Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, UserValue nonInclEnd) + const { Index count = 0; @@ -671,7 +731,10 @@ Count CommandOptions::getOptionCountInRange(LookupKind kind, UserValue start, Us } -bool CommandOptions::hasContiguousUserValueRange(LookupKind kind, UserValue start, UserValue nonInclEnd) const +bool CommandOptions::hasContiguousUserValueRange( + LookupKind kind, + UserValue start, + UserValue nonInclEnd) const { const Count rangeCount = Count(nonInclEnd) - Count(start); SLANG_ASSERT(rangeCount >= 0); @@ -686,5 +749,3 @@ bool CommandOptions::hasContiguousUserValueRange(LookupKind kind, UserValue star } } // namespace Slang - - diff --git a/source/core/slang-command-options.h b/source/core/slang-command-options.h index 8b6d7b0ce2..9d7af44d94 100644 --- a/source/core/slang-command-options.h +++ b/source/core/slang-command-options.h @@ -2,13 +2,13 @@ #define SLANG_CORE_COMMAND_OPTIONS_H #include "slang-basic.h" -#include "slang-string-slice-pool.h" #include "slang-name-value.h" +#include "slang-string-slice-pool.h" namespace Slang { -/* For convenience we encode within "names" flags. +/* For convenience we encode within "names" flags. "-D..." means that -D *must* be followed by the value "-D?..." means that -D *can* be a prefix, or it might be followed with the arg */ @@ -23,29 +23,36 @@ struct CommandOptions enum class LookupKind : int32_t { - Category = -2, ///< Lookup a category name - Option = -1, ///< Lookup an option name (all options use the same lookup index even if in different categories) - Base = 0, ///< Lookup via category index + Category = -2, ///< Lookup a category name + Option = -1, ///< Lookup an option name (all options use the same lookup index even if in + ///< different categories) + Base = 0, ///< Lookup via category index }; - /// A key type that uses the combination of the lookup kind and a name index. - /// Maps to a target index that could be a category or an option index. + /// A key type that uses the combination of the lookup kind and a name index. + /// Maps to a target index that could be a category or an option index. struct NameKey { typedef NameKey ThisType; - SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const { return kind == rhs.kind && nameIndex == rhs.nameIndex; } + SLANG_FORCE_INLINE bool operator==(const ThisType& rhs) const + { + return kind == rhs.kind && nameIndex == rhs.nameIndex; + } SLANG_FORCE_INLINE bool operator!=(const ThisType& rhs) const { return !(*this == rhs); } - HashCode getHashCode() const { return combineHash(Slang::getHashCode(kind), Slang::getHashCode(nameIndex)); } + HashCode getHashCode() const + { + return combineHash(Slang::getHashCode(kind), Slang::getHashCode(nameIndex)); + } - LookupKind kind; ///< The kind of lookup - Index nameIndex; ///< The name index in the pool + LookupKind kind; ///< The kind of lookup + Index nameIndex; ///< The name index in the pool }; enum class CategoryKind { - Option, ///< Command line option (like "-D") - Value, ///< One of a set of values (such as an enum or some other kind of list of values) + Option, ///< Command line option (like "-D") + Value, ///< One of a set of values (such as an enum or some other kind of list of values) }; struct ValuePair @@ -71,128 +78,179 @@ struct CommandOptions { enum Enum : Flags { - CanPrefix = 0x1, /// Allows -Dfsggf or -D fdsfsd - IsPrefix = 0x2, /// Is an option that can only be a prefix + CanPrefix = 0x1, /// Allows -Dfsggf or -D fdsfsd + IsPrefix = 0x2, /// Is an option that can only be a prefix }; }; struct Option { - UnownedStringSlice names; ///< Comma delimited list of names, first name is the default - UnownedStringSlice usage; ///< Describes usage, can be empty - UnownedStringSlice description; ///< A description of usage + UnownedStringSlice names; ///< Comma delimited list of names, first name is the default + UnownedStringSlice usage; ///< Describes usage, can be empty + UnownedStringSlice description; ///< A description of usage UserValue userValue = kInvalidUserValue; - Index categoryIndex = -1; ///< Category this option belongs to - Flags flags = 0; ///< Flags about this option + Index categoryIndex = -1; ///< Category this option belongs to + Flags flags = 0; ///< Flags about this option }; - /// Get the first name + /// Get the first name UnownedStringSlice getFirstNameForOption(Index optionIndex); - /// Get the first name for the category + /// Get the first name for the category UnownedStringSlice getFirstNameForCategory(Index categoryIndex); - /// Get a name key for an opton + /// Get a name key for an opton NameKey getNameKeyForOption(Index optionIndex); - /// Get a name key for a category + /// Get a name key for a category NameKey getNameKeyForCategory(Index optionIndex); - /// Add a category - Index addCategory(CategoryKind kind, const char* name, const char* description, UserValue userValue = kInvalidUserValue); - /// Use an already known category. It's an error if the category isn't found + /// Add a category + Index addCategory( + CategoryKind kind, + const char* name, + const char* description, + UserValue userValue = kInvalidUserValue); + /// Use an already known category. It's an error if the category isn't found void setCategory(const char* name); - void add(const char* name, const char* usage, const char* description, UserValue userValue = kInvalidUserValue); - void add(const UnownedStringSlice* names, Count namesCount, const char* usage, const char* description, UserValue userValue = kInvalidUserValue, Flags flags = 0); + void add( + const char* name, + const char* usage, + const char* description, + UserValue userValue = kInvalidUserValue); + void add( + const UnownedStringSlice* names, + Count namesCount, + const char* usage, + const char* description, + UserValue userValue = kInvalidUserValue, + Flags flags = 0); void addValue(const UnownedStringSlice& name, UserValue userValue = kInvalidUserValue); - void addValue(const UnownedStringSlice& name, const UnownedStringSlice& description, UserValue userValue = kInvalidUserValue); - void addValue(const char* name, const char* description, UserValue userValue = kInvalidUserValue); + void addValue( + const UnownedStringSlice& name, + const UnownedStringSlice& description, + UserValue userValue = kInvalidUserValue); + void addValue( + const char* name, + const char* description, + UserValue userValue = kInvalidUserValue); void addValue(const char* name, UserValue userValue = kInvalidUserValue); - void addValue(const UnownedStringSlice* names, Count namesCount, UserValue userValue = kInvalidUserValue); + void addValue( + const UnownedStringSlice* names, + Count namesCount, + UserValue userValue = kInvalidUserValue); - /// Add values (without UserValue association) + /// Add values (without UserValue association) void addValues(const ValuePair* pairs, Count pairsCount); - /// Add values + /// Add values void addValues(const ConstArrayView& values); void addValues(const ConstArrayView& values); void addValues(const ConstArrayView& values); - /// Sometimes values are listed with *names* per value. This method will take into account the aliases + /// Sometimes values are listed with *names* per value. This method will take into account the + /// aliases void addValuesWithAliases(const ConstArrayView& values); - /// Get the target index based off the name and the kind - Index findTargetIndexByName(LookupKind kind, const UnownedStringSlice& name, NameKey* outNameKey = nullptr) const; - /// Given a kind and a user value lookup the target index + /// Get the target index based off the name and the kind + Index findTargetIndexByName( + LookupKind kind, + const UnownedStringSlice& name, + NameKey* outNameKey = nullptr) const; + /// Given a kind and a user value lookup the target index Index findTargetIndexByUserValue(LookupKind kind, UserValue userValue) const; - /// Finds the category by name or -1 if not found - Index findCategoryByName(const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind::Category, name); } - /// Finds the option index by name or -1 if not found - Index findOptionByName(const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind::Option, name); } - /// Find the option index of a value, using it's category index and the name - Index findValueByName(Index categoryIndex, const UnownedStringSlice& name) const { return findTargetIndexByName(LookupKind(categoryIndex), name); } - - /// Get the category index from a user value - Index findCategoryByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Category, userValue); } - /// Can only get options - Index findOptionByUserValue(UserValue userValue) const { return findTargetIndexByUserValue(LookupKind::Option, userValue); } - /// Get a value associated with a category - Index findValueByUserValue(Index categoryIndex, UserValue userValue) const { return findTargetIndexByUserValue(LookupKind(categoryIndex), userValue); } - - /// Given a category user value, find the associated name - /// Returns -1 if not found - Index findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) const; - - /// Find a category by case insensitive name. Returns -1 if not found + /// Finds the category by name or -1 if not found + Index findCategoryByName(const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind::Category, name); + } + /// Finds the option index by name or -1 if not found + Index findOptionByName(const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind::Option, name); + } + /// Find the option index of a value, using it's category index and the name + Index findValueByName(Index categoryIndex, const UnownedStringSlice& name) const + { + return findTargetIndexByName(LookupKind(categoryIndex), name); + } + + /// Get the category index from a user value + Index findCategoryByUserValue(UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind::Category, userValue); + } + /// Can only get options + Index findOptionByUserValue(UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind::Option, userValue); + } + /// Get a value associated with a category + Index findValueByUserValue(Index categoryIndex, UserValue userValue) const + { + return findTargetIndexByUserValue(LookupKind(categoryIndex), userValue); + } + + /// Given a category user value, find the associated name + /// Returns -1 if not found + Index findOptionByCategoryUserValue(UserValue categoryUserValue, const UnownedStringSlice& name) + const; + + /// Find a category by case insensitive name. Returns -1 if not found Index findCategoryByCaseInsensitiveName(const UnownedStringSlice& slice) const; - - /// Given a category index returns all the options associated. + + /// Given a category index returns all the options associated. ConstArrayView